Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
Portals committed Mar 1, 2024
1 parent 69d1aad commit 94c201a
Show file tree
Hide file tree
Showing 136 changed files with 840 additions and 6,482 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
- name: Docker Build-Tag-Push my-app
run: |
./gradlew bootBuildImage
docker tag gamma:1.0.0-SNAPSHOT ghcr.io/cthit/gamma:latest
docker tag gamma:2.0.0-SNAPSHOT ghcr.io/cthit/gamma:latest
docker push ghcr.io/cthit/gamma:latest
working-directory: ./app

Expand Down
5 changes: 3 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,10 @@ dependencies {
"org.springframework.boot:spring-boot-starter-thymeleaf:3.1.2",
"org.thymeleaf.extras:thymeleaf-extras-springsecurity6:3.1.1.RELEASE",

// htmx and hyperscript
// web dependencies
'org.webjars.npm:htmx.org:1.9.10',
'org.webjars.npm:hyperscript.org:0.9.12'
'org.webjars.npm:hyperscript.org:0.9.12',
"org.webjars.npm:picocss__pico:2.0.3"
)

testImplementation(
Expand Down
2 changes: 0 additions & 2 deletions app/src/main/java/it/chalmers/gamma/BootstrapRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ public class BootstrapRunner {
@Bean
public CommandLineRunner runBootStrap(
ApiKeyBootstrap apiKeyBootstrap,
ClientBootstrap clientBootstrap,
EnsureAnAdminUserBootstrap ensureAnAdminUserBootstrap,
EnsureSettingsBootstrap ensureSettingsBootstrap,
GroupBootstrap groupBootstrap,
Expand All @@ -36,7 +35,6 @@ public CommandLineRunner runBootStrap(
superGroupBootstrap.createSuperGroups();
groupBootstrap.createGroups();

clientBootstrap.runOauthClient();
apiKeyBootstrap.ensureApiKeys();

SecurityContextHolder.clearContext();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public GroupsResponse getGroups() {
return new GroupsResponse(this.groupFacade.getAllForInfoApi());
}

record GroupsResponse(List<GroupFacade.GroupWithMembersDTO> groups) {}
public record GroupsResponse(List<GroupFacade.GroupWithMembersDTO> groups) {}

private static class UserNotFoundResponse extends NotFoundResponse {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
import jakarta.annotation.Nullable;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

@Controller
Expand Down Expand Up @@ -47,12 +45,24 @@ public ModelAndView allow(
AllowCidForm request) {
try {
allowListFacade.allow(request.cid);
} catch (AllowListRepository.AlreadyAllowedException | IllegalArgumentException e) {
} catch (AllowListRepository.AlreadyAllowedException
| IllegalArgumentException
| AllowListFacade.AlreadyAUserException e) {
return getAllowList(htmxRequest, e.getMessage());
}

return new ModelAndView("redirect:allow-list");
}

public record AllowCidForm(String cid) {}

@DeleteMapping(value = "/allow-list/{cid}")
public ModelAndView removeCidFromAllowList(
@RequestHeader(value = "HX-Request", required = true) boolean htmxRequest,
@PathVariable("cid") String cid) {

this.allowListFacade.removeFromAllowList(cid);

return new ModelAndView("common/empty");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import it.chalmers.gamma.app.image.domain.ImageService;
import it.chalmers.gamma.app.user.MeFacade;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestHeader;
Expand Down Expand Up @@ -60,13 +63,25 @@ public ModelAndView getEditMe(

@PutMapping("/me")
public ModelAndView editMe(
@RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, EditMe form) {
this.meFacade.updateMe(
new MeFacade.UpdateMe(form.nick, form.firstName, form.lastName, form.email, form.language));

@RequestHeader(value = "HX-Request", required = true) boolean htmxRequest,
EditMe form,
final BindingResult bindingResult) {
ModelAndView mv = new ModelAndView();

// TODO: Use only getMe
try {
this.meFacade.updateMe(
new MeFacade.UpdateMe(
form.nick, form.firstName, form.lastName, form.email, form.language));
} catch (IllegalArgumentException e) {
bindingResult.addError(new ObjectError("global", e.getMessage()));

mv.setViewName("partial/edit-me");
mv.addObject("form", form);
mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult);

return mv;
}

MeFacade.MeDTO me = this.meFacade.getMe();

mv.setViewName("partial/edited-me");
Expand Down Expand Up @@ -118,12 +133,25 @@ public ModelAndView getEditPassword(
@PutMapping("/me/edit-password")
public ModelAndView editPassword(
@RequestHeader(value = "HX-Request", required = true) boolean htmxRequest,
EditPasswordForm form) {
// TODO: Move validation to facade
if (!form.newPassword.equals(form.confirmNewPassword)) {}
EditPasswordForm form,
final BindingResult bindingResult) {

try {
this.meFacade.updatePassword(
new MeFacade.UpdatePassword(
form.currentPassword, form.newPassword, form.confirmNewPassword));
} catch (MeFacade.NewPasswordNotConfirmedException e) {
bindingResult.addError(
new FieldError("form", "confirmNewPassword", "Passwords were not the same"));

this.meFacade.updatePassword(
new MeFacade.UpdatePassword(form.currentPassword, form.newPassword));
ModelAndView mv = new ModelAndView();

mv.setViewName("partial/edit-me-password");
mv.addObject("form", new MeFacade.UpdatePassword("", "", ""));
mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult);

return mv;
}

MeFacade.MeDTO me = this.meFacade.getMe();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import java.util.Optional;
import java.util.UUID;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

Expand Down Expand Up @@ -136,7 +138,11 @@ public ModelAndView getCreateUser(

@PostMapping("/users")
public ModelAndView createUser(
@RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, CreateUser form) {
@RequestHeader(value = "HX-Request", required = false) boolean htmxRequest,
CreateUser form,
final BindingResult bindingResult) {
ModelAndView mv = new ModelAndView();

try {
UUID userId =
this.userCreationFacade.createUser(
Expand All @@ -150,9 +156,25 @@ public ModelAndView createUser(
form.cid,
form.language));

return new ModelAndView("redirect:/users/" + userId);
} catch (UserCreationFacade.SomePropertyNotUniqueException e) {
throw new RuntimeException(e);
mv.setViewName("redirect:/users/" + userId);

return mv;
} catch (IllegalArgumentException
| UserCreationFacade.CidNotUniqueException
| UserCreationFacade.EmailNotUniqueException e) {
bindingResult.addError(new ObjectError("global", e.getMessage()));

if (htmxRequest) {
mv.setViewName("pages/create-user");
} else {
mv.setViewName("index");
mv.addObject("page", "pages/create-user");
}

mv.addObject("form", form);
mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult);

return mv;
}
}

Expand Down Expand Up @@ -192,16 +214,30 @@ public ModelAndView getEditUser(
public ModelAndView editUser(
@RequestHeader(value = "HX-Request", required = true) boolean htmxRequest,
@PathVariable("id") UUID userId,
EditUser form) {
this.userFacade.updateUser(
new UserFacade.UpdateUser(
userId,
form.nick,
form.firstName,
form.lastName,
form.email,
form.language,
form.acceptanceYear));
EditUser form,
BindingResult bindingResult) {
ModelAndView mv = new ModelAndView();

try {
this.userFacade.updateUser(
new UserFacade.UpdateUser(
userId,
form.nick,
form.firstName,
form.lastName,
form.email,
form.language,
form.acceptanceYear));
} catch (IllegalArgumentException e) {
bindingResult.addError(new ObjectError("global", e.getMessage()));

mv.setViewName("partial/edit-user");
mv.addObject("userId", userId);
mv.addObject("form", form);
mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult);

return mv;
}

Optional<UserFacade.UserExtendedWithGroupsDTO> user = this.userFacade.getAsAdmin(userId);

Expand All @@ -211,8 +247,6 @@ public ModelAndView editUser(

String name = form.firstName() + " '" + form.nick() + "' " + form.lastName();

ModelAndView mv = new ModelAndView();

mv.setViewName("partial/edited-user");
mv.addObject("name", name);
mv.addObject("cid", user.get().user().cid());
Expand All @@ -223,4 +257,14 @@ public ModelAndView editUser(

return mv;
}

@DeleteMapping("/users/{id}")
public ModelAndView deleteUser(
@RequestHeader(value = "HX-Request", required = true) boolean htmxRequest,
@PathVariable("id") UUID userId) {

this.userFacade.deleteUser(userId);

return new ModelAndView("redirect:/users");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,6 @@ public void delete(ApiKeyId apiKeyId) throws ApiKeyNotFoundException {
}
}

@Override
public ApiKeyToken resetApiKeyToken(ApiKeyId apiKeyId) throws ApiKeyNotFoundException {
ApiKeyToken newToken = ApiKeyToken.generate();
ApiKeyEntity entity =
this.repository.findById(apiKeyId.value()).orElseThrow(ApiKeyNotFoundException::new);
entity.setApiKeyToken(newToken.value());
this.repository.saveAndFlush(entity);
return newToken;
}

@Override
public List<ApiKey> getAll() {
return this.repository.findAll().stream()
Expand All @@ -87,6 +77,7 @@ public Optional<ApiKey> getById(ApiKeyId apiKeyId) {

@Override
public Optional<ApiKey> getByToken(ApiKeyToken apiKeyToken) {
System.out.println(apiKeyToken.value());
return this.repository
.findByToken(apiKeyToken.value())
.map(this.apiKeyEntityConverter::toDomain);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public ClientEntity toEntity(Client client) {

clientEntity.clientUid = client.clientUid().value();
clientEntity.clientId = client.clientId().value();
clientEntity.clientSecret = this.passwordEncoder.encode(client.clientSecret().value());
clientEntity.clientSecret = client.clientSecret().value();
clientEntity.prettyName = client.prettyName().value();
clientEntity.webServerRedirectUrl = client.clientRedirectUrl().value();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ public class UserRepositoryAdapter implements UserRepository {
private final PasswordEncoder passwordEncoder;

private final PersistenceErrorState cidNotUnique =
new PersistenceErrorState("ituser_cid_key", PersistenceErrorState.Type.NOT_UNIQUE);
new PersistenceErrorState("g_user_cid_key", PersistenceErrorState.Type.NOT_UNIQUE);

private final PersistenceErrorState emailNotUnique =
new PersistenceErrorState("ituser_email_key", PersistenceErrorState.Type.NOT_UNIQUE);
new PersistenceErrorState("g_user_email_key", PersistenceErrorState.Type.NOT_UNIQUE);

public UserRepositoryAdapter(
UserJpaRepository repository,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public AuthorizationRepositoryAdapter(
this.authorizationTokenMapperRedisRepository = authorizationTokenMapperRedisRepository;
}

// HMM den sparar bara gamma-authorization och gamma-authorization-token?
// HMM den sparar bara gamma-authorization och gamma-authorization-rawToken?
// Också, ta bort GammaAuthorization och spara OAuth2Authorization direkt bara.

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;

@RedisHash(value = "token", timeToLive = 3600)
@RedisHash(value = "rawToken", timeToLive = 3600)
public class AuthorizationTokenMapperValue {

@Id String tokenKey;
Expand Down
24 changes: 8 additions & 16 deletions app/src/main/java/it/chalmers/gamma/app/apikey/ApiKeyFacade.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,20 @@
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

@Component
public class ApiKeyFacade extends Facade {

private final ApiKeyRepository apiKeyRepository;
private final PasswordEncoder passwordEncoder;

public ApiKeyFacade(AccessGuard accessGuard, ApiKeyRepository apiKeyRepository) {
public ApiKeyFacade(
AccessGuard accessGuard, ApiKeyRepository apiKeyRepository, PasswordEncoder passwordEncoder) {
super(accessGuard);
this.apiKeyRepository = apiKeyRepository;
this.passwordEncoder = passwordEncoder;
}

public String[] getApiKeyTypes() {
Expand Down Expand Up @@ -48,15 +52,15 @@ public CreatedApiKey create(NewApiKey newApiKey) {
}

ApiKeyId apiKeyId = ApiKeyId.generate();
ApiKeyToken apiKeyToken = ApiKeyToken.generate();
ApiKeyToken.GeneratedApiKeyToken generated = ApiKeyToken.generate(passwordEncoder);
apiKeyRepository.create(
new ApiKey(
apiKeyId,
new PrettyName(newApiKey.prettyName),
new Text(newApiKey.svDescription, newApiKey.enDescription),
type,
apiKeyToken));
return new CreatedApiKey(apiKeyId.value(), apiKeyToken.value());
generated.apiKeyToken()));
return new CreatedApiKey(apiKeyId.value(), generated.rawToken());
}

public void delete(UUID apiKeyId) throws ApiKeyNotFoundException {
Expand All @@ -81,18 +85,6 @@ public List<ApiKeyDTO> getAll() {
return this.apiKeyRepository.getAll().stream().map(ApiKeyDTO::new).toList();
}

public String resetApiKeyToken(UUID apiKeyId) throws ApiKeyNotFoundException {
this.accessGuard.require(isAdmin());

ApiKeyToken token;
try {
token = this.apiKeyRepository.resetApiKeyToken(new ApiKeyId(apiKeyId));
} catch (ApiKeyRepository.ApiKeyNotFoundException e) {
throw new ApiKeyNotFoundException();
}
return token.value();
}

public record NewApiKey(
String prettyName, String svDescription, String enDescription, String keyType) {}

Expand Down
Loading

0 comments on commit 94c201a

Please sign in to comment.