Skip to content

Commit

Permalink
Add Repository settings UI (#1078)
Browse files Browse the repository at this point in the history
Motivation:
To provide users with a dedicated interface for managing repository settings.

Modifications:
- Added `RepositorySettingsPage` component for centralized repository settings management.
- Refactored UI code for improved maintainability and reusability:
  - Consolidated `ProjectRole` definitions into a single location
  - Merged `AppMemberList` and `AppTokenList` into a unified `AppEntityList` component to reduce code duplication
  - Merged `DeleteMember` and `DeleteToken` functionalities into a single `DeleteAppEntity` component to reduce code duplication
- Implemented repository-level credential APIs to support new settings features

Result:
- New RepositorySettingsPage accessible to users for managing repository-specific settings.
  • Loading branch information
minwoox authored Jan 7, 2025
1 parent 8555040 commit 015db56
Show file tree
Hide file tree
Showing 53 changed files with 1,414 additions and 503 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,12 @@ void testMirror(boolean useRawApi) {
null));
for (Credential credential : CREDENTIALS) {
final Command<CommitResult> command =
metaRepo.createPushCommand(credential, Author.SYSTEM, false).join();
metaRepo.createCredentialPushCommand(credential, Author.SYSTEM, false).join();
pmExtension.executor().execute(command).join();
}
for (MirrorDto mirror : mirrors) {
final Command<CommitResult> command =
metaRepo.createPushCommand(mirror, Author.SYSTEM, null, false).join();
metaRepo.createMirrorPushCommand(mirror, Author.SYSTEM, null, false).join();
pmExtension.executor().execute(command).join();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import com.linecorp.centraldogma.server.metadata.User;
import com.linecorp.centraldogma.server.storage.project.Project;
import com.linecorp.centraldogma.server.storage.repository.MetaRepository;
import com.linecorp.centraldogma.server.storage.repository.Repository;

/**
* Annotated service object for managing credential service.
Expand All @@ -69,16 +70,21 @@ public CredentialServiceV1(ProjectApiManager projectApiManager, CommandExecutor
@Get("/projects/{projectName}/credentials")
public CompletableFuture<List<Credential>> listCredentials(User loginUser,
@Param String projectName) {
final CompletableFuture<List<Credential>> future = metaRepo(projectName, loginUser).credentials();
final CompletableFuture<List<Credential>> future =
metaRepo(projectName, loginUser).projectCredentials();
return maybeMaskSecret(loginUser, future);
}

private static CompletableFuture<List<Credential>> maybeMaskSecret(
User loginUser,
CompletableFuture<List<Credential>> future) {
if (loginUser.isSystemAdmin()) {
return future;
}
return future.thenApply(credentials -> {
return credentials
.stream()
.map(Credential::withoutSecret)
.collect(toImmutableList());
});
return future.thenApply(credentials -> credentials
.stream()
.map(Credential::withoutSecret)
.collect(toImmutableList()));
}

/**
Expand All @@ -90,7 +96,7 @@ public CompletableFuture<List<Credential>> listCredentials(User loginUser,
@Get("/projects/{projectName}/credentials/{id}")
public CompletableFuture<Credential> getCredentialById(User loginUser,
@Param String projectName, @Param String id) {
final CompletableFuture<Credential> future = metaRepo(projectName, loginUser).credential(id);
final CompletableFuture<Credential> future = metaRepo(projectName, loginUser).projectCredential(id);
if (loginUser.isSystemAdmin()) {
return future;
}
Expand Down Expand Up @@ -135,7 +141,7 @@ public CompletableFuture<PushResultDto> updateCredential(@Param String projectNa
public CompletableFuture<Void> deleteCredential(@Param String projectName,
@Param String id, Author author, User user) {
final MetaRepository metaRepository = metaRepo(projectName, user);
return metaRepository.credential(id).thenCompose(credential -> {
return metaRepository.projectCredential(id).thenCompose(credential -> {
// credential exists.
final Command<CommitResult> command =
Command.push(author, projectName, metaRepository.name(),
Expand All @@ -147,15 +153,117 @@ public CompletableFuture<Void> deleteCredential(@Param String projectName,

private CompletableFuture<PushResultDto> createOrUpdate(String projectName, Credential credential,
Author author, User user, boolean update) {
return metaRepo(projectName, user).createPushCommand(credential, author, update).thenCompose(
command -> {
return executor().execute(command).thenApply(result -> {
return new PushResultDto(result.revision(), command.timestamp());
});
});
final CompletableFuture<Command<CommitResult>> future =
metaRepo(projectName, user).createCredentialPushCommand(credential, author, update);
return push(future);
}

private CompletableFuture<PushResultDto> push(
CompletableFuture<Command<CommitResult>> future) {
return future.thenCompose(
command -> executor().execute(command).thenApply(
result -> new PushResultDto(result.revision(), command.timestamp())));
}

private MetaRepository metaRepo(String projectName, User user) {
return projectApiManager.getProject(projectName, user).metaRepo();
}

// Repository level credential management APIs.

/**
* GET /projects/{projectName}/repos/{repoName}/credentials
*
* <p>Returns the list of the credentials in the repository.
*/
@RequiresRepositoryRole(RepositoryRole.ADMIN)
@Get("/projects/{projectName}/repos/{repoName}/credentials")
public CompletableFuture<List<Credential>> listRepoCredentials(User loginUser,
@Param String projectName,
Repository repository) {
final CompletableFuture<List<Credential>> future =
metaRepo(projectName, loginUser).repoCredentials(repository.name());
return maybeMaskSecret(loginUser, future);
}

/**
* GET /projects/{projectName}/credentials/{id}
*
* <p>Returns the credential for the ID in the project.
*/
@RequiresRepositoryRole(RepositoryRole.ADMIN)
@Get("/projects/{projectName}/repos/{repoName}/credentials/{id}")
public CompletableFuture<Credential> getRepoCredentialById(User loginUser,
@Param String projectName,
Repository repository,
@Param String id) {
final CompletableFuture<Credential> future =
metaRepo(projectName, loginUser).repoCredential(repository.name(), id);
if (loginUser.isSystemAdmin()) {
return future;
}
return future.thenApply(Credential::withoutSecret);
}

/**
* POST /projects/{projectName}/credentials
*
* <p>Creates a new credential.
*/
@ConsumesJson
@StatusCode(201)
@RequiresRepositoryRole(RepositoryRole.ADMIN)
@Post("/projects/{projectName}/repos/{repoName}/credentials")
public CompletableFuture<PushResultDto> createRepoCredential(@Param String projectName,
Repository repository,
Credential credential, Author author,
User user) {
return createOrUpdateRepo(projectName, repository.name(), credential, author, user, false);
}

/**
* PUT /projects/{projectName}/credentials/{id}
*
* <p>Update the existing credential.
*/
@ConsumesJson
@RequiresRepositoryRole(RepositoryRole.ADMIN)
@Put("/projects/{projectName}/repos/{repoName}/credentials/{id}")
public CompletableFuture<PushResultDto> updateRepoCredential(@Param String projectName,
Repository repository,
@Param String id,
Credential credential, Author author,
User user) {
checkArgument(id.equals(credential.id()), "The credential ID (%s) can't be updated", id);
return createOrUpdateRepo(projectName, repository.name(), credential, author, user, true);
}

private CompletableFuture<PushResultDto> createOrUpdateRepo(
String projectName, String repoName, Credential credential,
Author author, User user, boolean update) {
final CompletableFuture<Command<CommitResult>> future =
metaRepo(projectName, user).createCredentialPushCommand(repoName, credential, author, update);
return push(future);
}

/**
* DELETE /projects/{projectName}/credentials/{id}
*
* <p>Delete the existing credential.
*/
@RequiresRepositoryRole(RepositoryRole.ADMIN)
@Delete("/projects/{projectName}/repos/{repoName}/credentials/{id}")
public CompletableFuture<Void> deleteRepoCredential(@Param String projectName,
Repository repository,
@Param String id, Author author, User user) {
final MetaRepository metaRepository = metaRepo(projectName, user);
return metaRepository.repoCredential(repository.name(), id).thenCompose(credential -> {
// credential exists.
final Command<CommitResult> command =
Command.push(author, projectName, metaRepository.name(),
Revision.HEAD, "Delete credential: " + id, "",
Markup.PLAINTEXT, Change.ofRemoval(credentialFile(repository.name(), id)));
return executor().execute(command).thenApply(result -> null);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ private CompletableFuture<PushResultDto> createOrUpdate(String projectName,
MirrorDto newMirror,
Author author, boolean update) {
return metaRepo(projectName)
.createPushCommand(newMirror, author, zoneConfig, update).thenCompose(command -> {
.createMirrorPushCommand(newMirror, author, zoneConfig, update).thenCompose(command -> {
return executor().execute(command).thenApply(result -> {
return new PushResultDto(result.revision(), command.timestamp());
});
Expand Down
Loading

0 comments on commit 015db56

Please sign in to comment.