@@ -10,6 +10,7 @@ import { User } from "../entities/user";
1010import { Team } from "../entities/team" ;
1111import { Project } from "../entities/project" ;
1212import { Criterion } from "../entities/criterion" ;
13+ import { UserRole } from "../entities/user-role" ;
1314
1415export interface ProjectRatingResult {
1516 project : Project ;
@@ -18,21 +19,18 @@ export interface ProjectRatingResult {
1819
1920export interface IRatingService extends IService {
2021 /**
21- * Get all ratings
22+ * Get the ratings for a specific project, cast by a specific user.
23+ * Users may only read their own created ratings.
2224 */
23- getAllRatings ( ) : Promise < readonly Rating [ ] > ;
25+ getUsersRatingsForProject ( projectId : number , user : User ) : Promise < readonly Rating [ ] > ;
2426 /**
25- * Create new rating
27+ * Upsert a rating
2628 */
27- createRating ( rating : Rating , user : User ) : Promise < Rating > ;
28- /**
29- * Update rating
30- */
31- updateRating ( rating : Rating , user : User ) : Promise < Rating > ;
29+ upsertRating ( rating : Rating , user : User ) : Promise < Rating > ;
3230 /**
3331 * Get rating by id
3432 */
35- getRatingByID ( id : number ) : Promise < RatingDTO | undefined > ;
33+ getRatingByID ( id : number , user : User ) : Promise < RatingDTO | undefined > ;
3634 /**
3735 * Delete single rating by id
3836 */
@@ -74,49 +72,48 @@ export class RatingService implements IRatingService {
7472 }
7573
7674 /**
77- * Gets all ratings.
78- */
79- public async getAllRatings ( ) : Promise < readonly Rating [ ] > {
80- return this . _database . getRepository ( Rating ) . find ( ) ;
81- }
82-
83- /**
84- * Updates a rating.
85- * @param rating The rating to update
75+ * Get the ratings for a specific project, cast by a specific user.
76+ * Users may only read their own created ratings.
8677 */
87- public async updateRating ( rating : Rating , user : User ) : Promise < Rating > {
88- const originRating = await this . _ratings . findOneBy ( { id : rating . id } ) ;
89-
90- if ( ! originRating ) {
91- throw new NotFoundError ( "Rating not found" ) ;
92- }
93-
94- if ( user . id !== originRating . user . id ) {
95- throw new ForbiddenError ( "You can only update your own ratings" ) ;
96- }
97-
98- await this . checkPermission ( rating , user ) ;
99-
100- return this . _ratings . save ( rating ) ;
78+ public async getUsersRatingsForProject ( projectId : number , user : User ) : Promise < readonly Rating [ ] > {
79+ // TODO test
80+ return this . _database . getRepository ( Rating ) . find ( {
81+ where : {
82+ project : {
83+ id : projectId
84+ } ,
85+ user : {
86+ id : user . id
87+ }
88+ }
89+ } ) ;
10190 }
10291
10392 /**
104- * Creates a rating.
93+ * Upsert a rating.
10594 * @param rating The rating to create
10695 */
107- public async createRating ( rating : Rating , user : User ) : Promise < Rating > {
96+ public async upsertRating ( rating : Rating , user : User ) : Promise < Rating > {
10897 await this . checkPermission ( rating , user ) ;
10998
110- const existing = await this . _ratings . findOne ( {
111- where : {
112- user : { id : user . id } ,
113- project : { id : rating . project . id } ,
114- criterion : { id : rating . criterion . id } ,
99+ const existingRating = await this . _ratings . findOneBy ( {
100+ user : {
101+ id : user . id
115102 } ,
103+ project : {
104+ id : rating . project . id
105+ } ,
106+ criterion : {
107+ id : rating . criterion . id
108+ }
116109 } ) ;
117110
118- if ( existing ) {
119- throw new BadRequestError ( "You have already rated this project for this criterion" ) ;
111+ if ( existingRating !== null ) {
112+ // Update
113+ return this . _ratings . save ( {
114+ ...rating ,
115+ id : existingRating . id
116+ } ) ;
120117 }
121118
122119 return this . _ratings . save ( rating ) ;
@@ -126,8 +123,17 @@ export class RatingService implements IRatingService {
126123 * Gets a rating by its id.
127124 * @param id The id of the rating
128125 */
129- public async getRatingByID ( id : number ) : Promise < RatingDTO | undefined > {
126+ public async getRatingByID ( id : number , user : User ) : Promise < RatingDTO | undefined > {
130127 const rating = await this . _ratings . findOneBy ( { id } ) ;
128+
129+ if ( ! rating ) {
130+ throw new NotFoundError ( "Rating not found" ) ;
131+ }
132+
133+ if ( rating . user . id !== user . id && user . role !== UserRole . Root ) {
134+ throw new ForbiddenError ( )
135+ }
136+
131137 return rating ? convertBetweenEntityAndDTO ( rating , RatingDTO ) : undefined ;
132138 }
133139
@@ -196,6 +202,9 @@ export class RatingService implements IRatingService {
196202 return result ;
197203 }
198204
205+ /**
206+ * Check if the user is permitted to create/modify/delete this rating.
207+ */
199208 private async checkPermission ( rating : Rating , user : User ) : Promise < void > {
200209 const settings = await this . _settings . getSettings ( ) ;
201210 if ( ! settings . application . allowRatingProjects ) {
@@ -207,7 +216,7 @@ export class RatingService implements IRatingService {
207216 throw new NotFoundError ( "Project not found" ) ;
208217 }
209218 if ( ! project . allowRating ) {
210- throw new ForbiddenError ( "Rating this project is not allowed" )
219+ throw new ForbiddenError ( "Rating this project is not allowed" ) ;
211220 }
212221
213222 const team = await this . _teams . findOneBy ( { id : project . team . id } )
0 commit comments