diff --git a/yky-social/src/Operations.ts b/yky-social/src/Operations.ts index 46b28179..255e3bf2 100644 --- a/yky-social/src/Operations.ts +++ b/yky-social/src/Operations.ts @@ -49,13 +49,15 @@ async function comparePasswords(password: string, hashedPassword: string): Promi return isMatch; } +type ORMTC = TransactionContext; + @DefaultRequiredRole(['user']) export class Operations { @OperonTransaction() @RequiredRole([]) -static async createUser(ctx: TransactionContext, first:string, last:string, uname:string, @SkipLogging pass:string) : +static async createUser(ctx: ORMTC, first:string, last:string, uname:string, @SkipLogging pass:string) : Promise { const manager = ctx.client; @@ -88,10 +90,10 @@ static async createUser(ctx: TransactionContext, first:string, la return await manager.save(user); } -static async logInUser(manager:EntityManager, uname:string, pass:string) : +static async logInUser(ctx: ORMTC, uname:string, pass:string) : Promise { - const userRep = manager.getRepository(UserLogin); + const userRep = ctx.client.getRepository(UserLogin); const existingUser = await userRep.findOneBy({ user_name: uname, }); @@ -102,10 +104,10 @@ static async logInUser(manager:EntityManager, uname:string, pass:string) : return existingUser; } -static async logInUserId(manager:EntityManager, uname:string, pass:string) : +static async logInUserId(ctx: ORMTC, uname:string, pass:string) : Promise { - const userRep = manager.getRepository(UserLogin); + const userRep = ctx.client.getRepository(UserLogin); const existingUser = await userRep.findOneBy({ user_name: uname, }); @@ -116,16 +118,16 @@ static async logInUserId(manager:EntityManager, uname:string, pass:string) : return existingUser.id; } -static async getMyProfile(manager:EntityManager, curUid:string) : +static async getMyProfile(ctx: ORMTC, curUid:string) : Promise { - const upRep = manager.getRepository(UserProfile); + const upRep = ctx.client.getRepository(UserProfile); return upRep.findOneBy({id: curUid}); } @OperonTransaction({readOnly: true}) @RequiredRole([]) -static async getMyProfilePhotoKey(ctx: TransactionContext, curUid:string) : +static async getMyProfilePhotoKey(ctx: ORMTC, curUid:string) : Promise { const mRep = ctx.client.getRepository(MediaItem); @@ -139,10 +141,10 @@ static async getMyProfilePhotoKey(ctx: TransactionContext, curUid return mi.media_url; } -static async getPost(manager:EntityManager, _curUid: string, post:string) : +static async getPost(ctx: ORMTC, _curUid: string, post:string) : Promise { - const pRep = manager.getRepository(Post); + const pRep = ctx.client.getRepository(Post); const res = pRep.findOne({ where: {id: post}, relations: { @@ -154,7 +156,7 @@ static async getPost(manager:EntityManager, _curUid: string, post:string) : // // Returns other user's login, profile (if requested), our listing for his status, and his for us @OperonTransaction({readOnly: true}) -static async findUser(ctx: TransactionContext, curUid:string, uname:string, getProfile:boolean, getStatus: boolean) : +static async findUser(ctx: ORMTC, curUid:string, uname:string, getProfile:boolean, getStatus: boolean) : Promise<[UserLogin?, UserProfile?, GraphType?, GraphType?]> { const manager = ctx.client; @@ -205,10 +207,10 @@ static async findUser(ctx: TransactionContext, curUid:string, una return [otherUser, profile, sgtype, tgtype]; } -static async getGraphStatus(manager: EntityManager, curUid : string, otherUid : string) +static async getGraphStatus(ctx: ORMTC, curUid : string, otherUid : string) : Promise { - const sgRep = manager.getRepository(SocialGraph); + const sgRep = ctx.client.getRepository(SocialGraph); const rGraph = await sgRep.findOneBy({ src_id: curUid, tgt_id: otherUid }); @@ -220,10 +222,10 @@ static async getGraphStatus(manager: EntityManager, curUid : string, otherUid : } // Set graph status -static async setGraphStatus(manager: EntityManager, curUid : string, otherUid : string, status : GraphType) +static async setGraphStatus(ctx: ORMTC, curUid : string, otherUid : string, status : GraphType) : Promise { - const sgRep = manager.getRepository(SocialGraph); + const sgRep = ctx.client.getRepository(SocialGraph); const ug = new SocialGraph(); ug.link_type = status; ug.src_id = curUid; @@ -239,7 +241,7 @@ static async setGraphStatus(manager: EntityManager, curUid : string, otherUid : // Compose a post @OperonTransaction() -static async makePost(ctx: TransactionContext, txt : string) +static async makePost(ctx: ORMTC, txt : string) { const manager = ctx.client; @@ -273,7 +275,7 @@ static async makePost(ctx: TransactionContext, txt : string) // Send a post @OperonTransaction() -static async distributePost(ctx: TransactionContext, p: Post) { +static async distributePost(ctx: ORMTC, p: Post) { const manager = ctx.client; // Deliver post to followers - TODO cross shard; TODO block list @@ -300,7 +302,7 @@ static async distributePost(ctx: TransactionContext, p: Post) { } // TODO: Deliver a post -static async makePM(manager: EntityManager, curUid : string, toUid : string, txt : string) : +static async makePM(ctx: ORMTC, curUid : string, toUid : string, txt : string) : Promise { // Create post @@ -313,7 +315,7 @@ static async makePM(manager: EntityManager, curUid : string, toUid : string, txt p.post_time = new Date(); p.post_type = PostType.PM; - const postRep = manager.getRepository(Post); + const postRep = ctx.client.getRepository(Post); await postRep.insert(p); // TODO: Decompose to allow media upload @@ -326,11 +328,11 @@ static async makePM(manager: EntityManager, curUid : string, toUid : string, txt st.send_date = p.post_time; st.user_id = curUid; - const sendRep = manager.getRepository(TimelineSend); + const sendRep = ctx.client.getRepository(TimelineSend); await sendRep.insert(st); // Deliver post to recipient - TODO cross shard; TODO block list - const recvRep = manager.getRepository(TimelineRecv); + const recvRep = ctx.client.getRepository(TimelineRecv); const rt = new TimelineRecv(); rt.post = p; rt.post_id = p.id; @@ -344,11 +346,11 @@ static async makePM(manager: EntityManager, curUid : string, toUid : string, txt } // Read a send timeline -static async readSendTimeline(manager: EntityManager, _curUser : string, timelineUser : string, type : SendType[], getPosts : boolean) +static async readSendTimeline(ctx: ORMTC, _curUser : string, timelineUser : string, type : SendType[], getPosts : boolean) : Promise { // TODO: Permissions - const tsRep = manager.getRepository(TimelineSend); + const tsRep = ctx.client.getRepository(TimelineSend); return tsRep.find({ where: { user_id: timelineUser, @@ -365,10 +367,10 @@ static async readSendTimeline(manager: EntityManager, _curUser : string, timelin // TODO: Read a recv timeline // TODO: other filters -static async readRecvTimeline(manager: EntityManager, curUser : string, type : RecvType[], getPosts : boolean) +static async readRecvTimeline(ctx: ORMTC, curUser : string, type : RecvType[], getPosts : boolean) : Promise { - const trRep = manager.getRepository(TimelineRecv); + const trRep = ctx.client.getRepository(TimelineRecv); return trRep.find({ where: { user_id: curUser, @@ -428,7 +430,7 @@ static async ensureS3FileDropped(ctx: OperonContext, key: string, bucket: string } @OperonTransaction() -static async writeMediaPost(ctx: TransactionContext, mid: string, mkey: string) { +static async writeMediaPost(ctx: ORMTC, mid: string, mkey: string) { const m = new MediaItem(); m.media_url = mkey; m.media_id = mid; @@ -440,7 +442,7 @@ static async writeMediaPost(ctx: TransactionContext, mid: string, } @OperonTransaction() -static async writeMediaProfilePhoto(ctx: TransactionContext, mid: string, mkey: string) { +static async writeMediaProfilePhoto(ctx: ORMTC, mid: string, mkey: string) { const m = new MediaItem(); m.media_url = mkey; m.media_id = mid; diff --git a/yky-social/src/app.ts b/yky-social/src/app.ts index c6bcbe11..5234952d 100644 --- a/yky-social/src/app.ts +++ b/yky-social/src/app.ts @@ -98,9 +98,7 @@ export class YKY @GetApi('/recvtimeline') static async receiveTimeline(ctx: TransactionContext) { - const manager = ctx.client; - - const rtl = await Operations.readRecvTimeline(manager, ctx.authenticatedUser, [RecvType.POST], true); // TODO #4 - Integrate typeORM into transaction context + const rtl = await Operations.readRecvTimeline(ctx, ctx.authenticatedUser, [RecvType.POST], true); const tl = rtl.map((tle) => { return {postId: tle.post_id, fromUserId:tle.from_user_id, unread:tle.unread, sendDate: tle.send_date, recvType:tle.recv_type, postText: tle.post?.text, postMentions: tle.post?.mentions}; @@ -115,9 +113,8 @@ export class YKY { // TODO: User id and modes const userid = ctx.authenticatedUser; - const manager = ctx.client; - const rtl = await Operations.readSendTimeline(manager, userid, userid, [SendType.PM, SendType.POST, SendType.REPOST], true); + const rtl = await Operations.readSendTimeline(ctx, userid, userid, [SendType.PM, SendType.POST, SendType.REPOST], true); const tl = rtl.map((tle) => { return {postId: tle.post_id, fromUserId:tle.user_id, sendDate: tle.send_date, sendType:tle.send_type, postText: tle.post?.text, postMentions: tle.post?.mentions}; @@ -143,8 +140,7 @@ export class YKY static async getPost(ctx: TransactionContext, @ArgRequired @ArgSource(ArgSources.URL) id: string) { // TODO Validate user permissions - const manager = ctx.client; - const post = await Operations.getPost(manager, ctx.authenticatedUser, id); + const post = await Operations.getPost(ctx, ctx.authenticatedUser, id); if (post) { return { message: 'Retrieved.', post:post }; } else { @@ -156,8 +152,7 @@ export class YKY @PostApi("/login") @RequiredRole([]) // Don't need any roles to log in static async doLogin(ctx: TransactionContext, @ArgRequired username: string, @ArgRequired @LogMask(LogMasks.HASH) password: string) { - const manager = ctx.client; - const user = await Operations.logInUser(manager, username, password); + const user = await Operations.logInUser(ctx, username, password); return { message: 'Successful login.', id:user.id }; } @@ -181,9 +176,8 @@ export class YKY @OperonTransaction() @PostApi("/follow") static async doFollow(ctx: TransactionContext, followUid: string) { - const manager = ctx.client; - const curStatus = await Operations.getGraphStatus(manager, ctx.authenticatedUser, followUid); - await Operations.setGraphStatus(manager, ctx.authenticatedUser, followUid, curStatus == GraphType.FRIEND ? GraphType.FOLLOW_FRIEND : GraphType.FOLLOW); + const curStatus = await Operations.getGraphStatus(ctx, ctx.authenticatedUser, followUid); + await Operations.setGraphStatus(ctx, ctx.authenticatedUser, followUid, curStatus == GraphType.FRIEND ? GraphType.FOLLOW_FRIEND : GraphType.FOLLOW); // TODO: That UID wasn't validated - maybe the DB should validate it return {message: "Followed."};