1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.linecorp.centraldogma.server.internal.storage.project;
17
18 import static com.linecorp.centraldogma.internal.Util.INTERNAL_PROJECT_PREFIX;
19 import static com.linecorp.centraldogma.server.storage.project.InternalProjectInitializer.INTERNAL_PROJECT_DOGMA;
20
21 import java.time.Instant;
22 import java.util.Collections;
23 import java.util.LinkedHashMap;
24 import java.util.Map;
25 import java.util.concurrent.CompletableFuture;
26
27 import javax.annotation.Nullable;
28
29 import com.linecorp.centraldogma.common.Author;
30 import com.linecorp.centraldogma.common.PermissionException;
31 import com.linecorp.centraldogma.common.Revision;
32 import com.linecorp.centraldogma.server.command.Command;
33 import com.linecorp.centraldogma.server.command.CommandExecutor;
34 import com.linecorp.centraldogma.server.internal.admin.auth.AuthUtil;
35 import com.linecorp.centraldogma.server.metadata.MetadataService;
36 import com.linecorp.centraldogma.server.metadata.ProjectMetadata;
37 import com.linecorp.centraldogma.server.metadata.User;
38 import com.linecorp.centraldogma.server.storage.project.Project;
39 import com.linecorp.centraldogma.server.storage.project.ProjectManager;
40
41
42
43
44
45 public final class ProjectApiManager {
46
47 private final ProjectManager projectManager;
48 private final CommandExecutor commandExecutor;
49 private final MetadataService metadataService;
50
51 public ProjectApiManager(ProjectManager projectManager, CommandExecutor commandExecutor,
52 MetadataService metadataService) {
53 this.projectManager = projectManager;
54 this.commandExecutor = commandExecutor;
55 this.metadataService = metadataService;
56 }
57
58 public Map<String, Project> listProjects(@Nullable User user) {
59 final Map<String, Project> projects = projectManager.list();
60 if (isSystemAdmin()) {
61 return projects;
62 }
63
64 return listProjectsWithoutInternal(projects, user);
65 }
66
67 private static boolean isSystemAdmin() {
68 final User currentUserOrNull = AuthUtil.currentUserOrNull();
69 if (currentUserOrNull == null) {
70 return false;
71 }
72
73 return currentUserOrNull.isSystemAdmin();
74 }
75
76 public static Map<String, Project> listProjectsWithoutInternal(Map<String, Project> projects,
77 @Nullable User user) {
78 final Map<String, Project> result = new LinkedHashMap<>(projects.size() - 1);
79 for (Map.Entry<String, Project> entry : projects.entrySet()) {
80 if (isInternalProject(entry.getKey())) {
81 if (user != null) {
82 final ProjectMetadata metadata = entry.getValue().metadata();
83 if (metadata != null) {
84
85 if (metadata.memberOrDefault(user.id(), null) != null) {
86 result.put(entry.getKey(), entry.getValue());
87 }
88 }
89 }
90 } else {
91 result.put(entry.getKey(), entry.getValue());
92 }
93 }
94 return Collections.unmodifiableMap(result);
95 }
96
97 public Map<String, Instant> listRemovedProjects() {
98 return projectManager.listRemoved();
99 }
100
101 public CompletableFuture<Void> createProject(String projectName, Author author) {
102 checkInternalProject(projectName, "create");
103 return commandExecutor.execute(Command.createProject(author, projectName));
104 }
105
106 private static void checkInternalProject(String projectName, String operation) {
107 if (isInternalProject(projectName)) {
108 throw new IllegalArgumentException("Cannot " + operation + ' ' + projectName);
109 }
110 }
111
112 public CompletableFuture<ProjectMetadata> getProjectMetadata(String projectName) {
113 return metadataService.getProject(projectName);
114 }
115
116 public CompletableFuture<Void> removeProject(String projectName, Author author) {
117 checkInternalProject(projectName, "remove");
118
119 return metadataService.removeProject(author, projectName)
120 .thenCompose(unused -> commandExecutor.execute(
121 Command.removeProject(author, projectName)));
122 }
123
124 public CompletableFuture<Void> purgeProject(String projectName, Author author) {
125 checkInternalProject(projectName, "purge");
126 return commandExecutor.execute(Command.purgeProject(author, projectName));
127 }
128
129 public CompletableFuture<Revision> unremoveProject(String projectName, Author author) {
130 checkInternalProject(projectName, "unremove");
131
132 return commandExecutor.execute(Command.unremoveProject(author, projectName))
133 .thenCompose(unused -> metadataService.restoreProject(author, projectName));
134 }
135
136 public Project getProject(String projectName) {
137 return getProject(projectName, AuthUtil.currentUserOrNull());
138 }
139
140 public Project getProject(String projectName, @Nullable User user) {
141 final Project project = projectManager.get(projectName);
142
143 if (!isInternalProject(projectName)) {
144 return project;
145 }
146
147 if (user == null) {
148 throw new IllegalArgumentException("Cannot access " + projectName);
149 }
150
151 if (user.isSystemAdmin()) {
152 return project;
153 }
154 final ProjectMetadata metadata = project.metadata();
155 if (metadata != null) {
156
157 if (metadata.memberOrDefault(user.id(), null) != null) {
158 return project;
159 }
160 }
161 throw new PermissionException("Cannot access " + projectName);
162 }
163
164 private static boolean isInternalProject(String projectName) {
165 return projectName.startsWith(INTERNAL_PROJECT_PREFIX) || INTERNAL_PROJECT_DOGMA.equals(projectName);
166 }
167
168 public boolean exists(String projectName) {
169 if (isInternalProject(projectName) && !isSystemAdmin()) {
170 throw new IllegalArgumentException("Cannot access " + projectName);
171 }
172 return projectManager.exists(projectName);
173 }
174 }