diff --git a/.circleci/config.yml b/.circleci/config.yml index 4cac75f5c..1e776da03 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -16,7 +16,7 @@ aliases: sudo npm install --quiet node-gyp -g sudo npm install cordova -g sudo npm install ionic -g - sudo npm config set python /usr/bin/python + sudo npm config set python /usr/bin/python - &install-chrome name: Install Chrome command: | @@ -40,8 +40,8 @@ defaults: &defaults # we define default work dir, however almost every job redefine it working_directory: /tmp/workspace environment: - JVM_OPTS: -Xmx3200m - ANDROID_HOME: /usr/local/android-sdk-linux + JVM_OPTS: -Xmx3200m + ANDROID_HOME: /usr/local/android-sdk-linux jobs: build-monorepo-root: @@ -151,7 +151,7 @@ jobs: steps: - checkout - run: *install-deps - - run: + - run: name: Install Yarn command: sudo npm install -g yarn --force - run: *install-gradle @@ -178,19 +178,19 @@ jobs: command: cd carrier/mobile-ionic && yarn ionic cordova platform rm android - run: name: Add new android platform - command: | - cd carrier/mobile-ionic - yarn ionic cordova platform add android@8.0.0 --noresources - ionic config set -g telemetry true - # echo y | android update sdk --no-ui --all --filter tools,platform-tools,extra-google-m2repository,extra-google-google_play_services,extra-android-support,extra-android-m2repository,android-25 - # echo y | android update sdk --no-ui --all --filter build-tools-25.0.0 + command: | + cd carrier/mobile-ionic + yarn ionic cordova platform add android@8.0.0 --noresources + ionic config set -g telemetry true + # echo y | android update sdk --no-ui --all --filter tools,platform-tools,extra-google-m2repository,extra-google-google_play_services,extra-android-support,extra-android-m2repository,android-25 + # echo y | android update sdk --no-ui --all --filter build-tools-25.0.0 - run: name: Run Cordova Build for Android (Debug) - command: | - cd carrier/mobile-ionic - yarn cordova:build - mkdir -p /tmp/apk - cp -r platforms/android/app/build/outputs/apk/debug/app-debug.apk /tmp/apk/carrier.apk + command: | + cd carrier/mobile-ionic + yarn cordova:build + mkdir -p /tmp/apk + cp -r platforms/android/app/build/outputs/apk/debug/app-debug.apk /tmp/apk/carrier.apk - save_cache: name: Save Yarn Package Cache key: yarn-packages-carrier-mobile-ionic-{{ checksum "yarn.lock" }} @@ -198,7 +198,7 @@ jobs: - ~/.cache/yarn - store_artifacts: path: /tmp/apk - destination: apks + destination: apks - persist_to_workspace: root: /tmp/workspace/carrier/mobile-ionic paths: @@ -211,10 +211,10 @@ jobs: steps: - checkout - run: *install-deps - - run: + - run: name: Install Yarn command: sudo npm install -g yarn --force - - run: *install-gradle + - run: *install-gradle - run: name: 'Pull Submodules' command: | @@ -238,19 +238,19 @@ jobs: command: cd shop/mobile-ionic && yarn ionic cordova platform rm android - run: name: Add new android platform - command: | - cd shop/mobile-ionic - yarn ionic cordova platform add android@8.0.0 --noresources - ionic config set -g telemetry true - # echo y | android update sdk --no-ui --all --filter tools,platform-tools,extra-google-m2repository,extra-google-google_play_services,extra-android-support,extra-android-m2repository,android-25 - # echo y | android update sdk --no-ui --all --filter build-tools-25.0.0 + command: | + cd shop/mobile-ionic + yarn ionic cordova platform add android@8.0.0 --noresources + ionic config set -g telemetry true + # echo y | android update sdk --no-ui --all --filter tools,platform-tools,extra-google-m2repository,extra-google-google_play_services,extra-android-support,extra-android-m2repository,android-25 + # echo y | android update sdk --no-ui --all --filter build-tools-25.0.0 - run: name: Run Cordova Build for Android (Debug) - command: | - cd shop/mobile-ionic - yarn cordova:build - mkdir -p /tmp/apk - cp -r platforms/android/app/build/outputs/apk/debug/app-debug.apk /tmp/apk/shop.apk + command: | + cd shop/mobile-ionic + yarn cordova:build + mkdir -p /tmp/apk + cp -r platforms/android/app/build/outputs/apk/debug/app-debug.apk /tmp/apk/shop.apk - save_cache: name: Save Yarn Package Cache key: yarn-packages-shop-mobile-ionic-{{ checksum "yarn.lock" }} @@ -304,7 +304,7 @@ jobs: steps: - checkout - run: *install-deps - - run: + - run: name: Install Yarn command: sudo npm install -g yarn --force - run: *install-gradle @@ -312,7 +312,7 @@ jobs: name: 'Pull Submodules' command: | git submodule init - git submodule update --remote + git submodule update --remote - restore_cache: name: Restore Yarn Package Cache keys: @@ -331,19 +331,19 @@ jobs: command: cd merchant/tablet-ionic && yarn ionic cordova platform rm android - run: name: Add new android platform - command: | - cd merchant/tablet-ionic - yarn ionic cordova platform add android@8.0.0 --noresources - ionic config set -g telemetry true - # echo y | android update sdk --no-ui --all --filter tools,platform-tools,extra-google-m2repository,extra-google-google_play_services,extra-android-support,extra-android-m2repository,android-25 - # echo y | android update sdk --no-ui --all --filter build-tools-25.0.0 + command: | + cd merchant/tablet-ionic + yarn ionic cordova platform add android@8.0.0 --noresources + ionic config set -g telemetry true + # echo y | android update sdk --no-ui --all --filter tools,platform-tools,extra-google-m2repository,extra-google-google_play_services,extra-android-support,extra-android-m2repository,android-25 + # echo y | android update sdk --no-ui --all --filter build-tools-25.0.0 - run: name: Run Cordova Build for Android (Debug) - command: | - cd merchant/tablet-ionic - yarn cordova:build - mkdir -p /tmp/apk - cp -r platforms/android/app/build/outputs/apk/debug/app-debug.apk /tmp/apk/merchant.apk + command: | + cd merchant/tablet-ionic + yarn cordova:build + mkdir -p /tmp/apk + cp -r platforms/android/app/build/outputs/apk/debug/app-debug.apk /tmp/apk/merchant.apk - save_cache: name: Save Yarn Package Cache key: yarn-packages-merchant-tablet-ionic-{{ checksum "yarn.lock" }} @@ -364,7 +364,7 @@ jobs: steps: - run: *install-deps - run: *install-yarn - - run: *install-chrome + - run: *install-chrome - attach_workspace: at: /tmp/workspace/carrier/mobile-ionic - run: diff --git a/LICENSE.md b/LICENSE.md index 667f649b2..f90a21cb4 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -30,21 +30,22 @@ You should have received a copy of the relevant GNU Licenses along with this pro We suggest to check a great overview about different open-source licenses at . For example, for AGPL v3 (strongest copyleft license we use) conditions can be summarized as following: -- making available complete source code of licensed works and modifications, which include larger works using a licensed work, under the same license. -- Copyright and license notices must be preserved -- Contributors provide an express grant of patent rights. -- When a modified version is used to provide a service over a network, the complete source code of the modified version must be made available. + +- making available complete source code of licensed works and modifications, which include larger works using a licensed work, under the same license. +- Copyright and license notices must be preserved +- Contributors provide an express grant of patent rights. +- When a modified version is used to provide a service over a network, the complete source code of the modified version must be made available. Feel free to [Contact Us](https://github.com/ever-co/ever#contact-us) for an additional information about used open-source licenses! ### _Ever Platform Small Business_ License -Ever® Platform Small Business™ License can be purchased by businesses with annual revenues do not exceed $1 million. +Ever® Platform Small Business™ License can be purchased by businesses with annual revenues do not exceed \$1 million. For more information, please contact . ### _Ever Platform Enterprise_ License -Ever® Platform Enterprise™ License can be purchased by businesses with more than $1 million in annual revenue. +Ever® Platform Enterprise™ License can be purchased by businesses with more than \$1 million in annual revenue. For more information, please contact . ## Credits diff --git a/README.md b/README.md index 9a5a76128..7876d5eb9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -#### *** If you are running IT Company, check our new project [Gauzy](https://github.com/ever-co/gauzy) *** +#### **_ If you are running IT Company, check our new project [Gauzy](https://github.com/ever-co/gauzy) _** [![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/ever) [![Gitter](https://badges.gitter.im/JoinChat.svg)](https://gitter.im/ever-co/ever?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) @@ -155,12 +155,12 @@ See relevant section in our [documentation](https://github.com/ever-co/ever/wiki Finally, each project from Ever Platform could start by single command from this list: -* Run API server `yarn run:server` -* Run Admin Website `yarn run:admin` and open http://localhost:4200 -* Run Shopping Mobile App `yarn run:shopmobile` and open http://localhost:4201 -* Run Merchant Ionic Tablet App `yarn run:merchant` and open http://localhost:4202 -* Run Carrier Mobile app `yarn run:carrier` and open http://localhost:4203 -* Run Shopping Website `yarn run:shopweb` and open http://localhost:3000 +- Run API server `yarn run:server` +- Run Admin Website `yarn run:admin` and open http://localhost:4200 +- Run Shopping Mobile App `yarn run:shopmobile` and open http://localhost:4201 +- Run Merchant Ionic Tablet App `yarn run:merchant` and open http://localhost:4202 +- Run Carrier Mobile app `yarn run:carrier` and open http://localhost:4203 +- Run Shopping Website `yarn run:shopweb` and open http://localhost:3000 Note 1: during development you can run server with `yarn run:server:dev` to enable watch on TS files changes @@ -237,9 +237,10 @@ In a production setup, all client-side to server-side (backend, APIs) communicat ## License This software is available under following licenses: -- [Ever® Platform Community™ Edition](https://github.com/ever-co/ever/blob/master/LICENSE.md#ever-platform-community-edition-license) -- [Ever® Platform Small Business™](https://github.com/ever-co/ever/blob/master/LICENSE.md#ever-platform-small-business-license) -- [Ever® Platform Enterprise™](https://github.com/ever-co/ever/blob/master/LICENSE.md#ever-platform-enterprise-license) + +- [Ever® Platform Community™ Edition](https://github.com/ever-co/ever/blob/master/LICENSE.md#ever-platform-community-edition-license) +- [Ever® Platform Small Business™](https://github.com/ever-co/ever/blob/master/LICENSE.md#ever-platform-small-business-license) +- [Ever® Platform Enterprise™](https://github.com/ever-co/ever/blob/master/LICENSE.md#ever-platform-enterprise-license) #### The default Ever® Platform™ license, without a valid Ever® Platform Enterprise™ or Ever® Platform Small Business™ License agreement, is the Ever® Platform Community™ Edition License. @@ -267,4 +268,4 @@ All other brand and product names are trademarks, registered trademarks or servi [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fever-co%2Fever.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fever-co%2Fever?ref=badge_shield) [![lerna](https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg)](https://lernajs.io) -#### *** If you are running IT Company, check our new project [Gauzy](https://github.com/ever-co/gauzy) *** +#### **_ If you are running IT Company, check our new project [Gauzy](https://github.com/ever-co/gauzy) _** diff --git a/backend/api/src/@pyro/db-server/db-service.ts b/backend/api/src/@pyro/db-server/db-service.ts index f63e33f6e..0dd3de8a3 100644 --- a/backend/api/src/@pyro/db-server/db-service.ts +++ b/backend/api/src/@pyro/db-server/db-service.ts @@ -222,17 +222,18 @@ export abstract class DBService> if (lastValue == null) { throw new Error(".remove(objectId) error - Object don't exist"); } else { - this.existence.next({ - id: objectId, - value: null, - lastValue, - type: ExistenceEventType.Removed - }); + const callId = uuid(); - this.log.info( - { callId, objectId, lastValue }, - '.remove(objectId) removed object' - ); + this.log.info({ callId }, '.removeAll() called!'); + + try { + await this.Model.remove({}).exec(); + } catch (err) { + this.log.error({ callId, err }, '.removeAll() thrown error!'); + throw err; + } + + this.log.info({ callId }, '.removeAll() removed all!'); } } diff --git a/backend/api/src/@pyro/db-server/typeorm-service.ts b/backend/api/src/@pyro/db-server/typeorm-service.ts new file mode 100644 index 000000000..342eae547 --- /dev/null +++ b/backend/api/src/@pyro/db-server/typeorm-service.ts @@ -0,0 +1,361 @@ +import { IDbService } from './i-db-service'; +import { Model, Document } from 'mongoose'; +import { Subject, Observable, from, of } from 'rxjs'; +import { ExistenceEvent, ExistenceEventType } from './existence'; +import { DBObject } from '@pyro/db'; +import { inject, injectable, optional, interfaces } from 'inversify'; +import { Repository, getRepository } from 'typeorm'; +import * as uuid from 'uuid'; +import * as Logger from 'bunyan'; +import * as _ from 'lodash'; + +import { RawObject } from '@pyro/db/db-raw-object'; +import { createEverLogger } from '../../helpers/Log'; +import { filter, map, share, concat, tap, exhaustMap } from 'rxjs/operators'; + +@injectable() +export class TypeORMService> + implements IDbService { + DBObject: { new (arg: T['CreateObjectTYPE']): T; modelName: string }; + + // TODO: Refactor IDbService so Model is not of type Model + Model: Model; + existence: Subject>; + protected readonly log: Logger = createEverLogger({ name: 'adminService' }); + + constructor( + @optional() + private _repository: Repository + ) { + this.existence = new Subject>(); + } + + async create(createObject: T['CreateObjectTYPE']): Promise { + const callId = uuid(); + + this.log.info({ callId, createObject }, '.create(createObject) called'); + + let object; + + try { + object = this._repository.create(createObject); + this._repository.save(object); + } catch (error) { + this.log.error( + { callId, createObject, error }, + '.create(createObject) thrown error!' + ); + throw error; + } + + this.existence.next({ + id: object.id, + value: object, + lastValue: null, + type: ExistenceEventType.Created + }); + + this.log.info( + { callId, createObject, object }, + '.create(createObject) created object' + ); + + return object as T; + } + async remove(objectId: string): Promise { + const callId = uuid(); + + this.log.info({ callId }, '.removeAll() called!'); + + try { + const object = await this._repository.findByIds([objectId]); + await this.repository.remove(object[0]); + } catch (err) { + this.log.error({ callId, err }, '.remove() thrown error!'); + throw err; + } + + this.log.info({ callId }, '.removeAll() removed all!'); + } + async removeMultiple(conditions: any): Promise { + const callId = uuid(); + + this.log.info( + { callId, conditions }, + '.removeMultiple(conditions) called' + ); + + let lastValues: T[]; + + try { + lastValues = await this._repository.find(conditions); + await this._repository.remove(lastValues); + } catch (err) { + this.log.error( + { callId, conditions, err }, + '.removeMultiple(conditions) thrown error!' + ); + throw err; + } + + lastValues.forEach((lastValue) => { + this.existence.next({ + id: lastValue.id, + lastValue, + value: null, + type: ExistenceEventType.Removed + }); + }); + + this.log.info( + { + callId, + conditions, + lastValues + }, + '.removeMultiple(conditions) removed objects' + ); + } + async removeAll(): Promise { + const callId = uuid(); + + this.log.info({ callId }, '.removeAll() called!'); + + try { + const objects = await this._repository.find(); + await this._repository.remove(objects); + } catch (err) { + this.log.error({ callId, err }, '.removeAll() thrown error!'); + throw err; + } + + this.log.info({ callId }, '.removeAll() removed all!'); + } + get(id: string): Observable { + const callId = uuid(); + + this.log.info({ objectId: id, callId }, '.get(id) called'); + + return from(this.getCurrent(id)).pipe( + concat( + this.existence.pipe( + filter((existenceEvent) => id === existenceEvent.id), + map((existenceEvent) => existenceEvent.value), + share() + ) + ), + tap({ + next: (obj) => { + this.log.info( + { + objectId: id, + object: obj, + callId + }, + '.get(id) emitted next value' + ); + }, + error: (err) => { + this.log.error( + { + objectId: id, + err, + callId + }, + '.get(id), emitted error!' + ); + } + }) + ); + } + async getCurrent(id: string): Promise { + const callId = uuid(); + + this.log.info({ objectId: id, callId }, '.getCurrent(id) called'); + + const obj = await this._repository.findByIds([id])[0]; + + return obj as RawObject; + } + getMultiple(ids: string[]): Observable { + const callId = uuid(); + + this.log.info({ objectIds: ids, callId }, '.getMultiple(ids) called'); + + return of(null).pipe( + concat( + this.existence.pipe( + filter((event) => _.includes(ids, event.id)), + share() + ) + ), + exhaustMap(() => this.getCurrentMultiple(ids)), + tap({ + next: (objects) => { + this.log.info( + { objectIds: ids, objects, callId }, + '.getMultiple(ids) emitted next value' + ); + }, + error: (err) => { + this.log.error( + { objectIds: ids, err, callId }, + '.getMultiple(ids), emitted error!' + ); + } + }) + ); + } + async getCurrentMultiple(ids: string[]): Promise { + const callId = uuid(); + + this.log.info( + { objectIds: ids, callId }, + '.getCurrentMultiple(ids) called' + ); + + const objs = await this._repository.findByIds(ids); + + return objs; + } + find(conditions: any): Promise { + return this._repository.find({ ...conditions }); + } + findOne(conditions: any): Promise { + return this._repository.findOne(conditions); + } + + async update(id: string, updateObj: any): Promise { + const callId = uuid(); + this.log.info( + { callId, id, updateObj }, + '.update(id, updateObj) called' + ); + + let beforeUpdateObject: T | null; + + let updatedObject: T; + + try { + beforeUpdateObject = await this.getCurrent(id); + + if (beforeUpdateObject != null) { + // const obj = (await this.Model.findByIdAndUpdate( + // id, + // updateObj as any, + // { new: true } + // ) + // .lean() + // .exec()) as RawObject; + let tempObject = await this._repository.update(id, { + ...updateObj + }); + updatedObject = tempObject as RawObject; + } else { + throw new Error( + `There is no such object with the id ${beforeUpdateObject}` + ); + } + } catch (err) { + this.log.error( + { callId, id, updateObj, err }, + '.update(id, updateObj) thrown error!' + ); + throw err; + } + + this.existence.next({ + id: id, + value: updatedObject, + lastValue: beforeUpdateObject, + type: ExistenceEventType.Updated + }); + + this.log.info( + { + callId, + id, + updateObj, + updatedValue: updatedObject, + lastValue: beforeUpdateObject + }, + '.update(objectId, updateObj) updated object' + ); + + return updatedObject; + } + async updateMultiple(findObj: any, updateObj: any): Promise { + const callId = uuid(); + this.log.info( + { callId, findObj, updateObj }, + '.updateMultiple(findObj, updateObj) called' + ); + + let lastValues: any[]; + let updatedObjects: any[]; + + try { + lastValues = await this.find(findObj); + + lastValues.forEach((obj) => { + obj = { ...obj, ...updateObj }; + obj.save(); + updatedObjects.push(obj); + }); + } catch (err) { + this.log.error( + { callId, findObj, updateObj, err }, + '.updateMultiple(findObj, updateObj) thrown error!' + ); + throw err; + } + + lastValues.forEach((lastValue) => { + const newValue = _.find( + updatedObjects, + (obj) => obj.id === lastValue.id + ) as T; + + this.existence.next({ + id: lastValue.id, + lastValue, + value: newValue, + type: ExistenceEventType.Updated + }); + }); + + this.log.info( + { + callId, + findObj, + updateObj, + lastValues, + updatedObjects + }, + '.updateMultiple(objectId, updateObj) updated objects' + ); + + return updatedObjects as T[]; + } + async updateMultipleByIds(ids: string[], updateObj: any): Promise { + const promises = ids.map((id) => this.update(id, updateObj)); + return Promise.all(promises); + } + count(conditions: any): Promise { + return this._repository.count(conditions); + } + + public set repository(repo: Repository) { + this._repository = repo; + } +} + +export const typeORMServiceFactory = (context: interfaces.Context) => { + return >(repository: Repository) => { + const service = context.container.get>( + TypeORMService + ); + service.repository = repository; + return service; + }; +}; diff --git a/backend/api/src/app.module.ts b/backend/api/src/app.module.ts index 84c12518e..52d1aebf1 100644 --- a/backend/api/src/app.module.ts +++ b/backend/api/src/app.module.ts @@ -58,7 +58,7 @@ export const CommandHandlers = [GetAboutUsHandler]; // Add here all CQRS event handlers export const EventHandlers = []; -const entities = ServicesApp.getEntities(); +// const entities = ServicesApp.getEntities(); @Module({ controllers: [TestController], @@ -71,20 +71,23 @@ const entities = ServicesApp.getEntities(); AdminsModule, ConfigModule, // configure TypeORM Connection which will be possible to use inside NestJS (e.g. resolvers) - TypeOrmModule.forRoot({ - type: 'mongodb', - host: 'localhost', - database: 'test', - entities, - synchronize: true, - useNewUrlParser: true, - autoReconnect: true, - logging: true - }), + // TypeOrmModule.forRoot({ + // type: 'mysql', + // host: 'localhost', + // port: 3306, + // database: 'test', + // username: 'ever', + // password: 'ever', + // entities, + // synchronize: true, + // // useNewUrlParser: true, + // // autoReconnect: true, + // logging: true + // }), // define which repositories shall be registered in the current scope (each entity will have own repository). // Thanks to that we can inject the XXXXRepository to the NestJS using the @InjectRepository() decorator // NOTE: this could be used inside NestJS only, not inside our services - TypeOrmModule.forFeature(entities), + // TypeOrmModule.forFeature(entities), SubscriptionsModule.forRoot(env.GQLPORT_SUBSCRIPTIONS), GraphQLModule.forRoot({ typePaths: ['./**/*.graphql'], diff --git a/backend/api/src/main.ts b/backend/api/src/main.ts index 1fed61c0a..77949647f 100644 --- a/backend/api/src/main.ts +++ b/backend/api/src/main.ts @@ -64,9 +64,9 @@ process.on('unhandledRejection', (err, promise) => { (mongoose as any).Promise = BluebirdPromise; (async () => { - // needs TypeORM connection to be ready before we initialize Services - await ServicesApp.CreateTypeORMConnection(); + await ServicesApp.createTypeORMConnection(); + // needs TypeORM connection to be ready before we initialize Services const app = servicesContainer.get(ServicesApp); await app.start(async () => { diff --git a/backend/api/src/nest-bootstrap.ts b/backend/api/src/nest-bootstrap.ts index ad8c3a8d3..c424ac307 100644 --- a/backend/api/src/nest-bootstrap.ts +++ b/backend/api/src/nest-bootstrap.ts @@ -36,6 +36,8 @@ export async function bootstrapNest(): Promise { SwaggerModule.setup('api', app, document); + console.log(`APP IS LISTENING ON PORT ${port}`); + await app.listen(port + ''); if (module.hot) { diff --git a/backend/api/src/services/admins/AdminsService.ts b/backend/api/src/services/admins/AdminsService.ts index eeddc7aa3..013819be5 100644 --- a/backend/api/src/services/admins/AdminsService.ts +++ b/backend/api/src/services/admins/AdminsService.ts @@ -1,4 +1,4 @@ -import { DBService } from '@pyro/db-server'; +import { DBService, IDbService } from '@pyro/db-server'; import Admin from '@modules/server.common/entities/Admin'; import { createEverLogger } from '../../helpers/Log'; import { AuthService, AuthServiceFactory } from '../auth'; @@ -12,6 +12,7 @@ import { asyncListener, observableListener } from '@pyro/io'; import { inject, injectable } from 'inversify'; import { first, map, switchMap } from 'rxjs/operators'; import { Repository } from 'typeorm'; +import { FindObject } from '@pyro/db/db-find-object'; // TODO: Rename! "Admin" is not a great name, but currently "Users" mean "Customers"... /** @@ -26,12 +27,16 @@ export class AdminsService extends DBService implements IAdminRouter { private readonly authService: AuthService; + private databaseService: IDbService; + constructor( @inject('Factory') authServiceFactory: AuthServiceFactory, // TypeORM Repository - temporary here, will be moved into DBService later @inject('AdminRepository') - private readonly _adminRepository: Repository + private readonly _adminRepository: Repository, + @inject('DatabaseService') + private databaseServiceFactory: (type) => IDbService ) { super(); @@ -45,6 +50,8 @@ export class AdminsService extends DBService implements IAdminRouter { console.log(e); }); + this.databaseService = this.databaseServiceFactory('Admin'); + this.authService = authServiceFactory({ role: 'admin', Entity: Admin, @@ -65,12 +72,13 @@ export class AdminsService extends DBService implements IAdminRouter { @asyncListener() async getByEmail(email: Admin['email']): Promise { - return super.findOne({ email, isDeleted: { $eq: false } }); + return this.databaseService.findOne({ email }); + // return super.findOne({ email, isDeleted: { $eq: false } }); } @asyncListener() async register(input: IAdminRegistrationInput): Promise { - const admin = await this.create({ + const admin = await this.databaseService.create({ ...input.admin, ...(input.password ? { @@ -139,4 +147,12 @@ export class AdminsService extends DBService implements IAdminRouter { throw Error(`Admin with id '${adminId}' does not exists!`); } } + + async count(findObj: FindObject): Promise { + return this.databaseService.count(findObj); + } + + async find(conditions: any): Promise { + return this.databaseService.find(conditions); + } } diff --git a/backend/api/src/services/carriers/CarriersService.ts b/backend/api/src/services/carriers/CarriersService.ts index 6c7b05f7d..8384dfcae 100644 --- a/backend/api/src/services/carriers/CarriersService.ts +++ b/backend/api/src/services/carriers/CarriersService.ts @@ -2,7 +2,7 @@ import * as Logger from 'bunyan'; import CarrierStatus from '@modules/server.common/enums/CarrierStatus'; import Carrier from '@modules/server.common/entities/Carrier'; import { createEverLogger } from '../../helpers/Log'; -import { DBService } from '@pyro/db-server'; +import { DBService, IDbService } from '@pyro/db-server'; import { inject, injectable } from 'inversify'; import ICarrierRouter, { ICarrierLoginResponse, @@ -17,11 +17,12 @@ import { import IService from '../IService'; import GeoLocation from '@modules/server.common/entities/GeoLocation'; import IGeoLocation from '@modules/server.common/interfaces/IGeoLocation'; -import { concat, of, Observable } from 'rxjs'; +import { concat, of, Observable, from } from 'rxjs'; import { exhaustMap, filter, first, map, switchMap } from 'rxjs/operators'; import { env } from '../../env'; import { AuthService, AuthServiceFactory } from '../auth'; import IPagingOptions from '@modules/server.common/interfaces/IPagingOptions'; +import { Repository } from 'typeorm'; @injectable() @routerName('carrier') @@ -33,22 +34,36 @@ export class CarriersService extends DBService }); private readonly authService: AuthService; + private databaseService: IDbService; constructor( @inject('Factory') - private readonly authServiceFactory: AuthServiceFactory + private readonly authServiceFactory: AuthServiceFactory, + @inject('CarrierRepository') + private readonly _carrierRepository: Repository, + @inject('DatabaseService') + private databaseServiceFactory: (type) => IDbService ) { super(); + _carrierRepository + .count() + .then((c) => { + console.log('Cariers count: ' + c); + }) + .catch((e) => { + console.log(e); + }); this.authService = this.authServiceFactory({ role: 'carrier', Entity: Carrier, saltRounds: env.CARRIER_PASSWORD_BCRYPT_SALT_ROUNDS }); + this.databaseService = this.databaseServiceFactory('Carrier'); } @observableListener() get(id: Carrier['id']) { - return super.get(id).pipe( + return from(this.databaseService.get(id)).pipe( map(async (carrier) => { await this.throwIfNotExists(id); return carrier; @@ -67,24 +82,20 @@ export class CarriersService extends DBService } protected async _getAllActive() { - return super.find({ isActive: true, isDeleted: { $eq: false } }); + return this.databaseService.find({ isActive: true, isDeleted: false }); } async getMultipleByIds( carrierIds: string[] ): Promise> { - const carriers = await this.find({ - _id: { $in: carrierIds }, - isDeleted: { $eq: false } - }); - - const carriersIdsToReturn = carriers.map((c) => c.id); - return this.getMultiple(carriersIdsToReturn); + return this.databaseService + .getMultiple(carrierIds) + .pipe(map((arr) => arr.filter((elem) => !elem.isDeleted))); } @asyncListener() async register(input: ICarrierRegistrationInput) { - const carrier = await super.create({ + const carrier = await this.databaseService.create({ ...input.carrier, ...(input.password ? { @@ -130,7 +141,7 @@ export class CarriersService extends DBService status: CarrierStatus ): Promise { await this.throwIfNotExists(carrierId); - return super.update(carrierId, { status }); + return this.databaseService.update(carrierId, { status }); } @asyncListener() @@ -139,7 +150,7 @@ export class CarriersService extends DBService isActive: boolean ): Promise { await this.throwIfNotExists(carrierId); - return super.update(carrierId, { isActive }); + return this.databaseService.update(carrierId, { isActive }); } /** @@ -163,7 +174,7 @@ export class CarriersService extends DBService geoLocation: GeoLocation ): Promise { await this.throwIfNotExists(carrierId); - return super.update(carrierId, { geoLocation }); + return this.databaseService.update(carrierId, { geoLocation }); } @asyncListener() @@ -172,7 +183,7 @@ export class CarriersService extends DBService updateObject: Partial ): Promise { await this.throwIfNotExists(id); - return super.update(id, updateObject); + return this.databaseService.update(id, updateObject); } async increaseNumberOfDeliveries( @@ -181,13 +192,13 @@ export class CarriersService extends DBService ): Promise { await this.throwIfNotExists(carrierId); - return super.update(carrierId, { - $inc: { numberOfDeliveries: n } + return this.databaseService.update(carrierId, { + numberOfDeliveries: n }); } async throwIfNotExists(carrierId: string) { - const carrier = await super + const carrier = await this.databaseService .get(carrierId) .pipe(first()) .toPromise(); @@ -203,15 +214,10 @@ export class CarriersService extends DBService sortObj[pagingOptions.sort.field] = pagingOptions.sort.sortBy; } - return this.Model.find({ + return this.databaseService.find({ ...findInput, - isDeleted: { $eq: false } - }) - .sort(sortObj) - .skip(pagingOptions.skip) - .limit(pagingOptions.limit) - .lean() - .exec(); + isDeleted: false + }); } } diff --git a/backend/api/src/services/devices/DevicesService.ts b/backend/api/src/services/devices/DevicesService.ts index d80f4e10d..ce0721a1e 100644 --- a/backend/api/src/services/devices/DevicesService.ts +++ b/backend/api/src/services/devices/DevicesService.ts @@ -1,4 +1,4 @@ -import { injectable } from 'inversify'; +import { injectable, inject } from 'inversify'; import { IDeviceCreateObject } from '@modules/server.common/interfaces/IDevice'; import Device from '@modules/server.common/entities/Device'; import { DBService } from '@pyro/db-server'; @@ -9,6 +9,7 @@ import IDeviceRouter from '@modules/server.common/routers/IDeviceRouter'; import ILanguage from '@modules/server.common/interfaces/ILanguage'; import IService from '../IService'; import { first, switchMap, map } from 'rxjs/operators'; +import { Repository } from 'typeorm'; @injectable() @routerName('device') @@ -18,6 +19,21 @@ export class DevicesService extends DBService protected readonly log = createEverLogger({ name: 'devicesService' }); + constructor( + @inject('DeviceRepository') + private readonly _deviceRepository: Repository + ) { + super(); + _deviceRepository + .count() + .then((c) => { + console.log('Devices count: ' + c); + }) + .catch((e) => { + console.log(e); + }); + } + @observableListener() get(id: string): Observable { return super.get(id).pipe( diff --git a/backend/api/src/services/inversify.config.ts b/backend/api/src/services/inversify.config.ts index 5509e48e4..0a622b7af 100644 --- a/backend/api/src/services/inversify.config.ts +++ b/backend/api/src/services/inversify.config.ts @@ -1,5 +1,5 @@ import 'reflect-metadata'; -import { Container, interfaces, ContainerModule } from 'inversify'; +import { Container, interfaces, ContainerModule, injectable } from 'inversify'; import * as _ from 'lodash'; import { IRoutersManager, RoutersManager, RouterSymbol } from '@pyro/io'; import { CarriersOrdersService, CarriersService } from './carriers'; @@ -39,6 +39,20 @@ import Admin from '@modules/server.common/entities/Admin'; import Device from '@modules/server.common/entities/Device'; import { FakeOrdersService } from './fake-data/FakeOrdersService'; import { CurrenciesService } from './currency/CurrencyService'; +import Product from '@modules/server.common/entities/Product'; +import { ObjectLiteralExpression } from 'ts-morph'; +import Carrier from '@modules/server.common/entities/Carrier'; +import Currency from '@modules/server.common/entities/Currency'; +import Invite from '@modules/server.common/entities/Invite'; +import InviteRequest from '@modules/server.common/entities/InviteRequest'; +import Order from '@modules/server.common/entities/Order'; +import ProductCategory from '@modules/server.common/entities/ProductsCategory'; +import User from '@modules/server.common/entities/User'; +import Warehouse from '@modules/server.common/entities/Warehouse'; +import { + TypeORMService, + typeORMServiceFactory +} from '@pyro/db-server/typeorm-service'; function getRepository(t: any): any { const conn = getConnection('typeorm'); @@ -46,18 +60,33 @@ function getRepository(t: any): any { } const bindings = new ContainerModule((bind: interfaces.Bind) => { - bind>('AdminRepository') - .toDynamicValue(() => { - return getRepository(Admin); - }) - .inRequestScope(); - - bind>('DeviceRepository') - .toDynamicValue(() => { - return getRepository(Device); - }) - .inRequestScope(); + const database = 'mysql' || process.env.DB; + + console.log(`Database is ${database}`); + + [ + Admin, + Carrier, + Device, + Invite, + InviteRequest, + Order, + Product, + ProductCategory, + User, + Warehouse + ].forEach((el: any) => { + const { modelName } = el; + bind>(`${el.modelName}Repository`) + .toDynamicValue(() => { + return getRepository(el.modelName); + }) + .inRequestScope(); + // bind>( + // `TypeORMService<${modelName}>` + // ).toConstantValue(TypeORMService) + }); _.each( [ ConfigService, @@ -106,8 +135,10 @@ const bindings = new ContainerModule((bind: interfaces.Bind) => { ); bind(AuthService).toSelf(); + bind(TypeORMService).toSelf(); bind('Factory').toFactory(authServiceFactory); + bind('Factory').toFactory(typeORMServiceFactory); bind('RoutersManager') .to(RoutersManager) @@ -116,6 +147,25 @@ const bindings = new ContainerModule((bind: interfaces.Bind) => { bind(ServicesApp) .toSelf() .inSingletonScope(); + + // [TypeORMService].forEach((Service) => { + // bind(Service).to(Service); + // }); + + bind('DatabaseService').toFactory((context) => { + return (model) => { + if (database === 'mongo') { + return context.container.get>( + TypeORMService + ); + } + const repo = context.container.get>( + `${model}Repository` + ); + return typeORMServiceFactory(context)(repo); + // return context.container.get('Factory')(model); + }; + }); }); const container = new Container(); diff --git a/backend/api/src/services/invites/InvitesRequestsService.ts b/backend/api/src/services/invites/InvitesRequestsService.ts index 91b6bdcd6..36ad98839 100644 --- a/backend/api/src/services/invites/InvitesRequestsService.ts +++ b/backend/api/src/services/invites/InvitesRequestsService.ts @@ -22,6 +22,7 @@ import { IGeoLocationCreateObject } from '@modules/server.common/interfaces/IGeo import { Country } from '@modules/server.common/entities/GeoLocation'; import IPagingOptions from '@modules/server.common/interfaces/IPagingOptions'; import * as faker from 'faker'; +import { Repository } from 'typeorm'; @injectable() @routerName('invite-request') @@ -36,7 +37,9 @@ export class InvitesRequestsService extends DBService constructor( @inject(InvitesService) protected invitesService: InvitesService, - @inject(DevicesService) protected devicesService: DevicesService + @inject(DevicesService) protected devicesService: DevicesService, + @inject('InviteRequestRepository') + private readonly _inviteRequestRepository: Repository ) { super(); @@ -69,6 +72,14 @@ export class InvitesRequestsService extends DBService ); } }); + _inviteRequestRepository + .count() + .then((c) => { + console.log('InviteRequests count: ' + c); + }) + .catch((e) => { + console.log(e); + }); } @observableListener() diff --git a/backend/api/src/services/invites/InvitesService.ts b/backend/api/src/services/invites/InvitesService.ts index 8d9ed5b98..0440cfb19 100644 --- a/backend/api/src/services/invites/InvitesService.ts +++ b/backend/api/src/services/invites/InvitesService.ts @@ -1,5 +1,5 @@ import * as Logger from 'bunyan'; -import { injectable } from 'inversify'; +import { injectable, inject } from 'inversify'; import Utils from '@modules/server.common/utils'; import { createEverLogger } from '../../helpers/Log'; import Invite from '@modules/server.common/entities/Invite'; @@ -29,6 +29,7 @@ import { IInviteRequestCreateObject } from '@modules/server.common/interfaces/II import * as faker from 'faker'; import { Country } from '@modules/server.common/entities/GeoLocation'; import IPagingOptions from '@modules/server.common/interfaces/IPagingOptions'; +import { Repository } from 'typeorm'; @injectable() @routerName('invite') @@ -44,13 +45,25 @@ export class InvitesService extends DBService private static readonly InviteWorkingDistance = 50000; - constructor() { + constructor( + @inject('InviteRepository') + private readonly _inviteRepository: Repository + ) { super(); this._invitedStreetLocations = of(null).pipe( concat(this.existence), exhaustMap(() => this._getInvitedStreetLocations()) ); + + _inviteRepository + .count() + .then((c) => { + console.log('Invites count: ' + c); + }) + .catch((e) => { + console.log(e); + }); } @observableListener() diff --git a/backend/api/src/services/orders/OrdersService.ts b/backend/api/src/services/orders/OrdersService.ts index 69eb5706a..f76bab8b2 100644 --- a/backend/api/src/services/orders/OrdersService.ts +++ b/backend/api/src/services/orders/OrdersService.ts @@ -31,6 +31,7 @@ import OrderStatus from '@modules/server.common/enums/OrderStatus'; import User from '@modules/server.common/entities/User'; import { ProductsService } from '../../services/products'; import { Observable } from 'rxjs'; +import { Repository } from 'typeorm'; // TODO: this and other Stripe related things should be inside separate Payments Service const stripe: Stripe = new Stripe(env.STRIPE_SECRET_KEY); @@ -82,9 +83,19 @@ export class OrdersService extends DBService @inject(new LazyServiceIdentifer(() => WarehousesService)) protected _storesService: WarehousesService, @inject(new LazyServiceIdentifer(() => ProductsService)) - protected _productsService: ProductsService + protected _productsService: ProductsService, + @inject('OrderRepository') + private readonly _orderRepository: Repository ) { super(); + _orderRepository + .count() + .then((c) => { + console.log('Orders count: ' + c); + }) + .catch((e) => { + console.log(e); + }); } async generateOrdersPerEachCustomer(customers: any[]): Promise { @@ -430,7 +441,9 @@ export class OrdersService extends DBService if (!wProduct) { throw new Error( - `WarehouseOrdersService got call to create(userId, orderProducts) - But there is no product with the id ${args.productId}!` + `WarehouseOrdersService got call to create(userId, orderProducts) - But there is no product with the id ${ + args.productId + }!` ); } @@ -536,7 +549,9 @@ export class OrdersService extends DBService if (!wProduct) { throw new Error( - `WarehouseOrdersService got call to create(userId, orderProducts) - But there is no product with the id ${args.productId}!` + `WarehouseOrdersService got call to create(userId, orderProducts) - But there is no product with the id ${ + args.productId + }!` ); } diff --git a/backend/api/src/services/products/ProductsCategoriesService.ts b/backend/api/src/services/products/ProductsCategoriesService.ts index 315b64291..103ea27f5 100644 --- a/backend/api/src/services/products/ProductsCategoriesService.ts +++ b/backend/api/src/services/products/ProductsCategoriesService.ts @@ -1,35 +1,51 @@ import * as Logger from 'bunyan'; -import { injectable } from 'inversify'; +import { injectable, inject } from 'inversify'; import { createEverLogger } from '../../helpers/Log'; import { DBService } from '@pyro/db-server'; import IProductsCategoryRouter from '@modules/server.common/routers/IProductsCategoryRouter'; import { Observable } from 'rxjs'; import { asyncListener, observableListener, routerName } from '@pyro/io'; import IService from '../IService'; -import ProductsCategory from '@modules/server.common/entities/ProductsCategory'; import { UpdateObject } from '@pyro/db/db-update-object'; import { CreateObject } from '@pyro/db/db-create-object'; import { first, switchMap, map } from 'rxjs/operators'; +import { Repository } from 'typeorm'; +import ProductCategory from '@modules/server.common/entities/ProductsCategory'; @injectable() @routerName('products-category') -export class ProductsCategoriesService extends DBService +export class ProductsCategoriesService extends DBService implements IProductsCategoryRouter, IService { - public readonly DBObject = ProductsCategory; + public readonly DBObject = ProductCategory; protected readonly log: Logger = createEverLogger({ name: 'productsCategoriesService' }); + constructor( + @inject('ProductCategoryRepository') + private readonly _productCategoryRepository: Repository + ) { + super(); + _productCategoryRepository + .count() + .then((c) => { + console.log('Product Categories count: ' + c); + }) + .catch((e) => { + console.log(e); + }); + } + /** * Get Product Category by Id * - * @param {ProductsCategory['id']} id - * @returns {(Observable)} + * @param {ProductCategory['id']} id + * @returns {(Observable)} * @memberof ProductsCategoriesService */ @observableListener() - get(id: ProductsCategory['id']): Observable { + get(id: ProductCategory['id']): Observable { return super.get(id).pipe( map(async (category) => { await this.throwIfNotExists(id); @@ -42,14 +58,14 @@ export class ProductsCategoriesService extends DBService /** * Create new Product Category * - * @param {CreateObject} category - * @returns {Promise} + * @param {CreateObject} category + * @returns {Promise} * @memberof ProductsCategoriesService */ @asyncListener() async create( - category: CreateObject - ): Promise { + category: CreateObject + ): Promise { return super.create(category); } @@ -57,15 +73,15 @@ export class ProductsCategoriesService extends DBService * Updates existed Product Category * * @param {string} id - * @param {UpdateObject} updateObject - * @returns {Promise} + * @param {UpdateObject} updateObject + * @returns {Promise} * @memberof ProductsCategoriesService */ @asyncListener() async update( id: string, - updateObject: UpdateObject - ): Promise { + updateObject: UpdateObject + ): Promise { await this.throwIfNotExists(id); return super.update(id, updateObject); } diff --git a/backend/api/src/services/products/ProductsService.ts b/backend/api/src/services/products/ProductsService.ts index 1a83dca95..f6475ce6d 100644 --- a/backend/api/src/services/products/ProductsService.ts +++ b/backend/api/src/services/products/ProductsService.ts @@ -1,5 +1,5 @@ import * as Logger from 'bunyan'; -import { injectable } from 'inversify'; +import { injectable, inject } from 'inversify'; import { createEverLogger } from '../../helpers/Log'; import Product from '@modules/server.common/entities/Product'; import { DBService } from '@pyro/db-server'; @@ -17,6 +17,7 @@ import { CreateObject } from '@pyro/db/db-create-object'; import { UpdateObject } from '@pyro/db/db-update-object'; import { first, switchMap, map } from 'rxjs/operators'; import IPagingOptions from '@modules/server.common/interfaces/IPagingOptions'; +import { Repository } from 'typeorm'; @injectable() @routerName('product') @@ -28,6 +29,21 @@ export class ProductsService extends DBService name: 'productsService' }); + constructor( + @inject('ProductRepository') + private readonly _productRepository: Repository + ) { + super(); + _productRepository + .count() + .then((c) => { + console.log('Products count: ' + c); + }) + .catch((e) => { + console.log(e); + }); + } + @observableListener() get(id: Product['id']): Observable { return super.get(id).pipe( diff --git a/backend/api/src/services/services.app.ts b/backend/api/src/services/services.app.ts index 7e50c496f..e5c8414c1 100644 --- a/backend/api/src/services/services.app.ts +++ b/backend/api/src/services/services.app.ts @@ -34,7 +34,7 @@ import Invite from '@modules/server.common/entities/Invite'; import InviteRequest from '@modules/server.common/entities/InviteRequest'; import Order from '@modules/server.common/entities/Order'; import Product from '@modules/server.common/entities/Product'; -import ProductsCategory from '@modules/server.common/entities/ProductsCategory'; +import ProductCategory from '@modules/server.common/entities/ProductsCategory'; import User from '@modules/server.common/entities/User'; import Warehouse from '@modules/server.common/entities/Warehouse'; import { ConfigService } from '../config/config.service'; @@ -82,12 +82,13 @@ export class ServicesApp { http.globalAgent.maxSockets = maxSockets; https.globalAgent.maxSockets = maxSockets; - this._configDB(); + this._configMongoDB(); } async start(callback: () => void) { this.callback = callback; - await this._connectDB(); + await this._onDBConnect(); + console.log('end'); } static getEntities() { @@ -99,14 +100,14 @@ export class ServicesApp { InviteRequest, Order, Product, - ProductsCategory, + ProductCategory, User, Warehouse ]; return entities; } - static async CreateTypeORMConnection() { + static async createTypeORMConnection() { const typeORMLog = createEverLogger({ name: 'TypeORM' }); // list of entities for which Repositories will be greated in TypeORM @@ -115,16 +116,22 @@ export class ServicesApp { const conn = await createConnection({ name: 'typeorm', // TODO: put this into settings (it's mongo only during testing of TypeORM integration!) - type: 'mongodb', - url: env.DB_URI, + // type: 'mongodb', + // url: env.DB_URI, + type: 'mysql', + host: 'localhost', + port: 3306, + database: 'test', + username: 'ever', + password: 'ever', entities, synchronize: true, - useNewUrlParser: true, - autoReconnect: true, - reconnectTries: Number.MAX_VALUE, - poolSize: ServicesApp._poolSize, - connectTimeoutMS: ServicesApp._connectTimeoutMS, - logging: true + // useNewUrlParser: true, + // autoReconnect: true, + // reconnectTries: Number.MAX_VALUE, + // poolSize: ServicesApp._poolSize, + // connectTimeoutMS: ServicesApp._connectTimeoutMS, + logging: false }); console.log( @@ -155,7 +162,7 @@ export class ServicesApp { } } - private _configDB() { + private _configMongoDB() { this.db.on('error', (err) => this.log.error(err)); this.db.on('disconnected', () => { @@ -182,7 +189,7 @@ export class ServicesApp { .on('SIGTERM', this._gracefulExit); } - private async _connectDB() { + private async _connectToMongo() { try { const connectionOptions: mongoose.ConnectionOptions = { useCreateIndex: true, @@ -212,9 +219,15 @@ export class ServicesApp { this.log.info({ db: this.db_server }, 'Connected to DB'); - await this._registerModels(); + if (process.env.DB === 'mongo') { + console.log('registering models'); + await this._registerModels(); + } + await this._registerEntityAdministrator(); + console.log('start passport'); this._passportSetup(); + console.log('start express'); await this._startExpress(); await this._startSocketIO(); @@ -242,12 +255,14 @@ export class ServicesApp { const adminEmail = 'admin@ever.co'; // TODO: put to config const adminPassword = 'admin'; // TODO: put to config + console.log('Counting admins'); const adminCollectionCount = await this._adminsService.count({ email: adminEmail }); + console.log('Finished Counting admins'); if (adminCollectionCount === 0) { - this._adminsService.register({ + await this._adminsService.register({ admin: { email: adminEmail, name: 'Admin', diff --git a/backend/api/src/services/users/UsersService.ts b/backend/api/src/services/users/UsersService.ts index 34a45b50f..480fe66f6 100644 --- a/backend/api/src/services/users/UsersService.ts +++ b/backend/api/src/services/users/UsersService.ts @@ -45,6 +45,7 @@ import _ = require('lodash'); import * as faker from 'faker'; import { WarehousesService } from '../../services/warehouses'; import IPagingOptions from '@modules/server.common/interfaces/IPagingOptions'; +import { Repository } from 'typeorm'; // TODO: this and other Stripe related things should be inside separate Payments Service const stripe: Stripe = new Stripe(env.STRIPE_SECRET_KEY); @@ -83,10 +84,21 @@ export class UsersService extends DBService @inject(new LazyServiceIdentifer(() => DevicesService)) protected devicesService: DevicesService, @inject(new LazyServiceIdentifer(() => WarehousesService)) - protected _storesService: WarehousesService + protected _storesService: WarehousesService, + @inject('UserRepository') + private readonly _userRepository: Repository ) { super(); + _userRepository + .count() + .then((c) => { + console.log('Users count: ' + c); + }) + .catch((e) => { + console.log(e); + }); + // TODO: too many hardcoded constants used below. Refactor! this.watchedFiles = _.zipObject( ['aboutUs', 'privacy', 'termsOfUse'], diff --git a/backend/api/src/services/warehouses/WarehousesProductsService.ts b/backend/api/src/services/warehouses/WarehousesProductsService.ts index b1dbd4515..d554fbb50 100644 --- a/backend/api/src/services/warehouses/WarehousesProductsService.ts +++ b/backend/api/src/services/warehouses/WarehousesProductsService.ts @@ -460,7 +460,9 @@ export class WarehousesProductsService if (product != null) { this.log.info( - `Product price before: ${product.price} and we want to change it to: ${price}` + `Product price before: ${ + product.price + } and we want to change it to: ${price}` ); product.price = price; @@ -513,7 +515,9 @@ export class WarehousesProductsService if (product != null) { this.log.info( - `Product count before remove: ${product.count} and we want to remove ${count} products` + `Product count before remove: ${ + product.count + } and we want to remove ${count} products` ); if (product.count >= count) { @@ -578,7 +582,9 @@ export class WarehousesProductsService if (product != null) { this.log.info( - `Product sold count before decrease: ${product.soldCount} and we want to decrease ${count} products` + `Product sold count before decrease: ${ + product.soldCount + } and we want to decrease ${count} products` ); if (product.soldCount >= count) { diff --git a/backend/api/src/services/warehouses/WarehousesService.ts b/backend/api/src/services/warehouses/WarehousesService.ts index bdedeb4f7..7cd56cb9d 100644 --- a/backend/api/src/services/warehouses/WarehousesService.ts +++ b/backend/api/src/services/warehouses/WarehousesService.ts @@ -25,6 +25,7 @@ import { env } from '../../env'; import { AuthService, AuthServiceFactory } from '../auth'; import { v1 as uuid } from 'uuid'; import IPagingOptions from '@modules/server.common/interfaces/IPagingOptions'; +import { Repository } from 'typeorm'; /** * Warehouses Service @@ -49,7 +50,9 @@ export class WarehousesService extends DBService @inject(ProductsService) private readonly productsService: ProductsService, @inject('Factory') - private readonly authServiceFactory: AuthServiceFactory + private readonly authServiceFactory: AuthServiceFactory, + @inject('WarehouseRepository') + private readonly _warehouseRepository: Repository ) { super(); this.authService = this.authServiceFactory({ @@ -57,6 +60,15 @@ export class WarehousesService extends DBService Entity: Warehouse, saltRounds: env.USER_PASSWORD_BCRYPT_SALT_ROUNDS }); + + _warehouseRepository + .count() + .then((c) => { + console.log('Warehouses count: ' + c); + }) + .catch((e) => { + console.log(e); + }); } /** diff --git a/crowdin.yml b/crowdin.yml index 9fdd2da5e..36bef9b28 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -1,3 +1,3 @@ files: - - source: /admin/website-angular/src/assets/i18n/en.json - translation: /admin/website-angular/src/assets/i18n/%two_letters_code%.json + - source: /admin/website-angular/src/assets/i18n/en.json + translation: /admin/website-angular/src/assets/i18n/%two_letters_code%.json diff --git a/package.json b/package.json index 6f934721b..ac9c10a5e 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "@ngx-translate/http-loader": "^4.0.0", "angular2-logger": "^0.7.0", "fstream": "^1.0.12", + "mysql": "^2.17.1", "lodash.template": "^4.5.0", "lodash.templatesettings": "^4.2.0", "npm": "^6.9.0", diff --git a/shared/core-angular/typeorm-placeholder.ts b/shared/core-angular/typeorm-placeholder.ts index d196f4c50..7b7fbf6ee 100644 --- a/shared/core-angular/typeorm-placeholder.ts +++ b/shared/core-angular/typeorm-placeholder.ts @@ -9,3 +9,17 @@ export function Column(options?: any): Function { export function PrimaryColumn(options?: any): Function { return () => {}; } + +export function PrimaryGeneratedColumn(options?: any): Function { + return () => {}; +} + +export function CreateDateColumn(options?: any): Function { + return () => {}; +} + +export function UpdateDateColumn(options?: any): Function { + return () => {}; +} + +export class Repository {} diff --git a/shared/core/@pyro/db/db-create-object.ts b/shared/core/@pyro/db/db-create-object.ts index 267b9f0dd..48bcaf18a 100644 --- a/shared/core/@pyro/db/db-create-object.ts +++ b/shared/core/@pyro/db/db-create-object.ts @@ -2,7 +2,7 @@ import { PyroObjectId } from './object-id'; import { DBObject } from '@pyro/db/db-object'; export interface DBCreateObject { - _id?: PyroObjectId; + _id?: PyroObjectId | string; } export type CreateObject> = T['CreateObjectTYPE']; diff --git a/shared/core/@pyro/db/db-object.ts b/shared/core/@pyro/db/db-object.ts index 2a89d89d4..180b80844 100644 --- a/shared/core/@pyro/db/db-object.ts +++ b/shared/core/@pyro/db/db-object.ts @@ -5,7 +5,13 @@ import { PyroObjectId } from './object-id'; import * as mongoose from 'mongoose'; import { toDate } from '../../utils'; import * as _ from 'lodash'; -import { Column, PrimaryColumn } from 'typeorm'; +import { + Column, + PrimaryColumn, + CreateDateColumn, + UpdateDateColumn, + PrimaryGeneratedColumn +} from 'typeorm'; export interface DBObjectClass extends Function { modelName?: string; @@ -26,21 +32,21 @@ export abstract class DBObject< constructor(obj: RawObject) { _.assign(this, obj); - if ( - mongoose != null && - mongoose.Types != null && - mongoose.Types.ObjectId != null - ) { - if (obj && obj['_id']) { - this['_id'] = mongoose.Types.ObjectId.createFromHexString( - obj['_id'].toString() - ); - } - } + // if ( + // mongoose != null && + // mongoose.Types != null && + // mongoose.Types.ObjectId != null + // ) { + // if (obj && obj['_id']) { + // this['_id'] = mongoose.Types.ObjectId.createFromHexString( + // obj['_id'].toString() + // ); + // } + // } } - @PrimaryColumn() - _id: PyroObjectId; + @PrimaryGeneratedColumn() + _id: string; /** * Time when entity was created @@ -49,7 +55,7 @@ export abstract class DBObject< * @type {(Date | string)} * @memberof DBObject */ - @Column() + @CreateDateColumn() _createdAt: Date | string; /** @@ -58,7 +64,7 @@ export abstract class DBObject< * @type {(Date | string)} * @memberof DBObject */ - @Column() + @UpdateDateColumn() _updatedAt: Date | string; get createdAt(): Date { diff --git a/shared/core/@pyro/db/db-raw-object.ts b/shared/core/@pyro/db/db-raw-object.ts index 10d03a715..256e69aab 100644 --- a/shared/core/@pyro/db/db-raw-object.ts +++ b/shared/core/@pyro/db/db-raw-object.ts @@ -6,7 +6,7 @@ import { DBObject } from '@pyro/db/db-object'; * Data Transfer Object (DTO) */ export interface DBRawObject extends DBCreateObject { - _id: PyroObjectId; + _id: string | PyroObjectId; _createdAt: Date | string; _updatedAt: Date | string; } diff --git a/shared/core/@pyro/db/types.ts b/shared/core/@pyro/db/types.ts index 536012fc2..e22366cf0 100644 --- a/shared/core/@pyro/db/types.ts +++ b/shared/core/@pyro/db/types.ts @@ -39,7 +39,7 @@ export const Types = { const op = { ...options }; op.type = String; - op.ref = (multi ? Type[0] : Type).modelName; + op.ref = typeof (multi ? Type[0] : Type); Schema(multi ? [op] : op)(target, propertyKey); }; diff --git a/shared/core/entities/Admin.ts b/shared/core/entities/Admin.ts index 3fbf47fd7..85bbfcd88 100644 --- a/shared/core/entities/Admin.ts +++ b/shared/core/entities/Admin.ts @@ -64,7 +64,7 @@ class Admin extends DBObject implements IAdmin { * @memberof Admin */ @Types.Boolean(false) - @Column() + @Column({ default: false }) isDeleted: boolean; /** @@ -78,7 +78,7 @@ class Admin extends DBObject implements IAdmin { required: false, validate: new RegExp(`^[a-z ,.'-]+$`, 'i') }) - @Column() + @Column({ default: '' }) firstName?: string; /** @@ -92,7 +92,7 @@ class Admin extends DBObject implements IAdmin { required: false, validate: new RegExp(`^[a-z ,.'-]+$`, 'i') }) - @Column() + @Column({ default: '' }) lastName?: string; } diff --git a/shared/core/entities/Carrier.ts b/shared/core/entities/Carrier.ts index 1d54343c1..15694a2b2 100644 --- a/shared/core/entities/Carrier.ts +++ b/shared/core/entities/Carrier.ts @@ -185,7 +185,7 @@ class Carrier extends DBObject email: string; @Schema([String]) - @Column() + @Column('simple-array') skippedOrderIds: string[]; /** diff --git a/shared/core/entities/Product.ts b/shared/core/entities/Product.ts index 27e294007..678d9d02d 100644 --- a/shared/core/entities/Product.ts +++ b/shared/core/entities/Product.ts @@ -8,7 +8,7 @@ import IProduct, { IProductImage, IProductTitle } from '../interfaces/IProduct'; -import ProductsCategory from './ProductsCategory'; +import ProductCategory from './ProductsCategory'; import { IProductsCategory } from '../interfaces/IProductsCategory'; import { Entity, Column } from 'typeorm'; @@ -86,7 +86,7 @@ class Product extends DBObject * @type {IProductsCategory[]} * @memberof Product */ - @Types.Ref([ProductsCategory]) + @Types.Ref([ProductCategory]) categories: IProductsCategory[]; @Types.Boolean(false) diff --git a/shared/core/entities/ProductsCategory.ts b/shared/core/entities/ProductsCategory.ts index 19f42e77c..cde55895d 100644 --- a/shared/core/entities/ProductsCategory.ts +++ b/shared/core/entities/ProductsCategory.ts @@ -15,7 +15,7 @@ import { Entity, Column } from 'typeorm'; */ @ModelName('ProductCategory') @Entity({ name: 'productcategories' }) -class ProductsCategory +class ProductCategory extends DBObject implements IProductsCategory { /** @@ -45,4 +45,4 @@ class ProductsCategory isDeleted: boolean; } -export default ProductsCategory; +export default ProductCategory; diff --git a/shared/core/entities/Warehouse.ts b/shared/core/entities/Warehouse.ts index 82ba9999d..27048fe53 100644 --- a/shared/core/entities/Warehouse.ts +++ b/shared/core/entities/Warehouse.ts @@ -186,7 +186,7 @@ class Warehouse extends DBObject * @memberof Warehouse */ @Schema([Number]) - @Column() + @Column('simple-array') forwardOrdersUsing: ForwardOrdersMethod[]; /** diff --git a/shared/core/routers/IProductsCategoryRouter.ts b/shared/core/routers/IProductsCategoryRouter.ts index 01438fc14..b9d76eaca 100644 --- a/shared/core/routers/IProductsCategoryRouter.ts +++ b/shared/core/routers/IProductsCategoryRouter.ts @@ -1,21 +1,21 @@ import { Observable } from 'rxjs'; -import ProductsCategory from '../entities/ProductsCategory'; +import ProductCategory from '../entities/ProductsCategory'; import { CreateObject } from '@pyro/db/db-create-object'; import { UpdateObject } from '@pyro/db/db-update-object'; interface IProductsCategoryRouter { - get(id: ProductsCategory['id']): Observable; + get(id: ProductCategory['id']): Observable; create( - createInput: CreateObject - ): Promise; + createInput: CreateObject + ): Promise; update( - id: ProductsCategory['id'], - updateInput: UpdateObject - ): Promise; + id: ProductCategory['id'], + updateInput: UpdateObject + ): Promise; - remove(id: ProductsCategory['id']): Promise; + remove(id: ProductCategory['id']): Promise; } export default IProductsCategoryRouter; diff --git a/yarn.lock b/yarn.lock index f30068613..dee8d001e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1586,6 +1586,11 @@ better-assert@~1.0.0: dependencies: callsite "1.0.0" +bignumber.js@7.2.1: + version "7.2.1" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-7.2.1.tgz#80c048759d826800807c4bfd521e50edbba57a5f" + integrity sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ== + bin-links@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-1.1.2.tgz#fb74bd54bae6b7befc6c6221f25322ac830d9757" @@ -6027,6 +6032,16 @@ mute-stream@0.0.7, mute-stream@~0.0.4: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" +mysql@^2.17.1: + version "2.17.1" + resolved "https://registry.yarnpkg.com/mysql/-/mysql-2.17.1.tgz#62bba4a039a9b2f73638cd1652ce50fc6f682899" + integrity sha512-7vMqHQ673SAk5C8fOzTG2LpPcf3bNt0oL3sFpxPEEFp1mdlDcrLK0On7z8ZYKaaHrHwNcQ/MTUz7/oobZ2OyyA== + dependencies: + bignumber.js "7.2.1" + readable-stream "2.3.6" + safe-buffer "5.1.2" + sqlstring "2.3.1" + mz@^2.4.0: version "2.7.0" resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" @@ -7929,7 +7944,7 @@ rxjs@^6.5.1: dependencies: tslib "^1.9.0" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -8577,6 +8592,11 @@ sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" +sqlstring@2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.1.tgz#475393ff9e91479aea62dcaf0ca3d14983a7fb40" + integrity sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A= + sshpk@^1.7.0: version "1.14.2" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98"