aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortranstrike <transtrike@gmail.com>2021-02-03 12:31:32 +0200
committertranstrike <transtrike@gmail.com>2021-02-03 12:31:32 +0200
commitb417eb391795f157a9db894647730f1daf69a1d3 (patch)
tree8a59e5958172839b17e59f0f7cdeaf95ee0492c9
parent8174d2b35c1d3fa90df8b9cb4a75bb3381ea5e39 (diff)
parent5d0e9f2c19b68a73baeebf623980d458e3aab80c (diff)
downloadDevHive-b417eb391795f157a9db894647730f1daf69a1d3.tar
DevHive-b417eb391795f157a9db894647730f1daf69a1d3.tar.gz
DevHive-b417eb391795f157a9db894647730f1daf69a1d3.zip
Merge branch 'dev' of github.com:Team-Kaleidoscope/DevHive into dev
-rw-r--r--src/DevHive.Angular/src/app/components/comment/comment.component.html2
-rw-r--r--src/DevHive.Angular/src/app/components/feed/feed.component.html4
-rw-r--r--src/DevHive.Angular/src/app/components/post-page/post-page.component.ts8
-rw-r--r--src/DevHive.Angular/src/app/components/post/post.component.html2
-rw-r--r--src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.css35
-rw-r--r--src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.html12
-rw-r--r--src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.ts37
-rw-r--r--src/DevHive.Angular/src/app/components/profile/profile.component.html2
-rw-r--r--src/DevHive.Angular/src/app/services/user.service.ts17
-rw-r--r--src/DevHive.Angular/src/models/identity/user.ts14
-rw-r--r--src/DevHive.Data/DevHiveContext.cs5
-rw-r--r--src/DevHive.Data/Interfaces/Models/IProfilePicture.cs13
-rw-r--r--src/DevHive.Data/Interfaces/Models/IUser.cs2
-rw-r--r--src/DevHive.Data/Interfaces/Repositories/IUserRepository.cs1
-rw-r--r--src/DevHive.Data/Migrations/20210203071720_ProfilePicture.Designer.cs633
-rw-r--r--src/DevHive.Data/Migrations/20210203071720_ProfilePicture.cs52
-rw-r--r--src/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs36
-rw-r--r--src/DevHive.Data/Models/ProfilePicture.cs15
-rw-r--r--src/DevHive.Data/Models/User.cs2
-rw-r--r--src/DevHive.Data/Repositories/UserRepository.cs10
-rw-r--r--src/DevHive.Services/Configurations/Mapping/UserMappings.cs6
-rw-r--r--src/DevHive.Services/Interfaces/IUserService.cs1
-rw-r--r--src/DevHive.Services/Models/Identity/User/ProfilePictureServiceModel.cs7
-rw-r--r--src/DevHive.Services/Models/Identity/User/UpdateProfilePictureServiceModel.cs12
-rw-r--r--src/DevHive.Services/Models/Identity/User/UpdateUserServiceModel.cs2
-rw-r--r--src/DevHive.Services/Models/Identity/User/UserServiceModel.cs2
-rw-r--r--src/DevHive.Services/Services/UserService.cs29
-rw-r--r--src/DevHive.Web/Configurations/Mapping/UserMappings.cs3
-rw-r--r--src/DevHive.Web/Controllers/UserController.cs17
-rw-r--r--src/DevHive.Web/Models/Identity/User/ProfilePictureWebModel.cs7
-rw-r--r--src/DevHive.Web/Models/Identity/User/UpdateProfilePictureWebModel.cs9
-rw-r--r--src/DevHive.Web/Models/Identity/User/UserWebModel.cs2
32 files changed, 973 insertions, 26 deletions
diff --git a/src/DevHive.Angular/src/app/components/comment/comment.component.html b/src/DevHive.Angular/src/app/components/comment/comment.component.html
index 8908b25..718e25c 100644
--- a/src/DevHive.Angular/src/app/components/comment/comment.component.html
+++ b/src/DevHive.Angular/src/app/components/comment/comment.component.html
@@ -3,7 +3,7 @@
<div class="comment rounded-border" *ngIf="loaded">
<div class="content">
<div class="author" (click)="goToAuthorProfile()">
- <img class="round-image" [src]="user.imageUrl">
+ <img class="round-image" [src]="user.profilePictureURL">
<div class="author-info">
<div class="name">
{{ user.firstName }} {{ user.lastName }}
diff --git a/src/DevHive.Angular/src/app/components/feed/feed.component.html b/src/DevHive.Angular/src/app/components/feed/feed.component.html
index 6d3da5f..c584055 100644
--- a/src/DevHive.Angular/src/app/components/feed/feed.component.html
+++ b/src/DevHive.Angular/src/app/components/feed/feed.component.html
@@ -3,7 +3,7 @@
<div id="feed-page" *ngIf="dataArrived">
<nav id="profile-bar" class="round-image rounded-border">
<div id="profile-info" (click)="goToProfile()">
- <img id="profile-bar-profile-pic" [src]="user.imageUrl" alt=""/>
+ <img id="profile-bar-profile-pic" class="round-image" [src]="user.profilePictureURL" alt=""/>
<div id="profile-bar-name">
{{ user.firstName }} {{ user.lastName }}
</div>
@@ -17,7 +17,7 @@
<div id="feed-content">
<nav id="top-bar">
<div id="main-content">
- <img id="top-bar-profile-pic" class="round-image" [src]="user.imageUrl" alt="" (click)="goToProfile()">
+ <img id="top-bar-profile-pic" class="round-image" [src]="user.profilePictureURL" alt="" (click)="goToProfile()">
<form id="create-post-form" class="rounded-border" [formGroup]="createPostFormGroup" (ngSubmit)="createPost()">
<div id="form-inputs">
<input id="top-bar-create-post" type="text" formControlName="newPostMessage" placeholder="What's on your mind?"/>
diff --git a/src/DevHive.Angular/src/app/components/post-page/post-page.component.ts b/src/DevHive.Angular/src/app/components/post-page/post-page.component.ts
index 3991870..ef046e1 100644
--- a/src/DevHive.Angular/src/app/components/post-page/post-page.component.ts
+++ b/src/DevHive.Angular/src/app/components/post-page/post-page.component.ts
@@ -45,7 +45,12 @@ export class PostPageComponent implements OnInit {
if (this.loggedIn) {
this.editable = this.post.creatorUsername === this._tokenService.getUsernameFromSessionStorageToken();
}
- this.loadFiles();
+ if (this.post.fileURLs.length > 0) {
+ this.loadFiles();
+ }
+ else {
+ this.dataArrived = true;
+ }
},
(err: HttpErrorResponse) => {
this._router.navigate(['/not-found']);
@@ -103,7 +108,6 @@ export class PostPageComponent implements OnInit {
this.files = this.files.filter(x => x.name !== fileName);
}
-
editPost(): void {
if (this._tokenService.getTokenFromSessionStorage() === '') {
this.toLogin();
diff --git a/src/DevHive.Angular/src/app/components/post/post.component.html b/src/DevHive.Angular/src/app/components/post/post.component.html
index 7347056..bc0d84a 100644
--- a/src/DevHive.Angular/src/app/components/post/post.component.html
+++ b/src/DevHive.Angular/src/app/components/post/post.component.html
@@ -3,7 +3,7 @@
<div class="post rounded-border" *ngIf="loaded">
<div class="content">
<div class="author" (click)="goToAuthorProfile()">
- <img class="round-image" [src]="user.imageUrl">
+ <img class="round-image" [src]="user.profilePictureURL">
<div class="author-info">
<div class="name">
{{ user.firstName }} {{ user.lastName }}
diff --git a/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.css b/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.css
index 716ffc9..27d1584 100644
--- a/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.css
+++ b/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.css
@@ -37,6 +37,41 @@ hr {
/* Form */
+#update-profile-picture {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0 .5em;
+}
+
+#profile-picture {
+ width: 5em;
+ height: 5em;
+}
+
+#submit-file {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 1em;
+}
+
+#upload-file:hover {
+ cursor: inherit;
+}
+
+#upload-file > input:hover {
+ cursor: pointer;
+}
+
+#upload-file > input::-webkit-file-upload-button {
+ visibility: hidden;
+}
+
+#update-user {
+ margin-top: 1.1em;
+}
+
.input-field {
border-color: var(--focus-color) !important;
caret-color: var(--focus-color);
diff --git a/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.html b/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.html
index f8493ab..d87c35c 100644
--- a/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.html
+++ b/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.html
@@ -7,7 +7,17 @@
</nav>
<hr>
<div class="scroll-standalone">
- <form [formGroup]="updateUserFormGroup" (ngSubmit)="onSubmit()">
+ <form id="update-profile-picture" [formGroup]="updateProfilePictureFormGroup" (ngSubmit)="updateProfilePicture()">
+ <img id="profile-picture" class="round-image" [src]="user.profilePictureURL">
+ <div id="submit-file">
+ <div id="upload-file" class="submit-btn">
+ <input type="file" formControlName="fileUpload" (change)="onFileUpload($event)">
+ </div>
+ <button class="submit-btn" type="submit">Update profile picture</button>
+ </div>
+ </form>
+ <hr>
+ <form id="update-user" [formGroup]="updateUserFormGroup" (ngSubmit)="onSubmit()">
<div class="input-selection">
<input type="text" class="input-field" formControlName="firstName" required>
<label class="input-field-label">First Name</label>
diff --git a/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.ts b/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.ts
index 4a401ef..463b980 100644
--- a/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.ts
+++ b/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.ts
@@ -29,6 +29,8 @@ export class ProfileSettingsComponent implements OnInit {
public showLanguages = false;
public showTechnologies = false;
public updateUserFormGroup: FormGroup;
+ public updateProfilePictureFormGroup: FormGroup;
+ public newProfilePicture: File;
public user: User;
public availableLanguages: Language[];
public availableTechnologies: Technology[];
@@ -44,6 +46,7 @@ export class ProfileSettingsComponent implements OnInit {
this.user = this._userService.getDefaultUser();
this.availableLanguages = [];
this.availableTechnologies = [];
+ this.newProfilePicture = new File([], '');
this._userService.getUserByUsernameRequest(this._urlUsername).subscribe(
(res: object) => {
@@ -76,7 +79,7 @@ export class ProfileSettingsComponent implements OnInit {
Object.assign(userFromToken, tokenRes);
if (userFromToken.userName === this._urlUsername) {
- this.initForm();
+ this.initForms();
this.dataArrived = true;
}
else {
@@ -93,7 +96,7 @@ export class ProfileSettingsComponent implements OnInit {
}
}
- private initForm(): void {
+ private initForms(): void {
this.updateUserFormGroup = this._fb.group({
firstName: new FormControl(this.user.firstName, [
Validators.required,
@@ -137,6 +140,10 @@ export class ProfileSettingsComponent implements OnInit {
this.updateUserFormGroup.patchValue({ technologyInput : value });
});
+ this.updateProfilePictureFormGroup = this._fb.group({
+ fileUpload: new FormControl('')
+ });
+
this.updateUserFormGroup.valueChanges.subscribe(() => {
this._successBar?.hideMsg();
this._errorBar?.hideError();
@@ -161,6 +168,23 @@ export class ProfileSettingsComponent implements OnInit {
});
}
+ onFileUpload(event: any): void {
+ this.newProfilePicture = event.target.files[0];
+ }
+
+ updateProfilePicture(): void {
+ if (this.newProfilePicture.size === 0) {
+ return;
+ }
+
+ this._userService.putProfilePictureFromSessionStorageRequest(this.newProfilePicture).subscribe(
+ (result: object) => {
+ this.reloadPage();
+ }
+ );
+ this.dataArrived = false;
+ }
+
onSubmit(): void {
this._successBar.hideMsg();
this._errorBar.hideError();
@@ -169,7 +193,7 @@ export class ProfileSettingsComponent implements OnInit {
this.patchTechnologiesControl();
this._userService.putUserFromSessionStorageRequest(this.updateUserFormGroup, this.user.roles, this.user.friends).subscribe(
- res => {
+ (result: object) => {
this._successBar.showMsg('Profile updated successfully!');
},
(err: HttpErrorResponse) => {
@@ -261,9 +285,16 @@ export class ProfileSettingsComponent implements OnInit {
this._errorBar.showError(err);
}
);
+ this.dataArrived = false;
}
else {
this.deleteAccountConfirm = true;
}
}
+
+ private reloadPage(): void {
+ this._router.routeReuseStrategy.shouldReuseRoute = () => false;
+ this._router.onSameUrlNavigation = 'reload';
+ this._router.navigate([this._router.url]);
+ }
}
diff --git a/src/DevHive.Angular/src/app/components/profile/profile.component.html b/src/DevHive.Angular/src/app/components/profile/profile.component.html
index e2dacd1..03a36bf 100644
--- a/src/DevHive.Angular/src/app/components/profile/profile.component.html
+++ b/src/DevHive.Angular/src/app/components/profile/profile.component.html
@@ -10,7 +10,7 @@
<hr>
<div class="scroll-standalone" (scroll)="onScroll($event)">
<div id="main-info" class="rounded-border">
- <img class="round-image" [src]="user.imageUrl" alt=""/>
+ <img class="round-image" [src]="user.profilePictureURL" alt=""/>
<div id="other-main-info">
<div id="name">
{{ user.firstName }} {{ user.lastName }}
diff --git a/src/DevHive.Angular/src/app/services/user.service.ts b/src/DevHive.Angular/src/app/services/user.service.ts
index 3bfc857..422d7db 100644
--- a/src/DevHive.Angular/src/app/services/user.service.ts
+++ b/src/DevHive.Angular/src/app/services/user.service.ts
@@ -36,6 +36,13 @@ export class UserService {
return this.putUserRequest(userId, token, updateUserFormGroup, userRoles, userFriends);
}
+ putProfilePictureFromSessionStorageRequest(newPicture: File): Observable<object> {
+ const userId = this._tokenService.getUserIdFromSessionStorageToken();
+ const token = this._tokenService.getTokenFromSessionStorage();
+
+ return this.putProfilePictureRequest(userId, token, newPicture);
+ }
+
deleteUserFromSessionStorageRequest(): Observable<object> {
const userId = this._tokenService.getUserIdFromSessionStorageToken();
const token = this._tokenService.getTokenFromSessionStorage();
@@ -98,6 +105,16 @@ export class UserService {
return this._http.put(AppConstants.API_USER_URL, body, options);
}
+ putProfilePictureRequest(userId: Guid, authToken: string, newPicture: File): Observable<object> {
+ const form = new FormData();
+ form.append('picture', newPicture);
+ const options = {
+ params: new HttpParams().set('UserId', userId.toString()),
+ headers: new HttpHeaders().set('Authorization', 'Bearer ' + authToken)
+ };
+ return this._http.put(AppConstants.API_USER_URL + '/ProfilePicture', form, options);
+ }
+
deleteUserRequest(userId: Guid, authToken: string): Observable<object> {
const options = {
params: new HttpParams().set('Id', userId.toString()),
diff --git a/src/DevHive.Angular/src/models/identity/user.ts b/src/DevHive.Angular/src/models/identity/user.ts
index 020a403..e0038e0 100644
--- a/src/DevHive.Angular/src/models/identity/user.ts
+++ b/src/DevHive.Angular/src/models/identity/user.ts
@@ -10,19 +10,19 @@ export class User {
private _firstName : string;
private _userName : string;
private _email: string;
- private _imageUrl : string;
+ private _profilePictureURL : string;
private _languages: Language[];
private _technologies: Technology[];
private _roles: Role[];
private _friends: Friend[];
- constructor(id: Guid, userName: string, firstName: string, lastName: string, email: string, imageUrl: string, languages: Language[], technologies: Technology[], roles: Role[], friends: Friend[]) {
+ constructor(id: Guid, userName: string, firstName: string, lastName: string, email: string, profilePictureURL: string, languages: Language[], technologies: Technology[], roles: Role[], friends: Friend[]) {
this.id = id;
this.userName = userName;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
- this.imageUrl = imageUrl;
+ this._profilePictureURL = profilePictureURL;
this.languages = languages;
this.technologies = technologies;
this.roles = roles;
@@ -63,11 +63,11 @@ export class User {
this._email = v;
}
- public get imageUrl(): string {
- return this._imageUrl;
+ public get profilePictureURL(): string {
+ return this._profilePictureURL;
}
- public set imageUrl(v: string) {
- this._imageUrl = v;
+ public set profilePictureURL(v: string) {
+ this._profilePictureURL = v;
}
public get languages(): Language[] {
diff --git a/src/DevHive.Data/DevHiveContext.cs b/src/DevHive.Data/DevHiveContext.cs
index 417de7f..b3ebd73 100644
--- a/src/DevHive.Data/DevHiveContext.cs
+++ b/src/DevHive.Data/DevHiveContext.cs
@@ -27,6 +27,11 @@ namespace DevHive.Data
.HasIndex(x => x.UserName)
.IsUnique();
+ builder.Entity<User>()
+ .HasOne(x => x.ProfilePicture)
+ .WithOne(x => x.User)
+ .HasForeignKey<ProfilePicture>(x => x.UserId);
+
/* Roles */
builder.Entity<User>()
.HasMany(x => x.Roles)
diff --git a/src/DevHive.Data/Interfaces/Models/IProfilePicture.cs b/src/DevHive.Data/Interfaces/Models/IProfilePicture.cs
new file mode 100644
index 0000000..c3fcbea
--- /dev/null
+++ b/src/DevHive.Data/Interfaces/Models/IProfilePicture.cs
@@ -0,0 +1,13 @@
+using System;
+using DevHive.Data.Models;
+
+namespace DevHive.Data.Interfaces.Models
+{
+ public interface IProfilePicture : IModel
+ {
+ Guid UserId { get; set; }
+ User User { get; set; }
+
+ string PictureURL { get; set; }
+ }
+}
diff --git a/src/DevHive.Data/Interfaces/Models/IUser.cs b/src/DevHive.Data/Interfaces/Models/IUser.cs
index eb262fd..fcd741c 100644
--- a/src/DevHive.Data/Interfaces/Models/IUser.cs
+++ b/src/DevHive.Data/Interfaces/Models/IUser.cs
@@ -10,7 +10,7 @@ namespace DevHive.Data.Interfaces.Models
string LastName { get; set; }
- string ProfilePictureUrl { get; set; }
+ ProfilePicture ProfilePicture { get; set; }
HashSet<Language> Languages { get; set; }
diff --git a/src/DevHive.Data/Interfaces/Repositories/IUserRepository.cs b/src/DevHive.Data/Interfaces/Repositories/IUserRepository.cs
index 4346e9c..5b6ab9e 100644
--- a/src/DevHive.Data/Interfaces/Repositories/IUserRepository.cs
+++ b/src/DevHive.Data/Interfaces/Repositories/IUserRepository.cs
@@ -11,6 +11,7 @@ namespace DevHive.Data.Interfaces.Repositories
//Read
Task<User> GetByUsernameAsync(string username);
IEnumerable<User> QueryAll();
+ Task<bool> UpdateProfilePicture(Guid userId, string pictureUrl);
//Validations
Task<bool> DoesEmailExistAsync(string email);
diff --git a/src/DevHive.Data/Migrations/20210203071720_ProfilePicture.Designer.cs b/src/DevHive.Data/Migrations/20210203071720_ProfilePicture.Designer.cs
new file mode 100644
index 0000000..b8dbd8e
--- /dev/null
+++ b/src/DevHive.Data/Migrations/20210203071720_ProfilePicture.Designer.cs
@@ -0,0 +1,633 @@
+// <auto-generated />
+using System;
+using System.Collections.Generic;
+using DevHive.Data;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+namespace DevHive.Data.Migrations
+{
+ [DbContext(typeof(DevHiveContext))]
+ [Migration("20210203071720_ProfilePicture")]
+ partial class ProfilePicture
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .UseIdentityByDefaultColumns()
+ .HasAnnotation("Relational:MaxIdentifierLength", 63)
+ .HasAnnotation("ProductVersion", "5.0.1");
+
+ modelBuilder.Entity("DevHive.Data.Models.Comment", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<Guid?>("CreatorId")
+ .HasColumnType("uuid");
+
+ b.Property<string>("Message")
+ .HasColumnType("text");
+
+ b.Property<Guid?>("PostId")
+ .HasColumnType("uuid");
+
+ b.Property<DateTime>("TimeCreated")
+ .HasColumnType("timestamp without time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CreatorId");
+
+ b.HasIndex("PostId");
+
+ b.ToTable("Comments");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Language", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<string>("Name")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Languages");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Post", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<Guid?>("CreatorId")
+ .HasColumnType("uuid");
+
+ b.Property<List<string>>("FileUrls")
+ .HasColumnType("text[]");
+
+ b.Property<string>("Message")
+ .HasColumnType("text");
+
+ b.Property<DateTime>("TimeCreated")
+ .HasColumnType("timestamp without time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CreatorId");
+
+ b.ToTable("Posts");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.ProfilePicture", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<string>("PictureURL")
+ .HasColumnType("text");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.ToTable("ProfilePicture");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Rating", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<int>("Rate")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.ToTable("Rating");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Role", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<string>("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("text");
+
+ b.Property<string>("Name")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property<string>("NormalizedName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedName")
+ .IsUnique()
+ .HasDatabaseName("RoleNameIndex");
+
+ b.ToTable("AspNetRoles");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Technology", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<string>("Name")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Technologies");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.User", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<int>("AccessFailedCount")
+ .HasColumnType("integer");
+
+ b.Property<string>("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("text");
+
+ b.Property<string>("Email")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property<bool>("EmailConfirmed")
+ .HasColumnType("boolean");
+
+ b.Property<string>("FirstName")
+ .HasColumnType("text");
+
+ b.Property<string>("LastName")
+ .HasColumnType("text");
+
+ b.Property<bool>("LockoutEnabled")
+ .HasColumnType("boolean");
+
+ b.Property<DateTimeOffset?>("LockoutEnd")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property<string>("NormalizedEmail")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property<string>("NormalizedUserName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property<string>("PasswordHash")
+ .HasColumnType("text");
+
+ b.Property<string>("PhoneNumber")
+ .HasColumnType("text");
+
+ b.Property<bool>("PhoneNumberConfirmed")
+ .HasColumnType("boolean");
+
+ b.Property<string>("SecurityStamp")
+ .HasColumnType("text");
+
+ b.Property<bool>("TwoFactorEnabled")
+ .HasColumnType("boolean");
+
+ b.Property<string>("UserName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedEmail")
+ .HasDatabaseName("EmailIndex");
+
+ b.HasIndex("NormalizedUserName")
+ .IsUnique()
+ .HasDatabaseName("UserNameIndex");
+
+ b.HasIndex("UserName")
+ .IsUnique();
+
+ b.ToTable("AspNetUsers");
+ });
+
+ modelBuilder.Entity("DevHive.Data.RelationModels.RatedPost", b =>
+ {
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.Property<Guid>("PostId")
+ .HasColumnType("uuid");
+
+ b.HasKey("UserId", "PostId");
+
+ b.HasIndex("PostId");
+
+ b.ToTable("RatedPosts");
+ });
+
+ modelBuilder.Entity("DevHive.Data.RelationModels.UserFriend", b =>
+ {
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.Property<Guid>("FriendId")
+ .HasColumnType("uuid");
+
+ b.HasKey("UserId", "FriendId");
+
+ b.HasIndex("FriendId");
+
+ b.ToTable("UserFriends");
+ });
+
+ modelBuilder.Entity("DevHive.Data.RelationModels.UserRate", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<bool>("Rate")
+ .HasColumnType("boolean");
+
+ b.Property<Guid?>("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("UserRates");
+ });
+
+ modelBuilder.Entity("LanguageUser", b =>
+ {
+ b.Property<Guid>("LanguagesId")
+ .HasColumnType("uuid");
+
+ b.Property<Guid>("UsersId")
+ .HasColumnType("uuid");
+
+ b.HasKey("LanguagesId", "UsersId");
+
+ b.HasIndex("UsersId");
+
+ b.ToTable("LanguageUser");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .UseIdentityByDefaultColumn();
+
+ b.Property<string>("ClaimType")
+ .HasColumnType("text");
+
+ b.Property<string>("ClaimValue")
+ .HasColumnType("text");
+
+ b.Property<Guid>("RoleId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetRoleClaims");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .UseIdentityByDefaultColumn();
+
+ b.Property<string>("ClaimType")
+ .HasColumnType("text");
+
+ b.Property<string>("ClaimValue")
+ .HasColumnType("text");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserClaims");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
+ {
+ b.Property<string>("LoginProvider")
+ .HasColumnType("text");
+
+ b.Property<string>("ProviderKey")
+ .HasColumnType("text");
+
+ b.Property<string>("ProviderDisplayName")
+ .HasColumnType("text");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("LoginProvider", "ProviderKey");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserLogins");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
+ {
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.Property<Guid>("RoleId")
+ .HasColumnType("uuid");
+
+ b.HasKey("UserId", "RoleId");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetUserRoles");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
+ {
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.Property<string>("LoginProvider")
+ .HasColumnType("text");
+
+ b.Property<string>("Name")
+ .HasColumnType("text");
+
+ b.Property<string>("Value")
+ .HasColumnType("text");
+
+ b.HasKey("UserId", "LoginProvider", "Name");
+
+ b.ToTable("AspNetUserTokens");
+ });
+
+ modelBuilder.Entity("RoleUser", b =>
+ {
+ b.Property<Guid>("RolesId")
+ .HasColumnType("uuid");
+
+ b.Property<Guid>("UsersId")
+ .HasColumnType("uuid");
+
+ b.HasKey("RolesId", "UsersId");
+
+ b.HasIndex("UsersId");
+
+ b.ToTable("RoleUser");
+ });
+
+ modelBuilder.Entity("TechnologyUser", b =>
+ {
+ b.Property<Guid>("TechnologiesId")
+ .HasColumnType("uuid");
+
+ b.Property<Guid>("UsersId")
+ .HasColumnType("uuid");
+
+ b.HasKey("TechnologiesId", "UsersId");
+
+ b.HasIndex("UsersId");
+
+ b.ToTable("TechnologyUser");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Comment", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", "Creator")
+ .WithMany("Comments")
+ .HasForeignKey("CreatorId");
+
+ b.HasOne("DevHive.Data.Models.Post", "Post")
+ .WithMany("Comments")
+ .HasForeignKey("PostId");
+
+ b.Navigation("Creator");
+
+ b.Navigation("Post");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Post", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", "Creator")
+ .WithMany("Posts")
+ .HasForeignKey("CreatorId");
+
+ b.Navigation("Creator");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.ProfilePicture", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", "User")
+ .WithOne("ProfilePicture")
+ .HasForeignKey("DevHive.Data.Models.ProfilePicture", "UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("DevHive.Data.RelationModels.RatedPost", b =>
+ {
+ b.HasOne("DevHive.Data.Models.Post", "Post")
+ .WithMany()
+ .HasForeignKey("PostId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("DevHive.Data.Models.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Post");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("DevHive.Data.RelationModels.UserFriend", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", "Friend")
+ .WithMany("FriendsOf")
+ .HasForeignKey("FriendId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("DevHive.Data.Models.User", "User")
+ .WithMany("MyFriends")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Friend");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("DevHive.Data.RelationModels.UserRate", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("LanguageUser", b =>
+ {
+ b.HasOne("DevHive.Data.Models.Language", null)
+ .WithMany()
+ .HasForeignKey("LanguagesId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UsersId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
+ {
+ b.HasOne("DevHive.Data.Models.Role", null)
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
+ {
+ b.HasOne("DevHive.Data.Models.Role", null)
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("RoleUser", b =>
+ {
+ b.HasOne("DevHive.Data.Models.Role", null)
+ .WithMany()
+ .HasForeignKey("RolesId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UsersId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("TechnologyUser", b =>
+ {
+ b.HasOne("DevHive.Data.Models.Technology", null)
+ .WithMany()
+ .HasForeignKey("TechnologiesId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UsersId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Post", b =>
+ {
+ b.Navigation("Comments");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.User", b =>
+ {
+ b.Navigation("Comments");
+
+ b.Navigation("FriendsOf");
+
+ b.Navigation("MyFriends");
+
+ b.Navigation("Posts");
+
+ b.Navigation("ProfilePicture");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/DevHive.Data/Migrations/20210203071720_ProfilePicture.cs b/src/DevHive.Data/Migrations/20210203071720_ProfilePicture.cs
new file mode 100644
index 0000000..1b0c2c6
--- /dev/null
+++ b/src/DevHive.Data/Migrations/20210203071720_ProfilePicture.cs
@@ -0,0 +1,52 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace DevHive.Data.Migrations
+{
+ public partial class ProfilePicture : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "ProfilePictureUrl",
+ table: "AspNetUsers");
+
+ migrationBuilder.CreateTable(
+ name: "ProfilePicture",
+ columns: table => new
+ {
+ Id = table.Column<Guid>(type: "uuid", nullable: false),
+ UserId = table.Column<Guid>(type: "uuid", nullable: false),
+ PictureURL = table.Column<string>(type: "text", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_ProfilePicture", x => x.Id);
+ table.ForeignKey(
+ name: "FK_ProfilePicture_AspNetUsers_UserId",
+ column: x => x.UserId,
+ principalTable: "AspNetUsers",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_ProfilePicture_UserId",
+ table: "ProfilePicture",
+ column: "UserId",
+ unique: true);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "ProfilePicture");
+
+ migrationBuilder.AddColumn<string>(
+ name: "ProfilePictureUrl",
+ table: "AspNetUsers",
+ type: "text",
+ nullable: true);
+ }
+ }
+}
diff --git a/src/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs b/src/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs
index 96cabad..0450670 100644
--- a/src/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs
+++ b/src/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs
@@ -86,6 +86,26 @@ namespace DevHive.Data.Migrations
b.ToTable("Posts");
});
+ modelBuilder.Entity("DevHive.Data.Models.ProfilePicture", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<string>("PictureURL")
+ .HasColumnType("text");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.ToTable("ProfilePicture");
+ });
+
modelBuilder.Entity("DevHive.Data.Models.Rating", b =>
{
b.Property<Guid>("Id")
@@ -190,9 +210,6 @@ namespace DevHive.Data.Migrations
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
- b.Property<string>("ProfilePictureUrl")
- .HasColumnType("text");
-
b.Property<string>("SecurityStamp")
.HasColumnType("text");
@@ -437,6 +454,17 @@ namespace DevHive.Data.Migrations
b.Navigation("Creator");
});
+ modelBuilder.Entity("DevHive.Data.Models.ProfilePicture", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", "User")
+ .WithOne("ProfilePicture")
+ .HasForeignKey("DevHive.Data.Models.ProfilePicture", "UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
modelBuilder.Entity("DevHive.Data.RelationModels.RatedPost", b =>
{
b.HasOne("DevHive.Data.Models.Post", "Post")
@@ -594,6 +622,8 @@ namespace DevHive.Data.Migrations
b.Navigation("MyFriends");
b.Navigation("Posts");
+
+ b.Navigation("ProfilePicture");
});
#pragma warning restore 612, 618
}
diff --git a/src/DevHive.Data/Models/ProfilePicture.cs b/src/DevHive.Data/Models/ProfilePicture.cs
new file mode 100644
index 0000000..d5cc397
--- /dev/null
+++ b/src/DevHive.Data/Models/ProfilePicture.cs
@@ -0,0 +1,15 @@
+using System;
+using DevHive.Data.Interfaces.Models;
+
+namespace DevHive.Data.Models
+{
+ public class ProfilePicture: IProfilePicture
+ {
+ public Guid Id { get; set; }
+
+ public Guid UserId { get; set; }
+ public User User { get; set; }
+
+ public string PictureURL { get; set; }
+ }
+}
diff --git a/src/DevHive.Data/Models/User.cs b/src/DevHive.Data/Models/User.cs
index 1c365e4..d73f989 100644
--- a/src/DevHive.Data/Models/User.cs
+++ b/src/DevHive.Data/Models/User.cs
@@ -14,7 +14,7 @@ namespace DevHive.Data.Models
public string LastName { get; set; }
- public string ProfilePictureUrl { get; set; }
+ public ProfilePicture ProfilePicture { get; set; }
public HashSet<Language> Languages { get; set; } = new();
diff --git a/src/DevHive.Data/Repositories/UserRepository.cs b/src/DevHive.Data/Repositories/UserRepository.cs
index 58f8188..ed8db49 100644
--- a/src/DevHive.Data/Repositories/UserRepository.cs
+++ b/src/DevHive.Data/Repositories/UserRepository.cs
@@ -40,6 +40,7 @@ namespace DevHive.Data.Repositories
.Include(x => x.Posts)
.Include(x => x.MyFriends)
.Include(x => x.FriendsOf)
+ .Include(x => x.ProfilePicture)
.FirstOrDefaultAsync(x => x.Id == id);
}
@@ -52,6 +53,7 @@ namespace DevHive.Data.Repositories
.Include(x => x.Posts)
.Include(x => x.MyFriends)
.Include(x => x.FriendsOf)
+ .Include(x => x.ProfilePicture)
.FirstOrDefaultAsync(x => x.UserName == username);
}
#endregion
@@ -97,6 +99,14 @@ namespace DevHive.Data.Repositories
return await this.SaveChangesAsync();
}
+
+ public async Task<bool> UpdateProfilePicture(Guid userId, string pictureUrl) {
+ User user = await this.GetByIdAsync(userId);
+
+ user.ProfilePicture.PictureURL = pictureUrl;
+
+ return await this.SaveChangesAsync();
+ }
#endregion
#region Validations
diff --git a/src/DevHive.Services/Configurations/Mapping/UserMappings.cs b/src/DevHive.Services/Configurations/Mapping/UserMappings.cs
index 5223d84..6922cd7 100644
--- a/src/DevHive.Services/Configurations/Mapping/UserMappings.cs
+++ b/src/DevHive.Services/Configurations/Mapping/UserMappings.cs
@@ -22,10 +22,12 @@ namespace DevHive.Services.Configurations.Mapping
CreateMap<UpdateFriendServiceModel, User>();
CreateMap<User, UserServiceModel>()
- .ForMember(dest => dest.Friends, src => src.MapFrom(p => p.MyFriends));
+ .ForMember(dest => dest.Friends, src => src.MapFrom(p => p.MyFriends))
+ .ForMember(dest => dest.ProfilePictureURL, src => src.MapFrom(p => p.ProfilePicture.PictureURL));
// .ForMember(dest => dest.Friends, src => src.MapFrom(p => p.Friends));
CreateMap<User, UpdateUserServiceModel>()
- .ForMember(x => x.Password, opt => opt.Ignore());
+ .ForMember(x => x.Password, opt => opt.Ignore())
+ .ForMember(dest => dest.ProfilePictureURL, src => src.MapFrom(p => p.ProfilePicture.PictureURL));
CreateMap<User, FriendServiceModel>();
CreateMap<UserFriend, FriendServiceModel>()
diff --git a/src/DevHive.Services/Interfaces/IUserService.cs b/src/DevHive.Services/Interfaces/IUserService.cs
index b701e4a..9e2b4e3 100644
--- a/src/DevHive.Services/Interfaces/IUserService.cs
+++ b/src/DevHive.Services/Interfaces/IUserService.cs
@@ -14,6 +14,7 @@ namespace DevHive.Services.Interfaces
Task<UserServiceModel> GetUserById(Guid id);
Task<UserServiceModel> UpdateUser(UpdateUserServiceModel updateModel);
+ Task<ProfilePictureServiceModel> UpdateProfilePicture(UpdateProfilePictureServiceModel updateProfilePictureServiceModel);
Task<bool> DeleteUser(Guid id);
diff --git a/src/DevHive.Services/Models/Identity/User/ProfilePictureServiceModel.cs b/src/DevHive.Services/Models/Identity/User/ProfilePictureServiceModel.cs
new file mode 100644
index 0000000..ad81057
--- /dev/null
+++ b/src/DevHive.Services/Models/Identity/User/ProfilePictureServiceModel.cs
@@ -0,0 +1,7 @@
+namespace DevHive.Services.Models.Identity.User
+{
+ public class ProfilePictureServiceModel
+ {
+ public string ProfilePictureURL { get; set; }
+ }
+}
diff --git a/src/DevHive.Services/Models/Identity/User/UpdateProfilePictureServiceModel.cs b/src/DevHive.Services/Models/Identity/User/UpdateProfilePictureServiceModel.cs
new file mode 100644
index 0000000..8563953
--- /dev/null
+++ b/src/DevHive.Services/Models/Identity/User/UpdateProfilePictureServiceModel.cs
@@ -0,0 +1,12 @@
+using System;
+using Microsoft.AspNetCore.Http;
+
+namespace DevHive.Services.Models.Identity.User
+{
+ public class UpdateProfilePictureServiceModel
+ {
+ public Guid UserId { get; set; }
+
+ public IFormFile Picture { get; set; }
+ }
+}
diff --git a/src/DevHive.Services/Models/Identity/User/UpdateUserServiceModel.cs b/src/DevHive.Services/Models/Identity/User/UpdateUserServiceModel.cs
index 5b197e4..b4e4400 100644
--- a/src/DevHive.Services/Models/Identity/User/UpdateUserServiceModel.cs
+++ b/src/DevHive.Services/Models/Identity/User/UpdateUserServiceModel.cs
@@ -12,6 +12,8 @@ namespace DevHive.Services.Models.Identity.User
public string Password { get; set; }
+ public string ProfilePictureURL { get; set; }
+
public HashSet<UpdateRoleServiceModel> Roles { get; set; } = new HashSet<UpdateRoleServiceModel>();
public HashSet<UpdateFriendServiceModel> Friends { get; set; } = new HashSet<UpdateFriendServiceModel>();
diff --git a/src/DevHive.Services/Models/Identity/User/UserServiceModel.cs b/src/DevHive.Services/Models/Identity/User/UserServiceModel.cs
index 5bf58ec..ac7bba2 100644
--- a/src/DevHive.Services/Models/Identity/User/UserServiceModel.cs
+++ b/src/DevHive.Services/Models/Identity/User/UserServiceModel.cs
@@ -8,6 +8,8 @@ namespace DevHive.Services.Models.Identity.User
{
public class UserServiceModel : BaseUserServiceModel
{
+ public string ProfilePictureURL { get; set; }
+
public HashSet<RoleServiceModel> Roles { get; set; } = new();
public HashSet<FriendServiceModel> Friends { get; set; } = new();
diff --git a/src/DevHive.Services/Services/UserService.cs b/src/DevHive.Services/Services/UserService.cs
index 40e894d..b3a4987 100644
--- a/src/DevHive.Services/Services/UserService.cs
+++ b/src/DevHive.Services/Services/UserService.cs
@@ -15,6 +15,7 @@ using DevHive.Data.Interfaces.Repositories;
using System.Linq;
using DevHive.Common.Models.Misc;
using DevHive.Data.RelationModels;
+using Microsoft.AspNetCore.Http;
namespace DevHive.Services.Services
{
@@ -26,13 +27,15 @@ namespace DevHive.Services.Services
private readonly ITechnologyRepository _technologyRepository;
private readonly IMapper _userMapper;
private readonly JWTOptions _jwtOptions;
+ private readonly ICloudService _cloudService;
public UserService(IUserRepository userRepository,
ILanguageRepository languageRepository,
IRoleRepository roleRepository,
ITechnologyRepository technologyRepository,
IMapper mapper,
- JWTOptions jwtOptions)
+ JWTOptions jwtOptions,
+ ICloudService cloudService)
{
this._userRepository = userRepository;
this._roleRepository = roleRepository;
@@ -40,6 +43,7 @@ namespace DevHive.Services.Services
this._jwtOptions = jwtOptions;
this._languageRepository = languageRepository;
this._technologyRepository = technologyRepository;
+ this._cloudService = cloudService;
}
#region Authentication
@@ -66,6 +70,7 @@ namespace DevHive.Services.Services
User user = this._userMapper.Map<User>(registerModel);
user.PasswordHash = PasswordModifications.GeneratePasswordHash(registerModel.Password);
+ user.ProfilePicture = new ProfilePicture() { PictureURL = String.Empty };
// Make sure the default role exists
//TODO: Move when project starts
@@ -119,6 +124,28 @@ namespace DevHive.Services.Services
User newUser = await this._userRepository.GetByIdAsync(user.Id);
return this._userMapper.Map<UserServiceModel>(newUser);
}
+
+ public async Task<ProfilePictureServiceModel> UpdateProfilePicture(UpdateProfilePictureServiceModel updateProfilePictureServiceModel)
+ {
+ User user = await this._userRepository.GetByIdAsync(updateProfilePictureServiceModel.UserId);
+
+ if (!String.IsNullOrEmpty(user.ProfilePicture.PictureURL))
+ {
+ bool success = await _cloudService.RemoveFilesFromCloud(new List<string> { user.ProfilePicture.PictureURL });
+ if (!success)
+ throw new InvalidCastException("Could not delete old profile picture!");
+ }
+
+ string fileUrl = (await this._cloudService.UploadFilesToCloud(new List<IFormFile> { updateProfilePictureServiceModel.Picture }))[0] ??
+ throw new ArgumentNullException("Unable to upload profile picture to cloud");
+
+ bool successful = await this._userRepository.UpdateProfilePicture(updateProfilePictureServiceModel.UserId, fileUrl);
+
+ if (!successful)
+ throw new InvalidOperationException("Unable to change profile picture!");
+
+ return new ProfilePictureServiceModel() { ProfilePictureURL = fileUrl };
+ }
#endregion
#region Delete
diff --git a/src/DevHive.Web/Configurations/Mapping/UserMappings.cs b/src/DevHive.Web/Configurations/Mapping/UserMappings.cs
index 1b26cc9..f58e7ca 100644
--- a/src/DevHive.Web/Configurations/Mapping/UserMappings.cs
+++ b/src/DevHive.Web/Configurations/Mapping/UserMappings.cs
@@ -23,6 +23,9 @@ namespace DevHive.Web.Configurations.Mapping
CreateMap<UsernameWebModel, FriendServiceModel>();
CreateMap<UsernameWebModel, UpdateFriendServiceModel>();
+ CreateMap<UpdateProfilePictureWebModel, UpdateProfilePictureServiceModel>();
+ CreateMap<ProfilePictureServiceModel, ProfilePictureWebModel>();
+
CreateMap<UpdateUserServiceModel, UpdateUserWebModel>();
CreateMap<FriendServiceModel, UsernameWebModel>();
}
diff --git a/src/DevHive.Web/Controllers/UserController.cs b/src/DevHive.Web/Controllers/UserController.cs
index fdf317c..109bbaa 100644
--- a/src/DevHive.Web/Controllers/UserController.cs
+++ b/src/DevHive.Web/Controllers/UserController.cs
@@ -94,6 +94,23 @@ namespace DevHive.Web.Controllers
return new AcceptedResult("UpdateUser", userWebModel);
}
+
+ [HttpPut]
+ [Route("ProfilePicture")]
+ [Authorize(Roles = "User,Admin")]
+ public async Task<IActionResult> UpdateProfilePicture(Guid userId, [FromForm] UpdateProfilePictureWebModel updateProfilePictureWebModel, [FromHeader] string authorization)
+ {
+ if (!await this._userService.ValidJWT(userId, authorization))
+ return new UnauthorizedResult();
+
+ UpdateProfilePictureServiceModel updateProfilePictureServiceModel = this._userMapper.Map<UpdateProfilePictureServiceModel>(updateProfilePictureWebModel);
+ updateProfilePictureServiceModel.UserId = userId;
+
+ ProfilePictureServiceModel profilePictureServiceModel = await this._userService.UpdateProfilePicture(updateProfilePictureServiceModel);
+ ProfilePictureWebModel profilePictureWebModel = this._userMapper.Map<ProfilePictureWebModel>(profilePictureServiceModel);
+
+ return new AcceptedResult("UpdateProfilePicture", profilePictureWebModel);
+ }
#endregion
#region Delete
diff --git a/src/DevHive.Web/Models/Identity/User/ProfilePictureWebModel.cs b/src/DevHive.Web/Models/Identity/User/ProfilePictureWebModel.cs
new file mode 100644
index 0000000..9fb1516
--- /dev/null
+++ b/src/DevHive.Web/Models/Identity/User/ProfilePictureWebModel.cs
@@ -0,0 +1,7 @@
+namespace DevHive.Web.Models.Identity.User
+{
+ public class ProfilePictureWebModel
+ {
+ public string ProfilePictureURL { get; set; }
+ }
+}
diff --git a/src/DevHive.Web/Models/Identity/User/UpdateProfilePictureWebModel.cs b/src/DevHive.Web/Models/Identity/User/UpdateProfilePictureWebModel.cs
new file mode 100644
index 0000000..6efe968
--- /dev/null
+++ b/src/DevHive.Web/Models/Identity/User/UpdateProfilePictureWebModel.cs
@@ -0,0 +1,9 @@
+using Microsoft.AspNetCore.Http;
+
+namespace DevHive.Web.Models.Identity.User
+{
+ public class UpdateProfilePictureWebModel
+ {
+ public IFormFile Picture { get; set; }
+ }
+}
diff --git a/src/DevHive.Web/Models/Identity/User/UserWebModel.cs b/src/DevHive.Web/Models/Identity/User/UserWebModel.cs
index 1a5484a..7ab8cca 100644
--- a/src/DevHive.Web/Models/Identity/User/UserWebModel.cs
+++ b/src/DevHive.Web/Models/Identity/User/UserWebModel.cs
@@ -10,6 +10,8 @@ namespace DevHive.Web.Models.Identity.User
{
public class UserWebModel : BaseUserWebModel
{
+ public string ProfilePictureURL { get; set; }
+
[NotNull]
[Required]
public HashSet<RoleWebModel> Roles { get; set; } = new();