Changeset 53bebc0


Ignore:
Timestamp:
11/09/21 16:14:30 (3 years ago)
Author:
Стојков Марко <mst@…>
Branches:
dev
Children:
6165fd0, e071d30
Parents:
74ad056 (diff), 9df3069 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merged feature/edit-answer-and-answer-response into dev

Location:
src
Files:
15 added
17 edited

Legend:

Unmodified
Added
Removed
  • src/Clients/Angular/finki-chattery/src/app/core/state/question-facade.service.ts

    r74ad056 r53bebc0  
    1515import {
    1616  AnswerQuestion,
     17  EditAnswerQuestion,
     18  EditAnswerResponse,
    1719  EffectStartedWorking,
    1820  GetPreviewQuestionsLatest,
     
    9193  }
    9294
     95  public editAnswerResponse(answerUid: string, questionUid: string, answerResponseUid: string, text: string): void {
     96    this.dispatchEffect(new EditAnswerResponse(questionUid, answerUid, answerResponseUid, text));
     97  }
     98
     99  public editAnswer(answerUid: string, questionUid: string, text: string): void {
     100    this.dispatchEffect(new EditAnswerQuestion(questionUid, answerUid, text));
     101  }
     102
    93103  public fetchQuestion(questionUid: string): void {
    94104    this.dispatchEffect(new GetQuestionState(questionUid));
  • src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.actions.ts

    r74ad056 r53bebc0  
    2929  AnswerQuestion = '[Question] AnswerQuestion',
    3030  AnswerQuestionSuccess = '[Question] AnswerQuestion Success',
     31  EditAnswerQuestion = '[Question] EditAnswerQuestion',
     32  EditAnswerQuestionSuccess = '[Question] EditAnswerQuestion Success',
     33  EditAnswerResponse = '[Question] EditAnswerResponse',
     34  EditAnswerResponseSuccess = '[Question] EditAnswerResponse Success',
    3135  EffectStartedWorking = '[Question] Effect Started Working',
    3236  EffectFinishedWorking = '[Question] Effect Finished Working',
    3337  EffectFinishedWorkingError = '[Question] Effect Finished Working error'
     38}
     39
     40export class EditAnswerQuestion implements Action {
     41  readonly type = QuestionActionTypes.EditAnswerQuestion;
     42
     43  constructor(public questionUid: string, public answerUid: string, public text: string) {}
     44}
     45
     46export class EditAnswerQuestionSuccess implements Action {
     47  readonly type = QuestionActionTypes.EditAnswerQuestionSuccess;
     48
     49  constructor(public payload: AnswerQuestionStateViewModel, public answerUid: string) {}
     50}
     51
     52export class EditAnswerResponse implements Action {
     53  readonly type = QuestionActionTypes.EditAnswerResponse;
     54
     55  constructor(public questionUid: string, public answerUid: string, public answerResponseUid: string, public text: string) {}
     56}
     57
     58export class EditAnswerResponseSuccess implements Action {
     59  readonly type = QuestionActionTypes.EditAnswerResponseSuccess;
     60
     61  constructor(public payload: AnswerResponseQuestionStateViewModel, public answerUid: string, public answerResponseUid: string) {}
    3462}
    3563
     
    157185  | RespondToAnswerSuccess
    158186  | AnswerQuestionSuccess
     187  | EditAnswerQuestionSuccess
     188  | EditAnswerResponseSuccess
    159189  | EffectStartedWorking
    160190  | EffectFinishedWorking
  • src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.effects.ts

    r74ad056 r53bebc0  
    1919  AnswerQuestion,
    2020  AnswerQuestionSuccess,
     21  EditAnswerQuestion,
     22  EditAnswerQuestionSuccess,
     23  EditAnswerResponse,
     24  EditAnswerResponseSuccess,
    2125  EffectFinishedWorking,
    2226  EffectFinishedWorkingError,
     
    186190    );
    187191  });
     192
     193  editResponseToAnswer$ = createEffect(() => {
     194    return this.actions$.pipe(
     195      ofType<EditAnswerResponse>(QuestionActionTypes.EditAnswerResponse),
     196      mergeMap((action) => {
     197        return this.api
     198          .put<AnswerResponseQuestionStateResponse>(
     199            `v1/questions/${action.questionUid}/answers/${action.answerUid}/answerresponses/${action.answerResponseUid}`,
     200            new RespondToAnswerRequest(action.text)
     201          )
     202          .pipe(
     203            tap((state) => this.notification.successNotification('success-edit-answer-response')),
     204            switchMap((state) => [
     205              new EditAnswerResponseSuccess(
     206                QuestionMapper.ToAnswerResponseQuestionStateViewModel(state),
     207                action.answerUid,
     208                action.answerResponseUid
     209              ),
     210              new EffectFinishedWorking()
     211            ]),
     212            catchError((err) => [new EffectFinishedWorkingError(err)])
     213          );
     214      })
     215    );
     216  });
     217
     218  editAnswer$ = createEffect(() => {
     219    return this.actions$.pipe(
     220      ofType<EditAnswerQuestion>(QuestionActionTypes.EditAnswerQuestion),
     221      mergeMap((action) => {
     222        return this.api
     223          .put<AnswerQuestionStateResponse>(
     224            `v1/questions/${action.questionUid}/answers/${action.answerUid}`,
     225            new AnswerQuestionRequest(action.text)
     226          )
     227          .pipe(
     228            tap((state) => this.notification.successNotification('success-edit-answer')),
     229            switchMap((state) => [
     230              new EditAnswerQuestionSuccess(QuestionMapper.ToAnswerQuestionStateViewModel(state), action.answerUid),
     231              new EffectFinishedWorking()
     232            ]),
     233            catchError((err) => [new EffectFinishedWorkingError(err)])
     234          );
     235      })
     236    );
     237  });
    188238}
  • src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.reducers.ts

    r74ad056 r53bebc0  
    114114      };
    115115    }
     116    case QuestionActionTypes.EditAnswerResponseSuccess: {
     117      if (state.question) {
     118        return {
     119          ...state,
     120          question: {
     121            ...state.question,
     122            answers: state.question.answers.map((x) => {
     123              if (x.uid === action.answerUid) {
     124                return {
     125                  ...x,
     126                  answerResponses: [...x.answerResponses.filter((y) => y.uid !== action.answerResponseUid), action.payload]
     127                };
     128              }
     129
     130              return x;
     131            })
     132          }
     133        };
     134      }
     135
     136      return {
     137        ...state
     138      };
     139    }
     140    case QuestionActionTypes.EditAnswerQuestionSuccess: {
     141      if (state.question) {
     142        return {
     143          ...state,
     144          question: {
     145            ...state.question,
     146            answers: state.question.answers.map((x) => {
     147              if (x.uid === action.answerUid) {
     148                return {
     149                  ...x,
     150                  text: action.payload.text
     151                };
     152              }
     153
     154              return x;
     155            })
     156          }
     157        };
     158      }
     159
     160      return {
     161        ...state
     162      };
     163    }
    116164    case QuestionActionTypes.AnswerQuestionSuccess: {
    117165      if (state.question) {
  • src/Clients/Angular/finki-chattery/src/app/shared-app/components/components.ts

    r74ad056 r53bebc0  
    77import { AnswerQuestionComponent } from './question/answer-question/answer-question.component';
    88import { AskQuestionSharedComponent } from './question/ask-question-shared/ask-question-shared.component';
     9import { EditAnswerDialogComponent } from './question/edit-answer-dialog/edit-answer-dialog.component';
     10import { EditAnswerResponseDialogComponent } from './question/edit-answer-response-dialog/edit-answer-response-dialog.component';
    911import { PreviewQuestionDisplayComponent } from './question/preview-question-display/preview-question-display.component';
    1012import { PreviewQuestionFullComponent } from './question/preview-question-full/preview-question-full.component';
     
    2830  TextEditorComponent,
    2931  RespondToAnswerDialogComponent,
    30   AnswerQuestionComponent
     32  AnswerQuestionComponent,
     33  EditAnswerDialogComponent,
     34  EditAnswerResponseDialogComponent
    3135];
  • src/Clients/Angular/finki-chattery/src/app/shared-app/components/question/question-preview/question-preview.component.html

    r74ad056 r53bebc0  
    4747              <mat-chip class="cursor">{{ answerResponse.student.index }}</mat-chip> -
    4848              {{ answerResponse.createdOn | momentDate: 'LL' }}
     49              <span
     50                class="cursor text-bold"
     51                *ngIf="studentQuestion.currentUserCanEditAnswerResponse(answerResponse)"
     52                (click)="editAnswerResponse(question.uid, answer.uid, answerResponse.uid, answerResponse.text)"
     53                >{{ 'question-preview-edit-answer-response' | translate }}</span
     54              >
    4955              <hr />
    5056            </div>
     
    5662          'question-preview-respond-to-answer-button' | translate
    5763        }}</app-button>
     64        <app-button
     65          *ngIf="studentQuestion.currentUserCanEditAnswer(answer)"
     66          (action)="editAnswer(question.uid, answer.uid, answer.text)"
     67          [buttonType]="ButtonType.Basic"
     68          >{{ 'question-preview-edit-answer' | translate }}</app-button
     69        >
    5870      </mat-card-actions>
    5971    </mat-card>
  • src/Clients/Angular/finki-chattery/src/app/shared-app/components/question/question-preview/question-preview.component.ts

    r74ad056 r53bebc0  
    22import { Component, OnInit } from '@angular/core';
    33import { NotificationService } from 'src/app/core/services/notification.service';
     4import { StudentQuestionService } from 'src/app/core/services/student-question.service';
    45import { QuestionFacadeService } from 'src/app/core/state/question-facade.service';
    56
     
    2122    private questionFacade: QuestionFacadeService,
    2223    private notification: NotificationService,
    23     private dialog: SharedDialogService
     24    private dialog: SharedDialogService,
     25    public studentQuestion: StudentQuestionService
    2426  ) {}
    2527
     
    4850    this.dialog.respondToAnswer(this.question.uid, answerUid);
    4951  }
     52
     53  editAnswer(questionUid: string, answerUid: string, text: string): void {
     54    this.dialog.editAnswer(questionUid, answerUid, text);
     55  }
     56
     57  editAnswerResponse(questionUid: string, answerUid: string, answerResponseUid: string, text: string): void {
     58    this.dialog.editResponseToAnswer(questionUid, answerUid, answerResponseUid, text);
     59  }
    5060}
  • src/Clients/Angular/finki-chattery/src/app/shared-app/components/question/respond-to-answer-dialog/respond-to-answer-dialog.component.html

    r74ad056 r53bebc0  
    1313</mat-dialog-content>
    1414<mat-dialog-actions>
    15   <app-button [buttonType]="ButtonType.Basic" (action)="dialogRef.close()">
     15  <app-button class="margin-right-sm" [buttonType]="ButtonType.Basic" (action)="dialogRef.close()">
    1616    {{ 'close-button' | translate }}
    1717  </app-button>
  • src/Clients/Angular/finki-chattery/src/app/shared-app/services/shared-dialog.service.ts

    r74ad056 r53bebc0  
    22import { MatDialog, MatDialogRef } from '@angular/material/dialog';
    33import { Observable } from 'rxjs';
     4import { EditAnswerDialogComponent } from '../components/question/edit-answer-dialog/edit-answer-dialog.component';
     5// tslint:disable-next-line: max-line-length
     6import { EditAnswerResponseDialogComponent } from '../components/question/edit-answer-response-dialog/edit-answer-response-dialog.component';
    47import { RespondToAnswerDialogComponent } from '../components/question/respond-to-answer-dialog/respond-to-answer-dialog.component';
    58
     
    2225    return dialogRef.afterClosed();
    2326  }
     27
     28  public editResponseToAnswer(questionUid: string, answerUid: string, answerResponseUid: string, text: string): Observable<any> {
     29    let dialogRef: MatDialogRef<EditAnswerResponseDialogComponent>;
     30    dialogRef = this.dialog.open(EditAnswerResponseDialogComponent, {
     31      width: '650px',
     32      height: 'auto'
     33    });
     34
     35    dialogRef.componentInstance.questionUid = questionUid;
     36    dialogRef.componentInstance.answerUid = answerUid;
     37    dialogRef.componentInstance.answerResponseUid = answerResponseUid;
     38    dialogRef.componentInstance.textFieldValue = text;
     39
     40    return dialogRef.afterClosed();
     41  }
     42
     43  public editAnswer(questionUid: string, answerUid: string, text: string): Observable<any> {
     44    let dialogRef: MatDialogRef<EditAnswerDialogComponent>;
     45    dialogRef = this.dialog.open(EditAnswerDialogComponent, {
     46      width: '650px',
     47      height: 'auto'
     48    });
     49
     50    dialogRef.componentInstance.questionUid = questionUid;
     51    dialogRef.componentInstance.answerUid = answerUid;
     52    dialogRef.componentInstance.textFieldValue = text;
     53
     54    return dialogRef.afterClosed();
     55  }
    2456}
  • src/Clients/Angular/finki-chattery/src/assets/translations/en.json

    r74ad056 r53bebc0  
    6767  "answer-question-title": "Give your answer to the question",
    6868  "answer-question-button": "Answer",
     69  "success-edit-answer-response": "Successfully edited response to answer",
     70  "success-edit-answer": "Successfully edited answer",
     71  "edit-respond-to-answer-title": "Edit answer response",
     72  "edit-answer-title": "Edit answer",
     73  "question-preview-edit-answer": "Edit answer",
     74  "question-preview-edit-answer-response": "Edit response",
    6975  "StudentDoesNotOwnQuestion": "You do not own this question",
    7076  "AnswerAlreadyUpvoted": "You have already upvoted this answer",
  • src/FinkiChattery/FinkiChattery.Api/Controllers/v1/AnswerResponsesController.cs

    r74ad056 r53bebc0  
    3131            return Ok(answerResponse.ToAnswerResponseQuestionStateResponse());
    3232        }
     33
     34        [HttpPut("{answerResponseUid:Guid}")]
     35        [Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme, Policy = AuthenticationPolicy.Student)]
     36        public async Task<IActionResult> EditAnswerResponse([FromRoute] Guid questionUid, [FromRoute] Guid answerUid, [FromRoute] Guid answerResponseUid, [FromBody] AnswerResponseRequest request)
     37        {
     38            var answerResponse = await MediatorService.SendAsync(new EditAnswerResponseCommand(questionUid, answerUid, answerResponseUid, request.Text));
     39            return Ok(answerResponse.ToAnswerResponseQuestionStateResponse());
     40        }
    3341    }
    3442}
  • src/FinkiChattery/FinkiChattery.Api/Controllers/v1/AnswersController.cs

    r74ad056 r53bebc0  
    3232        }
    3333
     34        [HttpPut("{answerUid:Guid}")]
     35        [Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme, Policy = AuthenticationPolicy.Student)]
     36        public async Task<IActionResult> EditAnswer([FromRoute] Guid questionUid, [FromRoute] Guid answerUid, [FromBody] AnswerQuestionRequest request)
     37        {
     38            var answer = await MediatorService.SendAsync(new EditAnswerCommand(questionUid, answerUid, request.Text));
     39            return Ok(answer.ToAnswerQuestionStateResponse());
     40        }
     41
    3442        [HttpPut("{answerUid:Guid}/correct")]
    3543        [Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme, Policy = AuthenticationPolicy.Student)]
  • src/FinkiChattery/FinkiChattery.Commands/Questioning/QuestioningErrorCodes.cs

    r74ad056 r53bebc0  
    1717        public const string AnswerInQuestionNotFound = "AnswerInQuestionNotFound";
    1818        public const string StudentDoesNotOwnQuestion = "StudentDoesNotOwnQuestion";
     19        public const string StudentDoesNotOwnAnswer = "StudentDoesNotOwnAnswer";
     20        public const string StudentDoesNotOwnAnswerResponse = "StudentDoesNotOwnAnswerResponse";
    1921        public const string AnswerIsAlreadyMarkedAsCorrect = "AnswerIsAlreadyMarkedAsCorrect";
    2022    }
  • src/FinkiChattery/FinkiChattery.Persistence/Repositories/Contracts/IAnswerRepo.cs

    r74ad056 r53bebc0  
    88    {
    99        Task<bool> AnswerInQuestionExists(Guid questionUid, Guid answerUid);
     10
     11        Task<bool> AnswerIsOwnedByStudent(Guid answerUid, long applicationUserId);
    1012    }
    1113}
  • src/FinkiChattery/FinkiChattery.Persistence/Repositories/Contracts/IAnswerResponseRepo.cs

    r74ad056 r53bebc0  
    11using FinkiChattery.Persistence.Models;
     2using System;
     3using System.Threading.Tasks;
    24
    35namespace FinkiChattery.Persistence.Repositories
     
    57    public interface IAnswerResponseRepo : IRepository<AnswerResponse>
    68    {
     9        Task<bool> StudentIsOwnerOfAnswerResponse(Guid answerResponseUid, long applicationUserId);
    710    }
    811}
  • src/FinkiChattery/FinkiChattery.Persistence/Repositories/Implementations/AnswerRepo.cs

    r74ad056 r53bebc0  
    2121                .AnyAsync();
    2222        }
     23
     24        public async Task<bool> AnswerIsOwnedByStudent(Guid answerUid, long applicationUserId)
     25        {
     26            return await DbSet
     27                .AsNoTracking()
     28                .Where(x => x.Uid == answerUid && x.Student.ApplicationUserFk == applicationUserId)
     29                .AnyAsync();
     30        }
    2331    }
    2432}
  • src/FinkiChattery/FinkiChattery.Persistence/Repositories/Implementations/AnswerResponseRepo.cs

    r74ad056 r53bebc0  
    11using FinkiChattery.Persistence.Context;
    22using FinkiChattery.Persistence.Models;
     3using Microsoft.EntityFrameworkCore;
     4using System;
     5using System.Linq;
     6using System.Threading.Tasks;
    37
    48namespace FinkiChattery.Persistence.Repositories
     
    913        {
    1014        }
     15
     16        public async Task<bool> StudentIsOwnerOfAnswerResponse(Guid answerResponseUid, long applicationUserId)
     17        {
     18            return await DbSet
     19                .AsNoTracking()
     20                .Where(x => x.Uid == answerResponseUid && x.Student.ApplicationUserFk == applicationUserId)
     21                .AnyAsync();
     22        }
    1123    }
    1224}
Note: See TracChangeset for help on using the changeset viewer.