import { Service } from "root-ts" import { MongodbService } from "root-ts" import { AuthenticationService } from "./authenticationService" import * as crypto from "crypto" import * as uuid from "uuid/v4" import * as Leaf from "leaf-ts" export const Errors = Leaf.ErrorDoc.build({ NotFound: {}, UnknownError: {}, DBError: {}, AlreadyExists: {}, InvalidParameter: {}, NameAlreadyExists: {}, EmailAlreadyExists: {}, }) export class AccountService extends Service { readonly name = "AccountService" protected collectionName = "account" readonly dependencies = ["MongodbService", "AuthenticationService"] services: { MongodbService: MongodbService AuthenticationService: AuthenticationService } accountCollection: any initialize(done) { this.accountCollection = this.services.MongodbService.db.collection(this.collectionName) this.accountCollection.createIndex({ id: 1 }, { unique: true }) done() } create(option: { account: TAccountDefinition }, callback: Callback) { if (!option.account.id) { option.account.id = uuid() } this.accountCollection.insert(option.account, (err, result) => { if (err) { callback(new Errors.AlreadyExists) return } callback(null, option.account) }) } createFromAuthentication(option: { authentication: Type.Account.AuthenticationService.AuthenticationData id?: string name?: string displayName?: string // Useful information // Critical informations props?: TAccountDefinition["props"] role?: TAccountDefinition["role"] }, callback: Callback) { let auth = option.authentication let def = this.services.AuthenticationService.getDefinition(auth.type) if (!def) { callback(new Errors.InvalidParameter("Unknown authentication type: " + auth.type)) return } let account: TAccountDefinition = { id: option.id || uuid(), displayName: option.displayName || def.about(auth.meta, "displayName"), name: option.name || def.about(auth.meta, "name"), props: def.props(auth.meta) || {} } as any if (option.props) { account.props = { ...account.props, ...option.props as any, } } if (option.role || def.about(auth.meta, "role")) { account.role = option.role || def.about(auth.meta, "role") } this.accountCollection.insert(account, (err, result) => { if (err) { callback(new Errors.AlreadyExists) return } callback(null, account) }) } get(id: string, callback: Callback) { this.accountCollection.findOne({ id }, (err, obj) => { if (err || !obj) { callback(new Errors.NotFound) return } delete obj["_id"] callback(null, obj) }) } gets(ids: string[], callback: Callback) { this.accountCollection.find({ id: { $in: ids } }).toArray((err, accounts: TAccountDefinition[]) => { if (err || !accounts) { callback(null, []) return } callback(null, accounts) }) } update(option: { account: TAccountDefinition mongoUpdates?: any }, callback: Callback) { let updates = { $set: option.account } if (option.mongoUpdates) { updates = option.mongoUpdates } this.accountCollection.findOneAndUpdate({ id: option.account.id }, updates, (err, result) => { if (err) { callback(new Errors.DBError("Failt to update", { via: err })) return } let updated = result.value delete updated["_id"] callback(null, updated) }) } register(option: { type: string, role?: TAccountDefinition["role"] meta: TAuthenticationData["meta"] }, callback: Callback) { let authentication: Type.Account.AuthenticationService.AuthenticationData = { type: option.type, meta: option.meta } this.services.AuthenticationService.create({ authentication }, (err, authentication) => { if (err) { callback(err) return } this.createFromAuthentication({ authentication, role: option.role || "account" }, (err, account) => { if (err) { callback(err) return } authentication.accountId = account.id this.services.AuthenticationService.update({ authentication }, (err, result) => { if (err) { callback(err) return } callback(null, account) }) }) }) } }