Skip to content

Commit 1bf3a4d

Browse files
committed
WIP settings + s3 storage
1 parent a678fff commit 1bf3a4d

File tree

10 files changed

+215
-15
lines changed

10 files changed

+215
-15
lines changed

service/src/app.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ import { ExtensionsModule } from '~/extensions/extensions.module'
2020
import { EventEmitterModule } from '@nestjs/event-emitter'
2121
import { FactorydriveModule, FactorydriveService } from '@streamkits/nestjs_module_factorydrive'
2222
import { AwsS3Storage } from '@streamkits/nestjs_module_factorydrive-s3'
23+
import { SettingsModule } from '~/core/settings/settings.module'
2324

2425
@Module({
2526
imports: [
2627
ConfigModule.forRoot({
2728
isGlobal: true,
2829
load: [config],
2930
}),
31+
SettingsModule.forRoot(),
3032
MongooseModule.forRootAsync({
3133
imports: [ConfigModule],
3234
inject: [ConfigService],

service/src/config.ts

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { HelmetOptions } from 'helmet'
66
import { RedisOptions } from 'ioredis'
77
import * as process from 'process'
88
import { StorageManagerConfig } from '@streamkits/nestjs_module_factorydrive'
9+
import { AmazonWebServicesS3StorageConfig } from '@streamkits/nestjs_module_factorydrive-s3'
10+
import { Settings } from '~/core/settings/settings.interface'
911

1012
export interface MongoosePlugin {
1113
package: string
@@ -34,11 +36,16 @@ export interface ConfigInstance {
3436
// options: BuildOpenIdClientOptions
3537
// }
3638
factorydrive: {
37-
options: StorageManagerConfig
39+
options: StorageManagerConfig | {
40+
disks: {
41+
[key: string]: {
42+
driver: 's3'
43+
config: AmazonWebServicesS3StorageConfig
44+
}
45+
}
46+
}
3847
}
39-
// s3: {
40-
// options: S3ClientConfig
41-
// }
48+
settings: Settings
4249
i18n: {
4350
fallbackLanguage: string
4451
}
@@ -121,17 +128,35 @@ export default (): ConfigInstance => ({
121128
root: process.cwd() + '/storage',
122129
},
123130
},
124-
// s3: {
125-
// driver: 's3',
126-
// config: {
127-
// key: 'AKIAIOSFODNN7EXAMPLE',
128-
// secret: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
129-
// endpoint: 'http://teaket-minio:9000/',
130-
// },
131-
// },
131+
s3: {
132+
driver: 's3',
133+
config: {
134+
credentials: {
135+
accessKeyId: 'AKIAIOSFODNN7EXAMPLE',
136+
secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
137+
},
138+
endpoint: 'http://localhost:9000/',
139+
region: 'us-east-1',
140+
bucket: 'teaket',
141+
forcePathStyle: true,
142+
},
143+
},
132144
},
133145
},
134146
},
147+
settings: {
148+
tickets: {
149+
ticket: {
150+
schema: {
151+
sequence: {
152+
prefix: 'TK',
153+
suffix: '',
154+
length: 6,
155+
},
156+
}
157+
}
158+
},
159+
},
135160
i18n: {
136161
fallbackLanguage: 'en',
137162
},

service/src/core/auth/auth.controller.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import { ModuleRef } from '@nestjs/core'
88
import { AuthGuard } from '@nestjs/passport'
99
import { IdentityType } from '~/_common/types/identity.type'
1010
import { ReqIdentity } from '~/_common/decorators/params/req-identity.decorator'
11+
import { SettingsService } from '~/core/settings/settings.service'
12+
import { SettingFor } from '~/core/settings/_enum/setting-for.enum'
1113

1214
@Public()
1315
@ApiTags('core')
@@ -16,6 +18,7 @@ export class AuthController extends AbstractController {
1618
constructor(
1719
protected moduleRef: ModuleRef,
1820
private readonly service: AuthService,
21+
private readonly settings: SettingsService,
1922
) {
2023
super()
2124
}
@@ -34,8 +37,12 @@ export class AuthController extends AbstractController {
3437
@UseGuards(AuthGuard('jwt'))
3538
public async session(@Res() res: Response, @ReqIdentity() identity: IdentityType): Promise<Response> {
3639
const user = await this.service.getSessionData(identity)
40+
const settings = await this.settings.settings([SettingFor.USER, SettingFor.ROLE], identity)
3741
return res.status(HttpStatus.OK).json({
38-
user,
42+
user: {
43+
...user,
44+
settings,
45+
},
3946
})
4047
}
4148

service/src/core/projects/project.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { AbstractServiceSchema } from '~/_common/abstracts/abstract.service.sche
66

77
@Injectable()
88
export class ProjectService extends AbstractServiceSchema {
9-
constructor(@InjectModel(Project.name) protected _model: Model<Project>) {
9+
public constructor(@InjectModel(Project.name) protected _model: Model<Project>) {
1010
super()
1111
}
1212
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export enum SettingFor {
2+
ALL = 0,
3+
ROLE = 25,
4+
USER = 99,
5+
}
6+
7+
export const SettingForList: number[] = Object.keys(SettingFor)
8+
.filter((k) => typeof SettingFor[k as any] === 'number')
9+
.map((k) => parseInt(SettingFor[k as any], 10))
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'
2+
import { AbstractSchema } from '~/_common/abstracts/schemas/abstract.schema'
3+
import { Schema as MongooseSchema } from 'mongoose'
4+
import { MixedSettingValue } from '~/core/settings/settings.interface'
5+
import { SettingFor, SettingForList } from '~/core/settings/_enum/setting-for.enum'
6+
7+
@Schema({
8+
collection: 'settings',
9+
versionKey: false,
10+
})
11+
export class Setting extends AbstractSchema {
12+
@Prop({
13+
type: String,
14+
required: true,
15+
})
16+
public key: string
17+
18+
@Prop({
19+
type: Number,
20+
default: SettingFor.ALL,
21+
enum: SettingForList,
22+
})
23+
public for: SettingFor
24+
25+
@Prop({
26+
type: String,
27+
})
28+
public scope?: string
29+
30+
@Prop({
31+
type: MongooseSchema.Types.Mixed,
32+
required: true,
33+
})
34+
public value: MixedSettingValue
35+
}
36+
37+
export const SettingSchema = SchemaFactory.createForClass(Setting)
38+
.index({ key: 1, for: 1, scope: 1 }, { unique: true })
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Types } from 'mongoose'
2+
3+
export type MixedSettingValue = string | Types.ObjectId | Date | number | boolean | null | object
4+
5+
export interface SettingsDefaults {
6+
[key: string]: SettingsDefaults | MixedSettingValue
7+
}
8+
9+
export interface Settings extends SettingsDefaults {
10+
tickets: {
11+
ticket: {
12+
schema: {
13+
sequence: {
14+
prefix: string
15+
suffix: string
16+
length: number
17+
}
18+
}
19+
}
20+
}
21+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { DynamicModule, Global, Module } from '@nestjs/common'
2+
import { MongooseModule } from '@nestjs/mongoose'
3+
import { SettingsService } from '~/core/settings/settings.service'
4+
import { Setting, SettingSchema } from '~/core/settings/_schemas/setting.schema'
5+
6+
@Global()
7+
@Module({
8+
imports: [
9+
MongooseModule.forFeatureAsync([
10+
{
11+
name: Setting.name,
12+
useFactory: () => SettingSchema,
13+
},
14+
]),
15+
],
16+
providers: [SettingsService],
17+
exports: [SettingsService],
18+
})
19+
export class SettingsModule {
20+
public static forRoot(): DynamicModule {
21+
return {
22+
module: this,
23+
}
24+
}
25+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { Injectable } from '@nestjs/common'
2+
import { InjectModel } from '@nestjs/mongoose'
3+
import { Model } from 'mongoose'
4+
import { Setting } from '~/core/settings/_schemas/setting.schema'
5+
import { AbstractService } from '~/_common/abstracts/abstract.service'
6+
import { ConfigService } from '@nestjs/config'
7+
import { MixedSettingValue } from '~/core/settings/settings.interface'
8+
import { SettingFor } from '~/core/settings/_enum/setting-for.enum'
9+
import { IdentityType } from '~/_common/types/identity.type'
10+
import { set } from 'radash'
11+
12+
@Injectable()
13+
export class SettingsService extends AbstractService {
14+
public constructor(
15+
protected readonly config: ConfigService,
16+
@InjectModel(Setting.name) protected _model: Model<Setting>,
17+
) {
18+
super()
19+
}
20+
21+
public async settings(forType: SettingFor[], identity: IdentityType): Promise<any> {
22+
const settingsBase = this.config.get<MixedSettingValue>(`settings`)
23+
const filters = [{ for: SettingFor.ALL, scope: null }]
24+
forType.forEach((type) => {
25+
switch (type) {
26+
case SettingFor.USER: {
27+
filters.push({ for: type, scope: identity._id.toString() })
28+
break
29+
}
30+
case SettingFor.ROLE: {
31+
for (const role of identity.roles) {
32+
filters.push({ for: type, scope: role })
33+
}
34+
}
35+
}
36+
})
37+
const settings = await this._model.find(
38+
{ $or: filters },
39+
{ key: 1, value: 1, _id: 0 },
40+
{ sort: { for: 1, scope: 1 } },
41+
)
42+
43+
for (const setting of settings) {
44+
set(settingsBase as object, setting.key, setting.value)
45+
}
46+
return settingsBase
47+
}
48+
49+
protected setting<T>(name: string): T | MixedSettingValue {
50+
return this.config.get<MixedSettingValue>(`settings.${name}`)
51+
}
52+
53+
public async get<T>(name: string): Promise<T | MixedSettingValue> {
54+
const setting = await this._model.findOne({ name })
55+
if (setting) return setting.value
56+
return this.setting<T>(name)
57+
}
58+
59+
public async set<T>(
60+
key: string,
61+
value: T | MixedSettingValue,
62+
options?: { for: SettingFor, scope: string },
63+
): Promise<T | MixedSettingValue> {
64+
const updated = await this._model.findOneAndUpdate(
65+
{ key },
66+
{ $set: { value, ...options } },
67+
{ upsert: true, new: true },
68+
)
69+
return updated.value
70+
}
71+
}

service/src/tickets/ticket/ticket.service.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ import { FragmentType } from '~/tickets/thread/_enum/fragment-type.enum'
1111
import { ThreadType } from '~/tickets/thread/_enum/thread-type.enum'
1212
import { I18nService } from 'nestjs-i18n'
1313
import { isEqual, reduce } from 'radash'
14+
import { SettingsService } from '~/core/settings/settings.service'
1415

1516
@Injectable({ scope: Scope.REQUEST })
1617
export class TicketService extends AbstractServiceSchema {
1718
public constructor(
1819
protected readonly moduleRef: ModuleRef,
1920
@Inject(forwardRef(() => ThreadService))
2021
protected readonly threadService: ThreadService,
22+
protected readonly settings: SettingsService,
2123
private readonly i18n: I18nService,
2224
// private readonly i18n: I18nService<I18nTranslations>,
2325
@InjectModel(Ticket.name) protected _model: Model<Ticket>,
@@ -45,7 +47,7 @@ export class TicketService extends AbstractServiceSchema {
4547
updated = await super.update<T>(_id, update, { ...options, session })
4648
const diff = await reduce(
4749
Object.keys(update),
48-
async (acc, key) => isEqual(update[key], beforeData[key]) ? acc : acc.concat(key),
50+
async (acc, key) => isEqual(update[key], beforeData[key]) ? acc : acc.concat(key),
4951
[],
5052
)
5153
if (diff.length) {

0 commit comments

Comments
 (0)