Changes in / [7899209:466d1ac]


Ignore:
Location:
src
Files:
5 deleted
18 edited

Legend:

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

    r7899209 r466d1ac  
    55import { catchError, filter, map } from 'rxjs/operators';
    66
    7 import {
    8   PreviewQuestionsOrderEnum,
    9   PreviewQuestionViewModel,
    10   QuestionStateViewModel,
    11   SearchQuestionsQueryViewModel
    12 } from 'src/app/shared-app/models';
     7import { PreviewQuestionsOrderEnum, PreviewQuestionViewModel, QuestionStateViewModel } from 'src/app/shared-app/models';
    138import {
    149  EffectStartedWorking,
    1510  GetPreviewQuestionsLatest,
    1611  GetPreviewQuestionsPopular,
    17   GetQuestionState,
    18   GetSearchQuestions
     12  GetQuestionState
    1913} from './question-state/question.actions';
    2014import { questionStateQuery } from './question-state/question.selectors';
     
    4943  }
    5044
    51   public getSearchQuestions(): Observable<PreviewQuestionViewModel[]> {
    52     return this.store.select(questionStateQuery.getSearchQuestions);
    53   }
    54 
    55   public getSearchQuestionsQuery(): Observable<SearchQuestionsQueryViewModel> {
    56     return this.store
    57       .select(questionStateQuery.getSearchQuestionsQuery)
    58       .pipe(filter((x: SearchQuestionsQueryViewModel | null): x is SearchQuestionsQueryViewModel => x !== null));
    59   }
    60 
    6145  public getPreviewQuestionsLatest(): Observable<PreviewQuestionViewModel[]> {
    6246    return this.store.select(questionStateQuery.getPreviewQuestionsLatest);
     
    7963  }
    8064
    81   public searchQuestions(searchText: string, categories: string[]): void {
    82     this.dispatchEffect(new GetSearchQuestions(searchText, categories));
    83   }
    84 
    8565  private fetchPreviewQuestionsLatest(): void {
    8666    this.dispatchEffect(new GetPreviewQuestionsLatest());
  • src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.actions.ts

    r7899209 r466d1ac  
    22import { Action } from '@ngrx/store';
    33
    4 import { PreviewQuestionViewModel, QuestionStateViewModel, SearchQuestionsQueryViewModel } from 'src/app/shared-app/models';
     4import { PreviewQuestionViewModel, QuestionStateViewModel } from 'src/app/shared-app/models';
     5import { PreviewQuestionResponse } from './question-state.models';
    56
    67export enum QuestionActionTypes {
     
    1112  GetPreviewQuestionsPopular = '[Question] Get preview questions Popular',
    1213  GetPreviewQuestionsPopularSuccess = '[Question] Get preview questions Popular Success',
    13   GetSearchQuestions = '[Question] Get search questions',
    14   GetSearchQuestionsSuccess = '[Question] Get search questions Success',
    1514  EffectStartedWorking = '[Question] Effect Started Working',
    1615  EffectFinishedWorking = '[Question] Effect Finished Working',
     
    5453}
    5554
    56 export class GetSearchQuestions implements Action {
    57   readonly type = QuestionActionTypes.GetSearchQuestions;
    58 
    59   constructor(public searchText: string, public categories: string[]) {}
    60 }
    61 
    62 export class GetSearchQuestionsSuccess implements Action {
    63   readonly type = QuestionActionTypes.GetSearchQuestionsSuccess;
    64 
    65   constructor(public payload: PreviewQuestionViewModel[], public query: SearchQuestionsQueryViewModel) {}
    66 }
    67 
    6855export class EffectStartedWorking implements Action {
    6956  readonly type = QuestionActionTypes.EffectStartedWorking;
     
    8875  | GetPreviewQuestionsLatestSuccess
    8976  | GetPreviewQuestionsPopularSuccess
    90   | GetSearchQuestionsSuccess
    9177  | EffectStartedWorking
    9278  | EffectFinishedWorking
  • src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.effects.ts

    r7899209 r466d1ac  
    11import { Injectable } from '@angular/core';
    2 import { act, Actions, createEffect, ofType } from '@ngrx/effects';
    3 import { catchError, filter, mergeMap, switchMap, withLatestFrom } from 'rxjs/operators';
    4 import { PreviewQuestionsOrderEnum, SearchQuestionsQueryViewModel } from 'src/app/shared-app/models';
     2import { Actions, createEffect, ofType } from '@ngrx/effects';
     3import { catchError, filter, switchMap, withLatestFrom } from 'rxjs/operators';
     4import { PreviewQuestionsOrderEnum } from 'src/app/shared-app/models';
    55import { TranslateFromJsonService } from 'src/app/shared-app/services';
    66
     
    1111  EffectFinishedWorking,
    1212  EffectFinishedWorkingError,
    13   GetPreviewQuestionsLatest,
    1413  GetPreviewQuestionsLatestSuccess,
    15   GetPreviewQuestionsPopular,
    1614  GetPreviewQuestionsPopularSuccess,
    1715  GetQuestionState,
    1816  GetQuestionStateSuccess,
    19   GetSearchQuestions,
    20   GetSearchQuestionsSuccess,
    2117  QuestionActionTypes
    2218} from './question.actions';
     
    4844  getPreviewQuestionsLatest$ = createEffect(() => {
    4945    return this.actions$.pipe(
    50       ofType<GetPreviewQuestionsLatest>(QuestionActionTypes.GetPreviewQuestionsLatest),
     46      ofType<GetQuestionState>(QuestionActionTypes.GetPreviewQuestionsLatest),
    5147      withLatestFrom(this.facade.getPreviewQuestionsLatest()),
    5248      filter(([action, questions]) => questions.length === 0),
     
    6561  getPreviewQuestionsPopular$ = createEffect(() => {
    6662    return this.actions$.pipe(
    67       ofType<GetPreviewQuestionsPopular>(QuestionActionTypes.GetPreviewQuestionsPopular),
     63      ofType<GetQuestionState>(QuestionActionTypes.GetPreviewQuestionsPopular),
    6864      withLatestFrom(this.facade.getPreviewQuestionsPopular()),
    6965      filter(([action, questions]) => questions.length === 0),
     
    7975    );
    8076  });
    81 
    82   getSearchQuestions$ = createEffect(() => {
    83     return this.actions$.pipe(
    84       ofType<GetSearchQuestions>(QuestionActionTypes.GetSearchQuestions),
    85       mergeMap((action) => {
    86         const categoriesAsString = action.categories !== null ? action.categories.join(',') : '';
    87         return this.api
    88           .get<PreviewQuestionResponse[]>(`v1/questions/search?searchText=${action.searchText}&categories=${categoriesAsString}`)
    89           .pipe(
    90             switchMap((state) => [
    91               new GetSearchQuestionsSuccess(
    92                 QuestionMapper.ToPreviwQuestionsViewModel(state, this.translate),
    93                 new SearchQuestionsQueryViewModel(action.searchText)
    94               ),
    95               new EffectFinishedWorking()
    96             ]),
    97             catchError((err) => [new EffectFinishedWorkingError(err)])
    98           );
    99       })
    100     );
    101   });
    10277}
  • src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.reducers.ts

    r7899209 r466d1ac  
    1818        ...state,
    1919        previewQuestionsPopular: action.payload
    20       };
    21     case QuestionActionTypes.GetSearchQuestionsSuccess:
    22       return {
    23         ...state,
    24         searchQuestions: action.payload,
    25         searchQuestionsQuery: action.query
    2620      };
    2721    case QuestionActionTypes.EffectStartedWorking: {
  • src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.selectors.ts

    r7899209 r466d1ac  
    77const getPreviewQuestionsLatest = createSelector(getQuestionState, (state) => state.previewQuestionsLatest);
    88const getPreviewQuestionsPopular = createSelector(getQuestionState, (state) => state.previewQuestionsPopular);
    9 const getSearchQuestions = createSelector(getQuestionState, (state) => state.searchQuestions);
    10 const getSearchQuestionsQuery = createSelector(getQuestionState, (state) => state.searchQuestionsQuery);
    119const effectWorking = createSelector(getQuestionState, (state) => state.effectWorking);
    1210
     
    1513  getQuestion,
    1614  getPreviewQuestionsLatest,
    17   getPreviewQuestionsPopular,
    18   getSearchQuestions,
    19   getSearchQuestionsQuery
     15  getPreviewQuestionsPopular
    2016};
  • src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.state.ts

    r7899209 r466d1ac  
    11import { HttpErrorResponse } from '@angular/common/http';
    2 import { PreviewQuestionViewModel, QuestionStateViewModel, SearchQuestionsQueryViewModel } from 'src/app/shared-app/models';
     2import { PreviewQuestionViewModel, QuestionStateViewModel } from 'src/app/shared-app/models';
    33
    44export const questionStateKey = 'question';
     
    99  previewQuestionsPopular: PreviewQuestionViewModel[];
    1010  effectWorking: boolean | HttpErrorResponse;
    11   searchQuestions: PreviewQuestionViewModel[];
    12   searchQuestionsQuery: SearchQuestionsQueryViewModel | null;
    1311}
    1412
     
    1715  previewQuestionsLatest: [],
    1816  previewQuestionsPopular: [],
    19   searchQuestions: [],
    20   effectWorking: false,
    21   searchQuestionsQuery: null
     17  effectWorking: false
    2218};
  • src/Clients/Angular/finki-chattery/src/app/modules/questioning/components/questioning-components.ts

    r7899209 r466d1ac  
    22import { QuestioningGeneralComponent } from './questioning-general/questioning-general.component';
    33import { QuestionsPreviewGeneralComponent } from './questions-preview-general/questions-preview-general.component';
    4 import { QuestionsSearchComponent } from './questions-search/questions-search.component';
    54
    65export const QUESTIONING_COMPONENTS: any[] = [
    76  QuestionPreviewGeneralComponent,
    87  QuestionsPreviewGeneralComponent,
    9   QuestioningGeneralComponent,
    10   QuestionsSearchComponent
     8  QuestioningGeneralComponent
    119];
  • src/Clients/Angular/finki-chattery/src/app/modules/questioning/components/questions-preview-general/questions-preview-general.component.html

    r7899209 r466d1ac  
    1 <app-search-question (searched)="routeToSearch()"></app-search-question>
     1<app-search-question></app-search-question>
    22<div class="margin-x-lg">
    33  <h1 class="mat-headline">{{ 'questions-preview' | translate }}</h1>
  • src/Clients/Angular/finki-chattery/src/app/modules/questioning/components/questions-preview-general/questions-preview-general.component.ts

    r7899209 r466d1ac  
    3636    this.router.navigateByUrl(`questioning/${uid}`);
    3737  }
    38 
    39   routeToSearch(): void {
    40     this.router.navigateByUrl(`questioning/search`);
    41   }
    4238}
  • src/Clients/Angular/finki-chattery/src/app/modules/questioning/questioning.routes.ts

    r7899209 r466d1ac  
    44import { QuestioningGeneralComponent } from './components/questioning-general/questioning-general.component';
    55import { QuestionsPreviewGeneralComponent } from './components/questions-preview-general/questions-preview-general.component';
    6 import { QuestionsSearchComponent } from './components/questions-search/questions-search.component';
    76
    87const routes: Routes = [
     
    1514        pathMatch: 'full',
    1615        component: QuestionsPreviewGeneralComponent
    17       },
    18       {
    19         path: 'search',
    20         pathMatch: 'full',
    21         component: QuestionsSearchComponent
    2216      },
    2317      {
  • src/Clients/Angular/finki-chattery/src/app/shared-app/components/question/search-question/search-question.component.html

    r7899209 r466d1ac  
    1111      <mat-icon matSuffix>search</mat-icon>
    1212    </mat-form-field>
    13     <mat-form-field class="full-width" appearance="fill">
     13    <mat-form-field appearance="fill">
    1414      <mat-select
    1515        [formControl]="questionCategoriesFormContor"
  • src/Clients/Angular/finki-chattery/src/app/shared-app/components/question/search-question/search-question.component.ts

    r7899209 r466d1ac  
    1 import { Component, EventEmitter, OnInit, Output } from '@angular/core';
     1import { Component, OnInit } from '@angular/core';
    22import { FormControl, Validators } from '@angular/forms';
    3 
    43import { CategoryFacadeService } from 'src/app/core/state/category-facade.service';
    5 import { QuestionFacadeService } from 'src/app/core/state/question-facade.service';
     4import { CategoryStateViewModel } from 'src/app/shared-app/models';
    65import { ButtonType } from '../../generic/button/button.models';
    76
     
    1211})
    1312export class SearchQuestionComponent implements OnInit {
    14   @Output() searched = new EventEmitter();
    15 
    1613  ButtonType = ButtonType;
    1714  questionSearchFormContor = new FormControl('', [Validators.required, Validators.maxLength(250)]);
     
    1916  categories$ = this.categoriesFacade.getCategories();
    2017
    21   constructor(private categoriesFacade: CategoryFacadeService, private questionsFacade: QuestionFacadeService) {}
     18  constructor(private categoriesFacade: CategoryFacadeService) {}
    2219
    2320  ngOnInit(): void {}
     
    3027
    3128  public searchQuestions(): void {
    32     this.questionsFacade.searchQuestions(this.questionSearchFormContor.value, this.questionCategoriesFormContor.value);
    33     this.searched.emit();
     29    alert('SEARCH');
    3430  }
    3531}
  • src/Clients/Angular/finki-chattery/src/app/shared-app/models/question-state-view-models.models.ts

    r7899209 r466d1ac  
    6969  constructor(public uid: string, public text: string, public nameTranslated: string) {}
    7070}
    71 
    72 export class SearchQuestionsQueryViewModel {
    73   constructor(public text: string) {}
    74 }
  • src/Clients/Angular/finki-chattery/src/assets/translations/en.json

    r7899209 r466d1ac  
    4343  "questions-preview-question-subtitle": "Asked on: {{date}}",
    4444  "questions-preview-question-answers": "Answers",
    45   "questions-preview-question-views": "Views",
    46   "questions-search-title": "Search results for: {{searchQuery}}"
     45  "questions-preview-question-views": "Views"
    4746}
  • src/FinkiChattery/FinkiChattery.Api/Controllers/v1/QuestionsController.cs

    r7899209 r466d1ac  
    3535        [HttpGet("{questionUid:Guid}")]
    3636        [Authorize]
    37         public async Task<IActionResult> GetQuestionState([FromRoute] Guid questionUid)
     37        public async Task<IActionResult> GetQuestionState([FromRoute]Guid questionUid)
    3838        {
    3939            var questionDto = await MediatorService.SendQueryAsync(new GetQuestionStateQuery(questionUid));
     
    4848            return Ok(questions.ToPreviewQuestionsResponse());
    4949        }
    50 
    51         [HttpGet("search")]
    52         [Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme, Policy = AuthenticationPolicy.Student)]
    53         public async Task<IActionResult> SearchQuestions([FromQuery] string searchText, [FromQuery] string categories)
    54         {
    55             var questions = await MediatorService.SendQueryAsync(new SearchQuestionsQuery(searchText, categories));
    56             return Ok(questions.ToPreviewQuestionsResponse());
    57         }
    5850    }
    5951}
  • src/FinkiChattery/FinkiChattery.Database/FullTextSearch/FullTextIndexQuestion.sql

    r7899209 r466d1ac  
    11CREATE FULLTEXT INDEX ON [dbo].[Question] ([Search])
    22KEY INDEX [PK_Question] ON [QuestionFullTextCatalog]
    3 WITH (CHANGE_TRACKING AUTO, STOPLIST OFF)
     3WITH (CHANGE_TRACKING AUTO)
  • src/FinkiChattery/FinkiChattery.Persistence/Repositories/Contracts/IQuestionRepo.cs

    r7899209 r466d1ac  
    99    public interface IQuestionRepo : IRepository<Question>
    1010    {
    11         Task<List<QuestionPreviewDto>> SearchQuestions(string searchText, IEnumerable<Guid> categories);
    12 
    1311        Task<QuestionStateDto> GetQuestionState(Guid questionUid);
    1412
  • src/FinkiChattery/FinkiChattery.Persistence/Repositories/Implementations/QuestionRepo.cs

    r7899209 r466d1ac  
    22using FinkiChattery.Persistence.Models;
    33using FinkiChattery.Persistence.Repositories.Contracts;
    4 using Microsoft.Data.SqlClient;
    54using Microsoft.EntityFrameworkCore;
    65using System;
     
    87using System.Linq;
    98using System.Linq.Expressions;
    10 using System.Text.RegularExpressions;
    119using System.Threading.Tasks;
    1210
     
    112110            return questionDto;
    113111        }
    114 
    115         public async Task<List<QuestionPreviewDto>> SearchQuestions(string searchText, IEnumerable<Guid> categories)
    116         {
    117             var search = Regex.Replace(searchText, "[\\\\/:*?\"<>\\]\\[|&'`~^=%,(){}_\\-]", " ")
    118                                      .Split(" ".ToArray(), StringSplitOptions.RemoveEmptyEntries)
    119                                      .Select(c => $"\"{c}*\"");
    120 
    121             var searchString = string.Join(" AND ", search);
    122 
    123             var rawQuery = (IQueryable<Question>)
    124                 DbSet.FromSqlRaw(@"
    125                         SELECT [q].[Id], [q].[Uid], [q].[Title], [q].[Views], [q].[AnswersCount], [q].[CreatedOn]
    126                         FROM [dbo].[Question] AS [q]
    127                         INNER JOIN CONTAINSTABLE(Question, Search, @searchString, 30) ccontains ON [q].[Id] = ccontains.[KEY]",
    128                         new SqlParameter("searchString", searchString))
    129                 .Include(x => x.QuestionCategories).ThenInclude(x => x.Category);
    130 
    131             if (categories.Any())
    132             {
    133                 rawQuery = rawQuery.Where(x => x.QuestionCategories.Any(y => categories.Contains(y.Category.Uid)));
    134             }
    135 
    136             return await rawQuery
    137                 .Select(x => new QuestionPreviewDto(x.Id,
    138                                     x.Uid,
    139                                     x.Title,
    140                                     x.Views,
    141                                     x.AnswersCount,
    142                                     x.CreatedOn,
    143                                     x.QuestionCategories.Select(y => new QuestionPreviewCategoryDto(y.Id, y.Uid, y.Category.Name))))
    144                 .ToListAsync();
    145         }
    146112    }
    147113}
Note: See TracChangeset for help on using the changeset viewer.