Added possibility for user to hide from global score list

This commit is contained in:
Martin Asprusten 2026-04-16 20:39:39 +02:00
parent 753b757d57
commit 3b265735ec
No known key found for this signature in database
10 changed files with 379 additions and 295 deletions

View File

@ -94,6 +94,7 @@
</div> </div>
<div class="other-users-div"> <div class="other-users-div">
<h3>Andre aktive:</h3> <h3>Andre aktive:</h3>
<input type="checkbox" id="hideMeCheckbox" x-model="$store.state.data.isHidden" x-on:click="$store.state.onClickHideCheckbox" /><label id="hideMeLabel" for="hideMeCheckbox">Skjul meg fra den globale listen</label>
<table> <table>
<tr> <tr>
<th>Navn</th><th>Total avstand</th><th>Første aktivitet</th><th>Siste aktivitet</th> <th>Navn</th><th>Total avstand</th><th>Første aktivitet</th><th>Siste aktivitet</th>

View File

@ -33,6 +33,8 @@ interface AlpineState {
removeAdministrator: (userId: number) => void, removeAdministrator: (userId: number) => void,
deleteUser: (userId: number) => void, deleteUser: (userId: number) => void,
onClickHideCheckbox: (event: Event) => void,
init: () => void, init: () => void,
setServerMessage: (newMessage: Sykkelaksjon) => void, setServerMessage: (newMessage: Sykkelaksjon) => void,
getServerMessage: () => Sykkelaksjon, getServerMessage: () => Sykkelaksjon,
@ -59,6 +61,8 @@ let alpineState: AlpineState = {
removeAdministrator: removeAdministrator, removeAdministrator: removeAdministrator,
deleteUser: deleteUser, deleteUser: deleteUser,
onClickHideCheckbox: onClickHideCheckbox,
init() { init() {
this.data = defaultData; this.data = defaultData;
}, },
@ -291,3 +295,20 @@ if (receivedData) {
loadingDiv?.setAttribute("style", "display: none"); loadingDiv?.setAttribute("style", "display: none");
contentDiv?.setAttribute("style", "display: block"); contentDiv?.setAttribute("style", "display: block");
} }
function onClickHideCheckbox(event: PointerEvent) {
let possibleCheckbox = event.target;
if (possibleCheckbox instanceof HTMLInputElement) {
let formData = new FormData();
let url;
let isChecked = possibleCheckbox.checked;
if (isChecked) {
url = apiUrl + "/hideMe"
} else {
url = apiUrl + "/showMe"
}
submitFormToUrl(url, formData, "PUT");
}
}

View File

@ -17,6 +17,10 @@ export interface Sykkelaksjon {
* Whether the connected user is an administrator * Whether the connected user is an administrator
*/ */
isAdmin: boolean; isAdmin: boolean;
/**
* Whether the connected user is hidden from the score lists
*/
isHidden?: boolean;
/** /**
* Available types of activities * Available types of activities
*/ */
@ -69,6 +73,10 @@ export interface Sykkelaksjon {
* Administrator info: whether the user listed is an administrator * Administrator info: whether the user listed is an administrator
*/ */
isAdmin?: boolean; isAdmin?: boolean;
/**
* Administrator info: whether the user is hidden from the global score table
*/
isHidden?: boolean;
/** /**
* Administrator info: the activity templates this user has defined * Administrator info: the activity templates this user has defined
*/ */

View File

@ -101,3 +101,7 @@ summary {
margin: -0.5em -0.5em 0; margin: -0.5em -0.5em 0;
padding: 0.5em; padding: 0.5em;
} }
#hideMeLabel {
width: 80%;
}

View File

@ -13,6 +13,10 @@
"type": "boolean", "type": "boolean",
"description": "Whether the connected user is an administrator" "description": "Whether the connected user is an administrator"
}, },
"isHidden": {
"type": "boolean",
"description": "Whether the connected user is hidden from the score lists"
},
"activityTypes": { "activityTypes": {
"type": "array", "type": "array",
"description": "Available types of activities", "description": "Available types of activities",
@ -77,6 +81,10 @@
"type": "boolean", "type": "boolean",
"description": "Administrator info: whether the user listed is an administrator" "description": "Administrator info: whether the user listed is an administrator"
}, },
"isHidden": {
"type": "boolean",
"description": "Administrator info: whether the user is hidden from the global score table"
},
"activityTemplates": { "activityTemplates": {
"type": "array", "type": "array",
"description": "Administrator info: the activity templates this user has defined", "description": "Administrator info: the activity templates this user has defined",

View File

@ -26,332 +26,363 @@ import java.util.List;
@RestController @RestController
@SpringBootApplication @SpringBootApplication
public class Server { public class Server {
@Autowired @Autowired
private ProfileManager profileManager; private ProfileManager profileManager;
@Autowired @Autowired
private UserService userService; private UserService userService;
@Autowired @Autowired
private ActivityTypeService activityTypeService; private ActivityTypeService activityTypeService;
@Autowired @Autowired
private ActivityService activityService; private ActivityService activityService;
@Autowired @Autowired
private ActivityTemplateService activityTemplateService; private ActivityTemplateService activityTemplateService;
@Value("${sykkelaksjon.openid.discoveryURI}") @Value("${sykkelaksjon.openid.discoveryURI}")
private String discoveryURI; private String discoveryURI;
@Value("${sykkelaksjon.openid.clientId}") @Value("${sykkelaksjon.openid.clientId}")
private String clientId; private String clientId;
@Value("$(sykkelaksjon.base-url)") @Value("$(sykkelaksjon.base-url)")
private String baseUrl; private String baseUrl;
private ActivityType getActivityTypeMessage(no.asprusten.sykkelaksjon.db.datatypes.ActivityType activityType) { private ActivityType getActivityTypeMessage(no.asprusten.sykkelaksjon.db.datatypes.ActivityType activityType) {
ActivityType activityTypeMessage = new ActivityType(); ActivityType activityTypeMessage = new ActivityType();
activityTypeMessage.setId(activityType.getId()); activityTypeMessage.setId(activityType.getId());
activityTypeMessage.setName(activityType.getActivityType()); activityTypeMessage.setName(activityType.getActivityType());
activityTypeMessage.setConversionFactor(activityType.getConversion()); activityTypeMessage.setConversionFactor(activityType.getConversion());
activityTypeMessage.setUnit(activityType.getUnit()); activityTypeMessage.setUnit(activityType.getUnit());
return activityTypeMessage; return activityTypeMessage;
} }
private ActivityTemplate getActivityTemplateMessage(no.asprusten.sykkelaksjon.db.datatypes.ActivityTemplate activityTemplate) { private ActivityTemplate getActivityTemplateMessage(no.asprusten.sykkelaksjon.db.datatypes.ActivityTemplate activityTemplate) {
ActivityTemplate templateMessage = new ActivityTemplate(); ActivityTemplate templateMessage = new ActivityTemplate();
templateMessage.setId(activityTemplate.getId()); templateMessage.setId(activityTemplate.getId());
templateMessage.setActivityType(getActivityTypeMessage(activityTemplate.getActivityType())); templateMessage.setActivityType(getActivityTypeMessage(activityTemplate.getActivityType()));
templateMessage.setName(activityTemplate.getName()); templateMessage.setName(activityTemplate.getName());
templateMessage.setNumberOfUnits(activityTemplate.getNumberOfUnits()); templateMessage.setNumberOfUnits(activityTemplate.getNumberOfUnits());
return templateMessage; return templateMessage;
} }
private Activity getActivityMessage(no.asprusten.sykkelaksjon.db.datatypes.Activity activity) { private Activity getActivityMessage(no.asprusten.sykkelaksjon.db.datatypes.Activity activity) {
Activity activityMessage = new Activity(); Activity activityMessage = new Activity();
activityMessage.setId(activity.getId()); activityMessage.setId(activity.getId());
activityMessage.setActivityType(getActivityTypeMessage(activity.getActivityType())); activityMessage.setActivityType(getActivityTypeMessage(activity.getActivityType()));
activityMessage.setDescription(activity.getDescription()); activityMessage.setDescription(activity.getDescription());
activityMessage.setNumberOfUnits(activity.getNumberOfUnits()); activityMessage.setNumberOfUnits(activity.getNumberOfUnits());
activityMessage.setDate(activity.getDate().format(DateTimeFormatter.ISO_LOCAL_DATE)); activityMessage.setDate(activity.getDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
return activityMessage; return activityMessage;
} }
@CrossOrigin @CrossOrigin(origins = {"http://localhost:5173"}, allowCredentials = "true")
@GetMapping("/api") @GetMapping("/api")
public ServerMessageSchema respondToRequest() throws ServerExceptionHandler.InvalidUserException { public ServerMessageSchema respondToRequest() throws ServerExceptionHandler.InvalidUserException {
var optionalUserProfile = profileManager.getProfile(); var optionalUserProfile = profileManager.getProfile();
if (optionalUserProfile.isEmpty()) { if (optionalUserProfile.isEmpty()) {
throw new ServerExceptionHandler.InvalidUserException(); throw new ServerExceptionHandler.InvalidUserException();
} }
var userProfile = optionalUserProfile.get(); var userProfile = optionalUserProfile.get();
var optionalUser = userService.getUser(userProfile.getUsername()); var optionalUser = userService.getUser(userProfile.getUsername());
var user = optionalUser var user = optionalUser
.orElseGet( .orElseGet(
() -> userService.createUser( () -> userService.createUser(
userProfile.getUsername(), userProfile.getUsername(),
userProfile.getAttribute("name").toString() userProfile.getAttribute("name").toString()
) )
); );
var allUsers = userService.list(); var allUsers = userService.list();
ServerMessageSchema serverMessage = new ServerMessageSchema(); ServerMessageSchema serverMessage = new ServerMessageSchema();
serverMessage.setName(user.getFullName()); serverMessage.setName(user.getFullName());
serverMessage.setIsAdmin(user.isAdmin()); serverMessage.setIsAdmin(user.isAdmin());
serverMessage.setIsHidden(user.isHidden());
boolean unitConversionNecessary = false; boolean unitConversionNecessary = false;
for (var activityType : activityTypeService.list()) { for (var activityType : activityTypeService.list()) {
serverMessage.getActivityTypes().add(getActivityTypeMessage(activityType)); serverMessage.getActivityTypes().add(getActivityTypeMessage(activityType));
unitConversionNecessary |= activityType.getConversion() != 1.0; unitConversionNecessary |= activityType.getConversion() != 1.0;
} }
serverMessage.setUnitConversionNecessary(unitConversionNecessary); serverMessage.setUnitConversionNecessary(unitConversionNecessary);
for (var activityTemplate : user.getTemplates()) { for (var activityTemplate : user.getTemplates()) {
serverMessage.getActivityTemplates().add(getActivityTemplateMessage(activityTemplate)); serverMessage.getActivityTemplates().add(getActivityTemplateMessage(activityTemplate));
} }
List<Activity> unsortedActivities = new ArrayList<>(); List<Activity> unsortedActivities = new ArrayList<>();
for (var activity : user.getActivities()) { for (var activity : user.getActivities()) {
unsortedActivities.add(getActivityMessage(activity)); unsortedActivities.add(getActivityMessage(activity));
} }
unsortedActivities.sort(Comparator.comparing(Activity::getDate)); unsortedActivities.sort(Comparator.comparing(Activity::getDate));
serverMessage.getActivities().addAll(unsortedActivities.reversed()); serverMessage.getActivities().addAll(unsortedActivities.reversed());
List<OtherUser> unsortedOtherUsers = new ArrayList<>(); List<OtherUser> unsortedOtherUsers = new ArrayList<>();
for (var otherUser : allUsers) { for (var otherUser : allUsers) {
// Don't describe the current user // Don't describe the current user
if (otherUser.getId().equals(user.getId())) { if (otherUser.getId().equals(user.getId())) {
continue; continue;
} }
// If this is not an active user, and the requesting user is not an admin, skip // If this is not an active user, and the requesting user is not an admin, skip
if (!otherUser.isActive() && !user.isAdmin()) { if (!otherUser.isActive() && !user.isAdmin()) {
continue; continue;
} }
// If the user has not registered anything yet, also skip it (unless admin) // If the user has not registered anything yet, also skip it (unless admin)
if (otherUser.getActivities().isEmpty() && !user.isAdmin()) { if (otherUser.getActivities().isEmpty() && !user.isAdmin()) {
continue; continue;
} }
OtherUser otherUserMessage = new OtherUser(); if (otherUser.isHidden() && !user.isAdmin()) {
otherUserMessage.setName(otherUser.getFullName()); continue;
}
double totalKilometers = otherUser.getActivities() OtherUser otherUserMessage = new OtherUser();
.stream() otherUserMessage.setName(otherUser.getFullName());
.mapToDouble(activity -> activity.getActivityType().getConversion() * activity.getNumberOfUnits())
.sum();
otherUserMessage.setTotalKilometers(totalKilometers);
otherUser.getActivities().stream() double totalKilometers = otherUser.getActivities()
.map(no.asprusten.sykkelaksjon.db.datatypes.Activity::getDate) .stream()
.min(LocalDate::compareTo) .mapToDouble(activity -> activity.getActivityType().getConversion() * activity.getNumberOfUnits())
.ifPresent(earliestDate -> .sum();
otherUserMessage.setEarliestActivity(earliestDate.format(DateTimeFormatter.ISO_LOCAL_DATE)) otherUserMessage.setTotalKilometers(totalKilometers);
);
otherUser.getActivities().stream() otherUser.getActivities().stream()
.map(no.asprusten.sykkelaksjon.db.datatypes.Activity::getDate) .map(no.asprusten.sykkelaksjon.db.datatypes.Activity::getDate)
.max(LocalDate::compareTo) .min(LocalDate::compareTo)
.ifPresent(latestDate -> .ifPresent(earliestDate ->
otherUserMessage.setLatestActivity(latestDate.format(DateTimeFormatter.ISO_LOCAL_DATE)) otherUserMessage.setEarliestActivity(earliestDate.format(DateTimeFormatter.ISO_LOCAL_DATE))
); );
// Additional info is only for administrators otherUser.getActivities().stream()
if (user.isAdmin()) { .map(no.asprusten.sykkelaksjon.db.datatypes.Activity::getDate)
otherUserMessage.setUserId(otherUser.getId()); .max(LocalDate::compareTo)
otherUserMessage.setUserName(otherUser.getUsername()); .ifPresent(latestDate ->
otherUserMessage.setIsActive(otherUser.isActive()); otherUserMessage.setLatestActivity(latestDate.format(DateTimeFormatter.ISO_LOCAL_DATE))
otherUserMessage.setIsAdmin(otherUser.isAdmin()); );
List<Activity> userUnsortedActivities = new ArrayList<>();
for (var activity : otherUser.getActivities()) {
userUnsortedActivities.add(getActivityMessage(activity));
}
userUnsortedActivities.sort(Comparator.comparing(Activity::getDate));
otherUserMessage.getActivities().addAll(userUnsortedActivities.reversed());
for (var activityTemplate : otherUser.getTemplates()) { // Additional info is only for administrators
otherUserMessage.getActivityTemplates().add(getActivityTemplateMessage(activityTemplate)); if (user.isAdmin()) {
} otherUserMessage.setUserId(otherUser.getId());
} otherUserMessage.setUserName(otherUser.getUsername());
otherUserMessage.setIsActive(otherUser.isActive());
otherUserMessage.setIsAdmin(otherUser.isAdmin());
otherUserMessage.setIsHidden(otherUser.isHidden());
List<Activity> userUnsortedActivities = new ArrayList<>();
for (var activity : otherUser.getActivities()) {
userUnsortedActivities.add(getActivityMessage(activity));
}
userUnsortedActivities.sort(Comparator.comparing(Activity::getDate));
otherUserMessage.getActivities().addAll(userUnsortedActivities.reversed());
unsortedOtherUsers.add(otherUserMessage); for (var activityTemplate : otherUser.getTemplates()) {
} otherUserMessage.getActivityTemplates().add(getActivityTemplateMessage(activityTemplate));
}
}
unsortedOtherUsers.sort(Comparator.comparing(OtherUser::getTotalKilometers)); unsortedOtherUsers.add(otherUserMessage);
serverMessage.getOtherUsers().addAll(unsortedOtherUsers.reversed()); }
return serverMessage;
}
@CrossOrigin unsortedOtherUsers.sort(Comparator.comparing(OtherUser::getTotalKilometers));
@PostMapping(path = "/api/submitActivity", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) serverMessage.getOtherUsers().addAll(unsortedOtherUsers.reversed());
public void submitActivity( return serverMessage;
@RequestParam("activity-type") Long activityTypeId, }
@RequestParam("activity-distance") double distance,
@RequestParam("activity-description") String description,
@RequestParam("activity-date") String date
) {
profileManager.getProfile().ifPresent(userProfile -> {
String username = userProfile.getUsername();
userService.getUser(username).ifPresent(dbUser -> {
activityTypeService.getById(activityTypeId).ifPresent(activityType -> {
no.asprusten.sykkelaksjon.db.datatypes.Activity activity = new no.asprusten.sykkelaksjon.db.datatypes.Activity(
activityType,
dbUser,
distance,
description,
LocalDate.parse(date)
);
activityService.saveActivity(activity);
});
});
});
}
@CrossOrigin @CrossOrigin(origins = {"http://localhost:5173"}, allowCredentials = "true")
@PostMapping(path = "/api/submitActivityTemplate", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @PostMapping(path = "/api/submitActivity", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public void submitActivityTemplate( public void submitActivity(
@RequestParam("activity-type") Long activityTypeId, @RequestParam("activity-type") Long activityTypeId,
@RequestParam("activity-distance") double distance, @RequestParam("activity-distance") double distance,
@RequestParam("activity-description") String description, @RequestParam("activity-description") String description,
@RequestParam("activity-date") String date @RequestParam("activity-date") String date
) { ) {
profileManager.getProfile().ifPresent(userProfile -> { profileManager.getProfile().ifPresent(userProfile -> {
String username = userProfile.getUsername(); String username = userProfile.getUsername();
userService.getUser(username).ifPresent(dbUser -> { userService.getUser(username).ifPresent(dbUser -> {
activityTypeService.getById(activityTypeId).ifPresent(activityType -> { activityTypeService.getById(activityTypeId).ifPresent(activityType -> {
no.asprusten.sykkelaksjon.db.datatypes.ActivityTemplate activityTemplate = new no.asprusten.sykkelaksjon.db.datatypes.ActivityTemplate( no.asprusten.sykkelaksjon.db.datatypes.Activity activity = new no.asprusten.sykkelaksjon.db.datatypes.Activity(
dbUser, activityType,
activityType, dbUser,
description, distance,
distance description,
); LocalDate.parse(date)
);
activityService.saveActivity(activity);
});
});
});
}
activityTemplateService.saveActivityTemplate(activityTemplate); @CrossOrigin(origins = {"http://localhost:5173"}, allowCredentials = "true")
}); @PostMapping(path = "/api/submitActivityTemplate", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
}); public void submitActivityTemplate(
}); @RequestParam("activity-type") Long activityTypeId,
} @RequestParam("activity-distance") double distance,
@RequestParam("activity-description") String description,
@RequestParam("activity-date") String date
) {
profileManager.getProfile().ifPresent(userProfile -> {
String username = userProfile.getUsername();
userService.getUser(username).ifPresent(dbUser -> {
activityTypeService.getById(activityTypeId).ifPresent(activityType -> {
no.asprusten.sykkelaksjon.db.datatypes.ActivityTemplate activityTemplate = new no.asprusten.sykkelaksjon.db.datatypes.ActivityTemplate(
dbUser,
activityType,
description,
distance
);
@CrossOrigin activityTemplateService.saveActivityTemplate(activityTemplate);
@DeleteMapping(path = "/api/deleteActivityTemplate", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) });
public void deleteActivityTemplate(@RequestParam("activity-template-id") Long activityTemplateId) { });
profileManager.getProfile().ifPresent(userProfile -> { });
String username = userProfile.getUsername(); }
userService.getUser(username).ifPresent(dbUser -> {
activityTemplateService.findById(activityTemplateId).ifPresent(activityTemplate -> {
if (activityTemplate.getOwner().equals(dbUser)) {
activityTemplateService.deleteActivityTemplate(activityTemplate.getId());
}
});
});
});
}
@CrossOrigin @CrossOrigin(origins = {"http://localhost:5173"}, allowCredentials = "true")
@DeleteMapping(path = "/api/deleteActivity", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @DeleteMapping(path = "/api/deleteActivityTemplate", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public void deleteActivity(@RequestParam("activity-id") Long activityId) { public void deleteActivityTemplate(@RequestParam("activity-template-id") Long activityTemplateId) {
profileManager.getProfile().ifPresent(userProfile -> { profileManager.getProfile().ifPresent(userProfile -> {
String username = userProfile.getUsername(); String username = userProfile.getUsername();
userService.getUser(username).ifPresent(dbUser -> { userService.getUser(username).ifPresent(dbUser -> {
activityService.findById(activityId).ifPresent(activity -> { activityTemplateService.findById(activityTemplateId).ifPresent(activityTemplate -> {
if (activity.getActivityOwner().equals(dbUser) || dbUser.isAdmin()) { if (activityTemplate.getOwner().equals(dbUser)) {
activityService.deleteActivity(activityId); activityTemplateService.deleteActivityTemplate(activityTemplate.getId());
} }
}); });
}); });
}); });
} }
@CrossOrigin @CrossOrigin(origins = {"http://localhost:5173"}, allowCredentials = "true")
@PostMapping(path = "/api/addActivityType", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @DeleteMapping(path = "/api/deleteActivity", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public void createActivityType( public void deleteActivity(@RequestParam("activity-id") Long activityId) {
@RequestParam("activity-type-name") String name, profileManager.getProfile().ifPresent(userProfile -> {
@RequestParam("activity-type-unit") String unit, String username = userProfile.getUsername();
@RequestParam("activity-type-conversion-factor") double conversionFactor userService.getUser(username).ifPresent(dbUser -> {
) { activityService.findById(activityId).ifPresent(activity -> {
profileManager.getProfile().ifPresent(userProfile -> { if (activity.getActivityOwner().equals(dbUser) || dbUser.isAdmin()) {
String username = userProfile.getUsername(); activityService.deleteActivity(activityId);
userService.getUser(username).ifPresent(dbUser -> { }
if (dbUser.isAdmin()) { });
no.asprusten.sykkelaksjon.db.datatypes.ActivityType activityType = new no.asprusten.sykkelaksjon.db.datatypes.ActivityType( });
name, unit, conversionFactor });
); }
activityTypeService.saveActivityType(activityType);
}
});
});
}
@CrossOrigin @CrossOrigin(origins = {"http://localhost:5173"}, allowCredentials = "true")
@DeleteMapping(path = "/api/deleteActivityType", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @PostMapping(path = "/api/addActivityType", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public void deleteActivityType(@RequestParam("activity-type-id") Long activityTypeId) { public void createActivityType(
profileManager.getProfile().ifPresent(userProfile -> { @RequestParam("activity-type-name") String name,
String username = userProfile.getUsername(); @RequestParam("activity-type-unit") String unit,
userService.getUser(username).ifPresent(dbUser -> { @RequestParam("activity-type-conversion-factor") double conversionFactor
if (dbUser.isAdmin()) { ) {
activityTypeService.deleteActivityType(activityTypeId); profileManager.getProfile().ifPresent(userProfile -> {
} String username = userProfile.getUsername();
}); userService.getUser(username).ifPresent(dbUser -> {
}); if (dbUser.isAdmin()) {
} no.asprusten.sykkelaksjon.db.datatypes.ActivityType activityType = new no.asprusten.sykkelaksjon.db.datatypes.ActivityType(
name, unit, conversionFactor
);
activityTypeService.saveActivityType(activityType);
}
});
});
}
@CrossOrigin @CrossOrigin(origins = {"http://localhost:5173"}, allowCredentials = "true")
@PutMapping(path = "/api/makeAdmin", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @DeleteMapping(path = "/api/deleteActivityType", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public void makeAdmin(@RequestParam("user-id") Long userId) { public void deleteActivityType(@RequestParam("activity-type-id") Long activityTypeId) {
profileManager.getProfile().ifPresent(userProfile -> { profileManager.getProfile().ifPresent(userProfile -> {
String username = userProfile.getUsername(); String username = userProfile.getUsername();
userService.getUser(username).ifPresent(dbUser -> { userService.getUser(username).ifPresent(dbUser -> {
if (dbUser.isAdmin()) { if (dbUser.isAdmin()) {
userService.getUserById(userId).ifPresent(elevatedUser -> { activityTypeService.deleteActivityType(activityTypeId);
elevatedUser.setAdmin(true); }
userService.saveUser(elevatedUser); });
}); });
} }
});
});
}
@CrossOrigin @CrossOrigin(origins = {"http://localhost:5173"}, allowCredentials = "true")
@PutMapping(path = "/api/removeAdmin", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @PutMapping(path = "/api/makeAdmin", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public void removeAdmin(@RequestParam("user-id") Long userId) { public void makeAdmin(@RequestParam("user-id") Long userId) {
profileManager.getProfile().ifPresent(userProfile -> { profileManager.getProfile().ifPresent(userProfile -> {
String username = userProfile.getUsername(); String username = userProfile.getUsername();
userService.getUser(username).ifPresent(dbUser -> { userService.getUser(username).ifPresent(dbUser -> {
if (dbUser.isAdmin()) { if (dbUser.isAdmin()) {
userService.getUserById(userId).ifPresent(elevatedUser -> { userService.getUserById(userId).ifPresent(elevatedUser -> {
elevatedUser.setAdmin(false); elevatedUser.setAdmin(true);
userService.saveUser(elevatedUser); userService.saveUser(elevatedUser);
}); });
} }
}); });
}); });
} }
@CrossOrigin @CrossOrigin(origins = {"http://localhost:5173"}, allowCredentials = "true")
@DeleteMapping(path = "/api/deleteUser", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @PutMapping(path = "/api/removeAdmin", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public void deleteUser(@RequestParam("user-id") Long userId) { public void removeAdmin(@RequestParam("user-id") Long userId) {
profileManager.getProfile().ifPresent(userProfile -> { profileManager.getProfile().ifPresent(userProfile -> {
String username = userProfile.getUsername(); String username = userProfile.getUsername();
userService.getUser(username).ifPresent(dbUser -> { userService.getUser(username).ifPresent(dbUser -> {
if (dbUser.isAdmin()) { if (dbUser.isAdmin()) {
userService.deleteUserById(userId); userService.getUserById(userId).ifPresent(elevatedUser -> {
} elevatedUser.setAdmin(false);
}); userService.saveUser(elevatedUser);
}); });
} }
});
});
}
@CrossOrigin @CrossOrigin(origins = {"http://localhost:5173"}, allowCredentials = "true")
@GetMapping(path = "/api/openid") @DeleteMapping(path = "/api/deleteUser", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public OpenidSchema provideOpenidConfig() { public void deleteUser(@RequestParam("user-id") Long userId) {
OpenidSchema openidSchema = new OpenidSchema(); profileManager.getProfile().ifPresent(userProfile -> {
openidSchema.setClientId(clientId); String username = userProfile.getUsername();
openidSchema.setOpenidDiscoveryUri(discoveryURI); userService.getUser(username).ifPresent(dbUser -> {
return openidSchema; if (dbUser.isAdmin()) {
} userService.deleteUserById(userId);
}
});
});
}
public static void main(String[] args) { @CrossOrigin(origins = {"http://localhost:5173"}, allowCredentials = "true")
SpringApplication application = new SpringApplication(Server.class); @GetMapping(path = "/api/openid")
application.addListeners(new PropertiesListener()); public OpenidSchema provideOpenidConfig() {
application.run(args); OpenidSchema openidSchema = new OpenidSchema();
} openidSchema.setClientId(clientId);
openidSchema.setOpenidDiscoveryUri(discoveryURI);
return openidSchema;
}
@CrossOrigin(origins = {"http://localhost:5173"}, allowCredentials = "true")
@PutMapping(path = "/api/hideMe")
public void hideUser() {
profileManager.getProfile().ifPresent(userProfile -> {
String username = userProfile.getUsername();
userService.getUser(username).ifPresent(dbUser -> {
dbUser.setHidden(true);
userService.saveUser(dbUser);
});
});
}
@CrossOrigin(origins = {"http://localhost:5173"}, allowCredentials = "true")
@PutMapping(path = "/api/showMe")
public void showUser() {
profileManager.getProfile().ifPresent(userProfile -> {
String username = userProfile.getUsername();
userService.getUser(username).ifPresent(dbUser -> {
dbUser.setHidden(false);
userService.saveUser(dbUser);
});
});
}
public static void main(String[] args) {
SpringApplication application = new SpringApplication(Server.class);
application.addListeners(new PropertiesListener());
application.run(args);
}
} }

View File

@ -10,7 +10,7 @@ public class Activity {
@GeneratedValue @GeneratedValue
private long id; private long id;
@ManyToOne( optional = false) @ManyToOne(optional = false)
private ActivityType activityType; private ActivityType activityType;
@ManyToOne(optional = false) @ManyToOne(optional = false)
private WebUser activityOwner; private WebUser activityOwner;

View File

@ -4,7 +4,7 @@ import jakarta.persistence.*;
@Entity @Entity
@Table(uniqueConstraints = { @Table(uniqueConstraints = {
@UniqueConstraint(name = "UniqueNamesPerUser", columnNames = { "owner", "name" }) @UniqueConstraint(name = "UniqueNamesPerUser", columnNames = {"owner", "name"})
}) })
public class ActivityTemplate { public class ActivityTemplate {
@Id @Id

View File

@ -7,7 +7,7 @@ import java.util.List;
@Entity @Entity
@Table(uniqueConstraints = { @Table(uniqueConstraints = {
@UniqueConstraint(name = "OnlyOneActiveWithUsername", columnNames = { "username", "zeroIfActive" }) @UniqueConstraint(name = "OnlyOneActiveWithUsername", columnNames = {"username", "zeroIfActive"})
}) })
public class WebUser { public class WebUser {
@Id @Id
@ -20,6 +20,8 @@ public class WebUser {
private boolean isAdmin; private boolean isAdmin;
@Column(nullable = false) @Column(nullable = false)
private Long zeroIfActive; private Long zeroIfActive;
@Column(nullable = false)
private boolean isHidden = false;
@OneToMany(mappedBy = "activityOwner", fetch = FetchType.EAGER) @OneToMany(mappedBy = "activityOwner", fetch = FetchType.EAGER)
private List<Activity> activities = new ArrayList<>(); private List<Activity> activities = new ArrayList<>();
@ -70,6 +72,14 @@ public class WebUser {
isAdmin = admin; isAdmin = admin;
} }
public boolean isHidden() {
return isHidden;
}
public void setHidden(boolean hidden) {
isHidden = hidden;
}
public void setActive(boolean active) { public void setActive(boolean active) {
if (active) { if (active) {
zeroIfActive = 0L; zeroIfActive = 0L;

View File

@ -7,7 +7,8 @@ import org.springframework.web.bind.annotation.ResponseStatus;
@ControllerAdvice @ControllerAdvice
public class ServerExceptionHandler { public class ServerExceptionHandler {
public static class InvalidUserException extends Exception {} public static class InvalidUserException extends Exception {
}
@ResponseStatus(HttpStatus.FORBIDDEN) @ResponseStatus(HttpStatus.FORBIDDEN)
@ExceptionHandler(InvalidUserException.class) @ExceptionHandler(InvalidUserException.class)