Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implements Organizations Administrator Views #2

Merged
merged 2 commits into from
Jan 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.hua.hermes.frontend.constant;

public class CrudConstants
{
public static final String DISCARD_MESSAGE = "There are unsaved modifications. Discard changes?";
public static final String DELETE_MESSAGE = "Are you sure you want to delete the selected %s? This action cannot be undone.";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.hua.hermes.frontend.constant;

public class DateTimeConstants
{
public static final String DATE_FORMAT = "dd/MM/yyyy";
public static final String DATE_TIME_FORMAT = "dd/MM/yyyy HH:mm:ss";
}
11 changes: 11 additions & 0 deletions src/main/java/org/hua/hermes/frontend/constant/RouteConstants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.hua.hermes.frontend.constant;

public class RouteConstants
{
public static final String PAGE_ORGS_ADMIN = "organizations";
public static final String PAGE_ORG_SUPERVISORS = "organizations/supervisors";

public static final String TITLE_ORGS_ADMIN = "Organizations Management";

public static final String SECURITY_ORGS_ADMIN = "hasRole('ROLE_ORGS_ADMIN')";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.hua.hermes.frontend.constant;

public class SecurityConstants
{
public static final String HAS_ORGS_ADMIN_ROLE = "hasRole('ROLE_ORGS_ADMIN')";
public static final String HAS_ORG_SUPERVISOR_ROLE = "hasRole('ROLE_ORG_SUPERVISOR')";
public static final String HAS_ORG_EMPLOYEE_ROLE = "hasRole('ROLE_ORG_EMPLOYEE')";
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.hua.hermes.frontend.data;
package org.hua.hermes.frontend.constant;

public class GenericValidationMessages
public class ValidationConstants
{
public static final String REQUIRED_TEXT = "This field is mandatory";
public static final String INVALID_EMAIL_TEXT = "Invalid email format.";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.hua.hermes.frontend.constant.entity;

public class OrganizationEntityConstants
{
public static final String ENTITY_NAME = "Organization";

public static final String ID = "Id";
public static final String NAME = "Name";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.hua.hermes.frontend.constant.entity;

public class UserEntityConstants
{
public static final String SUPERVISOR_NAME = "Supervisor";
public static final String EMPLOYEE_NAME = "Employee";

public static final String ID_LABEL = "Id";
public static final String USERNAME_LABEL = "Username";
public static final String FIRST_NAME_LABEL = "First Name";
public static final String LAST_NAME_LABEL = "Last Name";
public static final String GENDER_LABEL = "Gender";

//We respect all genders. After a quick research there are 25+ mainstream genders.
//If this were a professional app, we would handle this differently.
public static final String[] GENDER_CHOICES = {"Male", "Female", "Other"};
public static final String PHONE_LABEL = "Phone Number";
public static final String EMAIL_LABEL = "Email";
public static final String ENABLED_LABEL = "User Enabled";
public static final String BIRTHDATE_LABEL = "Date of Birth";
public static final String STREET_ADDRESS_LABEL = "Address";
public static final String POSTAL_CODE_LABEL = "Postal Code";
public static final String LOCALITY_LABEL = "Locality";
public static final String REGION_LABEL = "Region";
public static final String COUNTRY_LABEL = "Country";
public static final String PASSWORD_LABEL = "Password";
public static final String CONFIRM_PASSWORD_LABEL = "Confirm Password";
public static final String TEMPORARY_PASSWORD_LABEL = "Force user to change password upon first login";
public static final String CREATED_ON_LABEL = "Created On";
public static final String ACCOUNT_STATUS_LABEL = "Account Status";

public static final String BIRTHDATE = "birthdate";
public static final String PHONE = "phone_number";
public static final String GENDER = "gender";
public static final String STREET_ADDRESS = "street_address";
public static final String POSTAL_CODE = "postal_code";
public static final String LOCALITY = "locality";
public static final String REGION = "region";
public static final String COUNTRY = "country";
public static final String FORMATTED_LOCATION = "formatted";


}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.hua.hermes.frontend.error.exception;

public class InternalServerErrorException extends RuntimeException
{
public InternalServerErrorException(String message)
{
super(message);
}

public InternalServerErrorException(Throwable cause)
{
super(cause);
}

public InternalServerErrorException(String message, Throwable cause)
{
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package org.hua.hermes.frontend.error.view;


import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import org.hua.hermes.frontend.view.HomeView;

@Route("403")
@PageTitle("403 - Forbidden")
public class ForbiddenView extends ErrorView
{
public ForbiddenView()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.hua.hermes.frontend.error.view;

import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import org.hua.hermes.frontend.view.HomeView;

@Route("500")
@PageTitle("500 - Internal Server Error")
public class InternalServerErrorView extends ErrorView
{
public InternalServerErrorView()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.hua.hermes.frontend.error.view;

import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import org.hua.hermes.frontend.view.HomeView;

@Route("404")
@PageTitle("404 - Page Not Found")
public class NotFoundView extends ErrorView
{
public NotFoundView()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.hua.hermes.frontend.repository;

import org.keycloak.representations.idm.GroupRepresentation;

import java.util.List;
import java.util.Optional;

public interface OrganizationRepository
{
Optional<GroupRepresentation> findById(String orgName);
List<GroupRepresentation> findAll(int offset, int limit);
Integer count();
boolean save(GroupRepresentation organization);
boolean update(GroupRepresentation organization);
boolean delete(GroupRepresentation organization);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.hua.hermes.frontend.repository;

import org.hua.hermes.keycloak.client.exception.ConflictException;
import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.UserRepresentation;

import java.util.List;
import java.util.Optional;

public interface OrganizationSupervisorsRepository
{
Optional<UserRepresentation> findById(GroupRepresentation organization, String userId);
List<UserRepresentation> findAll(GroupRepresentation organization, int offset, int limit);
Integer count(GroupRepresentation organization);
boolean save(GroupRepresentation organization, UserRepresentation user);
boolean update(GroupRepresentation organization, UserRepresentation user);
boolean delete(GroupRepresentation organization, UserRepresentation user);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package org.hua.hermes.frontend.repository.impl;

import org.hua.hermes.frontend.error.exception.InternalServerErrorException;
import org.hua.hermes.frontend.repository.OrganizationRepository;
import org.hua.hermes.keycloak.client.HermesKeycloak;
import org.hua.hermes.keycloak.client.exception.ConflictException;
import org.keycloak.representations.idm.GroupRepresentation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

@Repository
public class OrganizationRepositoryImpl implements OrganizationRepository
{

private final HermesKeycloak client;

@Value("${keycloak.realm}")
private String realm;

public OrganizationRepositoryImpl(HermesKeycloak client)
{
this.client = client;
}


@Override
public Optional<GroupRepresentation> findById(String orgName)
{
return Optional.ofNullable(client
.organizations()
.organization(orgName)
.manage()
.toRepresentation());
}

@Override
public List<GroupRepresentation> findAll(int offset, int limit)
{
return client.organizations().list(offset,limit);
}

@Override
public Integer count()
{
return client.organizations().count();
}

@Override
public boolean save(GroupRepresentation organization)
{
var response = client
.organizations()
.create(organization.getName());

if(response.getStatus() == 409)
throw new ConflictException("Please ensure that there isn't any organization with the name " + organization.getName());

//Just to be sure
if(response.getStatus() != 201)
throw new InternalServerErrorException("Save failed");

return true;
}

@Override
public boolean update(GroupRepresentation organization)
{
client.realm(realm)
.groups()
.group(organization.getId())
.update(organization);
return true;
}

@Override
public boolean delete(GroupRepresentation organization)
{
client.realm(realm)
.groups()
.group(organization.getId())
.remove();
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package org.hua.hermes.frontend.repository.impl;

import org.hua.hermes.frontend.error.exception.InternalServerErrorException;
import org.hua.hermes.frontend.repository.OrganizationSupervisorsRepository;
import org.hua.hermes.keycloak.client.exception.ConflictException;
import org.hua.hermes.keycloak.client.HermesKeycloak;
import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

@Repository
public class OrganizationSupervisorsRepositoryImpl implements OrganizationSupervisorsRepository
{

@Autowired
private HermesKeycloak client;

@Value("${keycloak.realm}")
private String realm;

public Optional<UserRepresentation> findById(GroupRepresentation organization, String userId)
{
var user = client.organizations()
.organization(organization.getName())
.supervisors()
.supervisor(userId)
.toRepresentation();

return Optional.of(user);
}

public List<UserRepresentation> findAll(GroupRepresentation organization, int offset, int limit)
{
return client.organizations()
.organization(organization.getName())
.supervisors()
.list(offset,limit);
}


public Integer count(GroupRepresentation organization)
{
return client.organizations()
.organization(organization.getName())
.supervisors()
.count();
}

public boolean save(GroupRepresentation organization, UserRepresentation user)
{
user.setGroups(List.of("ORGANIZATIONS/" + organization.getName() + "/SUPERVISORS"));
var response = client.realm(realm)
.users()
.create(user);

if(response.getStatus() == 409)
throw new ConflictException("Please ensure that there isn't any user with the same username or password.");

//Just to be sure
if(response.getStatus() != 201)
throw new InternalServerErrorException("Save failed");

return true;
}

public boolean update(GroupRepresentation organization, UserRepresentation user)
{
client.organizations()
.organization(organization.getName())
.supervisors()
.supervisor(user.getId())
.update(user);
return true;
}

public boolean delete(GroupRepresentation organization, UserRepresentation user)
{
client.organizations()
.organization(organization.getName())
.supervisors()
.supervisor(user.getId())
.remove();
return true;
}


}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Εδώ ενώ στο περίπου καταλαβαίνω τι κάνεις.Γιατί εγώ χρησιμοποίησα διαφορετικό τρόπο?έχει σχεση με το keycloak?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ναι το έχω ξαναπεί. Άλλιώς επικοινωνούμε με τον σέρβερ του keycloak και αλλιώς με το δικό μας backend.

Το keycloak ως εμπορικό προϊόν έχει και δικό του admin client για το API του. Αυτόν τον client τον τροποποίησα για να υποστηρίζει και το Organzations Endpoint που περιγράφω στο NickDelta/hermes-keycloak-image#4.

Το back-end μας δεν έχει τέτοιο client υλοποιημένο. Εσύ χρησιμοποιείς το KeycloakRestTemplate για την επικοινωνία.

Ίδιος σκοπός στην τελική, διαφορετικά εργαλεία για την επίτευξή τους. That's how software works.

Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
public class FormattingConstants
{
public static final String DATE_FORMAT = "dd/MM/yyyy";
public static final String DATE_TIME_FORMAT = "dd/MM/yyyy HH:mm:ss";
}
Loading