Skip to content

Commit

Permalink
Merge pull request #50 from ls1intum/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
valentin-boehm authored Nov 25, 2023
2 parents 68ab780 + cef09a9 commit 93ceae8
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public ArtemisUserService(ArtemisUserRepository artemisUserRepository) {
* @return a list of the created ArtemisUsers
*/
public List<ArtemisUser> createArtemisUsersByPattern(ArtemisServer server, ArtemisUserPatternDTO pattern) {
log.info("Creating ArtemisUsers by pattern for {}", server);
if (pattern.getFrom() >= pattern.getTo() || pattern.getFrom() <= 0) {
throw new BadRequestAlertException("from must be smaller than to and greater than 0", "artemisUser", "invalidRange");
} else if (!pattern.getUsernamePattern().contains("{i}") || !pattern.getPasswordPattern().contains("{i}")) {
Expand All @@ -59,9 +60,10 @@ public List<ArtemisUser> createArtemisUsersByPattern(ArtemisServer server, Artem
try {
createdUsers.add(saveArtemisUser(artemisUser));
} catch (BadRequestAlertException e) {
log.warn(e.getMessage() + ". Skipping user.");
log.debug(e.getMessage() + ". Skipping user.");
}
}
log.info("Created {} ArtemisUsers by pattern", createdUsers.size());
return createdUsers;
}

Expand All @@ -74,6 +76,7 @@ public List<ArtemisUser> createArtemisUsersByPattern(ArtemisServer server, Artem
* @throws BadRequestAlertException if the server-wide ID is already taken, negative or the username or password is invalid
*/
public ArtemisUser createArtemisUser(ArtemisServer server, ArtemisUserForCreationDTO artemisUserDTO) {
log.info("Creating ArtemisUser for {}", server);
ArtemisUser artemisUser = new ArtemisUser();
artemisUser.setServer(server);
artemisUser.setUsername(artemisUserDTO.getUsername());
Expand Down Expand Up @@ -101,6 +104,7 @@ public void deleteArtemisUser(long id) {
}

public void deleteByServer(ArtemisServer server) {
log.info("Deleting all ArtemisUsers for {}", server);
artemisUserRepository.deleteByServer(server);
}

Expand All @@ -112,6 +116,7 @@ public void deleteByServer(ArtemisServer server) {
* @return a list of the created ArtemisUsers
*/
public List<ArtemisUser> createArtemisUsersFromCSV(MultipartFile file, ArtemisServer server) {
log.info("Creating ArtemisUsers from CSV for {}", server);
List<ArtemisUserForCreationDTO> artemisUserDTOs;
try (Reader reader = new BufferedReader(new InputStreamReader(file.getInputStream()))) {
CsvToBean<ArtemisUserForCreationDTO> cb = new CsvToBeanBuilder<ArtemisUserForCreationDTO>(reader)
Expand All @@ -131,9 +136,10 @@ public List<ArtemisUser> createArtemisUsersFromCSV(MultipartFile file, ArtemisSe
try {
result.add(createArtemisUser(server, artemisUserDTO));
} catch (BadRequestAlertException e) {
log.warn(e.getMessage() + ". Skipping user.");
log.debug(e.getMessage() + ". Skipping user.");
}
}
log.info("Created {} ArtemisUsers from CSV", result.size());
return result;
}

Expand Down Expand Up @@ -171,6 +177,7 @@ private ArtemisUser saveArtemisUser(ArtemisUser artemisUser) {
* @return the updated ArtemisUser
*/
public ArtemisUser updateArtemisUser(Long id, ArtemisUser artemisUser) {
log.info("Updating ArtemisUser with ID {}", id);
if (!Objects.equals(id, artemisUser.getId())) {
throw new IllegalArgumentException("Id in path and body do not match!");
}
Expand Down
47 changes: 39 additions & 8 deletions src/main/webapp/app/artemis-users/artemis-users.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,25 @@ <h3 class="mb-0 mt-5">Admin Account</h3>
</div>
</td>
<td class="col-3 pe-5">
<input type="password" class="form-control" [(ngModel)]="adminUserCopy!.password" />
<div class="input-group">
@if (showAdminPassword) {
<fa-icon class="input-group-text" [icon]="faEyeSlash" role="button" (click)="showAdminPassword = false"></fa-icon>
} @else {
<fa-icon class="input-group-text" [icon]="faEye" role="button" (click)="showAdminPassword = true"></fa-icon>
}
<input [type]="showAdminPassword ? 'text' : 'password'" class="form-control" [(ngModel)]="adminUserCopy!.password" />
</div>
</td>
<td class="col-3">
<button type="button" class="btn btn-primary me-1" [disabled]="!adminValid() || actionInProgress" (click)="updateAdminUser()">
<button
type="button"
class="btn btn-primary me-1"
[disabled]="!adminValid() || actionInProgress"
(click)="showAdminPassword = false; updateAdminUser()"
>
Save
</button>
<button type="button" class="btn btn-danger" (click)="adminUserCopy = undefined">Cancel</button>
<button type="button" class="btn btn-danger" (click)="showAdminPassword = false; adminUserCopy = undefined">Cancel</button>
</td>
}
</tr>
Expand Down Expand Up @@ -87,6 +99,7 @@ <h3>Student Accounts</h3>
<div class="border mt-2 w-60 ps-3 pe-3 mb-3" #collapse="ngbCollapse" [(ngbCollapse)]="isCollapsed">
<jhi-create-user-box
[actionInProgress]="actionInProgress"
[loading]="loadingCreate"
(createUser)="createUser($event)"
(createUserPattern)="createUserPattern($event)"
(createUserCsv)="createUserCsv($event)"
Expand Down Expand Up @@ -114,8 +127,14 @@ <h3>Student Accounts</h3>
<fa-icon [icon]="faEye" role="button" (click)="showPasswords = true" ngbTooltip="Show passwords"></fa-icon>
}
</th>
<th scope="col" class="col-3">
<button type="button" class="btn btn-danger" (click)="deleteAll(deleteModal)">Delete All</button>
<th scope="col" class="col-3 space-between-wrapper">
<button type="button" class="btn btn-danger" (click)="deleteAll(deleteModal)">
@if (loadingDelete) {
<fa-icon class="me-2" [icon]="faSpinner" class="fa-spin" style="display: inline-block"></fa-icon>
}
Delete All
</button>
Total: {{ (users$ | async)?.length }}
</th>
</tr>
</thead>
Expand Down Expand Up @@ -144,13 +163,25 @@ <h3>Student Accounts</h3>
<input type="text" class="form-control" [(ngModel)]="editedUser!.username" />
</td>
<td class="col-3 pe-5">
<input [type]="showPasswords ? 'text' : 'password'" class="form-control" [(ngModel)]="editedUser!.password" />
<div class="input-group">
@if (showEditUserPassword) {
<fa-icon class="input-group-text" [icon]="faEyeSlash" role="button" (click)="showEditUserPassword = false"></fa-icon>
} @else {
<fa-icon class="input-group-text" [icon]="faEye" role="button" (click)="showEditUserPassword = true"></fa-icon>
}
<input [type]="showEditUserPassword ? 'text' : 'password'" class="form-control" [(ngModel)]="editedUser!.password" />
</div>
</td>
<td class="col-3 flex-wrapper">
<button type="button" class="btn btn-primary me-2" [disabled]="!editValid() || actionInProgress" (click)="updateUser()">
<button
type="button"
class="btn btn-primary me-2"
[disabled]="!editValid() || actionInProgress"
(click)="showEditUserPassword = false; updateUser()"
>
Save
</button>
<button type="button" class="btn btn-danger" (click)="editedUser = undefined">Cancel</button>
<button type="button" class="btn btn-danger" (click)="editedUser = undefined; showEditUserPassword = false">Cancel</button>
</td>
</tr>
}
Expand Down
16 changes: 14 additions & 2 deletions src/main/webapp/app/artemis-users/artemis-users.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { ArtemisUsersService } from './artemis-users.service';
import { ArtemisUserForCreationDTO } from './artemisUserForCreationDTO';
import { NgbCollapse, NgbModal, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
import { CreateUserBoxComponent } from '../layouts/create-user-box/create-user-box.component';
import { faCircleInfo, faEye, faEyeSlash, faMagnifyingGlass } from '@fortawesome/free-solid-svg-icons';
import { faCircleInfo, faEye, faEyeSlash, faMagnifyingGlass, faSpinner } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { ArtemisUserPatternDTO } from './artemisUserPatternDTO';
import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
Expand All @@ -25,6 +25,7 @@ export class ArtemisUsersComponent implements OnInit {
faEyeSlash = faEyeSlash;
faCircleInfo = faCircleInfo;
faMagnifyingGlass = faMagnifyingGlass;
faSpinner = faSpinner;

server: ArtemisServer = ArtemisServer.TS1;
users: ArtemisUser[] = [];
Expand All @@ -36,11 +37,14 @@ export class ArtemisUsersComponent implements OnInit {
adminUser?: ArtemisUser;
adminUserCopy?: ArtemisUser;
showAdminPassword = false;
showEditUserPassword = false;
actionInProgress = false;
error = false;
errorMsg = '';
filter = new FormControl('', { nonNullable: true });
usersChanged = new Subject<void>();
loadingCreate = false;
loadingDelete = false;

protected readonly ArtemisServer = ArtemisServer;

Expand Down Expand Up @@ -95,32 +99,38 @@ export class ArtemisUsersComponent implements OnInit {

createUserPattern(userPatternDTO: ArtemisUserPatternDTO): void {
this.actionInProgress = true;
this.loadingCreate = true;
this.artemisUsersService.createUsersFromPattern(this.server, userPatternDTO).subscribe({
next: (users: ArtemisUser[]) => {
this.users.push(...users);
this.users.sort((a, b) => a.serverWideId - b.serverWideId);
this.actionInProgress = false;
this.loadingCreate = false;
this.usersChanged.next(void 0);
},
error: () => {
this.showError('Error creating users');
this.actionInProgress = false;
this.loadingCreate = false;
},
});
}

createUserCsv(file: File): void {
this.actionInProgress = true;
this.loadingCreate = true;
this.artemisUsersService.createUsersFromCsv(this.server, file).subscribe({
next: (users: ArtemisUser[]) => {
this.users.push(...users);
this.users.sort((a, b) => a.serverWideId - b.serverWideId);
this.actionInProgress = false;
this.loadingCreate = false;
this.usersChanged.next(void 0);
},
error: () => {
this.showError('Error creating users');
this.actionInProgress = false;
this.loadingCreate = false;
},
});
}
Expand All @@ -145,18 +155,20 @@ export class ArtemisUsersComponent implements OnInit {

deleteAll(content: any): void {
this.actionInProgress = true;

this.modalService.open(content, { ariaLabelledBy: 'delete-modal-title' }).result.then(
() => {
this.loadingDelete = true;
this.artemisUsersService.deleteByServer(this.server).subscribe({
next: () => {
this.users = [];
this.actionInProgress = false;
this.loadingDelete = false;
this.usersChanged.next(void 0);
},
error: () => {
this.showError('Error deleting users');
this.actionInProgress = false;
this.loadingDelete = false;
},
});
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<nav ngbNav #nav="ngbNav" class="nav-tabs mt-3">
<nav ngbNav #nav="ngbNav" class="nav-tabs mt-3" (navChange)="showPassword = false">
<ng-container ngbNavItem>
<button ngbNavLink>Manually</button>
<ng-template ngbNavContent>
Expand All @@ -22,9 +22,14 @@
<input type="text" class="form-control" id="username-input" [(ngModel)]="username" [ngModelOptions]="{ standalone: true }" />
</div>
<div class="me-3 mb-3 w-40">
<label for="password-input" class="form-label">Password</label>
<label for="password-input" class="form-label me-2">Password</label>
@if (!showPassword) {
<fa-icon role="button" [icon]="faEye" ngbTooltip="Show password" (click)="showPassword = true"></fa-icon>
} @else {
<fa-icon role="button" [icon]="faEyeSlash" ngbTooltip="Hide password" (click)="showPassword = false"></fa-icon>
}
<input
type="password"
[type]="showPassword ? 'text' : 'password'"
class="form-control"
id="password-input"
[(ngModel)]="password"
Expand Down Expand Up @@ -64,9 +69,14 @@
</div>
</div>
<div class="me-3 mb-3 w-40">
<label for="password-pattern-input" class="form-label">Password Pattern</label>
<label for="password-pattern-input" class="form-label me-2">Password Pattern</label>
@if (!showPassword) {
<fa-icon role="button" [icon]="faEye" ngbTooltip="Show password pattern" (click)="showPassword = true"></fa-icon>
} @else {
<fa-icon role="button" [icon]="faEyeSlash" ngbTooltip="Hide password pattern" (click)="showPassword = false"></fa-icon>
}
<input
type="password"
[type]="showPassword ? 'text' : 'password'"
class="form-control"
id="password-pattern-input"
[(ngModel)]="passwordPattern"
Expand Down Expand Up @@ -95,6 +105,9 @@
</div>
</div>
<button type="submit" class="btn btn-primary" [disabled]="!isValidPattern() || actionInProgress" (click)="onCreatePattern()">
@if (loading) {
<fa-icon [icon]="faSpinner" class="fa-spin" style="display: inline-block"></fa-icon>
}
Create {{ to - from }} Users
</button>
</form>
Expand All @@ -114,6 +127,9 @@
<input #fileInput class="form-control" type="file" id="csv-file" (change)="onFileSelect($event)" accept="text/csv" />
</div>
<button type="submit" class="btn btn-primary mb-3" [disabled]="file === undefined || actionInProgress" (click)="onSubmitCsv()">
@if (loading) {
<fa-icon [icon]="faSpinner" class="fa-spin" style="display: inline-block"></fa-icon>
}
Upload File and Create Users
</button>
</ng-template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ArtemisUserForCreationDTO } from '../../artemis-users/artemisUserForCre
import { FormsModule } from '@angular/forms';
import { NgbAlertModule, NgbNavModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
import { ArtemisUserPatternDTO } from '../../artemis-users/artemisUserPatternDTO';
import { faCircleInfo } from '@fortawesome/free-solid-svg-icons';
import { faCircleInfo, faEye, faEyeSlash, faSpinner } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';

@Component({
Expand All @@ -16,8 +16,12 @@ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
})
export class CreateUserBoxComponent {
faCircleInfo = faCircleInfo;
faSpinner = faSpinner;
faEye = faEye;
faEyeSlash = faEyeSlash;

@Input() actionInProgress = false;
@Input() loading = false;

username: string = '';
password: string = '';
Expand All @@ -31,6 +35,8 @@ export class CreateUserBoxComponent {
file?: File;
@ViewChild('fileInput') fileInput?: ElementRef;

showPassword = false;

@Output() createUser = new EventEmitter<ArtemisUserForCreationDTO>();
@Output() createUserPattern = new EventEmitter<ArtemisUserPatternDTO>();
@Output() createUserCsv = new EventEmitter<File>();
Expand Down

0 comments on commit 93ceae8

Please sign in to comment.