View Javadoc
1   /*
2    * The coLAB project
3    * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO
4    *
5    * Licensed under the MIT License
6    */
7   package ch.colabproject.colab.api.rest.project;
8   
9   import ch.colabproject.colab.api.controller.project.ProjectManager;
10  import ch.colabproject.colab.api.controller.team.TeamManager;
11  import ch.colabproject.colab.api.exceptions.ColabMergeException;
12  import ch.colabproject.colab.api.model.DuplicationParam;
13  import ch.colabproject.colab.api.model.card.AbstractCardType;
14  import ch.colabproject.colab.api.model.card.Card;
15  import ch.colabproject.colab.api.model.card.CardContent;
16  import ch.colabproject.colab.api.model.link.ActivityFlowLink;
17  import ch.colabproject.colab.api.model.project.CopyParam;
18  import ch.colabproject.colab.api.model.project.Project;
19  import ch.colabproject.colab.api.persistence.jpa.project.CopyParamDao;
20  import ch.colabproject.colab.api.persistence.jpa.project.ProjectDao;
21  import ch.colabproject.colab.api.rest.project.bean.ProjectCreationData;
22  import ch.colabproject.colab.api.rest.project.bean.ProjectStructure;
23  import ch.colabproject.colab.generator.model.annotations.AdminResource;
24  import ch.colabproject.colab.generator.model.annotations.AuthenticationRequired;
25  import ch.colabproject.colab.generator.model.exceptions.HttpErrorMessage;
26  import java.util.List;
27  import java.util.Set;
28  import jakarta.inject.Inject;
29  import jakarta.ws.rs.Consumes;
30  import jakarta.ws.rs.GET;
31  import jakarta.ws.rs.POST;
32  import jakarta.ws.rs.PUT;
33  import jakarta.ws.rs.Path;
34  import jakarta.ws.rs.PathParam;
35  import jakarta.ws.rs.Produces;
36  import jakarta.ws.rs.core.MediaType;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  
40  /**
41   * REST Project controller
42   *
43   * @author maxence
44   */
45  @Path("projects")
46  @Consumes(MediaType.APPLICATION_JSON)
47  @Produces(MediaType.APPLICATION_JSON)
48  @AuthenticationRequired
49  public class ProjectRestEndpoint {
50  
51      /** logger */
52      private static final Logger logger = LoggerFactory.getLogger(ProjectRestEndpoint.class);
53  
54      /** Project business logic */
55      @Inject
56      private ProjectManager projectManager;
57  
58      /** TeamMembers and roles management */
59      @Inject
60      private TeamManager teamManager;
61  
62      /** Project persistence */
63      @Inject
64      private ProjectDao projectDao;
65  
66      /** Copy parameters persistence */
67      @Inject
68      private CopyParamDao copyParamDao;
69  
70      // *********************************************************************************************
71      // get
72      // *********************************************************************************************
73  
74      /**
75       * Get project identified by the given id.
76       *
77       * @param id id of the project to fetch
78       *
79       * @return the project or null
80       */
81      @GET
82      @Path("/{id: [0-9]+}")
83      public Project getProject(@PathParam("id") Long id) {
84          logger.debug("Get project #{}", id);
85          return projectDao.findProject(id);
86      }
87  
88      /**
89       * Get all projects the current user is a team member of
90       *
91       * @return list of projects
92       */
93      @GET
94      @Path("Mine")
95      public List<Project> getProjectsWhereTeamMember() {
96          logger.debug("Get projects where current user is a team member of");
97          return projectManager.findProjectsWhereTeamMember();
98      }
99  
100     /**
101      * Get all global models
102      * @return  list of global models
103      */
104     @GET
105     @Path("Global")
106     public List<Project> getAllGlobalModels() {
107         logger.debug("Get all global projects");
108         return projectDao.findAllGlobalModels();
109     }
110 
111     /**
112      * Get all projects the current user is an instance maker for
113      *
114      * @return list of matching projects
115      */
116     @GET
117     @Path("MyInstanceableModels")
118     public List<Project> getInstanceableModels() {
119         logger.debug("Get all models linked by a instancemaker to the current user");
120         return projectManager.findInstanceableModelsForCurrentUser();
121     }
122 
123     /**
124      * Retrieve the list of all projects. This is available to admin only
125      *
126      * @return all known project
127      */
128     @GET
129     @AdminResource
130     public List<Project> getAllProjects() {
131         logger.debug("Get all projects");
132         return projectDao.findAllProject();
133     }
134 
135 
136     // *********************************************************************************************
137     // create
138     // *********************************************************************************************
139 
140     /**
141      * Create a new project from scratch with the provided data and register current user as a
142      * member.
143      *
144      * @param creationData the data needed to fill the project
145      *
146      * @return id of the persisted new project
147      */
148     @POST
149     @Path("createProject")
150     public Long createProject(ProjectCreationData creationData) {
151         logger.debug("Create a project with {}", creationData);
152 
153         Project project = projectManager.createProject(creationData);
154 
155         creationData.getGuestsEmail().stream().forEach(email -> {
156             teamManager.invite(project.getId(), email);
157         });
158 
159         return project.getId();
160     }
161 
162     /**
163      * Duplicate the given project
164      *
165      * @param baseProjectId the id of the project we want to duplicate
166      * @param name          the name of the new project
167      * @param params        the parameters to fine tune the duplication
168      *
169      * @return the id of the duplicated project
170      *
171      * @throws ColabMergeException if the name cannot be updated
172      */
173     @POST
174     @Path("copyProject/{id: [0-9]+}/{name}")
175     public Long duplicateProject(@PathParam("id") Long baseProjectId,
176         @PathParam("name") String name, DuplicationParam params) throws ColabMergeException {
177         logger.debug("duplicate the project #{} with params {}", baseProjectId, params);
178 
179         DuplicationParam effectiveParams = params;
180         if (effectiveParams == null) {
181             effectiveParams = DuplicationParam.buildDefaultForProjectDuplication();
182         }
183 
184         // check forced parameters
185         if (effectiveParams.isMakeOnlyCardTypeReferences()) {
186             throw new IllegalArgumentException();
187         }
188 
189         Project newProject = projectManager.duplicateProject(baseProjectId, effectiveParams);
190 
191         newProject.setName(name);
192 
193         projectDao.updateProject(newProject);
194 
195         return newProject.getId();
196     }
197 
198     // *********************************************************************************************
199     // update
200     // *********************************************************************************************
201 
202     /**
203      * Save changes to database.
204      *
205      * @param project project to update
206      *
207      * @throws ColabMergeException if the merge is not possible
208      */
209     @PUT
210     public void updateProject(Project project) throws ColabMergeException {
211         logger.debug("Update project {}", project);
212         projectDao.updateProject(project);
213     }
214 
215     /**
216      * Save changes to database.
217      *
218      * @param copyParam the copy parameters to update
219      *
220      * @throws ColabMergeException if the merge is not possible
221      */
222     @PUT
223     @Path("copyParam")
224     public void updateCopyParam(CopyParam copyParam) throws ColabMergeException {
225         logger.debug("Update copy param {}", copyParam);
226         copyParamDao.updateCopyParam(copyParam);
227     }
228 
229     // *********************************************************************************************
230     // delete
231     // *********************************************************************************************
232 
233     /**
234      * Put the given project in the bin. (= set DeletionStatus to BIN + set erasure
235      * tracking data)
236      *
237      * @param projectId the id of the project
238      *
239      * @throws HttpErrorMessage if project does not exist
240      */
241     @PUT
242     @Path("{projectId: [0-9]+}/PutInBin")
243     public void putProjectInBin(@PathParam("projectId") Long projectId) {
244         logger.debug("put in bin project #{}", projectId);
245         projectManager.putProjectInBin(projectId);
246     }
247 
248     /**
249      * Restore from the bin. The project won't contain any deletion or erasure data
250      * anymore.
251      * <p>
252      * It means that the project is back at its place.
253      *
254      * @param projectId the id of the project
255      *
256      * @throws HttpErrorMessage if project does not exist
257      */
258     @PUT
259     @Path("{projectId: [0-9]+}/RestoreFromBin")
260     public void restoreProjectFromBin(@PathParam("projectId") Long projectId) {
261         logger.debug("restore from bin project #{}", projectId);
262         projectManager.restoreProjectFromBin(projectId);
263     }
264 
265     /**
266      * Set the deletion status to TO_DELETE.
267      * <p>
268      * It means that the project is only visible in the bin panel.
269      *
270      * @param projectId the id of the project
271      *
272      * @throws HttpErrorMessage if project does not exist
273      */
274     @PUT
275     @Path("{projectId: [0-9]+}/FlagAsToDeleteForever")
276     public void flagProjectAsToDeleteForever(@PathParam("projectId") Long projectId) {
277         logger.debug("flag project #{} as to delete forever", projectId);
278         projectManager.flagProjectAsToDeleteForever(projectId);
279     }
280 
281     // *********************************************************************************************
282     // get project content
283     // *********************************************************************************************
284 
285     /**
286      * Get the root card of the project
287      *
288      * @param projectId the id of the project
289      *
290      * @return the matching card
291      */
292     @GET
293     @Path("{id: [0-9]+}/RootCard")
294     public Card getRootCardOfProject(@PathParam("id") Long projectId) {
295         logger.debug("get the root card of the project #{}", projectId);
296         return projectManager.getRootCard(projectId);
297     }
298 
299     /**
300      * Get all card types belonging to a project
301      *
302      * @param projectId the id of the project
303      *
304      * @return list of card types
305      */
306     @GET
307     @Path("{id: [0-9]+}/CardTypes")
308     public Set<AbstractCardType> getCardTypesOfProject(@PathParam("id") Long projectId) {
309         logger.debug("Get project #{} card types", projectId);
310         return projectManager.getCardTypes(projectId);
311     }
312 
313     /**
314      * Get all cards belonging to a project
315      *
316      * @param projectId the id of the project
317      *
318      * @return list of cards
319      */
320     @GET
321     @Path("{id: [0-9]+}/Cards")
322     public Set<Card> getCardsOfProject(@PathParam("id") Long projectId) {
323         logger.debug("Get project #{} cards", projectId);
324         return projectManager.getCards(projectId);
325     }
326 
327     /**
328      * Get all cardContents belonging to a project
329      *
330      * @param projectId the id of the project
331      *
332      * @return list of cardContents
333      */
334     @GET
335     @Path("{id: [0-9]+}/CardContents")
336     public Set<CardContent> getCardContentsOfProject(@PathParam("id") Long projectId) {
337         logger.debug("Get project #{} cardContents", projectId);
338         return projectManager.getCardContents(projectId);
339     }
340 
341     /**
342      * Get all cards, cardContents and structure of a project in one shot.
343      *
344      * @param projectId the id of the project
345      *
346      * @return full structure of the project
347      */
348     @GET
349     @Path("{id: [0-9]+}/structure")
350     public ProjectStructure getStructureOfProject(@PathParam("id") Long projectId) {
351         logger.debug("Get project #{} cardContents", projectId);
352         return projectManager.getStructure(projectId);
353     }
354 
355     /**
356      * Get all activity flow links belonging to a project
357      *
358      * @param projectId the id of the project
359      *
360      * @return list of activity flow links
361      */
362     @GET
363     @Path("{id: [0-9]+}/ActivityFlowLink")
364     public Set<ActivityFlowLink> getActivityFlowLinks(@PathParam("id") Long projectId) {
365         logger.debug("Get project #{} activityflowlinks", projectId);
366         return projectManager.getActivityFlowLinks(projectId);
367     }
368 
369     /**
370      * Get the copy parameters of the project
371      *
372      * @param projectId the id of the project
373      *
374      * @return the related copy parameters
375      */
376     @GET
377     @Path("{id: [0-9]+}/copyParams")
378     public CopyParam getCopyParam(@PathParam("id") Long projectId) {
379         CopyParam copyParam = projectManager.getCopyParam(projectId);
380         logger.debug("Got project #{} copy param : {}", projectId, copyParam);
381         return copyParam;
382     }
383 
384     // *********************************************************************************************
385     //
386     // *********************************************************************************************
387 
388 }