Changeset c205cc4
- Timestamp:
- 10/27/21 21:29:11 (3 years ago)
- Branches:
- dev
- Children:
- 32cd040
- Parents:
- d2b1fa6
- Location:
- src
- Files:
-
- 2 deleted
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Clients/Angular/finki-chattery/src/app/app-routing.module.ts
rd2b1fa6 rc205cc4 6 6 const routes: Routes = [ 7 7 { 8 path: 'questioning', 9 canActivate: [AuthorizedGuard], 10 loadChildren: () => import('./modules/questioning/questioning.module').then((x) => x.QuestioningModule) 11 }, 12 { 8 13 path: 'auth-callback', 14 pathMatch: 'full', 9 15 component: AuthCallbackComponent 10 16 }, 11 17 { 12 path: ' questioning',13 canActivate: [AuthorizedGuard],14 loadChildren: () => import('./modules/questioning/questioning.module').then((x) => x.QuestioningModule)18 path: '', 19 pathMatch: 'full', 20 redirectTo: 'questioning/preview' 15 21 }, 16 22 { -
src/Clients/Angular/finki-chattery/src/app/core/core.module.ts
rd2b1fa6 rc205cc4 9 9 import { SharedMaterialModule } from '../shared-material/shared-material.module'; 10 10 import { COMPONENTS } from './components/components'; 11 import { GUARDS } from './guards/guards';12 11 import { LoaderInterceptor } from './interceptors/loader.interceptor'; 13 12 import { reducers } from './state'; … … 20 19 declarations: [COMPONENTS], 21 20 providers: [ 22 GUARDS,23 21 { provide: HTTP_INTERCEPTORS, useClass: LoaderInterceptor, multi: true }, 24 22 { provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true } -
src/Clients/Angular/finki-chattery/src/app/core/services/auth.service.ts
rd2b1fa6 rc205cc4 1 1 import { Injectable } from '@angular/core'; 2 import { User, UserManager } from 'oidc-client';2 import { User, UserManager, WebStorageStateStore } from 'oidc-client'; 3 3 import { Observable, of } from 'rxjs'; 4 4 5 5 import { environment } from '@env/environment'; 6 import { ApplicationUser, SelfUserResponse } from 'src/app/shared-app/models';6 import { ApplicationUser, ApplicationUserType, SelfUserResponse } from 'src/app/shared-app/models'; 7 7 import { BaseApiService } from 'src/app/shared-app/services/base-api.service'; 8 8 … … 17 17 response_type: 'id_token token', 18 18 scope: 'openid app.api.finki-chattery profile', 19 post_logout_redirect_uri: window.location.origin 19 post_logout_redirect_uri: window.location.origin, 20 filterProtocolClaims: true, 21 loadUserInfo: true, 22 userStore: new WebStorageStateStore({ store: window.localStorage }) 20 23 }); 21 24 … … 23 26 public oidcUser: User | null = null; 24 27 25 constructor(private baseApi: BaseApiService) {} 28 constructor(private baseApi: BaseApiService) { 29 this.userManager.getUser().then((user) => { 30 this.oidcUser = user; 31 this.user = new ApplicationUser( 32 user?.profile.id, 33 user?.profile.userType, 34 user?.profile.emailAddress, 35 user?.profile.username, 36 user?.profile.isVerified 37 ); 38 }); 39 } 26 40 27 41 public login(): void { … … 38 52 } 39 53 return false; 54 } 55 56 public isStudent(): boolean { 57 return this.user?.userType === ApplicationUserType.Student; 40 58 } 41 59 -
src/Clients/Angular/finki-chattery/src/app/modules/questioning/components/ask-question/ask-question.component.html
rd2b1fa6 rc205cc4 1 1 <form class="example-container" [formGroup]="questionFormGroup"> 2 <mat-form-field class="full-width " appearance="standard" appHandleInputFormErrors>3 <mat-label> STAVI TRANSLATE</mat-label>2 <mat-form-field class="full-width margin-bottom-sm" appearance="fill" appHandleInputFormErrors> 3 <mat-label>{{ 'ask-question-question-title' | translate }}</mat-label> 4 4 <input matInput [formControl]="titleForm" /> 5 5 </mat-form-field> … … 7 7 <editor 8 8 matInput 9 class="margin-bottom-sm" 9 10 [formControl]="textForm" 10 11 [init]="{ 12 apiKey: 'fx28x0d64jeufa35u7mcd80fgveayg5c4ap9gnr6posehzny', 11 13 menubar: false, 12 14 plugins: [ … … 16 18 ], 17 19 toolbar: 18 'undo redo | formatselect | bold italic backcolor | \20 'undo redo | formatselect | bold italic backcolor | code | \ 19 21 alignleft aligncenter alignright alignjustify | \ 20 22 bullist numlist outdent indent | removeformat | help' … … 22 24 ></editor> 23 25 <mat-error *ngIf="textForm?.touched && textForm?.errors?.required">{{ 'not-found' | translate }}</mat-error> 24 <mat-error *ngIf="textForm?.touched && textForm?.errors?.maxlength">STAVI TRANSL ATE MAX LENGTH</mat-error> 26 <mat-error *ngIf="textForm?.touched && textForm?.errors?.maxlength">{{ 27 'error-message-max-length' | translate: { maxlength: textForm?.errors?.maxlength?.requiredLength } 28 }}</mat-error> 25 29 26 <mat-form-field class="full-width " appearance="standard" appHandleInputFormErrors>27 <mat-label> STAVI TRANSLATE</mat-label>30 <mat-form-field class="full-width margin-bottom-sm" appearance="fill" appHandleInputFormErrors> 31 <mat-label>{{ 'ask-question-categories' | translate }}</mat-label> 28 32 <mat-select [formControl]="categoriesForm" multiple> 29 <mat-option *ngFor="let category of categoriesList " [value]="category.uid">{{ category.name }}</mat-option>33 <mat-option *ngFor="let category of categoriesList$ | async" [value]="category.uid">{{ category.translatedName }}</mat-option> 30 34 </mat-select> 31 35 </mat-form-field> 32 36 33 37 <app-button [disabled]="questionFormGroup.invalid" [buttonType]="ButtonType.CallToAction" (action)="askQuestion()"> 34 {{ ' not-found' | translate }}38 {{ 'ask-question-ask-button' | translate }} 35 39 </app-button> 36 40 </form> -
src/Clients/Angular/finki-chattery/src/app/modules/questioning/components/ask-question/ask-question.component.scss
rd2b1fa6 rc205cc4 1 .full-width {2 width: 100%;3 } -
src/Clients/Angular/finki-chattery/src/app/modules/questioning/components/ask-question/ask-question.component.ts
rd2b1fa6 rc205cc4 1 1 import { Component, OnInit } from '@angular/core'; 2 2 import { FormControl, FormGroup, Validators } from '@angular/forms'; 3 import { Router } from '@angular/router'; 3 4 5 import { CategoryFacadeService } from 'src/app/core/state/category-facade.service'; 4 6 import { ButtonType } from 'src/app/shared-app/components/generic/button/button.models'; 5 import { CategoryViewModel } from 'src/app/shared-app/models';6 7 import { AskQuestionRequest } from '../../models/questioning-request.models'; 7 8 import { QuestioningApiService } from '../../services/questioning-api.service'; … … 16 17 public textForm = new FormControl('', [Validators.required, Validators.maxLength(4000)]); 17 18 public categoriesForm = new FormControl([]); 18 19 19 public questionFormGroup: FormGroup; 20 20 public ButtonType = ButtonType; 21 public categoriesList$ = this.categoriesFacade.getCategories(); 21 22 22 // TODO: PULL FROM ENDPOINT OR FROM STORE (BETTER FROM STORE) 23 public categoriesList: CategoryViewModel[] = [ 24 new CategoryViewModel('123', 'test'), 25 new CategoryViewModel('345', 'test 2'), 26 new CategoryViewModel('345', 'test 3'), 27 new CategoryViewModel('345', 'test 4'), 28 new CategoryViewModel('345', 'test 5') 29 ]; 30 31 constructor(private api: QuestioningApiService) { 23 constructor(private api: QuestioningApiService, private categoriesFacade: CategoryFacadeService, private router: Router) { 32 24 this.questionFormGroup = new FormGroup({ 33 25 title: this.titleForm, … … 41 33 public askQuestion(): void { 42 34 const body = new AskQuestionRequest(this.titleForm.value, this.textForm.value, this.categoriesForm.value); 43 this.api.askQuestion(body).subscribe(() => {}); 35 this.api.askQuestion(body).subscribe((questionUid) => { 36 this.router.navigateByUrl(`questioning/${questionUid}`); 37 }); 44 38 } 45 39 } -
src/Clients/Angular/finki-chattery/src/app/modules/questioning/components/questioning-general/questioning-general.component.ts
rd2b1fa6 rc205cc4 1 1 import { Component, OnInit } from '@angular/core'; 2 import { CategoryFacadeService } from 'src/app/core/state/category-facade.service'; 2 3 3 4 @Component({ … … 7 8 }) 8 9 export class QuestioningGeneralComponent implements OnInit { 9 constructor( ) {}10 constructor(private categoriesFacade: CategoryFacadeService) {} 10 11 11 ngOnInit(): void {} 12 ngOnInit(): void { 13 this.categoriesFacade.fetchCategories(); 14 } 12 15 } -
src/Clients/Angular/finki-chattery/src/app/modules/questioning/components/questions-preview-general/questions-preview-general.component.ts
rd2b1fa6 rc205cc4 17 17 questionsSortByForm = new FormControl(PreviewQuestionsOrderEnum.Latest); 18 18 19 constructor(private categoriesFacade: CategoryFacadeService, privatequestionFacade: QuestionFacadeService, private router: Router) {}19 constructor(private questionFacade: QuestionFacadeService, private router: Router) {} 20 20 21 21 ngOnInit(): void { 22 this.categoriesFacade.fetchCategories();23 22 this.questionFacade.fetchPreviewQuestions(PreviewQuestionsOrderEnum.Latest); 24 23 this.questionsSortByForm.valueChanges.subscribe((value: PreviewQuestionsOrderEnum) => { -
src/Clients/Angular/finki-chattery/src/app/modules/questioning/services/questioning-api.service.ts
rd2b1fa6 rc205cc4 13 13 } 14 14 15 askQuestion(body: AskQuestionRequest): Observable< void> {15 askQuestion(body: AskQuestionRequest): Observable<string> { 16 16 return this.post('v1/questions', body); 17 17 } -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/generic/header/header.component.html
rd2b1fa6 rc205cc4 2 2 <span>FinkiChattery</span> 3 3 <span class="right"></span> 4 <app-button *ngIf="auth.isLoggedIn()" (action)="logout()" [buttonType]="ButtonType.CallToAction">Logout</app-button> 4 <app-button class="margin-y-xs" *ngIf="auth.isStudent()" (action)="askQuestion()" [buttonType]="ButtonType.CallToAction">{{ 5 'header-ask-question' | translate 6 }}</app-button> 7 <app-button class="margin-y-xs" *ngIf="auth.isLoggedIn()" (action)="logout()" [buttonType]="ButtonType.Basic">{{ 8 'header-logout' | translate 9 }}</app-button> 5 10 </mat-toolbar> -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/generic/header/header.component.ts
rd2b1fa6 rc205cc4 1 1 import { Component, OnInit } from '@angular/core'; 2 import { Router } from '@angular/router'; 2 3 import { AuthService } from 'src/app/core/services'; 3 4 import { ButtonType } from '../button/button.models'; … … 11 12 ButtonType = ButtonType; 12 13 13 constructor(public auth: AuthService ) {}14 constructor(public auth: AuthService, private router: Router) {} 14 15 15 16 ngOnInit(): void {} … … 18 19 this.auth.logout(); 19 20 } 21 22 askQuestion(): void { 23 this.router.navigateByUrl('questioning/ask'); 24 } 20 25 } -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/question/question-preview/question-preview.component.html
rd2b1fa6 rc205cc4 20 20 </mat-chip-list> 21 21 22 <div class="margin-top-lg" [innerHTML]="question.text"></div> 22 <editor 23 class="margin-x-sm" 24 [init]="{ 25 apiKey: 'fx28x0d64jeufa35u7mcd80fgveayg5c4ap9gnr6posehzny', 26 menubar: false, 27 plugins: ['autoresize'], 28 toolbar: '' 29 }" 30 [disabled]="true" 31 [initialValue]="question.text" 32 ></editor> 23 33 <div class="align-right"> 24 34 <app-student-card … … 48 58 <app-vote [voteCount]="answer.upvotesCount" [correct]="answer.correctAnswer" fxFlex="6%"></app-vote> 49 59 <div fxFlex="92%"> 50 <div [innerHTML]="answer.text"></div> 60 <editor 61 class="margin-x-sm" 62 [init]="{ 63 apiKey: 'fx28x0d64jeufa35u7mcd80fgveayg5c4ap9gnr6posehzny', 64 menubar: false, 65 plugins: ['autoresize'], 66 toolbar: '' 67 }" 68 [disabled]="true" 69 [initialValue]="answer.text" 70 ></editor> 51 71 <div class="align-right"> 52 72 <app-student-card -
src/Clients/Angular/finki-chattery/src/assets/translations/en.json
rd2b1fa6 rc205cc4 44 44 "questions-preview-question-answers": "Answers", 45 45 "questions-preview-question-views": "Views", 46 "questions-search-title": "Search results for: {{searchQuery}}" 46 "questions-search-title": "Search results for: {{searchQuery}}", 47 "ask-question-question-title": "Question title", 48 "ask-question-categories": "Add categories to question", 49 "ask-question-ask-button": "Ask question", 50 "header-logout": "Logout", 51 "header-ask-question": "Ask question" 47 52 } -
src/FinkiChattery/FinkiChattery.Api/Controllers/v1/QuestionsController.cs
rd2b1fa6 rc205cc4 29 29 public async Task<IActionResult> AskQuestion([FromBody] AskQuestionRequest request) 30 30 { 31 await MediatorService.SendAsync(new AskQuestionCommand(request.Title, request.Text, request.Categories));32 return Ok( );31 var questionUid = await MediatorService.SendAsync(new AskQuestionCommand(request.Title, request.Text, request.Categories)); 32 return Ok(questionUid); 33 33 } 34 34 -
src/FinkiChattery/FinkiChattery.Persistence/Configurations/QuestionConfig.cs
rd2b1fa6 rc205cc4 24 24 builder.Property(x => x.Views).HasColumnName(@"Views").HasColumnType("bigint").IsRequired().HasDefaultValue(0); 25 25 builder.Property(x => x.LastActiveOn).HasColumnName(@"LastActiveOn").HasColumnType("smalldatetime").IsRequired(); 26 builder.Property(x => x.Search).HasCo lumnType(@"Search").HasColumnType("nvarchar").HasMaxLength(4000).IsRequired();26 builder.Property(x => x.Search).HasComputedColumnSql(@"Search").HasColumnType("nvarchar").ValueGeneratedOnAddOrUpdate().HasMaxLength(4000).IsRequired(); 27 27 builder.Property(x => x.AnswersCount).HasColumnType(@"AnswersCount").HasColumnType("bigint").IsRequired().HasDefaultValue(0); 28 28 -
src/FinkiChattery/FinkiChattery.Persistence/Models/Question.cs
rd2b1fa6 rc205cc4 1 1 using System; 2 2 using System.Collections.Generic; 3 using System.ComponentModel.DataAnnotations.Schema; 3 4 4 5 namespace FinkiChattery.Persistence.Models … … 32 33 public DateTime LastActiveOn { get; set; } 33 34 35 [DatabaseGenerated(DatabaseGeneratedOption.Computed)] 34 36 public string Search { get; set; } 35 37
Note:
See TracChangeset
for help on using the changeset viewer.