Changes in / [e071d30:53bebc0]
- Location:
- src
- Files:
-
- 8 deleted
- 18 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Clients/Angular/finki-chattery/src/app/core/services/student-question.service.ts
re071d30 r53bebc0 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 }30 18 } -
src/Clients/Angular/finki-chattery/src/app/core/state/question-facade.service.ts
re071d30 r53bebc0 15 15 import { 16 16 AnswerQuestion, 17 DeleteAnswer,18 DeleteAnswerResponse,19 17 EditAnswerQuestion, 20 18 EditAnswerResponse, … … 103 101 } 104 102 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 113 103 public fetchQuestion(questionUid: string): void { 114 104 this.dispatchEffect(new GetQuestionState(questionUid)); -
src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.actions.ts
re071d30 r53bebc0 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',39 35 EffectStartedWorking = '[Question] Effect Started Working', 40 36 EffectFinishedWorking = '[Question] Effect Finished Working', 41 37 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) {}66 38 } 67 39 … … 215 187 | EditAnswerQuestionSuccess 216 188 | EditAnswerResponseSuccess 217 | DeleteAnswerSuccess218 | DeleteAnswerResponseSuccess219 189 | EffectStartedWorking 220 190 | EffectFinishedWorking -
src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.effects.ts
re071d30 r53bebc0 19 19 AnswerQuestion, 20 20 AnswerQuestionSuccess, 21 DeleteAnswer,22 DeleteAnswerResponse,23 DeleteAnswerResponseSuccess,24 DeleteAnswerSuccess,25 21 EditAnswerQuestion, 26 22 EditAnswerQuestionSuccess, … … 240 236 ); 241 237 }); 242 243 deleteResponseToAnswer$ = createEffect(() => {244 return this.actions$.pipe(245 ofType<DeleteAnswerResponse>(QuestionActionTypes.DeleteAnswerResponse),246 mergeMap((action) => {247 return this.api248 .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 });270 238 } -
src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.reducers.ts
re071d30 r53bebc0 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 ...state177 };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 ...state201 };202 }203 164 case QuestionActionTypes.AnswerQuestionSuccess: { 204 165 if (state.question) { -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/components.ts
re071d30 r53bebc0 1 1 import { ButtonComponent } from './generic/button/button.component'; 2 import { DeleteConfirmDialogComponent } from './generic/delete-confirm-dialog/delete-confirm-dialog.component';3 2 import { FileUploadComponent } from './generic/file-upload/file-upload.component'; 4 3 import { FormErrorComponent } from './generic/form-error/form-error.component'; … … 33 32 AnswerQuestionComponent, 34 33 EditAnswerDialogComponent, 35 EditAnswerResponseDialogComponent, 36 DeleteConfirmDialogComponent 34 EditAnswerResponseDialogComponent 37 35 ]; -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/question/question-preview/question-preview.component.html
re071d30 r53bebc0 48 48 {{ answerResponse.createdOn | momentDate: 'LL' }} 49 49 <span 50 class="cursor text-bold padding-right-sm"50 class="cursor text-bold" 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 <span56 class="cursor text-bold"57 *ngIf="studentQuestion.currentUserCanDeleteAnswerResponse(answerResponse)"58 (click)="deleteAnswerResponse(question.uid, answer.uid, answerResponse.uid)"59 >{{ 'delete-button' | translate }}</span60 54 > 61 55 <hr /> … … 74 68 >{{ 'question-preview-edit-answer' | translate }}</app-button 75 69 > 76 <app-button77 *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-button84 >85 70 </mat-card-actions> 86 71 </mat-card> -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/question/question-preview/question-preview.component.ts
re071d30 r53bebc0 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 }76 60 } -
src/Clients/Angular/finki-chattery/src/app/shared-app/services/shared-dialog.service.ts
re071d30 r53bebc0 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';5 4 import { EditAnswerDialogComponent } from '../components/question/edit-answer-dialog/edit-answer-dialog.component'; 6 5 // tslint:disable-next-line: max-line-length … … 55 54 return dialogRef.afterClosed(); 56 55 } 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 }71 56 } -
src/Clients/Angular/finki-chattery/src/assets/translations/en.json
re071d30 r53bebc0 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",80 75 "StudentDoesNotOwnQuestion": "You do not own this question", 81 76 "AnswerAlreadyUpvoted": "You have already upvoted this answer", -
src/FinkiChattery/FinkiChattery.Api/Controllers/v1/AnswerResponsesController.cs
re071d30 r53bebc0 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 }49 41 } 50 42 } -
src/FinkiChattery/FinkiChattery.Api/Controllers/v1/AnswersController.cs
re071d30 r53bebc0 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 50 42 [HttpPut("{answerUid:Guid}/correct")] 51 43 [Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme, Policy = AuthenticationPolicy.Student)] -
src/FinkiChattery/FinkiChattery.Database/dbo/Tables/AnswerResponse/AnswerResponse.sql
re071d30 r53bebc0 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]) ON DELETE CASCADE,9 CONSTRAINT [FK_AnswerResponse_Answer_AnswerFk] FOREIGN KEY ([AnswerFk]) REFERENCES [dbo].[Answer] ([Id]), 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
re071d30 r53bebc0 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]) ON DELETE CASCADE,8 CONSTRAINT [FK_Vote_Answer_AnswerFk] FOREIGN KEY ([AnswerFk]) REFERENCES [dbo].[Answer] ([Id]), 9 9 CONSTRAINT [FK_Vote_Student_StudentFk] FOREIGN KEY ([StudentFk]) REFERENCES [dbo].[Student] ([Id]) 10 10 ); -
src/FinkiChattery/FinkiChattery.Persistence/Configurations/AnswerResponseConfig.cs
re071d30 r53bebc0 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. Cascade);29 builder.HasOne(x => x.Answer).WithMany(x => x.AnswerResponses).HasForeignKey(x => x.AnswerFk).OnDelete(DeleteBehavior.Restrict); 30 30 builder.HasOne(x => x.Student).WithMany().HasForeignKey(x => x.StudentFk).OnDelete(DeleteBehavior.Restrict); 31 31 } -
src/FinkiChattery/FinkiChattery.Persistence/Configurations/VoteConfig.cs
re071d30 r53bebc0 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. Cascade);24 builder.HasOne(x => x.Answer).WithMany(x => x.Votes).HasForeignKey(x => x.AnswerFk).OnDelete(DeleteBehavior.Restrict); 25 25 } 26 26 } -
src/FinkiChattery/FinkiChattery.Persistence/Repositories/Base/IRepository.cs
re071d30 r53bebc0 13 13 Task<T> GetByIdAsync(int id); 14 14 15 void Delete(T entity);16 17 15 void Add(T entity); 18 16 } -
src/FinkiChattery/FinkiChattery.Persistence/Repositories/Base/Repository.cs
re071d30 r53bebc0 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 }45 40 } 46 41 }
Note:
See TracChangeset
for help on using the changeset viewer.