Skip to content

Commit

Permalink
[#2238] feat(server): Add the operations for the user (#2733)
Browse files Browse the repository at this point in the history
### What changes were proposed in this pull request?

Add the operations for the user.

### Why are the changes needed?


Fix: #2238

### Does this PR introduce _any_ user-facing change?
Yes,  I will add the open api and the document in the later pr.

### How was this patch tested?
Add a new UT.

---------

Co-authored-by: Heng Qin <qqtt@123.com>
  • Loading branch information
qqqttt123 and Heng Qin authored Apr 1, 2024
1 parent fd276b4 commit 0dcd308
Show file tree
Hide file tree
Showing 11 changed files with 773 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright 2024 Datastrato Pvt Ltd.
* This software is licensed under the Apache License version 2.
*/
package com.datastrato.gravitino.dto.authorization;

import com.datastrato.gravitino.Audit;
import com.datastrato.gravitino.authorization.User;
import com.datastrato.gravitino.dto.AuditDTO;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Preconditions;
import java.util.Collections;
import java.util.List;
import org.apache.commons.lang3.StringUtils;

/** Represents a User Data Transfer Object (DTO). */
public class UserDTO implements User {

@JsonProperty("name")
private String name;

@JsonProperty("audit")
private AuditDTO audit;

@JsonProperty("roles")
private List<String> roles;

/** Default constructor for Jackson deserialization. */
protected UserDTO() {}

/**
* Creates a new instance of UserDTO.
*
* @param name The name of the User DTO.
* @param roles The roles of the User DTO.
* @param audit The audit information of the User DTO.
*/
protected UserDTO(String name, List<String> roles, AuditDTO audit) {
this.name = name;
this.audit = audit;
this.roles = roles;
}

/** @return The name of the User DTO. */
@Override
public String name() {
return name;
}

/**
* The roles of the user. A user can have multiple roles. Every role binds several privileges.
*
* @return The roles of the user.
*/
@Override
public List<String> roles() {
return roles;
}

/** @return The audit information of the User DTO. */
@Override
public Audit auditInfo() {
return audit;
}

/**
* Creates a new Builder for constructing an User DTO.
*
* @return A new Builder instance.
*/
public static Builder builder() {
return new Builder();
}

/**
* Builder class for constructing a UserDTO instance.
*
* @param <S> The type of the builder instance.
*/
public static class Builder<S extends Builder> {

/** The name of the user. */
protected String name;

/** The roles of the user. */
protected List<String> roles = Collections.emptyList();

/** The audit information of the user. */
protected AuditDTO audit;

/**
* Sets the name of the user.
*
* @param name The name of the user.
* @return The builder instance.
*/
public S withName(String name) {
this.name = name;
return (S) this;
}

/**
* Sets the roles of the user.
*
* @param roles The roles of the user.
* @return The builder instance.
*/
public S withRoles(List<String> roles) {
if (roles != null) {
this.roles = roles;
}

return (S) this;
}

/**
* Sets the audit information of the user.
*
* @param audit The audit information of the user.
* @return The builder instance.
*/
public S withAudit(AuditDTO audit) {
this.audit = audit;
return (S) this;
}

/**
* Builds an instance of UserDTO using the builder's properties.
*
* @return An instance of UserDTO.
* @throws IllegalArgumentException If the name or audit are not set.
*/
public UserDTO build() {
Preconditions.checkArgument(StringUtils.isNotBlank(name), "name cannot be null or empty");
Preconditions.checkArgument(audit != null, "audit cannot be null");
return new UserDTO(name, roles, audit);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2024 Datastrato Pvt Ltd.
* This software is licensed under the Apache License version 2.
*/
package com.datastrato.gravitino.dto.requests;

import com.datastrato.gravitino.rest.RESTRequest;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Preconditions;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.jackson.Jacksonized;
import org.apache.commons.lang3.StringUtils;

/** Represents a request to add a user. */
@Getter
@EqualsAndHashCode
@ToString
@Builder
@Jacksonized
public class UserAddRequest implements RESTRequest {

@JsonProperty("name")
private final String name;

/** Default constructor for UserAddRequest. (Used for Jackson deserialization.) */
public UserAddRequest() {
this(null);
}

/**
* Creates a new UserAddRequest.
*
* @param name The name of the user.
*/
public UserAddRequest(String name) {
super();
this.name = name;
}

/**
* Validates the {@link UserAddRequest} request.
*
* @throws IllegalArgumentException If the request is invalid, this exception is thrown.
*/
@Override
public void validate() throws IllegalArgumentException {
Preconditions.checkArgument(
StringUtils.isNotBlank(name), "\"name\" field is required and cannot be empty");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2024 Datastrato Pvt Ltd.
* This software is licensed under the Apache License version 2.
*/
package com.datastrato.gravitino.dto.responses;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.EqualsAndHashCode;
import lombok.ToString;

/** Represents a response for a remove operation. */
@ToString
@EqualsAndHashCode(callSuper = true)
public class RemoveResponse extends BaseResponse {

@JsonProperty("removed")
private final boolean removed;

/**
* Constructor for RemoveResponse.
*
* @param removed Whether the remove operation was successful.
*/
public RemoveResponse(boolean removed) {
super(0);
this.removed = removed;
}

/** Default constructor for RemoveResponse (used by Jackson deserializer). */
public RemoveResponse() {
super();
this.removed = false;
}

/**
* Returns whether the remove operation was successful.
*
* @return True if the remove operation was successful, otherwise false.
*/
public boolean removed() {
return removed;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2024 Datastrato Pvt Ltd.
* This software is licensed under the Apache License version 2.
*/
package com.datastrato.gravitino.dto.responses;

import com.datastrato.gravitino.dto.authorization.UserDTO;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Preconditions;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;

/** Represents a response for a user. */
@Getter
@ToString
@EqualsAndHashCode(callSuper = true)
public class UserResponse extends BaseResponse {

@JsonProperty("user")
private final UserDTO user;

/**
* Constructor for UserResponse.
*
* @param user The user data transfer object.
*/
public UserResponse(UserDTO user) {
super(0);
this.user = user;
}

/** Default constructor for UserResponse. (Used for Jackson deserialization.) */
public UserResponse() {
super();
this.user = null;
}

/**
* Validates the response data.
*
* @throws IllegalArgumentException if the name or audit is not set.
*/
@Override
public void validate() throws IllegalArgumentException {
super.validate();

Preconditions.checkArgument(user != null, "user must not be null");
Preconditions.checkArgument(
StringUtils.isNotBlank(user.name()), "user 'name' must not be null and empty");
Preconditions.checkArgument(user.auditInfo() != null, "user 'auditInfo' must not be null");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
import com.datastrato.gravitino.Audit;
import com.datastrato.gravitino.Catalog;
import com.datastrato.gravitino.Metalake;
import com.datastrato.gravitino.authorization.User;
import com.datastrato.gravitino.dto.AuditDTO;
import com.datastrato.gravitino.dto.CatalogDTO;
import com.datastrato.gravitino.dto.MetalakeDTO;
import com.datastrato.gravitino.dto.authorization.UserDTO;
import com.datastrato.gravitino.dto.file.FilesetDTO;
import com.datastrato.gravitino.dto.rel.ColumnDTO;
import com.datastrato.gravitino.dto.rel.DistributionDTO;
Expand Down Expand Up @@ -327,6 +329,24 @@ public static IndexDTO toDTO(Index index) {
.build();
}

/**
* Converts a user implementation to a UserDTO.
*
* @param user The user implementation.
* @return The user DTO.
*/
public static UserDTO toDTO(User user) {
if (user instanceof UserDTO) {
return (UserDTO) user;
}

return UserDTO.builder()
.withName(user.name())
.withRoles(user.roles())
.withAudit(toDTO(user.auditInfo()))
.build();
}

/**
* Converts a Expression to an FunctionArg DTO.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.datastrato.gravitino.dto.AuditDTO;
import com.datastrato.gravitino.dto.CatalogDTO;
import com.datastrato.gravitino.dto.MetalakeDTO;
import com.datastrato.gravitino.dto.authorization.UserDTO;
import com.datastrato.gravitino.dto.rel.ColumnDTO;
import com.datastrato.gravitino.dto.rel.SchemaDTO;
import com.datastrato.gravitino.dto.rel.TableDTO;
Expand Down Expand Up @@ -223,4 +224,19 @@ void testOAuthErrorException() throws IllegalArgumentException {
OAuth2ErrorResponse response = new OAuth2ErrorResponse();
assertThrows(IllegalArgumentException.class, () -> response.validate());
}

@Test
void testUserResponse() throws IllegalArgumentException {
AuditDTO audit =
AuditDTO.builder().withCreator("creator").withCreateTime(Instant.now()).build();
UserDTO user = UserDTO.builder().withName("user1").withAudit(audit).build();
UserResponse response = new UserResponse(user);
response.validate(); // No exception thrown
}

@Test
void testUserResponseException() throws IllegalArgumentException {
UserResponse user = new UserResponse();
assertThrows(IllegalArgumentException.class, () -> user.validate());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package com.datastrato.gravitino.server;

import com.datastrato.gravitino.GravitinoEnv;
import com.datastrato.gravitino.authorization.AccessControlManager;
import com.datastrato.gravitino.catalog.CatalogManager;
import com.datastrato.gravitino.catalog.FilesetOperationDispatcher;
import com.datastrato.gravitino.catalog.SchemaOperationDispatcher;
Expand Down Expand Up @@ -75,6 +76,7 @@ private void initializeRestApi() {
protected void configure() {
bind(gravitinoEnv.metalakesManager()).to(MetalakeManager.class).ranked(1);
bind(gravitinoEnv.catalogManager()).to(CatalogManager.class).ranked(1);
bind(gravitinoEnv.accessControlManager()).to(AccessControlManager.class).ranked(1);
bind(gravitinoEnv.schemaOperationDispatcher())
.to(SchemaOperationDispatcher.class)
.ranked(1);
Expand Down
Loading

0 comments on commit 0dcd308

Please sign in to comment.