Changes in / [53bebc0:e071d30]
- Location:
- src
- Files:
-
- 8 added
- 18 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Clients/Angular/finki-chattery/src/app/core/services/student-question.service.ts
r53bebc0 re071d30 16 16 return this.auth.selfUser?.student?.uid === answerResponse.student.uid; 17 17 } 18 19 currentUserCanDeleteAnswer(answer: AnswerQuestionStateViewModel): boolean { 20 return this.auth.selfUser?.student?.uid === answer.student.uid; 21 } 22 23 currentUserCanNotDeleteAnswerBecauseMarkedCorrectEvenThoughHeIsTheAuthor(answer: AnswerQuestionStateViewModel): boolean { 24 return this.auth.selfUser?.student?.uid === answer.student.uid && answer.correctAnswer; 25 } 26 27 currentUserCanDeleteAnswerResponse(answerResponse: AnswerResponseQuestionStateViewModel): boolean { 28 return this.auth.selfUser?.student?.uid === answerResponse.student.uid; 29 } 18 30 } -
src/Clients/Angular/finki-chattery/src/app/core/state/question-facade.service.ts
r53bebc0 re071d30 15 15 import { 16 16 AnswerQuestion, 17 DeleteAnswer, 18 DeleteAnswerResponse, 17 19 EditAnswerQuestion, 18 20 EditAnswerResponse, … … 101 103 } 102 104 105 public deleteAnswerResponse(answerUid: string, questionUid: string, answerResponseUid: string): void { 106 this.dispatchEffect(new DeleteAnswerResponse(questionUid, answerUid, answerResponseUid)); 107 } 108 109 public deleteAnswer(answerUid: string, questionUid: string): void { 110 this.dispatchEffect(new DeleteAnswer(questionUid, answerUid)); 111 } 112 103 113 public fetchQuestion(questionUid: string): void { 104 114 this.dispatchEffect(new GetQuestionState(questionUid)); -
src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.actions.ts
r53bebc0 re071d30 33 33 EditAnswerResponse = '[Question] EditAnswerResponse', 34 34 EditAnswerResponseSuccess = '[Question] EditAnswerResponse Success', 35 DeleteAnswer = '[Question] DeleteAnswer', 36 DeleteAnswerSuccess = '[Question] DeleteAnswer Success', 37 DeleteAnswerResponse = '[Question] DeleteAnswerResponse', 38 DeleteAnswerResponseSuccess = '[Question] DeleteAnswerResponse Success', 35 39 EffectStartedWorking = '[Question] Effect Started Working', 36 40 EffectFinishedWorking = '[Question] Effect Finished Working', 37 41 EffectFinishedWorkingError = '[Question] Effect Finished Working error' 42 } 43 44 export class DeleteAnswer implements Action { 45 readonly type = QuestionActionTypes.DeleteAnswer; 46 47 constructor(public questionUid: string, public answerUid: string) {} 48 } 49 50 export class DeleteAnswerSuccess implements Action { 51 readonly type = QuestionActionTypes.DeleteAnswerSuccess; 52 53 constructor(public payload: string) {} 54 } 55 56 export class DeleteAnswerResponse implements Action { 57 readonly type = QuestionActionTypes.DeleteAnswerResponse; 58 59 constructor(public questionUid: string, public answerUid: string, public answerResponseUid: string) {} 60 } 61 62 export class DeleteAnswerResponseSuccess implements Action { 63 readonly type = QuestionActionTypes.DeleteAnswerResponseSuccess; 64 65 constructor(public payload: string, public answerUid: string) {} 38 66 } 39 67 … … 187 215 | EditAnswerQuestionSuccess 188 216 | EditAnswerResponseSuccess 217 | DeleteAnswerSuccess 218 | DeleteAnswerResponseSuccess 189 219 | EffectStartedWorking 190 220 | EffectFinishedWorking -
src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.effects.ts
r53bebc0 re071d30 19 19 AnswerQuestion, 20 20 AnswerQuestionSuccess, 21 DeleteAnswer, 22 DeleteAnswerResponse, 23 DeleteAnswerResponseSuccess, 24 DeleteAnswerSuccess, 21 25 EditAnswerQuestion, 22 26 EditAnswerQuestionSuccess, … … 236 240 ); 237 241 }); 242 243 deleteResponseToAnswer$ = createEffect(() => { 244 return this.actions$.pipe( 245 ofType<DeleteAnswerResponse>(QuestionActionTypes.DeleteAnswerResponse), 246 mergeMap((action) => { 247 return this.api 248 .delete<string>(`v1/questions/${action.questionUid}/answers/${action.answerUid}/answerresponses/${action.answerResponseUid}`) 249 .pipe( 250 tap((state) => this.notification.successNotification('success-delete-answer-response')), 251 switchMap((state) => [new DeleteAnswerResponseSuccess(state, action.answerUid), new EffectFinishedWorking()]), 252 catchError((err) => [new EffectFinishedWorkingError(err)]) 253 ); 254 }) 255 ); 256 }); 257 258 deleteAnswer$ = createEffect(() => { 259 return this.actions$.pipe( 260 ofType<DeleteAnswer>(QuestionActionTypes.DeleteAnswer), 261 mergeMap((action) => { 262 return this.api.delete<string>(`v1/questions/${action.questionUid}/answers/${action.answerUid}`).pipe( 263 tap((state) => this.notification.successNotification('success-delete-answer')), 264 switchMap((state) => [new DeleteAnswerSuccess(state), new EffectFinishedWorking()]), 265 catchError((err) => [new EffectFinishedWorkingError(err)]) 266 ); 267 }) 268 ); 269 }); 238 270 } -
src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.reducers.ts
r53bebc0 re071d30 162 162 }; 163 163 } 164 case QuestionActionTypes.DeleteAnswerSuccess: { 165 if (state.question) { 166 return { 167 ...state, 168 question: { 169 ...state.question, 170 answers: state.question.answers.filter((x) => x.uid !== action.payload) 171 } 172 }; 173 } 174 175 return { 176 ...state 177 }; 178 } 179 case QuestionActionTypes.DeleteAnswerResponseSuccess: { 180 if (state.question) { 181 return { 182 ...state, 183 question: { 184 ...state.question, 185 answers: state.question.answers.map((x) => { 186 if (x.uid === action.answerUid) { 187 return { 188 ...x, 189 answerResponses: x.answerResponses.filter((y) => y.uid !== action.payload) 190 }; 191 } 192 193 return x; 194 }) 195 } 196 }; 197 } 198 199 return { 200 ...state 201 }; 202 } 164 203 case QuestionActionTypes.AnswerQuestionSuccess: { 165 204 if (state.question) { -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/components.ts
r53bebc0 re071d30 1 1 import { ButtonComponent } from './generic/button/button.component'; 2 import { DeleteConfirmDialogComponent } from './generic/delete-confirm-dialog/delete-confirm-dialog.component'; 2 3 import { FileUploadComponent } from './generic/file-upload/file-upload.component'; 3 4 import { FormErrorComponent } from './generic/form-error/form-error.component'; … … 32 33 AnswerQuestionComponent, 33 34 EditAnswerDialogComponent, 34 EditAnswerResponseDialogComponent 35 EditAnswerResponseDialogComponent, 36 DeleteConfirmDialogComponent 35 37 ]; -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/question/question-preview/question-preview.component.html
r53bebc0 re071d30 48 48 {{ answerResponse.createdOn | momentDate: 'LL' }} 49 49 <span 50 class="cursor text-bold "50 class="cursor text-bold padding-right-sm" 51 51 *ngIf="studentQuestion.currentUserCanEditAnswerResponse(answerResponse)" 52 52 (click)="editAnswerResponse(question.uid, answer.uid, answerResponse.uid, answerResponse.text)" 53 53 >{{ 'question-preview-edit-answer-response' | translate }}</span 54 > 55 <span 56 class="cursor text-bold" 57 *ngIf="studentQuestion.currentUserCanDeleteAnswerResponse(answerResponse)" 58 (click)="deleteAnswerResponse(question.uid, answer.uid, answerResponse.uid)" 59 >{{ 'delete-button' | translate }}</span 54 60 > 55 61 <hr /> … … 68 74 >{{ 'question-preview-edit-answer' | translate }}</app-button 69 75 > 76 <app-button 77 *ngIf="studentQuestion.currentUserCanDeleteAnswer(answer)" 78 [disabled]="studentQuestion.currentUserCanNotDeleteAnswerBecauseMarkedCorrectEvenThoughHeIsTheAuthor(answer)" 79 matTooltip="{{ 'question-preview-can-not-delete-because-marked-correct' | translate }}" 80 [matTooltipDisabled]="!studentQuestion.currentUserCanNotDeleteAnswerBecauseMarkedCorrectEvenThoughHeIsTheAuthor(answer)" 81 (action)="deleteAnswer(question.uid, answer.uid)" 82 [buttonType]="ButtonType.Basic" 83 >{{ 'delete-button' | translate }}</app-button 84 > 70 85 </mat-card-actions> 71 86 </mat-card> -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/question/question-preview/question-preview.component.ts
r53bebc0 re071d30 58 58 this.dialog.editResponseToAnswer(questionUid, answerUid, answerResponseUid, text); 59 59 } 60 61 deleteAnswer(questionUid: string, answerUid: string): void { 62 this.dialog.confirmDelete().subscribe((canDelete) => { 63 if (canDelete) { 64 this.questionFacade.deleteAnswer(answerUid, questionUid); 65 } 66 }); 67 } 68 69 deleteAnswerResponse(questionUid: string, answerUid: string, answerResponseUid: string): void { 70 this.dialog.confirmDelete().subscribe((canDelete) => { 71 if (canDelete) { 72 this.questionFacade.deleteAnswerResponse(answerUid, questionUid, answerResponseUid); 73 } 74 }); 75 } 60 76 } -
src/Clients/Angular/finki-chattery/src/app/shared-app/services/shared-dialog.service.ts
r53bebc0 re071d30 2 2 import { MatDialog, MatDialogRef } from '@angular/material/dialog'; 3 3 import { Observable } from 'rxjs'; 4 import { DeleteConfirmDialogComponent } from '../components/generic/delete-confirm-dialog/delete-confirm-dialog.component'; 4 5 import { EditAnswerDialogComponent } from '../components/question/edit-answer-dialog/edit-answer-dialog.component'; 5 6 // tslint:disable-next-line: max-line-length … … 54 55 return dialogRef.afterClosed(); 55 56 } 57 58 public confirmDelete(title?: string): Observable<any> { 59 let dialogRef: MatDialogRef<DeleteConfirmDialogComponent>; 60 dialogRef = this.dialog.open(DeleteConfirmDialogComponent, { 61 width: '650px', 62 height: 'auto' 63 }); 64 65 if (title) { 66 dialogRef.componentInstance.title = title; 67 } 68 69 return dialogRef.afterClosed(); 70 } 56 71 } -
src/Clients/Angular/finki-chattery/src/assets/translations/en.json
r53bebc0 re071d30 73 73 "question-preview-edit-answer": "Edit answer", 74 74 "question-preview-edit-answer-response": "Edit response", 75 "success-delete-answer-response": "Successfully deleted answer response", 76 "success-delete-answer": "Successfully deleted answer", 77 "delete-button": "Delete", 78 "delete-basic-title": "Are you sure you want to delete this?", 79 "question-preview-can-not-delete-because-marked-correct": "Even though you are the author of the answer, it can not be deleted because it's marked as correct by the user who asked the question", 75 80 "StudentDoesNotOwnQuestion": "You do not own this question", 76 81 "AnswerAlreadyUpvoted": "You have already upvoted this answer", -
src/FinkiChattery/FinkiChattery.Api/Controllers/v1/AnswerResponsesController.cs
r53bebc0 re071d30 39 39 return Ok(answerResponse.ToAnswerResponseQuestionStateResponse()); 40 40 } 41 42 [HttpDelete("{answerResponseUid:Guid}")] 43 [Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme, Policy = AuthenticationPolicy.Student)] 44 public async Task<IActionResult> DeleteAnswerResponse([FromRoute] Guid questionUid, [FromRoute] Guid answerUid, [FromRoute] Guid answerResponseUid) 45 { 46 var uid = await MediatorService.SendAsync(new DeleteAnswerResponseCommand(questionUid, answerUid, answerResponseUid)); 47 return Ok(uid); 48 } 41 49 } 42 50 } -
src/FinkiChattery/FinkiChattery.Api/Controllers/v1/AnswersController.cs
r53bebc0 re071d30 40 40 } 41 41 42 [HttpDelete("{answerUid:Guid}")] 43 [Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme, Policy = AuthenticationPolicy.Student)] 44 public async Task<IActionResult> DeleteAnswer([FromRoute] Guid questionUid, [FromRoute] Guid answerUid) 45 { 46 var uid = await MediatorService.SendAsync(new DeleteAnswerCommand(questionUid, answerUid)); 47 return Ok(uid); 48 } 49 42 50 [HttpPut("{answerUid:Guid}/correct")] 43 51 [Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme, Policy = AuthenticationPolicy.Student)] -
src/FinkiChattery/FinkiChattery.Database/dbo/Tables/AnswerResponse/AnswerResponse.sql
r53bebc0 re071d30 7 7 [CreatedOn] SMALLDATETIME NOT NULL, 8 8 CONSTRAINT [PK_AnswerResponse] PRIMARY KEY CLUSTERED ([Id] ASC), 9 CONSTRAINT [FK_AnswerResponse_Answer_AnswerFk] FOREIGN KEY ([AnswerFk]) REFERENCES [dbo].[Answer] ([Id]) ,9 CONSTRAINT [FK_AnswerResponse_Answer_AnswerFk] FOREIGN KEY ([AnswerFk]) REFERENCES [dbo].[Answer] ([Id]) ON DELETE CASCADE, 10 10 CONSTRAINT [FK_AnswerResponse_Student_AnswerFk] FOREIGN KEY ([StudentFk]) REFERENCES [dbo].[Student] ([Id]) 11 11 ); -
src/FinkiChattery/FinkiChattery.Database/dbo/Tables/Vote/Vote.sql
r53bebc0 re071d30 6 6 [VoteType] TINYINT NOT NULL, 7 7 CONSTRAINT [PK_Vote] PRIMARY KEY CLUSTERED ([Id] ASC), 8 CONSTRAINT [FK_Vote_Answer_AnswerFk] FOREIGN KEY ([AnswerFk]) REFERENCES [dbo].[Answer] ([Id]) ,8 CONSTRAINT [FK_Vote_Answer_AnswerFk] FOREIGN KEY ([AnswerFk]) REFERENCES [dbo].[Answer] ([Id]) ON DELETE CASCADE, 9 9 CONSTRAINT [FK_Vote_Student_StudentFk] FOREIGN KEY ([StudentFk]) REFERENCES [dbo].[Student] ([Id]) 10 10 ); -
src/FinkiChattery/FinkiChattery.Persistence/Configurations/AnswerResponseConfig.cs
r53bebc0 re071d30 27 27 builder.Property(x => x.CreatedOn).HasColumnName(@"CreatedOn").HasColumnType("smalldatetime").IsRequired(); 28 28 29 builder.HasOne(x => x.Answer).WithMany(x => x.AnswerResponses).HasForeignKey(x => x.AnswerFk).OnDelete(DeleteBehavior. Restrict);29 builder.HasOne(x => x.Answer).WithMany(x => x.AnswerResponses).HasForeignKey(x => x.AnswerFk).OnDelete(DeleteBehavior.Cascade); 30 30 builder.HasOne(x => x.Student).WithMany().HasForeignKey(x => x.StudentFk).OnDelete(DeleteBehavior.Restrict); 31 31 } -
src/FinkiChattery/FinkiChattery.Persistence/Configurations/VoteConfig.cs
r53bebc0 re071d30 22 22 23 23 builder.HasOne(x => x.Student).WithMany().HasForeignKey(x => x.StudentFk).OnDelete(DeleteBehavior.Restrict); 24 builder.HasOne(x => x.Answer).WithMany(x => x.Votes).HasForeignKey(x => x.AnswerFk).OnDelete(DeleteBehavior. Restrict);24 builder.HasOne(x => x.Answer).WithMany(x => x.Votes).HasForeignKey(x => x.AnswerFk).OnDelete(DeleteBehavior.Cascade); 25 25 } 26 26 } -
src/FinkiChattery/FinkiChattery.Persistence/Repositories/Base/IRepository.cs
r53bebc0 re071d30 13 13 Task<T> GetByIdAsync(int id); 14 14 15 void Delete(T entity); 16 15 17 void Add(T entity); 16 18 } -
src/FinkiChattery/FinkiChattery.Persistence/Repositories/Base/Repository.cs
r53bebc0 re071d30 38 38 return await All().FirstOrDefaultAsync(f => f.Uid == uid); 39 39 } 40 41 public void Delete(T entity) 42 { 43 DbSet.Remove(entity); 44 } 40 45 } 41 46 }
Note:
See TracChangeset
for help on using the changeset viewer.