Changeset 6738cc0
- Timestamp:
- 01/19/22 19:14:27 (3 years ago)
- Branches:
- dev
- Parents:
- f3c4950
- Location:
- src
- Files:
-
- 11 added
- 25 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Clients/Angular/finki-chattery/package-lock.json
rf3c4950 r6738cc0 7801 7801 } 7802 7802 }, 7803 "ngx-pipes": { 7804 "version": "2.7.6", 7805 "resolved": "https://registry.npmjs.org/ngx-pipes/-/ngx-pipes-2.7.6.tgz", 7806 "integrity": "sha512-FAeMd1mI8jCnnrhUuNLXs+PaVT1ujhA0QD3KRBDuzGFcbnP7NMXR2EJ5KYbV39LDNuRCluhpfwZudQu/NvrVuA==", 7807 "requires": { 7808 "tslib": "^2.0.0" 7809 } 7810 }, 7803 7811 "ngx-toastr": { 7804 7812 "version": "13.2.1", -
src/Clients/Angular/finki-chattery/package.json
rf3c4950 r6738cc0 33 33 "ng2-file-upload": "^1.4.0", 34 34 "ngx-material-timepicker": "^5.5.3", 35 "ngx-pipes": "^2.7.6", 35 36 "ngx-toastr": "^13.2.1", 36 37 "oidc-client": "^1.11.5", -
src/Clients/Angular/finki-chattery/src/app/core/services/auth.service.ts
rf3c4950 r6738cc0 107 107 }); 108 108 } 109 110 public studentCheckedNotifications(): Observable<void> { 111 return this.baseApi.post('v1/students/checked-notifications'); 112 } 109 113 } -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/generic/header/header.component.html
rf3c4950 r6738cc0 19 19 'header-student-questions' | translate 20 20 }}</app-button> 21 <app-button 22 matBadge="{{ auth.selfUser?.student?.notifications?.length }}" 23 matBadgeHidden="{{ studentCheckedNotifications || auth.selfUser?.student?.notifications?.length === 0 }}" 24 [matMenuTriggerFor]="notificationMenu" 25 class="margin-y-xs" 26 *ngIf="auth.isStudent()" 27 (click)="studentCheckedNotificationsClick()" 28 [buttonType]="ButtonType.Basic" 29 > 30 <mat-icon>notifications</mat-icon> 31 </app-button> 21 32 <app-button class="margin-y-xs" *ngIf="auth.isLoggedIn()" (action)="logout()" [buttonType]="ButtonType.Basic">{{ 22 33 'header-logout' | translate … … 34 45 </button> 35 46 </mat-menu> 47 48 <mat-menu #notificationMenu="matMenu"> 49 <div (click)="goToQuestion(q.questionUid)" mat-menu-item *ngFor="let q of auth.selfUser?.student?.notifications"> 50 {{ q?.text }} <span class="time-ago">{{ q?.createdOn | timeAgo }}</span> 51 </div> 52 </mat-menu> -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/generic/header/header.component.scss
rf3c4950 r6738cc0 14 14 } 15 15 } 16 17 ::ng-deep.mat-menu-panel { 18 max-width: none !important; 19 } -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/generic/header/header.component.ts
rf3c4950 r6738cc0 11 11 export class HeaderComponent implements OnInit { 12 12 ButtonType = ButtonType; 13 14 public studentCheckedNotifications = false; 13 15 14 16 constructor(public auth: AuthService, private router: Router) {} … … 36 38 this.router.navigateByUrl(`questioning/${questionUid}`); 37 39 } 40 41 studentCheckedNotificationsClick(): void { 42 if (!this.studentCheckedNotifications) { 43 this.auth.studentCheckedNotifications().subscribe(); 44 } 45 this.studentCheckedNotifications = true; 46 } 38 47 } -
src/Clients/Angular/finki-chattery/src/app/shared-app/models/user.models.ts
rf3c4950 r6738cc0 1 import * as moment from 'moment'; 2 1 3 export class ApplicationUser { 2 4 constructor( … … 30 32 public questions!: StudentQuestionResponse[]; 31 33 public teams!: StudentTeamResponse[]; 34 public notifications!: StudentNotificationResponse[]; 35 } 36 37 export class StudentNotificationResponse { 38 public uid!: string; 39 public createdOn!: moment.Moment; 40 public questionUid!: string; 41 public text!: string; 42 43 constructor(uid: string, createdOn: moment.Moment, questionUid: string, text: string) { 44 this.uid = uid; 45 this.createdOn = createdOn; 46 this.questionUid = questionUid; 47 this.text = text; 48 } 32 49 } 33 50 -
src/Clients/Angular/finki-chattery/src/app/shared-app/services/base-api.service.ts
rf3c4950 r6738cc0 4 4 5 5 import { environment } from '@env/environment'; 6 import { SelfUserResponse } from '../models'; 6 import { SelfUserResponse, StudentNotificationResponse } from '../models'; 7 import { map } from 'rxjs/operators'; 8 import * as moment from 'moment'; 7 9 8 10 @Injectable({ … … 19 21 20 22 public getSelfUser(): Observable<SelfUserResponse> { 21 return this.get<SelfUserResponse>('v1/self'); 23 return this.get<SelfUserResponse>('v1/self').pipe( 24 map((x) => { 25 if (x.student) { 26 x.student.notifications = x.student.notifications.map( 27 (y) => new StudentNotificationResponse(y.uid, moment(y.createdOn), y.questionUid, y.text) 28 ); 29 } 30 31 return x; 32 }) 33 ); 22 34 } 23 35 -
src/Clients/Angular/finki-chattery/src/app/shared-app/shared-app.module.ts
rf3c4950 r6738cc0 14 14 import { SERVICES } from './services/services'; 15 15 import { PIPES } from './pipes/pipes'; 16 import { NgPipesModule } from 'ngx-pipes'; 16 17 17 18 @NgModule({ … … 27 28 FileUploadModule, 28 29 NgxMaterialTimepickerModule, 29 EditorModule 30 EditorModule, 31 NgPipesModule 30 32 ], 31 33 exports: [ … … 41 43 PIPES, 42 44 SharedMaterialModule, 43 EditorModule 45 EditorModule, 46 NgPipesModule 44 47 ] 45 48 }) -
src/FinkiChattery/FinkiChattery.Api/ApplicationServices/User/Mapper/SelfUserMapper.cs
rf3c4950 r6738cc0 17 17 dto.StudentSelf.ImageUrl, 18 18 dto.StudentSelf.Questions.Select(x => new StudentQuestionResponse(x.QuestionUid, x.Title)), 19 dto.StudentSelf.Teams.Select(x => new StudentTeamResponse(x.TeamUid, x.Name))); 19 dto.StudentSelf.Teams.Select(x => new StudentTeamResponse(x.TeamUid, x.Name)), 20 dto.StudentSelf.Notifications.Select(x => new StudentNotificationResponse(x.Uid, x.Text, x.CreatedOn, x.QuestionUid))); 20 21 21 22 return new SelfUserResponse(student); -
src/FinkiChattery/FinkiChattery.Commands/Questioning/MarkAnswerCorrect/AnswerMarkedAsCorrectEvent.cs
rf3c4950 r6738cc0 6 6 public class AnswerMarkedAsCorrectEvent : IEvent 7 7 { 8 public AnswerMarkedAsCorrectEvent(Guid questionUid, Guid answerUid )8 public AnswerMarkedAsCorrectEvent(Guid questionUid, Guid answerUid, long studentFk) 9 9 { 10 10 QuestionUid = questionUid; 11 11 AnswerUid = answerUid; 12 StudentFk = studentFk; 12 13 } 13 14 14 15 public Guid QuestionUid { get; } 15 16 public Guid AnswerUid { get; } 17 public long StudentFk { get; } 16 18 } 17 19 } -
src/FinkiChattery/FinkiChattery.Commands/Questioning/MarkAnswerCorrect/MarkAnswerCorrectCommand.cs
rf3c4950 r6738cc0 38 38 await UnitOfWork.SaveAsync(); 39 39 40 EventService.Enqueue(new AnswerMarkedAsCorrectEvent(request.QuestionUid, request.AnswerUid ));40 EventService.Enqueue(new AnswerMarkedAsCorrectEvent(request.QuestionUid, request.AnswerUid, answer.StudentFk)); 41 41 42 42 return answer.Uid; -
src/FinkiChattery/FinkiChattery.Contracts/User/GetSelfUser/SelfUserResponse.cs
rf3c4950 r6738cc0 23 23 public class StudentSelfResponse 24 24 { 25 public StudentSelfResponse(Guid uid, long applicationUserId, string index, long reputation, string imageUrl, IEnumerable<StudentQuestionResponse> questions, IEnumerable<StudentTeamResponse> teams )25 public StudentSelfResponse(Guid uid, long applicationUserId, string index, long reputation, string imageUrl, IEnumerable<StudentQuestionResponse> questions, IEnumerable<StudentTeamResponse> teams, IEnumerable<StudentNotificationResponse> notifications) 26 26 { 27 27 Uid = uid; … … 32 32 Questions = questions; 33 33 Teams = teams; 34 Notifications = notifications; 34 35 } 35 36 … … 41 42 public IEnumerable<StudentQuestionResponse> Questions { get; } 42 43 public IEnumerable<StudentTeamResponse> Teams { get; } 44 public IEnumerable<StudentNotificationResponse> Notifications { get; } 45 } 46 47 public class StudentNotificationResponse 48 { 49 public StudentNotificationResponse(Guid uid, string text, DateTime createdOn, Guid questionUid) 50 { 51 Uid = uid; 52 Text = text; 53 CreatedOn = createdOn; 54 QuestionUid = questionUid; 55 } 56 57 public Guid Uid { get; } 58 public string Text { get; } 59 public DateTime CreatedOn { get; } 60 public Guid QuestionUid { get; } 43 61 } 44 62 -
src/FinkiChattery/FinkiChattery.Database/FinkiChattery.Database.sqlproj
rf3c4950 r6738cc0 77 77 <Folder Include="dbo\Tables\Vote" /> 78 78 <Folder Include="dbo\Tables\Moderator" /> 79 <Folder Include="dbo\Tables\StudentNotification" /> 79 80 </ItemGroup> 80 81 <ItemGroup> … … 103 104 <Build Include="dbo\Tables\Moderator\Moderator.sql" /> 104 105 <None Include="dbo\Tables\Moderator\Moderator.Debug.Seed.sql" /> 106 <Build Include="dbo\Tables\StudentNotification\StudentNotification.sql" /> 105 107 </ItemGroup> 106 108 <ItemGroup> -
src/FinkiChattery/FinkiChattery.Database/dbo/Tables/Student/Student.sql
rf3c4950 r6738cc0 7 7 [ReportReputation] BIGINT DEFAULT (CONVERT([bigint],(0))) NOT NULL, 8 8 [ImageUrl] NVARCHAR (1000) NOT NULL, 9 [LastCheckedNotifications] SMALLDATETIME NOT NULL DEFAULT GETUTCDATE(), 9 10 CONSTRAINT [PK_Student] PRIMARY KEY CLUSTERED ([Id] ASC), 10 11 CONSTRAINT [FK_Student_AspNetUsers_ApplicationUserFk] FOREIGN KEY ([ApplicationUserFk]) REFERENCES [dbo].[AspNetUsers] ([Id]) -
src/FinkiChattery/FinkiChattery.Persistence/Configurations/StudentConfig.cs
rf3c4950 r6738cc0 1 using Microsoft.EntityFrameworkCore; 1 using FinkiChattery.Persistence.Models; 2 using Microsoft.EntityFrameworkCore; 2 3 using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 4 using System; 4 using System.Collections.Generic;5 using System.Linq;6 using System.Text;7 using System.Threading.Tasks;8 using FinkiChattery.Persistence.Models;9 5 10 6 namespace FinkiChattery.Persistence.Configurations … … 27 23 builder.Property(x => x.ReportReputation).HasColumnName(@"ReportReputation").HasColumnType("bigint").IsRequired().HasDefaultValue(0); 28 24 builder.Property(x => x.ImageUrl).HasColumnName(@"ImageUrl").HasColumnType("nvarchar").IsRequired().HasMaxLength(1000); 25 builder.Property(x => x.LastCheckedNotifications).HasColumnName(@"LastCheckedNotifications").HasColumnType("smalldatetime").IsRequired().HasConversion(v => v, v => DateTime.SpecifyKind(v, DateTimeKind.Utc)); 29 26 30 27 builder.HasOne(x => x.ApplicationUser).WithOne().HasForeignKey<Student>(x => x.ApplicationUserFk).OnDelete(DeleteBehavior.Restrict); -
src/FinkiChattery/FinkiChattery.Persistence/Context/ApplicationDbContext.cs
rf3c4950 r6738cc0 24 24 public DbSet<Team> Teams { get; set; } 25 25 public DbSet<Vote> Votes { get; set; } 26 public DbSet<StudentNotification> StudentNotifications { get; set; } 26 27 27 28 protected override void OnModelCreating(ModelBuilder builder) … … 43 44 builder.ApplyConfiguration(new TeamConfig(schema)); 44 45 builder.ApplyConfiguration(new VoteConfig(schema)); 46 builder.ApplyConfiguration(new StudentNotificationConfig(schema)); 45 47 } 46 48 } -
src/FinkiChattery/FinkiChattery.Persistence/Models/Student.cs
rf3c4950 r6738cc0 1 using System.Collections.Generic; 1 using System; 2 using System.Collections.Generic; 2 3 3 4 namespace FinkiChattery.Persistence.Models … … 5 6 public class Student : BaseEntity 6 7 { 8 public DateTime LastCheckedNotifications { get; set; } 9 7 10 public long ApplicationUserFk { get; set; } 8 11 … … 22 25 23 26 public virtual ICollection<StudentTeam> StudentTeams { get; set; } 27 28 public virtual ICollection<StudentNotification> StudentNotifications { get; set; } 24 29 } 25 30 } -
src/FinkiChattery/FinkiChattery.Persistence/Models/Team.cs
rf3c4950 r6738cc0 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 1 using System.Collections.Generic; 6 2 7 3 namespace FinkiChattery.Persistence.Models … … 13 9 public string Description { get; set; } 14 10 15 public virtual ICollection<Question> Questions { get; set; }11 public virtual ICollection<Question> Questions { get; set; } 16 12 17 13 public virtual ICollection<StudentTeam> TeamStudents { get; set; } -
src/FinkiChattery/FinkiChattery.Persistence/Repositories/Base/IRepository.cs
rf3c4950 r6738cc0 11 11 Task<T> GetByUidAsync(Guid uid); 12 12 13 Task<T> GetByIdAsync( intid);13 Task<T> GetByIdAsync(long id); 14 14 15 15 void Delete(T entity); -
src/FinkiChattery/FinkiChattery.Persistence/Repositories/Base/Repository.cs
rf3c4950 r6738cc0 24 24 } 25 25 26 public async Task<T> GetByIdAsync( intid)26 public async Task<T> GetByIdAsync(long id) 27 27 { 28 28 return await All().FirstOrDefaultAsync(f => f.Id == id); -
src/FinkiChattery/FinkiChattery.Persistence/Repositories/Contracts/Student/StudentSelfDto.cs
rf3c4950 r6738cc0 1 1 using System; 2 2 using System.Collections.Generic; 3 using System.Linq; 3 4 4 5 namespace FinkiChattery.Persistence.Repositories.Contracts … … 6 7 public class StudentSelfDto 7 8 { 8 public StudentSelfDto(Guid uid, long applicationUserId, string index, long reputation, string imageUrl, IEnumerable<StudentQuestionDto> questions, IEnumerable<StudentTeamDto> teams)9 public StudentSelfDto(Guid uid, long applicationUserId, string index, long reputation, string imageUrl, DateTime lastCheckedNotifications, IEnumerable<StudentQuestionDto> questions, IEnumerable<StudentTeamDto> teams, IEnumerable<StudentSelfNotificationDto> notifications = null) 9 10 { 10 11 Uid = uid; … … 13 14 Reputation = reputation; 14 15 ImageUrl = imageUrl; 16 LastCheckedNotifications = lastCheckedNotifications; 15 17 Questions = questions; 16 18 Teams = teams; 19 Notifications = notifications; 17 20 } 18 21 … … 22 25 public long Reputation { get; } 23 26 public string ImageUrl { get; } 27 public DateTime LastCheckedNotifications { get; } 24 28 public IEnumerable<StudentQuestionDto> Questions { get; } 25 29 public IEnumerable<StudentTeamDto> Teams { get; } 30 public IEnumerable<StudentSelfNotificationDto> Notifications { get; set; } 26 31 } 27 32 } -
src/FinkiChattery/FinkiChattery.Persistence/Repositories/Implementations/StudentRepo.cs
rf3c4950 r6738cc0 21 21 public async Task<StudentSelfDto> GetStudentSelfDto(long applicationUserFk) 22 22 { 23 returnawait DbSet23 var user = await DbSet 24 24 .AsNoTracking() 25 25 .Include(x => x.Questions) … … 31 31 x.Reputation, 32 32 x.ImageUrl, 33 x.LastCheckedNotifications, 33 34 x.Questions.Select(y => new StudentQuestionDto(y.Uid, y.Title)), 34 x.StudentTeams.Select(y => new StudentTeamDto(y.Team.Uid, y.Team.Name)))) 35 x.StudentTeams.Select(y => new StudentTeamDto(y.Team.Uid, y.Team.Name)), 36 null)) 35 37 .FirstOrDefaultAsync(); 38 39 user.Notifications = await DbContext.StudentNotifications 40 .Where(x => x.CreatedOn > user.LastCheckedNotifications) 41 .Select(x => new StudentSelfNotificationDto(x.Uid, x.Text, x.CreatedOn, x.QuestionUid)) 42 .ToListAsync(); 43 44 return user; 36 45 } 37 46 } -
src/FinkiChattery/FinkiChattery.Persistence/UnitOfWork/Contracts/IUnitOfWork.cs
rf3c4950 r6738cc0 16 16 IModeratorRepo Moderators { get; } 17 17 IAnswerResponseRepo AnswerResponses { get; } 18 IStudentNotificationRepo StudentNotifications { get; } 18 19 Task<int> SaveAsync(); 19 20 } -
src/FinkiChattery/FinkiChattery.Persistence/UnitOfWork/Implementations/UnitOfWork.cs
rf3c4950 r6738cc0 17 17 private TeacherRepo _teachers; 18 18 private AnswerResponseRepo _answerResponses; 19 private StudentNotificationRepo _studentNotifications; 19 20 20 21 public UnitOfWork(ApplicationDbContext dbContext) … … 33 34 34 35 return _answerResponses; 36 } 37 } 38 39 public IStudentNotificationRepo StudentNotifications 40 { 41 get 42 { 43 if (_studentNotifications == null) 44 { 45 _studentNotifications = new StudentNotificationRepo(DbContext); 46 } 47 48 return _studentNotifications; 35 49 } 36 50 }
Note:
See TracChangeset
for help on using the changeset viewer.