Changes in / [b9d7ae5:80e2fe0]
- Location:
- src
- Files:
-
- 23 deleted
- 24 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Clients/Angular/finki-chattery/src/app/core/services/auth.service.ts
rb9d7ae5 r80e2fe0 24 24 public user: ApplicationUser | null = null; 25 25 public oidcUser: User | null = null; 26 public selfUser: SelfUserResponse | null = null;27 26 28 27 constructor(private baseApi: BaseApiService) { … … 36 35 user?.profile.isVerified 37 36 ); 38 39 this.selfUserDto().subscribe((selfUser) => {40 if (selfUser) {41 this.selfUser = selfUser;42 }43 });44 37 }); 45 38 } … … 93 86 user.profile.isVerified 94 87 ); 95 96 if (!this.selfUser) {97 this.selfUserDto().subscribe((selfUser) => {98 if (selfUser) {99 this.selfUser = selfUser;100 }101 });102 }103 88 }); 104 89 } -
src/Clients/Angular/finki-chattery/src/app/core/state/question-facade.service.ts
rb9d7ae5 r80e2fe0 3 3 import { Action, Store } from '@ngrx/store'; 4 4 import { Observable, Subject } from 'rxjs'; 5 import { filter , map} from 'rxjs/operators';5 import { filter } from 'rxjs/operators'; 6 6 7 7 import { … … 12 12 VoteType 13 13 } from 'src/app/shared-app/models'; 14 import { AuthService } from '../services';15 14 import { 16 15 EffectStartedWorking, … … 19 18 GetQuestionState, 20 19 GetSearchQuestions, 21 SetCorrectAnswer,22 20 VoteAnswer 23 21 } from './question-state/question.actions'; … … 33 31 effectWorking$: Observable<boolean | HttpErrorResponse>; 34 32 35 constructor(private store: Store<QuestionState> , private auth: AuthService) {33 constructor(private store: Store<QuestionState>) { 36 34 this.effectWorking$ = this.store.select(questionStateQuery.effectWorking).pipe(filter((effect) => effect !== null)); 37 }38 39 public currentQuestionOwnedByCurrentUser(): Observable<boolean> {40 return this.getQuestion().pipe(map((question) => this.auth.selfUser?.student?.uid === question.student.uid));41 35 } 42 36 … … 77 71 } 78 72 79 public setCorrectAnswer(questionUid: string, answerUid: string): void {80 this.dispatchEffect(new SetCorrectAnswer(questionUid, answerUid));81 }82 83 73 public voteAnswer(answerUid: string, questionUid: string, voteType: VoteType): void { 84 74 this.dispatchEffect(new VoteAnswer(questionUid, answerUid, voteType)); -
src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.actions.ts
rb9d7ae5 r80e2fe0 13 13 GetQuestionState = '[Question] Get state', 14 14 GetQuestionStateSuccess = '[Question] Get state success', 15 SetCorrectAnswer = '[Question] Set Correct Answer',16 SetCorrectAnswerSuccess = '[Question] Set Correct Answer success',17 15 GetPreviewQuestionsLatest = '[Question] Get preview questions Latest', 18 16 GetPreviewQuestionsLatestSuccess = '[Question] Get preview questions Latest Success', … … 38 36 39 37 constructor(public payload: QuestionStateViewModel) {} 40 }41 42 export class SetCorrectAnswer implements Action {43 readonly type = QuestionActionTypes.SetCorrectAnswer;44 45 constructor(public questionUid: string, public answerUid: string) {}46 }47 48 export class SetCorrectAnswerSuccess implements Action {49 readonly type = QuestionActionTypes.SetCorrectAnswerSuccess;50 51 constructor(public payload: string) {}52 38 } 53 39 … … 124 110 | GetSearchQuestionsSuccess 125 111 | VoteAnswerSuccess 126 | SetCorrectAnswerSuccess127 112 | EffectStartedWorking 128 113 | EffectFinishedWorking -
src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.effects.ts
rb9d7ae5 r80e2fe0 1 1 import { Injectable } from '@angular/core'; 2 2 import { act, Actions, createEffect, ofType } from '@ngrx/effects'; 3 import { catchError, filter, mergeMap, switchMap, tap,withLatestFrom } from 'rxjs/operators';3 import { catchError, filter, mergeMap, switchMap, withLatestFrom } from 'rxjs/operators'; 4 4 import { PreviewQuestionsOrderEnum, SearchQuestionsQueryViewModel } from 'src/app/shared-app/models'; 5 5 import { TranslateFromJsonService } from 'src/app/shared-app/services'; 6 6 7 7 import { BaseApiService } from 'src/app/shared-app/services/base-api.service'; 8 import { NotificationService } from '../../services/notification.service';9 8 import { QuestionFacadeService } from '../question-facade.service'; 10 9 import { VoteAnswerRequest } from './question-state-request.models'; … … 22 21 GetSearchQuestionsSuccess, 23 22 QuestionActionTypes, 24 SetCorrectAnswer,25 SetCorrectAnswerSuccess,26 23 VoteAnswer, 27 24 VoteAnswerSuccess … … 37 34 private api: BaseApiService, 38 35 private translate: TranslateFromJsonService, 39 private facade: QuestionFacadeService, 40 private notification: NotificationService 36 private facade: QuestionFacadeService 41 37 ) {} 42 38 … … 117 113 const body = new VoteAnswerRequest(action.voteType); 118 114 return this.api.post<VoteAnswerResponse>(`v1/questions/${action.questionUid}/answers/${action.answerUid}/votes`, body).pipe( 119 tap((state) => this.notification.successNotification('sucess-vote')),120 115 switchMap((state) => [new VoteAnswerSuccess(QuestionMapper.ToVoteAnswerViewModel(state)), new EffectFinishedWorking()]), 121 116 catchError((err) => [new EffectFinishedWorkingError(err)]) … … 124 119 ); 125 120 }); 126 127 setCorrectAnswer$ = createEffect(() => {128 return this.actions$.pipe(129 ofType<SetCorrectAnswer>(QuestionActionTypes.SetCorrectAnswer),130 mergeMap((action) => {131 return this.api.put<string>(`v1/questions/${action.questionUid}/answers/${action.answerUid}/correct`).pipe(132 tap((state) => this.notification.successNotification('success-correct-answer')),133 switchMap((state) => [new SetCorrectAnswerSuccess(state), new EffectFinishedWorking()]),134 catchError((err) => [new EffectFinishedWorkingError(err)])135 );136 })137 );138 });139 121 } -
src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.reducers.ts
rb9d7ae5 r80e2fe0 1 import { AnswerQuestionStateViewModel,VoteType } from 'src/app/shared-app/models';1 import { VoteType } from 'src/app/shared-app/models'; 2 2 import { QuestionAction, QuestionActionTypes } from './question.actions'; 3 3 import { initialState, QuestionState } from './question.state'; … … 61 61 }; 62 62 } 63 case QuestionActionTypes.SetCorrectAnswerSuccess: {64 if (state.question) {65 return {66 ...state,67 question: {68 ...state.question,69 answers: state.question.answers.map((x) => {70 if (x.correctAnswer) {71 return {72 ...x,73 correctAnswer: false74 };75 }76 if (x.uid === action.payload) {77 return {78 ...x,79 correctAnswer: true80 };81 }82 return x;83 })84 }85 };86 }87 88 return {89 ...state90 };91 }92 63 case QuestionActionTypes.EffectStartedWorking: { 93 64 return { -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/generic/vote/vote.component.html
rb9d7ae5 r80e2fe0 1 <div class="main-div">1 <div> 2 2 <div class="vote-icons" fxLayout="column" fxLayoutAlign="center center"> 3 3 <mat-icon class="vote-icon" (click)="voted(VoteType.Upvote)" [inline]="true">arrow_drop_up</mat-icon> … … 7 7 >check</mat-icon 8 8 > 9 <mat-icon10 *ngIf="canSetCorrectAnswer && !correct"11 [inline]="true"12 class="text-center text-bold green set-correct-answer"13 (click)="setCorrectAnswer.emit()"14 >check</mat-icon15 >16 9 </div> 17 10 </div> -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/generic/vote/vote.component.scss
rb9d7ae5 r80e2fe0 14 14 cursor: pointer; 15 15 } 16 17 .show-on-hover {18 display: none;19 }20 21 .set-correct-answer {22 opacity: 0.3;23 visibility: hidden;24 }25 26 .main-div:hover > .vote-icons > .set-correct-answer {27 visibility: visible;28 }29 30 .main-div {31 height: 100%;32 } -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/generic/vote/vote.component.ts
rb9d7ae5 r80e2fe0 10 10 export class VoteComponent implements OnInit { 11 11 @Input() voteCount: number | undefined; 12 @Input() canSetCorrectAnswer: boolean | null = false;13 12 @Input() correct = false; 14 13 @Output() voteClicked = new EventEmitter<VoteType>(); 15 @Output() setCorrectAnswer = new EventEmitter<void>();16 14 17 15 VoteType = VoteType; -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/question/question-preview/question-preview.component.html
rb9d7ae5 r80e2fe0 15 15 <div fxLayout="row wrap" fxLayoutAlign="space-around none"> 16 16 <app-vote 17 [canSetCorrectAnswer]="canSetCorrectAnswer | async"18 17 [voteCount]="answer.votesCount" 19 18 [correct]="answer.correctAnswer" 20 19 (voteClicked)="answerVoted($event, answer.uid, question.uid)" 21 (setCorrectAnswer)="setCorrectAnswer(question.uid, answer.uid)"22 20 fxFlex="6%" 23 21 ></app-vote> -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/question/question-preview/question-preview.component.ts
rb9d7ae5 r80e2fe0 13 13 }) 14 14 export class QuestionPreviewComponent implements OnInit { 15 canSetCorrectAnswer = this.questionFacade.currentQuestionOwnedByCurrentUser();16 15 question!: QuestionStateViewModel; 17 16 working = true; … … 35 34 this.questionFacade.voteAnswer(answerUid, questionUid, voteType); 36 35 } 37 38 setCorrectAnswer(questionUid: string, answerUid: string): void {39 this.questionFacade.setCorrectAnswer(questionUid, answerUid);40 }41 36 } -
src/Clients/Angular/finki-chattery/src/app/shared-app/models/user.models.ts
rb9d7ae5 r80e2fe0 9 9 } 10 10 11 export class SelfUserResponse { 12 uid!: string; 13 } 14 11 15 export enum ApplicationUserType { 12 16 Student = 'Student', … … 15 19 Guest = 'Guest' 16 20 } 17 18 export class SelfUserResponse {19 public student?: StudentSelfResponse | null;20 public teacher?: TeacherSelfResponse | null;21 public moderator?: ModeratorSelfResponse | null;22 }23 24 export class StudentSelfResponse {25 public uid!: string;26 public applicationUserId!: number;27 public index!: string;28 public reputation!: number;29 public imageUrl!: string;30 public questions!: StudentQuestionResponse[];31 public teams!: StudentTeamResponse[];32 }33 34 export class StudentQuestionResponse {35 public questionUid!: string;36 public title!: string;37 }38 39 export class StudentTeamResponse {40 public teamUid!: string;41 public name!: string;42 }43 44 export class ModeratorSelfResponse {45 public uid!: string;46 public applicationUserId!: number;47 }48 49 export class TeacherSelfResponse {50 public uid!: string;51 public applicationUserId!: number;52 public teams!: TeacherTeamResponse[];53 }54 55 export class TeacherTeamResponse {56 public teamUid!: string;57 public name!: string;58 } -
src/Clients/Angular/finki-chattery/src/app/shared-app/services/base-api.service.ts
rb9d7ae5 r80e2fe0 19 19 20 20 public getSelfUser(): Observable<SelfUserResponse> { 21 return this.get<SelfUserResponse>(' v1/self');21 return this.get<SelfUserResponse>('self'); 22 22 } 23 23 -
src/Clients/Angular/finki-chattery/src/assets/translations/en.json
rb9d7ae5 r80e2fe0 53 53 "ask-question-stepper-ask": "Ask question", 54 54 "ask-question-ask-button-back": "Edit question", 55 "sucess-vote": "Successfully voted answer",56 "success-correct-answer": "Successfully set correct answer",57 55 "ask-question-ask-button": "Ask question", 58 56 "AnswerAlreadyUpvoted": "You have already upvoted this answer", -
src/FinkiChattery/FinkiChattery.Api/Controllers/v1/AnswersController.cs
rb9d7ae5 r80e2fe0 30 30 return Ok(answerUid); 31 31 } 32 33 [HttpPut("{answerUid:Guid}/correct")]34 [Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme, Policy = AuthenticationPolicy.Student)]35 public async Task<IActionResult> MarkAnswerCorrect([FromRoute] Guid questionUid, [FromRoute] Guid answerUid)36 {37 await MediatorService.SendAsync(new MarkAnswerCorrectCommand(questionUid, answerUid));38 return Ok(answerUid);39 }40 32 } 41 33 } -
src/FinkiChattery/FinkiChattery.Commands/Questioning/QuestioningErrorCodes.cs
rb9d7ae5 r80e2fe0 13 13 public const string StudentHasBadReputation = "StudentHasBadReputation"; 14 14 public const string AnswerTextLengthInvalid = "AnswerTextLengthInvalid"; 15 public const string QuestionNotFound = "QuestionNotFound"; 16 public const string AnswerInQuestionNotFound = "AnswerInQuestionNotFound"; 17 public const string StudentDoesNotOwnQuestion = "StudentDoesNotOwnQuestion"; 18 public const string AnswerIsAlreadyMarkedAsCorrect = "AnswerIsAlreadyMarkedAsCorrect"; 15 public const string QuestionNotFound = "QuestionNotFound"; 19 16 } 20 17 } -
src/FinkiChattery/FinkiChattery.Persistence/Models/Moderator.cs
rb9d7ae5 r80e2fe0 1 namespace FinkiChattery.Persistence.Models 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace FinkiChattery.Persistence.Models 2 8 { 3 9 public class Moderator : BaseEntity -
src/FinkiChattery/FinkiChattery.Persistence/Repositories/Contracts/IAnswerRepo.cs
rb9d7ae5 r80e2fe0 1 1 using FinkiChattery.Persistence.Models; 2 using System;3 using System.Threading.Tasks;4 2 5 3 namespace FinkiChattery.Persistence.Repositories … … 7 5 public interface IAnswerRepo : IRepository<Answer> 8 6 { 9 Task<bool> AnswerInQuestionExists(Guid questionUid, Guid answerUid);10 7 } 11 8 } -
src/FinkiChattery/FinkiChattery.Persistence/Repositories/Contracts/IQuestionRepo.cs
rb9d7ae5 r80e2fe0 16 16 17 17 Task<List<QuestionPreviewDto>> GetPreviewQuestionsPopular(); 18 19 Task<bool> QuestionIsOwnedByStudent(Guid questionUid, long applicationUserId);20 21 Task<Question> GetQuestionWithAnswersAndStudents(Guid questionUid);22 18 } 23 19 } -
src/FinkiChattery/FinkiChattery.Persistence/Repositories/Contracts/IStudentRepo.cs
rb9d7ae5 r80e2fe0 1 1 using FinkiChattery.Persistence.Models; 2 using FinkiChattery.Persistence.Repositories.Contracts;3 2 using System.Threading.Tasks; 4 3 … … 8 7 { 9 8 public Task<Student> GetStudent(long applicationUserFk); 10 public Task<StudentSelfDto> GetStudentSelfDto(long applicationUserFk);11 9 } 12 10 } -
src/FinkiChattery/FinkiChattery.Persistence/Repositories/Implementations/AnswerRepo.cs
rb9d7ae5 r80e2fe0 1 1 using FinkiChattery.Persistence.Context; 2 2 using FinkiChattery.Persistence.Models; 3 using Microsoft.EntityFrameworkCore;4 using System;5 using System.Linq;6 using System.Threading.Tasks;7 3 8 4 namespace FinkiChattery.Persistence.Repositories … … 13 9 { 14 10 } 15 16 public async Task<bool> AnswerInQuestionExists(Guid questionUid, Guid answerUid)17 {18 return await DbSet19 .AsNoTracking()20 .Where(x => x.Question.Uid == questionUid && x.Uid == answerUid)21 .AnyAsync();22 }23 11 } 24 12 } -
src/FinkiChattery/FinkiChattery.Persistence/Repositories/Implementations/QuestionRepo.cs
rb9d7ae5 r80e2fe0 144 144 .ToListAsync(); 145 145 } 146 147 public async Task<bool> QuestionIsOwnedByStudent(Guid questionUid, long applicationUserId)148 {149 return await DbSet150 .Where(x => x.Uid == questionUid && x.Student.ApplicationUserFk == applicationUserId)151 .AnyAsync();152 }153 154 public async Task<Question> GetQuestionWithAnswersAndStudents(Guid questionUid)155 {156 return await DbSet157 .Include(x => x.Answers).ThenInclude(x => x.Student)158 .FirstOrDefaultAsync(x => x.Uid == questionUid);159 }160 146 } 161 147 } -
src/FinkiChattery/FinkiChattery.Persistence/Repositories/Implementations/StudentRepo.cs
rb9d7ae5 r80e2fe0 1 1 using FinkiChattery.Persistence.Context; 2 2 using FinkiChattery.Persistence.Models; 3 using FinkiChattery.Persistence.Repositories.Contracts;4 3 using Microsoft.EntityFrameworkCore; 5 using System.Linq;6 4 using System.Threading.Tasks; 7 5 … … 18 16 return await DbSet.FirstOrDefaultAsync(x => x.ApplicationUserFk == applicationUserFk); 19 17 } 20 21 public async Task<StudentSelfDto> GetStudentSelfDto(long applicationUserFk)22 {23 return await DbSet24 .AsNoTracking()25 .Include(x => x.Questions)26 .Include(x => x.StudentTeams).ThenInclude(x => x.Team)27 .Where(x => x.ApplicationUserFk == applicationUserFk)28 .Select(x => new StudentSelfDto(x.Uid,29 x.ApplicationUserFk,30 x.IndexNumber,31 x.Reputation,32 x.ImageUrl,33 x.Questions.Select(y => new StudentQuestionDto(y.Uid, y.Title)),34 x.StudentTeams.Select(y => new StudentTeamDto(y.Team.Uid, y.Team.Name))))35 .FirstOrDefaultAsync();36 }37 18 } 38 19 } -
src/FinkiChattery/FinkiChattery.Persistence/UnitOfWork/Contracts/IUnitOfWork.cs
rb9d7ae5 r80e2fe0 13 13 IVoteRepo Votes { get; } 14 14 IAnswerRepo Answers { get; } 15 ITeacherRepo Teachers { get; }16 IModeratorRepo Moderators { get; }17 15 Task<int> SaveAsync(); 18 16 } -
src/FinkiChattery/FinkiChattery.Persistence/UnitOfWork/Implementations/UnitOfWork.cs
rb9d7ae5 r80e2fe0 14 14 private VoteRepo _votes; 15 15 private AnswerRepo _answers; 16 private ModeratorRepo _moderators;17 private TeacherRepo _teachers;18 16 19 17 public UnitOfWork(ApplicationDbContext dbContext) 20 18 { 21 19 DbContext = dbContext; 22 }23 24 public IModeratorRepo Moderators25 {26 get27 {28 if (_moderators == null)29 {30 _moderators = new ModeratorRepo(DbContext);31 }32 33 return _moderators;34 }35 }36 37 public ITeacherRepo Teachers38 {39 get40 {41 if (_teachers == null)42 {43 _teachers = new TeacherRepo(DbContext);44 }45 46 return _teachers;47 }48 20 } 49 21
Note:
See TracChangeset
for help on using the changeset viewer.