diff --git a/SystemKonkursow/4.2.1/angular/src/app/app-routing.module.ts b/SystemKonkursow/4.2.1/angular/src/app/app-routing.module.ts index 47fd4cc..a293f03 100644 --- a/SystemKonkursow/4.2.1/angular/src/app/app-routing.module.ts +++ b/SystemKonkursow/4.2.1/angular/src/app/app-routing.module.ts @@ -3,6 +3,7 @@ import { RouterModule } from '@angular/router'; import { AppComponent } from './app.component'; import { AppRouteGuard } from '@shared/auth/auth-route-guard'; import { HomeComponent } from './home/home.component'; +import { ProfileComponent } from './profile/profile.component'; import { AboutComponent } from './about/about.component'; import { UsersComponent } from './users/users.component'; import { TenantsComponent } from './tenants/tenants.component'; @@ -20,6 +21,7 @@ import { CompetitionCreateComponent } from '@app/competition-create/competition- component: AppComponent, children: [ { path: 'home', component: HomeComponent, canActivate: [AppRouteGuard] }, + { path: 'profile', component: ProfileComponent, canActivate: [AppRouteGuard] }, { path: 'users', component: UsersComponent, data: { permission: 'Pages.Users' }, canActivate: [AppRouteGuard] }, { path: 'roles', component: RolesComponent, data: { permission: 'Pages.Roles' }, canActivate: [AppRouteGuard] }, { path: 'tenants', component: TenantsComponent, data: { permission: 'Pages.Tenants' }, canActivate: [AppRouteGuard] }, diff --git a/SystemKonkursow/4.2.1/angular/src/app/app.module.ts b/SystemKonkursow/4.2.1/angular/src/app/app.module.ts index fbf7fee..3c115c5 100644 --- a/SystemKonkursow/4.2.1/angular/src/app/app.module.ts +++ b/SystemKonkursow/4.2.1/angular/src/app/app.module.ts @@ -16,6 +16,7 @@ import { ServiceProxyModule } from '@shared/service-proxies/service-proxy.module import { SharedModule } from '@shared/shared.module'; import { HomeComponent } from '@app/home/home.component'; +import { ProfileComponent } from '@app/profile/profile.component'; import { AboutComponent } from '@app/about/about.component'; import { UsersComponent } from '@app/users/users.component'; import { CreateUserComponent } from '@app/users/create-user/create-user.component'; @@ -54,6 +55,7 @@ import { declarations: [ AppComponent, HomeComponent, + ProfileComponent, AboutComponent, TenantsComponent, CreateTenantComponent, diff --git a/SystemKonkursow/4.2.1/angular/src/app/layout/sidebar-nav.component.ts b/SystemKonkursow/4.2.1/angular/src/app/layout/sidebar-nav.component.ts index 1c30dc2..91abeba 100644 --- a/SystemKonkursow/4.2.1/angular/src/app/layout/sidebar-nav.component.ts +++ b/SystemKonkursow/4.2.1/angular/src/app/layout/sidebar-nav.component.ts @@ -11,6 +11,7 @@ export class SideBarNavComponent extends AppComponentBase { menuItems: MenuItem[] = [ new MenuItem(this.l("Strona domowa"), "", "home", "/app/home"), + new MenuItem(this.l("Profil"), "", "person", "/app/profile"), new MenuItem(this.l("Konkursy"), "", "list", "/app/categories-list"), new MenuItem(this.l("Dodaj konkurs"), "Pages.Create.Competition", "add", "/app/competition-create"), diff --git a/SystemKonkursow/4.2.1/angular/src/app/layout/sidebar-user-area.component.html b/SystemKonkursow/4.2.1/angular/src/app/layout/sidebar-user-area.component.html index edb3372..d8828ad 100644 --- a/SystemKonkursow/4.2.1/angular/src/app/layout/sidebar-user-area.component.html +++ b/SystemKonkursow/4.2.1/angular/src/app/layout/sidebar-user-area.component.html @@ -2,7 +2,7 @@
User
-
+
diff --git a/SystemKonkursow/4.2.1/angular/src/app/layout/topbar.component.html b/SystemKonkursow/4.2.1/angular/src/app/layout/topbar.component.html index 5f2182e..7796d08 100644 --- a/SystemKonkursow/4.2.1/angular/src/app/layout/topbar.component.html +++ b/SystemKonkursow/4.2.1/angular/src/app/layout/topbar.component.html @@ -20,7 +20,8 @@ diff --git a/SystemKonkursow/4.2.1/angular/src/app/layout/topbar.component.ts b/SystemKonkursow/4.2.1/angular/src/app/layout/topbar.component.ts index 427e92a..5eb8507 100644 --- a/SystemKonkursow/4.2.1/angular/src/app/layout/topbar.component.ts +++ b/SystemKonkursow/4.2.1/angular/src/app/layout/topbar.component.ts @@ -1,5 +1,6 @@ import { Component, Injector, ViewEncapsulation } from '@angular/core'; import { AppComponentBase } from '@shared/app-component-base'; +import { AppAuthService } from '@shared/auth/app-auth.service'; @Component({ templateUrl: './topbar.component.html', @@ -11,8 +12,13 @@ export class TopBarComponent extends AppComponentBase { public logoUrl: string = '/assets/images/logo.png'; constructor( - injector: Injector + injector: Injector, + private _authService: AppAuthService ) { super(injector); } + + logout(): void { + this._authService.logout(); + } } \ No newline at end of file diff --git a/SystemKonkursow/4.2.1/angular/src/app/profile/profile.component.css b/SystemKonkursow/4.2.1/angular/src/app/profile/profile.component.css new file mode 100644 index 0000000..24e5a3e --- /dev/null +++ b/SystemKonkursow/4.2.1/angular/src/app/profile/profile.component.css @@ -0,0 +1,3 @@ +h2 { + color: #771111; +} \ No newline at end of file diff --git a/SystemKonkursow/4.2.1/angular/src/app/profile/profile.component.html b/SystemKonkursow/4.2.1/angular/src/app/profile/profile.component.html new file mode 100644 index 0000000..16da2ff --- /dev/null +++ b/SystemKonkursow/4.2.1/angular/src/app/profile/profile.component.html @@ -0,0 +1,58 @@ +
+
+
+
+

MÓJ PROFIL

+
+ +
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+ +
+ +
+
+
+
\ No newline at end of file diff --git a/SystemKonkursow/4.2.1/angular/src/app/profile/profile.component.ts b/SystemKonkursow/4.2.1/angular/src/app/profile/profile.component.ts new file mode 100644 index 0000000..cda0ae4 --- /dev/null +++ b/SystemKonkursow/4.2.1/angular/src/app/profile/profile.component.ts @@ -0,0 +1,70 @@ +import { Component, Injector, ElementRef, OnInit, OnDestroy, AfterViewInit, ViewChild } from '@angular/core'; +import { Router } from '@angular/router'; +import { UserProfileServiceProxy, UserProfileDto } from '@shared/service-proxies/service-proxies' +import { AppComponentBase } from '@shared/app-component-base'; +import { accountModuleAnimation } from '@shared/animations/routerTransition'; +import { finalize } from 'rxjs/operators'; +import { Subscription } from 'rxjs/Rx'; + +@Component({ + templateUrl: './profile.component.html', + styleUrls: ['./profile.component.css'], + animations: [accountModuleAnimation()] +}) +export class ProfileComponent extends AppComponentBase implements OnInit, OnDestroy, AfterViewInit { + + @ViewChild('cardBody') cardBody: ElementRef; + + public profileAreaId: string = 'profile-area'; + + public profile: UserProfileDto = new UserProfileDto(); + + private profileSubscription: Subscription; + + public possibleClasses = [ + {value: 1, viewValue: 'Klasa 1'}, + {value: 2, viewValue: 'Klasa 2'}, + {value: 3, viewValue: 'Klasa 3'}, + {value: 4, viewValue: 'Klasa 4'}, + {value: 5, viewValue: 'Klasa 5'}, + {value: 6, viewValue: 'Klasa 6'}, + {value: 7, viewValue: 'Klasa 7'}, + {value: 8, viewValue: 'Klasa 8'} + ]; + + constructor( + injector: Injector, + private userProfileService: UserProfileServiceProxy, + private router: Router, + ) { + super(injector); + } + + public ngAfterViewInit(): void { + } + + public ngOnInit(): void { + this.setBusy(this.profileAreaId); + + this.profileSubscription = this.userProfileService.getProfile() + .pipe(finalize(() => { this.clearBusy(this.profileAreaId); })) + .subscribe((result: UserProfileDto) => { + this.profile = result; + }); + } + + public ngOnDestroy(): void { + if (this.profileSubscription) { + this.profileSubscription.unsubscribe(); + } + } + + public saveProfile(): void { + this.profile.participantClass = +this.profile.participantClass; + this.userProfileService.updateProfile(this.profile) + .pipe(finalize(() => { this.router.navigate(['app/home']); })) + .subscribe(() => { + this.notify.success(this.l('Zapisano profil')); + }); + } +} diff --git a/SystemKonkursow/4.2.1/angular/src/shared/service-proxies/service-proxies.ts b/SystemKonkursow/4.2.1/angular/src/shared/service-proxies/service-proxies.ts index 72cfe72..54b5361 100644 --- a/SystemKonkursow/4.2.1/angular/src/shared/service-proxies/service-proxies.ts +++ b/SystemKonkursow/4.2.1/angular/src/shared/service-proxies/service-proxies.ts @@ -2065,6 +2065,122 @@ export class UserServiceProxy { } } +@Injectable() +export class UserProfileServiceProxy { + private http: HttpClient; + private baseUrl: string; + protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined; + + constructor(@Inject(HttpClient) http: HttpClient, @Optional() @Inject(API_BASE_URL) baseUrl?: string) { + this.http = http; + this.baseUrl = baseUrl ? baseUrl : ""; + } + + /** + * @return Success + */ + getProfile(): Observable { + let url_ = this.baseUrl + "/api/services/app/UserProfile/GetProfile"; + url_ = url_.replace(/[?&]$/, ""); + + let options_ : any = { + observe: "response", + responseType: "blob", + headers: new HttpHeaders({ + "Content-Type": "application/json", + "Accept": "application/json" + }) + }; + + return this.http.request("get", url_, options_).pipe(_observableMergeMap((response_ : any) => { + return this.processGetProfile(response_); + })).pipe(_observableCatch((response_: any) => { + if (response_ instanceof HttpResponseBase) { + try { + return this.processGetProfile(response_); + } catch (e) { + return >_observableThrow(e); + } + } else + return >_observableThrow(response_); + })); + } + + protected processGetProfile(response: HttpResponseBase): Observable { + const status = response.status; + const responseBlob = + response instanceof HttpResponse ? response.body : + (response).error instanceof Blob ? (response).error : undefined; + + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }}; + if (status === 200) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + let result200: any = null; + let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver); + result200 = resultData200 ? UserProfileDto.fromJS(resultData200) : new UserProfileDto(); + return _observableOf(result200); + })); + } else if (status !== 200 && status !== 204) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + })); + } + return _observableOf(null); + } + + /** + * @userProfile (optional) + * @return Success + */ + updateProfile(userProfile: UserProfileDto | null | undefined): Observable { + let url_ = this.baseUrl + "/api/services/app/UserProfile/UpdateProfile"; + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(userProfile); + + let options_ : any = { + body: content_, + observe: "response", + responseType: "blob", + headers: new HttpHeaders({ + "Content-Type": "application/json", + }) + }; + + return this.http.request("put", url_, options_).pipe(_observableMergeMap((response_ : any) => { + return this.processUpdateProfile(response_); + })).pipe(_observableCatch((response_: any) => { + if (response_ instanceof HttpResponseBase) { + try { + return this.processUpdateProfile(response_); + } catch (e) { + return >_observableThrow(e); + } + } else + return >_observableThrow(response_); + })); + } + + protected processUpdateProfile(response: HttpResponseBase): Observable { + const status = response.status; + const responseBlob = + response instanceof HttpResponse ? response.body : + (response).error instanceof Blob ? (response).error : undefined; + + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }}; + if (status === 200) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return _observableOf(null); + })); + } else if (status !== 200 && status !== 204) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + })); + } + return _observableOf(null); + } +} + export class IsTenantAvailableInput implements IIsTenantAvailableInput { tenancyName: string; @@ -4389,6 +4505,69 @@ export interface IPagedResultDtoOfUserDto { items: UserDto[] | undefined; } +export class UserProfileDto implements IUserProfileDto { + name: string; + surname: string; + userName: string; + emailAddress: string; + participantClass: number; + id: number | undefined; + + constructor(data?: IUserProfileDto) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.name = data["name"]; + this.surname = data["surname"]; + this.userName = data["userName"]; + this.emailAddress = data["emailAddress"]; + this.participantClass = data["participantClass"]; + this.id = data["id"]; + } + } + + static fromJS(data: any): UserProfileDto { + data = typeof data === 'object' ? data : {}; + let result = new UserProfileDto(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["name"] = this.name; + data["surname"] = this.surname; + data["userName"] = this.userName; + data["emailAddress"] = this.emailAddress; + data["participantClass"] = this.participantClass; + data["id"] = this.id; + return data; + } + + clone(): UserProfileDto { + const json = this.toJSON(); + let result = new UserProfileDto(); + result.init(json); + return result; + } +} + +export interface IUserProfileDto { + name: string; + surname: string; + userName: string; + emailAddress: string; + participantClass: number; + id: number | undefined; +} + export enum IsTenantAvailableOutputState { _1 = 1, _2 = 2, diff --git a/SystemKonkursow/4.2.1/angular/src/shared/service-proxies/service-proxy.module.ts b/SystemKonkursow/4.2.1/angular/src/shared/service-proxies/service-proxy.module.ts index 5db6691..3c9a5e9 100644 --- a/SystemKonkursow/4.2.1/angular/src/shared/service-proxies/service-proxy.module.ts +++ b/SystemKonkursow/4.2.1/angular/src/shared/service-proxies/service-proxy.module.ts @@ -16,6 +16,7 @@ import * as ApiServiceProxies from './service-proxies'; ApiServiceProxies.CategoryServiceProxy, ApiServiceProxies.CompetitionCategoryServiceProxy, ApiServiceProxies.CompetitionServiceProxy, + ApiServiceProxies.UserProfileServiceProxy, { provide: HTTP_INTERCEPTORS, useClass: AbpHttpInterceptor, multi: true } ] }) diff --git a/SystemKonkursow/4.2.1/aspnet-core/src/SystemKonkursow.Application/UserProfile/Dto/UserProfileDto.cs b/SystemKonkursow/4.2.1/aspnet-core/src/SystemKonkursow.Application/UserProfile/Dto/UserProfileDto.cs new file mode 100644 index 0000000..a71c951 --- /dev/null +++ b/SystemKonkursow/4.2.1/aspnet-core/src/SystemKonkursow.Application/UserProfile/Dto/UserProfileDto.cs @@ -0,0 +1,29 @@ +using Abp.Application.Services.Dto; +using Abp.Authorization.Users; +using System.ComponentModel.DataAnnotations; + +namespace SystemKonkursow.UserProfile.Dto +{ + public class UserProfileDto : EntityDto + { + [Required] + [StringLength(AbpUserBase.MaxNameLength)] + public string Name { get; set; } + + [Required] + [StringLength(AbpUserBase.MaxSurnameLength)] + public string Surname { get; set; } + + [Required] + [StringLength(AbpUserBase.MaxUserNameLength)] + public string UserName { get; set; } + + [Required] + [EmailAddress] + [StringLength(AbpUserBase.MaxEmailAddressLength)] + public string EmailAddress { get; set; } + + [Required] + public int ParticipantClass { get; set; } + } +} diff --git a/SystemKonkursow/4.2.1/aspnet-core/src/SystemKonkursow.Application/UserProfile/Dto/UserProfileMapProfile.cs b/SystemKonkursow/4.2.1/aspnet-core/src/SystemKonkursow.Application/UserProfile/Dto/UserProfileMapProfile.cs new file mode 100644 index 0000000..1c1454d --- /dev/null +++ b/SystemKonkursow/4.2.1/aspnet-core/src/SystemKonkursow.Application/UserProfile/Dto/UserProfileMapProfile.cs @@ -0,0 +1,25 @@ +using AutoMapper; +using SystemKonkursow.Authorization.Users; + +namespace SystemKonkursow.UserProfile.Dto +{ + public class UserProfileMapProfile : Profile + { + public UserProfileMapProfile() + { + CreateMap() + .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id)) + .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name)) + .ForMember(dest => dest.Surname, opt => opt.MapFrom(src => src.Surname)) + .ForMember(dest => dest.UserName, opt => opt.MapFrom(src => src.UserName)) + .ForMember(dest => dest.EmailAddress, opt => opt.MapFrom(src => src.EmailAddress)); + + CreateMap() + .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id)) + .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name)) + .ForMember(dest => dest.Surname, opt => opt.MapFrom(src => src.Surname)) + .ForMember(dest => dest.UserName, opt => opt.MapFrom(src => src.UserName)) + .ForMember(dest => dest.EmailAddress, opt => opt.MapFrom(src => src.EmailAddress)); + } + } +} diff --git a/SystemKonkursow/4.2.1/aspnet-core/src/SystemKonkursow.Application/UserProfile/UserProfileAppService.cs b/SystemKonkursow/4.2.1/aspnet-core/src/SystemKonkursow.Application/UserProfile/UserProfileAppService.cs new file mode 100644 index 0000000..f24a4d5 --- /dev/null +++ b/SystemKonkursow/4.2.1/aspnet-core/src/SystemKonkursow.Application/UserProfile/UserProfileAppService.cs @@ -0,0 +1,68 @@ +using Abp.Authorization; +using Abp.Domain.Repositories; +using Abp.Domain.Uow; +using Microsoft.EntityFrameworkCore; +using System.Threading.Tasks; +using SystemKonkursow.Authorization.Users; +using SystemKonkursow.UserProfile.Dto; + +namespace SystemKonkursow.UserProfile +{ + public class UserProfileAppService : SystemKonkursowAppServiceBase + { + private readonly UserManager _userManager; + private readonly IRepository _participantRepository; + + public UserProfileAppService(UserManager userManager, + IRepository participantRepository) + { + _userManager = userManager; + _participantRepository = participantRepository; + } + + [AbpAuthorize] + public async Task GetProfile() + { + var user = await GetCurrentUserAsync(); + + var mappedProfile = ObjectMapper.Map(user); + + var isParticipant = await _userManager.IsParticipantUserAsync(user); + + if (isParticipant) + { + var participant = await _participantRepository.GetAll() + .FirstOrDefaultAsync(t => t.UserId == user.Id); + + mappedProfile.ParticipantClass = participant.ParticipantClass; + } + else + { + mappedProfile.ParticipantClass = 0; + } + + return mappedProfile; + } + + [AbpAuthorize] + [UnitOfWork] + public async Task UpdateProfile(UserProfileDto userProfile) + { + var user = await _userManager.GetUserByIdAsync(userProfile.Id); + + ObjectMapper.Map(userProfile, user); + user.SetNormalizedNames(); + + CheckErrors(await _userManager.UpdateAsync(user)); + + if (userProfile.ParticipantClass != 0) + { + var participant = await _participantRepository.GetAll().FirstOrDefaultAsync(t => t.UserId == user.Id); + + participant.ParticipantClass = userProfile.ParticipantClass; + + await _participantRepository.UpdateAsync(participant); + } + } + } +}