From d1316704eb95efc6c707e24b7fab59172615ef02 Mon Sep 17 00:00:00 2001 From: Sean Sube Date: Sun, 20 Jan 2019 23:48:41 -0600 Subject: [PATCH] feat: user locale data (#112) --- README.md | 3 ++- src/controller/AccountController.ts | 3 ++- src/controller/UserController.ts | 3 ++- src/entity/auth/User.ts | 31 +++++++++++++++++++++++ src/index.ts | 2 +- src/migration/0001548049058-UserLocale.ts | 19 ++++++++++++++ src/module/MigrationModule.ts | 2 ++ test/entity/TestContext.ts | 4 ++- 8 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 src/migration/0001548049058-UserLocale.ts diff --git a/README.md b/README.md index 8df81ee0f..d45301b32 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ The [getting started guide](./docs/getting-started.md) has more information on u ## Status [![Pipeline status](https://img.shields.io/gitlab/pipeline/ssube/isolex.svg?gitlab_url=https%3A%2F%2Fgit.apextoaster.com&logo=gitlab)](https://git.apextoaster.com/ssube/isolex/commits/master) -[![Test coverage](https://codecov.io/gh/ssube/isolex/branch/master/graph/badge.svg)](https://codecov.io/gh/ssube/isolex) +[![Test coverage](https://sonarcloud.io/api/project_badges/measure?project=ssube_isolex&metric=coverage)](https://sonarcloud.io/dashboard?id=ssube_isolex) [![MIT license](https://img.shields.io/github/license/ssube/isolex.svg)](https://github.com/ssube/isolex/blob/master/LICENSE.md) [![Open bug count](https://img.shields.io/github/issues-raw/ssube/isolex/type-bug.svg)](https://github.com/ssube/isolex/issues?q=is%3Aopen+is%3Aissue+label%3Atype%2Fbug) @@ -25,6 +25,7 @@ The [getting started guide](./docs/getting-started.md) has more information on u [![Dependency status](https://img.shields.io/david/ssube/isolex.svg)](https://david-dm.org/ssube/isolex) [![Dev dependency status](https://img.shields.io/david/dev/ssube/isolex.svg)](https://david-dm.org/ssube/isolex?type=dev) +[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=ssube_isolex&metric=ncloc)](https://sonarcloud.io/dashboard?id=ssube_isolex) [![Maintainability score](https://api.codeclimate.com/v1/badges/5d4326d6f68a2fa137cd/maintainability)](https://codeclimate.com/github/ssube/isolex/maintainability) [![Technical debt ratio](https://img.shields.io/codeclimate/tech-debt/ssube/isolex.svg)](https://codeclimate.com/github/ssube/isolex/trends/technical_debt) [![Quality issues](https://img.shields.io/codeclimate/issues/ssube/isolex.svg)](https://codeclimate.com/github/ssube/isolex/issues) diff --git a/src/controller/AccountController.ts b/src/controller/AccountController.ts index 91102349e..1c84d21df 100644 --- a/src/controller/AccountController.ts +++ b/src/controller/AccountController.ts @@ -9,7 +9,7 @@ import { BaseController, BaseControllerOptions, ErrorReplyType } from 'src/contr import { createCommandCompletion } from 'src/controller/helpers'; import { Role } from 'src/entity/auth/Role'; import { Token } from 'src/entity/auth/Token'; -import { User } from 'src/entity/auth/User'; +import { LOCALE_DEFAULT, User } from 'src/entity/auth/User'; import { UserRepository } from 'src/entity/auth/UserRepository'; import { Command, CommandVerb } from 'src/entity/Command'; import { Context } from 'src/entity/Context'; @@ -104,6 +104,7 @@ export class AccountController extends BaseController imp }, }); const user = await this.userRepository.save(new User({ + locale: LOCALE_DEFAULT, name, roles, })); diff --git a/src/controller/UserController.ts b/src/controller/UserController.ts index 5f5ef8218..97f199048 100644 --- a/src/controller/UserController.ts +++ b/src/controller/UserController.ts @@ -6,7 +6,7 @@ import { INJECT_STORAGE } from 'src/BotService'; import { CheckRBAC, Controller, ControllerData, Handler } from 'src/controller'; import { BaseController, BaseControllerOptions } from 'src/controller/BaseController'; import { Role } from 'src/entity/auth/Role'; -import { User } from 'src/entity/auth/User'; +import { LOCALE_DEFAULT, User } from 'src/entity/auth/User'; import { UserRepository } from 'src/entity/auth/UserRepository'; import { Command, CommandVerb } from 'src/entity/Command'; import { Context } from 'src/entity/Context'; @@ -88,6 +88,7 @@ export class UserController extends BaseController implement this.logger.debug({ roles }, 'found roles'); const user = await this.userRepository.save(new User({ + locale: LOCALE_DEFAULT, name, roles, })); diff --git a/src/entity/auth/User.ts b/src/entity/auth/User.ts index 92f0d7d7a..b25215fe7 100644 --- a/src/entity/auth/User.ts +++ b/src/entity/auth/User.ts @@ -5,11 +5,29 @@ import { GRAPH_OUTPUT_ROLE, Role } from 'src/entity/auth/Role'; import { BaseEntity, BaseEntityOptions } from 'src/entity/base/BaseEntity'; import { doesExist } from 'src/utils'; +export interface UserLocale { + date: string; + lang: string; + time: string; + timezone: string; +} + export interface UserOptions extends BaseEntityOptions { + locale: UserLocale; name: string; roles: Array; } +/** + * TODO: do this without hard-coded fallbacks + */ +export const LOCALE_DEFAULT = { + date: 'YYYY-MM-DD', + lang: 'en-US', + time: 'HH:MM:SSZ', + timezone: 'GMT', +}; + export const TABLE_USER = 'user'; @Entity(TABLE_USER) @@ -17,6 +35,11 @@ export class User extends BaseEntity implements UserOptions { @PrimaryGeneratedColumn('uuid') public id?: string; + @Column({ + type: 'simple-json', + }) + public locale: UserLocale; + @Column({ unique: true, }) @@ -34,8 +57,16 @@ export class User extends BaseEntity implements UserOptions { super(options); if (doesExist(options)) { + this.locale = { + ...LOCALE_DEFAULT, + ...options.locale, + }; this.name = options.name; this.roles = options.roles; + } else { + this.locale = { + ...LOCALE_DEFAULT, + }; } } diff --git a/src/index.ts b/src/index.ts index bfbea0335..e580dda24 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,7 +15,7 @@ import { ParserModule } from 'src/module/ParserModule'; import { ServiceModule } from 'src/module/ServiceModule'; import { TransformModule } from 'src/module/TransformModule'; import { Schema } from 'src/schema'; -import { ServiceEvent, ServiceDefinition } from 'src/Service'; +import { ServiceDefinition, ServiceEvent } from 'src/Service'; import { BunyanLogger } from 'src/utils/BunyanLogger'; import { signal, SIGNAL_RELOAD, SIGNAL_RESET, SIGNAL_STOP } from 'src/utils/Signal'; import { VERSION_INFO } from 'src/version'; diff --git a/src/migration/0001548049058-UserLocale.ts b/src/migration/0001548049058-UserLocale.ts new file mode 100644 index 000000000..948fc84ba --- /dev/null +++ b/src/migration/0001548049058-UserLocale.ts @@ -0,0 +1,19 @@ +import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm'; + +import { TABLE_USER } from 'src/entity/auth/User'; + +const COLUMN_LOCALE = new TableColumn({ + default: '\'{}\'', + name: 'locale', + type: 'varchar', +}); + +export class UserLocale0001548049058 implements MigrationInterface { + public async up(query: QueryRunner): Promise { + await query.addColumn(TABLE_USER, COLUMN_LOCALE); + } + + public async down(query: QueryRunner): Promise { + await query.dropColumn(TABLE_USER, COLUMN_LOCALE); + } +} diff --git a/src/module/MigrationModule.ts b/src/module/MigrationModule.ts index 473e8af81..e06f1ba62 100644 --- a/src/module/MigrationModule.ts +++ b/src/module/MigrationModule.ts @@ -13,6 +13,7 @@ import { KeywordCommand0001545509108 } from 'src/migration/0001545509108-Keyword import { CreateTick0001546063195 } from 'src/migration/0001546063195-CreateTick'; import { Dates0001546236755 } from 'src/migration/0001546236755-Dates'; import { FragmentUser0001546283532 } from 'src/migration/0001546283532-FragmentUser'; +import { UserLocale0001548049058 } from 'src/migration/0001548049058-UserLocale'; export class MigrationModule extends Module { public async configure(options: ModuleOptions): Promise { @@ -32,6 +33,7 @@ export class MigrationModule extends Module { CreateTick0001546063195, Dates0001546236755, FragmentUser0001546283532, + UserLocale0001548049058, ]); } } diff --git a/test/entity/TestContext.ts b/test/entity/TestContext.ts index 28fa84bc4..2a01b0e03 100644 --- a/test/entity/TestContext.ts +++ b/test/entity/TestContext.ts @@ -2,7 +2,7 @@ import { expect } from 'chai'; import { ineeda } from 'ineeda'; import { Role } from 'src/entity/auth/Role'; -import { User } from 'src/entity/auth/User'; +import { LOCALE_DEFAULT, User } from 'src/entity/auth/User'; import { Context } from 'src/entity/Context'; import { Listener } from 'src/listener'; @@ -20,6 +20,7 @@ describeAsync('context entity', async () => { source: ineeda(), uid: 'test', user: new User({ + locale: LOCALE_DEFAULT, name: 'test', roles: [new Role({ grants, @@ -47,6 +48,7 @@ describeAsync('context entity', async () => { source: ineeda(), uid: 'test', user: new User({ + locale: LOCALE_DEFAULT, name: 'test', roles: [new Role({ grants,