JavaDoc for Admin UI

Jens Pelzetter 2020-12-10 15:28:12 +01:00
parent 93c300df1d
commit ce299163ab
56 changed files with 1016 additions and 126 deletions

View File

@ -19,6 +19,8 @@
package org.libreccm.ui.admin.applications; package org.libreccm.ui.admin.applications;
/** /**
* Interface for controllers providing the UI for managing the instances of
* an application.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */

View File

@ -21,22 +21,45 @@ package org.libreccm.ui.admin.applications;
import java.util.Objects; import java.util.Objects;
/** /**
* Data Transfer Object providing the information about an application. Used for
* rendering the informations the available applications in UI.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
public class ApplicationTypeInfoItem implements public class ApplicationTypeInfoItem implements
Comparable<ApplicationTypeInfoItem> { Comparable<ApplicationTypeInfoItem> {
/**
* Name of the application.
*/
private String name; private String name;
/**
* Localized title of the application, if available in the language of the
* current user.
*/
private String title; private String title;
/**
* Localized title of the application, if available in the language of the
* current user.
*/
private String description; private String description;
/**
* Is the application a singleton application?
*/
private boolean singleton; private boolean singleton;
/**
* Number of existing instances of the application.
*/
private long numberOfInstances; private long numberOfInstances;
/**
* Link the {@link ApplicationController} implementation of the application,
* if an implementation is available.
*/
private String controllerLink; private String controllerLink;
protected ApplicationTypeInfoItem() { protected ApplicationTypeInfoItem() {

View File

@ -40,6 +40,7 @@ import javax.ws.rs.GET;
import javax.ws.rs.Path; import javax.ws.rs.Path;
/** /**
* Controller for the UI for managing application instances.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -60,9 +61,13 @@ public class ApplicationsController {
@Inject @Inject
private Models models; private Models models;
// @Inject /**
// private MvcContext mvc; * Retrives the avaiable application types, creates
* {@link ApplicationTypeInfoItem}s for them and makes them available using
* {@link #models}.
*
* @return The template to render.
*/
@GET @GET
@Path("/") @Path("/")
@AuthorizationRequired @AuthorizationRequired
@ -83,6 +88,15 @@ public class ApplicationsController {
return "org/libreccm/ui/admin/applications/applicationtypes.xhtml"; return "org/libreccm/ui/admin/applications/applicationtypes.xhtml";
} }
/**
* Helper method for building an {@link ApplicationTypeInfoItem} for an
* {@link ApplicationType}.
*
* @param applicationType The application type.
*
* @return An {@link ApplicationTypeInfoItem} for the provided application
* type.
*/
private ApplicationTypeInfoItem buildTypeInfoItem( private ApplicationTypeInfoItem buildTypeInfoItem(
final ApplicationType applicationType final ApplicationType applicationType
) { ) {
@ -101,15 +115,9 @@ public class ApplicationsController {
final Class<? extends ApplicationController> controllerClass final Class<? extends ApplicationController> controllerClass
= applicationType.applicationController(); = applicationType.applicationController();
if (!DefaultApplicationController.class if (!DefaultApplicationController.class.isAssignableFrom(
.isAssignableFrom(controllerClass)) { controllerClass
// item.setControllerLink( )) {
// mvc.uri(
// String.format(
// "%s#getApplication", controllerClass.getSimpleName()
// )
// ).toString()
// );
item.setControllerLink( item.setControllerLink(
String.format( String.format(
"%s#getApplication", "%s#getApplication",

View File

@ -18,8 +18,6 @@
*/ */
package org.libreccm.ui.admin.applications; package org.libreccm.ui.admin.applications;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.libreccm.ui.admin.AdminConstants; import org.libreccm.ui.admin.AdminConstants;
import org.libreccm.ui.admin.AdminPage; import org.libreccm.ui.admin.AdminPage;
import org.libreccm.web.ApplicationManager; import org.libreccm.web.ApplicationManager;
@ -32,6 +30,7 @@ import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject; import javax.inject.Inject;
/** /**
* {@link AdminPage} for managing applications.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */

View File

@ -23,6 +23,10 @@ import javax.mvc.Controller;
import javax.ws.rs.Path; import javax.ws.rs.Path;
/** /**
* A default implementation of the {@link ApplicationController} used if there
* is not implementation of the {@link ApplicationController} interface for an
* application.
*
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2020 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
/**
* UI for managing application instances.
*/
package org.libreccm.ui.admin.applications;

View File

@ -50,6 +50,7 @@ import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
/** /**
* Primary controller for the UI for managing category systems and categories.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -79,6 +80,13 @@ public class CategoriesController {
@Inject @Inject
private Models models; private Models models;
/**
* Show details about a category.
*
* @param categoryIdentifier Identifier of the category to show.
*
* @return The template to render.
*/
@GET @GET
@Path("/{categoryIdentifier}") @Path("/{categoryIdentifier}")
@AuthorizationRequired @AuthorizationRequired
@ -120,6 +128,13 @@ public class CategoriesController {
} }
} }
/**
* Show the edit form for a category.
*
* @param categoryIdentifier Identifier of the category to edit.
*
* @return The template to render.
*/
@GET @GET
@Path("/{categoryIdentifier}/edit") @Path("/{categoryIdentifier}/edit")
@AuthorizationRequired @AuthorizationRequired
@ -161,6 +176,13 @@ public class CategoriesController {
} }
} }
/**
* Displays the form for creating a new subcategory.
*
* @param categoryIdentifier The identifier of the parent category.
*
* @return The template to render.
*/
@GET @GET
@Path("/{categoryIdentifier}/subcategories/new") @Path("/{categoryIdentifier}/subcategories/new")
@AuthorizationRequired @AuthorizationRequired
@ -202,6 +224,15 @@ public class CategoriesController {
} }
} }
/**
* Moves a category from one parent category to another. The target is
* provided
*
* @param categoryIdentifierParam Identifier of the category to move.
* @param targetIdentifierParam Identifier of the target category.
*
* @return Redirect to the detail page of the target category.
*/
@POST @POST
@Path("/{categoryIdentifier}/subcategories/move") @Path("/{categoryIdentifier}/subcategories/move")
@AuthorizationRequired @AuthorizationRequired
@ -286,6 +317,14 @@ public class CategoriesController {
); );
} }
/**
* Deletes a category.
*
* @param categoryIdentifier Identifier of the category to remove.
*
* @return Redirect to the details page of the parent category of the
* removed category.
*/
@POST @POST
@Path("/{categoryIdentifier}/subcategories/remove") @Path("/{categoryIdentifier}/subcategories/remove")
@AuthorizationRequired @AuthorizationRequired
@ -341,6 +380,15 @@ public class CategoriesController {
} }
} }
/**
* Adds a localized title the a category.
*
* @param identifierParam Identifier of the category.
* @param localeParam The locale of the title.
* @param value The localized title.
*
* @return Redirect to the details page of the category.
*/
@POST @POST
@Path("/{identifier}/title/add") @Path("/{identifier}/title/add")
@AuthorizationRequired @AuthorizationRequired
@ -390,6 +438,15 @@ public class CategoriesController {
} }
} }
/**
* Updates the localized title of a category.
*
* @param identifierParam Identifier of the category.
* @param localeParam The locale of the title.
* @param value The localized title.
*
* @return Redirect to the details page of the category.
*/
@POST @POST
@Path("/{identifier}/title/{locale}/edit") @Path("/{identifier}/title/{locale}/edit")
@AuthorizationRequired @AuthorizationRequired
@ -439,6 +496,14 @@ public class CategoriesController {
} }
} }
/**
* Removes the localized title of a category.
*
* @param categoryIdentifierParam Identifier of the category.
* @param localeParam The locale of the title.
*
* @return Redirect to the details page of the category.
*/
@POST @POST
@Path("/{identifier}/title/{locale}/remove") @Path("/{identifier}/title/{locale}/remove")
@AuthorizationRequired @AuthorizationRequired
@ -488,6 +553,15 @@ public class CategoriesController {
} }
} }
/**
* Adds a localized description the a category.
*
* @param identifierParam Identifier of the category.
* @param localeParam The locale of the description
* @param value The localized description.
*
* @return Redirect to the details page of the category.
*/
@POST @POST
@Path("/{identifier}decsription/add") @Path("/{identifier}decsription/add")
@AuthorizationRequired @AuthorizationRequired
@ -537,6 +611,15 @@ public class CategoriesController {
} }
} }
/**
* Updates the localized description the a category.
*
* @param identifierParam Identifier of the category.
* @param localeParam The locale of the description
* @param value The localized description.
*
* @return Redirect to the details page of the category.
*/
@POST @POST
@Path("/{identifier}/description/{locale}/edit") @Path("/{identifier}/description/{locale}/edit")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@ -587,6 +670,14 @@ public class CategoriesController {
} }
} }
/**
* Removes a localized description the a category.
*
* @param identifierParam Identifier of the category.
* @param localeParam The locale of the description
*
* @return Redirect to the details page of the category.
*/
@POST @POST
@Path("/{identifier}/description/{locale}/remove") @Path("/{identifier}/description/{locale}/remove")
@AuthorizationRequired @AuthorizationRequired
@ -635,6 +726,16 @@ public class CategoriesController {
} }
} }
/**
* Changes the order of the subcategories of a category.
*
* @param categoryIdentifierParam Identifier of the category.
* @param subCategoryIdentifierParam Identifier of the sub category to move.
* @param direction The direction, either
* {@code INCREASE or DECREASE}.
*
* @return Redirect to the details page of the category.
*/
@POST @POST
@Path("/{categoryIdentifier}/subcategories/{subCategoryIdentifier}/reorder") @Path("/{categoryIdentifier}/subcategories/{subCategoryIdentifier}/reorder")
@AuthorizationRequired @AuthorizationRequired

View File

@ -27,6 +27,8 @@ import java.util.Set;
import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.ApplicationScoped;
/** /**
* {@link AdminPage} implementation for the UI for managing categories.
*
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */

View File

@ -42,6 +42,7 @@ import javax.inject.Named;
import javax.transaction.Transactional; import javax.transaction.Transactional;
/** /**
* Model for the details of a category.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -202,6 +203,11 @@ public class CategoryDetailsModel {
this.invalidFields = new HashSet<>(invalidFields); this.invalidFields = new HashSet<>(invalidFields);
} }
/**
* Sets the model to the properties of the provided category.
*
* @param category The category.
*/
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
protected void setCategory(final Category category) { protected void setCategory(final Category category) {
Objects.requireNonNull(category); Objects.requireNonNull(category);

View File

@ -45,6 +45,8 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
/** /**
* Controller processing the POST requests from the form for creating and
* editing categories.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -86,6 +88,12 @@ public class CategoryFormController {
@FormParam("abstractCategory") @FormParam("abstractCategory")
private String abstractCategory; private String abstractCategory;
/**
* Create a new category.
*
* @param parentCategoryIdentifier Identifier of the parent category.
* @return Redirect to the details page of the parent category.
*/
@POST @POST
@Path("/{parentCategoryIdentifier}/new") @Path("/{parentCategoryIdentifier}/new")
@AuthorizationRequired @AuthorizationRequired
@ -158,6 +166,12 @@ public class CategoryFormController {
} }
} }
/**
* Updates a category with the data from the form.
*
* @param categoryIdentifierParam Identifier of the category to update.
* @return Redirect to the details page of the category.
*/
@POST @POST
@Path("/{categoryIdentifier}/edit") @Path("/{categoryIdentifier}/edit")
@AuthorizationRequired @AuthorizationRequired

View File

@ -21,6 +21,7 @@ package org.libreccm.ui.admin.categories;
import java.util.Objects; import java.util.Objects;
/** /**
* A DTO with the of a category shown in the UI.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */

View File

@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
* Model for displaying the path of category in the UI.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */

View File

@ -46,6 +46,9 @@ import javax.inject.Named;
import javax.transaction.Transactional; import javax.transaction.Transactional;
/** /**
* Model for the details of a category system (Domain)
*
* @see org.libreccm.categorization.Domain
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -227,6 +230,10 @@ public class CategorySystemDetailsModel {
this.invalidFields = new HashSet<>(invalidFields); this.invalidFields = new HashSet<>(invalidFields);
} }
/**
* Sets the properties of this model using the provided {@link Domain}.
* @param domain The domain to display.
*/
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
protected void setCategorySystem(final Domain domain) { protected void setCategorySystem(final Domain domain) {
Objects.requireNonNull(domain); Objects.requireNonNull(domain);

View File

@ -47,6 +47,8 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
/** /**
* Controller for processing the {@code POST} requests from the form for
* creating and editing category systems.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -82,6 +84,11 @@ public class CategorySystemFormController {
@FormParam("released") @FormParam("released")
private String released; private String released;
/**
* Creates a new category system (domain).
*
* @return Redirect to the list of category systems.
*/
@POST @POST
@Path("/new") @Path("/new")
@AuthorizationRequired @AuthorizationRequired
@ -117,6 +124,13 @@ public class CategorySystemFormController {
return "redirect:/categorymanager/categorysystems"; return "redirect:/categorymanager/categorysystems";
} }
/**
* Update a category with the data from the form.
*
* @param identifierParam Identifier of the category system to update.
*
* @return Redirect to the details page of the category system.
*/
@POST @POST
@Path("{categorySystemIdentifier}/edit") @Path("{categorySystemIdentifier}/edit")
@AuthorizationRequired @AuthorizationRequired
@ -191,6 +205,12 @@ public class CategorySystemFormController {
} }
} }
/**
* Helper method for converting the {@link #released} date to an ISO 8601
* formatted string.
*
* @return The released date in ISO 8601 format.
*/
private LocalDate convertReleased() { private LocalDate convertReleased() {
return LocalDate.parse( return LocalDate.parse(
released, released,
@ -198,6 +218,11 @@ public class CategorySystemFormController {
); );
} }
/**
* Helper method for validating a URI.
*
* @return {@code true} if the URI is valid, {@code false} otherwise.
*/
private boolean isValidUri() { private boolean isValidUri() {
final UrlValidator urlValidator = new UrlValidator(); final UrlValidator urlValidator = new UrlValidator();
return urlValidator.isValid(uri); return urlValidator.isValid(uri);

View File

@ -23,6 +23,7 @@ import org.libreccm.web.CcmApplication;
import java.util.Objects; import java.util.Objects;
/** /**
* DTO for the options for selecting the owner applications of a category system.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */

View File

@ -19,6 +19,7 @@
package org.libreccm.ui.admin.categories; package org.libreccm.ui.admin.categories;
/** /**
* Data for a row in the table of owner applications of a category system.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */

View File

@ -24,6 +24,7 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
/** /**
* Data for a row in the table of category systems.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */

View File

@ -49,6 +49,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
/** /**
* Controller for the UI for managing category systems.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -78,13 +79,11 @@ public class CategorySystemsController {
@Inject @Inject
private Models models; private Models models;
// @GET /**
// @Path("/") * Show a list of all available category systems.
// @AuthorizationRequired *
// @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) * @return The template to use.
// public String getCategoryManager() { */
// return getCategorySystems();
// }
@GET @GET
@Path("/") @Path("/")
@AuthorizationRequired @AuthorizationRequired
@ -93,6 +92,14 @@ public class CategorySystemsController {
return "org/libreccm/ui/admin/categories/categorysystems.xhtml"; return "org/libreccm/ui/admin/categories/categorysystems.xhtml";
} }
/**
* Display the details of a category system.
*
* @param categorySystemIdentifier Identifier of the category system to
* show.
*
* @return The template to use.
*/
@GET @GET
@Path("/{categorySystemIdentifier}/details") @Path("/{categorySystemIdentifier}/details")
@AuthorizationRequired @AuthorizationRequired
@ -141,6 +148,11 @@ public class CategorySystemsController {
} }
} }
/**
* Show the form for creating a new category system.
*
* @return The template to use.
*/
@GET @GET
@Path("/new") @Path("/new")
@AuthorizationRequired @AuthorizationRequired
@ -149,6 +161,14 @@ public class CategorySystemsController {
return "org/libreccm/ui/admin/categories/categorysystem-form.xhtml"; return "org/libreccm/ui/admin/categories/categorysystem-form.xhtml";
} }
/**
* Edit a category system.
*
* @param categorySystemIdentifier Identifier of the category system to
* edit.
*
* @return The template to use.
*/
@GET @GET
@Path("/{categorySystemIdentifier}/edit") @Path("/{categorySystemIdentifier}/edit")
@AuthorizationRequired @AuthorizationRequired
@ -198,6 +218,15 @@ public class CategorySystemsController {
} }
} }
/**
* Delete a category system and all its categories.
*
* @param categorySystemIdentifier Identifier of the category system to
* delete.
* @param confirmed Was the deletion confirmed by the user?
*
* @return Redirect to the categorysystems overview.
*/
@POST @POST
@Path("/{categorySystemIdentifier}/delete") @Path("/{categorySystemIdentifier}/delete")
@AuthorizationRequired @AuthorizationRequired
@ -250,6 +279,15 @@ public class CategorySystemsController {
return "redirect:categorymanager/categorysystems"; return "redirect:categorymanager/categorysystems";
} }
/**
* Adds a localized title the a category system.
*
* @param categorySystemIdentifier Identifier of the category system.
* @param localeParam The locale of the title.
* @param value The localized title.
*
* @return Redirect to the details page of the category system.
*/
@POST @POST
@Path("/{identifier}/title/add") @Path("/{identifier}/title/add")
@AuthorizationRequired @AuthorizationRequired
@ -306,6 +344,15 @@ public class CategorySystemsController {
} }
} }
/**
* Updates a localized title the a category system.
*
* @param categorySystemIdentifier Identifier of the category system.
* @param localeParam The locale of the title.
* @param value The localized title.
*
* @return Redirect to the details page of the category system.
*/
@POST @POST
@Path("/{identifier}/title/${locale}/edit") @Path("/{identifier}/title/${locale}/edit")
@AuthorizationRequired @AuthorizationRequired
@ -362,6 +409,14 @@ public class CategorySystemsController {
} }
} }
/**
* Removes a localized title the a category system.
*
* @param categorySystemIdentifier Identifier of the category system.
* @param localeParam The locale of the title.
*
* @return Redirect to the details page of the category system.
*/
@POST @POST
@Path("/{identifier}/title/${locale}/remove") @Path("/{identifier}/title/${locale}/remove")
@AuthorizationRequired @AuthorizationRequired
@ -422,6 +477,15 @@ public class CategorySystemsController {
} }
} }
/**
* Adds a localized description the a category system.
*
* @param categorySystemIdentifier Identifier of the category system.
* @param localeParam The locale of the description.
* @param value The localized description.
*
* @return Redirect to the details page of the category system.
*/
@POST @POST
@Path("/{identifier}/description/add") @Path("/{identifier}/description/add")
@AuthorizationRequired @AuthorizationRequired
@ -478,6 +542,15 @@ public class CategorySystemsController {
} }
} }
/**
* Updates a localized description the a category system.
*
* @param categorySystemIdentifier Identifier of the category system.
* @param localeParam The locale of the description.
* @param value The localized description.
*
* @return Redirect to the details page of the category system.
*/
@POST @POST
@Path( @Path(
"categorysystems/{identifier}/description/${locale}/edit" "categorysystems/{identifier}/description/${locale}/edit"
@ -536,6 +609,14 @@ public class CategorySystemsController {
} }
} }
/**
* Removes a localized description of a category system.
*
* @param categorySystemIdentifier Identifier of the category system.
* @param localeParam The locale of the description.
*
* @return Redirect to the details page of the category system.
*/
@POST @POST
@Path( @Path(
"categorysystems/{identifier}/description/${locale}/remove") "categorysystems/{identifier}/description/${locale}/remove")
@ -596,6 +677,15 @@ public class CategorySystemsController {
} }
} }
/**
* Adds an owner to a category system.
*
* @param categorySystemIdentifier Identifier of teh category system.
* @param applicationUuid UUID of the new owner.
* @param context An optional context.
*
* @return Redirect to the details page of the category system.
*/
@POST @POST
@Path("/{categorySystemIdentifier}/owners/add") @Path("/{categorySystemIdentifier}/owners/add")
@AuthorizationRequired @AuthorizationRequired
@ -675,6 +765,15 @@ public class CategorySystemsController {
} }
} }
/**
* Remove an owner from a category system.
*
* @param categorySystemIdentifier Identifier of teh category system.
* @param applicationUuid UUID of the owner to remove.
* @param confirmed Was the deletion confirmed by the user?
*
* @return Redirect to the details page of the category system.
*/
@POST @POST
@Path("/{categorySystemIdentifier}/owners/${applicationUuid}/remove") @Path("/{categorySystemIdentifier}/owners/${applicationUuid}/remove")
@AuthorizationRequired @AuthorizationRequired

View File

@ -38,6 +38,11 @@ import javax.transaction.Transactional;
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
/**
* Model providing the data for the table of category systems.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped @RequestScoped
@Named("CategorySystemsTableModel") @Named("CategorySystemsTableModel")
public class CategorySystemsTableModel { public class CategorySystemsTableModel {
@ -45,6 +50,13 @@ public class CategorySystemsTableModel {
@Inject @Inject
private DomainRepository domainRepository; private DomainRepository domainRepository;
/**
* Get all available category systems
*
* @return A list of
* {@link org.libreccm.ui.admin.categories.CategorySystemTableRow}
* items, one for each available category.
*/
@AuthorizationRequired @AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional @Transactional
@ -57,6 +69,16 @@ public class CategorySystemsTableModel {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
/**
* Helper method for building a
* {@link org.libreccm.ui.admin.categories.CategorySystemTableRow} instance
* for a category system.
*
* @param domain The domain (category system) to convert.
*
* @return A {@link org.libreccm.ui.admin.categories.CategorySystemTableRow}
* instance for the category.
*/
private CategorySystemTableRow buildTableRow(final Domain domain) { private CategorySystemTableRow buildTableRow(final Domain domain) {
final CategorySystemTableRow row = new CategorySystemTableRow(); final CategorySystemTableRow row = new CategorySystemTableRow();

View File

@ -18,7 +18,10 @@
*/ */
package org.libreccm.ui.admin.categories; package org.libreccm.ui.admin.categories;
import org.libreccm.categorization.Domain;
/** /**
* DTO with the data about a {@link Domain} shown in the UI.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2020 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
/**
* UI for managing category systems (domains) and categories.
*/
package org.libreccm.ui.admin.categories;

View File

@ -38,6 +38,7 @@ import javax.ws.rs.GET;
import javax.ws.rs.Path; import javax.ws.rs.Path;
/** /**
* Controller for the UI for managing the configuration of CCM.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -55,6 +56,11 @@ public class ConfigurationController {
@Inject @Inject
private Models models; private Models models;
/**
* Show all available configurations (groups of settings).
*
* @return The template to use.
*/
@GET @GET
@Path("/") @Path("/")
@AuthorizationRequired @AuthorizationRequired
@ -73,6 +79,16 @@ public class ConfigurationController {
return "org/libreccm/ui/admin/configuration/configuration.xhtml"; return "org/libreccm/ui/admin/configuration/configuration.xhtml";
} }
/**
* Helper method for converting a
* {@link org.libreccm.configuration.ConfigurationInfo} instance into a
* {@link org.libreccm.ui.admin.configuration.ConfigurationTableEntry}
* instance.
*
* @param confInfo Configuration info to convert.
*
* @return A {@link ConfigurationTableEntry} for the configuration.
*/
private ConfigurationTableEntry buildTableEntry( private ConfigurationTableEntry buildTableEntry(
final ConfigurationInfo confInfo final ConfigurationInfo confInfo
) { ) {

View File

@ -27,11 +27,14 @@ import java.util.Set;
import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.ApplicationScoped;
/** /**
* {@link AdminPage} implementation providing the UI for managing the
* configuration of CCM.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ApplicationScoped @ApplicationScoped
public class ConfigurationPage implements AdminPage { public class ConfigurationPage implements AdminPage {
@Override @Override
public Set<Class<?>> getControllerClasses() { public Set<Class<?>> getControllerClasses() {
final Set<Class<?>> classes = new HashSet<>(); final Set<Class<?>> classes = new HashSet<>();
@ -76,4 +79,5 @@ public class ConfigurationPage implements AdminPage {
public int getPosition() { public int getPosition() {
return 30; return 30;
} }
} }

View File

@ -21,6 +21,7 @@ package org.libreccm.ui.admin.configuration;
import java.util.Objects; import java.util.Objects;
/** /**
* A row in the table of available configurations.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */

View File

@ -54,6 +54,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
/** /**
* Controller for the UI for viewing and editing settings.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -78,6 +79,12 @@ public class SettingsController {
@Inject @Inject
private SettingManager settingManager; private SettingManager settingManager;
/**
* Show all settings of a configuration.
*
* @param configurationClass The configuration class
* @return The template to use.
*/
@GET @GET
@Path("/") @Path("/")
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
@ -146,6 +153,13 @@ public class SettingsController {
return "org/libreccm/ui/admin/configuration/settings.xhtml"; return "org/libreccm/ui/admin/configuration/settings.xhtml";
} }
/**
* Helper method for building a {@link SettingsTableEntry} for a setting.
*
* @param settingInfo The setting to convert.
* @param configuration The configuration to which the settings belongs.
* @return A {@link SettingsTableEntry} for the setting.
*/
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
private SettingsTableEntry buildSettingsTableEntry( private SettingsTableEntry buildSettingsTableEntry(
final SettingInfo settingInfo, final SettingInfo settingInfo,

View File

@ -21,6 +21,7 @@ package org.libreccm.ui.admin.configuration;
import java.util.Objects; import java.util.Objects;
/** /**
* Data for row in the table of settings of a configuration.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2020 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
/**
* UI for editing the configuration of LibreCCM.
*/
package org.libreccm.ui.admin.configuration;

View File

@ -28,6 +28,7 @@ import javax.ws.rs.GET;
import javax.ws.rs.Path; import javax.ws.rs.Path;
/** /**
* Controller for the dashboard page (start page) of the Admin UI:
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -36,6 +37,11 @@ import javax.ws.rs.Path;
@Path("/") @Path("/")
public class DashboardController { public class DashboardController {
/**
* Show the dashboard page.
*
* @return The template to use.
*/
@GET @GET
@Path("/") @Path("/")
@AuthorizationRequired @AuthorizationRequired

View File

@ -20,7 +20,6 @@ package org.libreccm.ui.admin.dashboard;
import org.libreccm.ui.admin.AdminConstants; import org.libreccm.ui.admin.AdminConstants;
import org.libreccm.ui.admin.AdminPage; import org.libreccm.ui.admin.AdminPage;
import org.libreccm.ui.admin.configuration.ConfigurationController;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@ -28,11 +27,13 @@ import java.util.Set;
import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.ApplicationScoped;
/** /**
* {@link AdminPage} implementation for the dashboard page.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ApplicationScoped @ApplicationScoped
public class DashboardPage implements AdminPage { public class DashboardPage implements AdminPage {
@Override @Override
public Set<Class<?>> getControllerClasses() { public Set<Class<?>> getControllerClasses() {
final Set<Class<?>> classes = new HashSet<>(); final Set<Class<?>> classes = new HashSet<>();
@ -76,4 +77,5 @@ public class DashboardPage implements AdminPage {
public int getPosition() { public int getPosition() {
return 0; return 0;
} }
} }

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2020 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
/**
* Start page of the Admin UI.
*/
package org.libreccm.ui.admin.dashboard;

View File

@ -25,17 +25,30 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
/** /**
* Data for an export task.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
public class ExportTask { public class ExportTask {
/**
* Name of the export archive.
*/
private final String name; private final String name;
/**
* When was the export task started?
*/
private final LocalDate started; private final LocalDate started;
/**
* The entities to export.
*/
private final Collection<Exportable> entities; private final Collection<Exportable> entities;
/**
* The status of the export task.
*/
private final ExportTaskStatus status; private final ExportTaskStatus status;
public ExportTask( public ExportTask(

View File

@ -25,17 +25,30 @@ import java.util.Comparator;
import java.util.Objects; import java.util.Objects;
/** /**
* Status of an export task.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
public class ExportTaskStatus implements Comparable<ExportTaskStatus> { public class ExportTaskStatus implements Comparable<ExportTaskStatus> {
/**
* Name of the export archive.
*/
private String name; private String name;
/**
* When was the task started?
*/
private LocalDateTime started; private LocalDateTime started;
/**
* Status of the export task.
*/
private ImExportTaskStatus status; private ImExportTaskStatus status;
/**
* If the proces throw an exception, it is stored here.
*/
private Throwable exception; private Throwable exception;
public String getName() { public String getName() {

View File

@ -41,11 +41,11 @@ import javax.mvc.Controller;
import javax.mvc.Models; import javax.mvc.Models;
import javax.ws.rs.FormParam; import javax.ws.rs.FormParam;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
/** /**
* Controller for the Import/Export UI.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -63,6 +63,12 @@ public class ImExportController {
@Inject @Inject
private Models models; private Models models;
/**
* Provides the main page with an overview of all running import/export
* processes.
*
* @return
*/
@GET @GET
@Path("/") @Path("/")
@AuthorizationRequired @AuthorizationRequired
@ -71,6 +77,11 @@ public class ImExportController {
return "org/libreccm/ui/admin/imexport/imexport.xhtml"; return "org/libreccm/ui/admin/imexport/imexport.xhtml";
} }
/**
* UI for starting exports.
*
* @return The template to use.
*/
@GET @GET
@Path("/export") @Path("/export")
@AuthorizationRequired @AuthorizationRequired
@ -99,6 +110,14 @@ public class ImExportController {
return "org/libreccm/ui/admin/imexport/export.xhtml"; return "org/libreccm/ui/admin/imexport/export.xhtml";
} }
/**
* Starts an export.
*
* @param selectedEntitiesParam The entity types selected for export.
* @param exportName The name of the export archive.
*
* @return Redirect to the main import/export page.
*/
@POST @POST
@Path("/export") @Path("/export")
@AuthorizationRequired @AuthorizationRequired
@ -135,6 +154,11 @@ public class ImExportController {
return "redirect:imexport"; return "redirect:imexport";
} }
/**
* Displays the import page that allows to select a import archive.
*
* @return The template to use.
*/
@GET @GET
@Path("/import") @Path("/import")
@AuthorizationRequired @AuthorizationRequired
@ -157,6 +181,13 @@ public class ImExportController {
return "org/libreccm/ui/admin/imexport/import.xhtml"; return "org/libreccm/ui/admin/imexport/import.xhtml";
} }
/**
* Execute an import.
*
* @param importArchive The name of the import archive to use.
*
* @return Redirect to to the main import/export page.
*/
@POST @POST
@Path("/import") @Path("/import")
@AuthorizationRequired @AuthorizationRequired
@ -169,10 +200,34 @@ public class ImExportController {
return "redirect:imexport"; return "redirect:imexport";
} }
/**
* Merge function for {@link Collectors#toMap(java.util.function.Function, java.util.function.Function, java.util.function.BinaryOperator, java.util.function.Supplier).
*
* @param str1 First key
* @param str2 Second key
*
* @return First key.
*
* @throws RuntimeException if both keys are equal.
*/
private String noDuplicateKeys(final String str1, final String str2) { private String noDuplicateKeys(final String str1, final String str2) {
if (str1.equals(str2)) {
throw new RuntimeException("No duplicate keys allowed."); throw new RuntimeException("No duplicate keys allowed.");
} else {
return str1;
}
} }
/**
* Helper method for adding required entities to an export task. Some entity
* types require also other entity types. This method traverses through the
* selected entity types of an export and adds required entity types if
* necessary.
*
* @param selectedNodes The selected entity types.
*
* @return The final list of exported types.
*/
private Set<EntityImExporterTreeNode> addRequiredEntities( private Set<EntityImExporterTreeNode> addRequiredEntities(
final Set<EntityImExporterTreeNode> selectedNodes final Set<EntityImExporterTreeNode> selectedNodes
) { ) {
@ -196,6 +251,16 @@ public class ImExportController {
} }
} }
/**
* Helper function to build an
* {@link org.libreccm.ui.admin.imexport.ImportOption} instance from a
* {@link org.libreccm.imexport.ImportManifest}.
*
* @param manifest The manifest to map to a
* {@link org.libreccm.ui.admin.imexport.ImportOption}.
*
* @return An {@link org.libreccm.ui.admin.imexport.ImportOption} instance.
*/
private ImportOption buildImportOption(final ImportManifest manifest) { private ImportOption buildImportOption(final ImportManifest manifest) {
return new ImportOption( return new ImportOption(
manifest.getImportName(), manifest.getImportName(),

View File

@ -27,6 +27,7 @@ import java.util.Set;
import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.ApplicationScoped;
/** /**
* Provides the UI for importing and exporting entities.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */

View File

@ -19,13 +19,23 @@
package org.libreccm.ui.admin.imexport; package org.libreccm.ui.admin.imexport;
/** /**
* Enumeration for the possible states of an export or import task.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
public enum ImExportTaskStatus { public enum ImExportTaskStatus {
/**
* An error occured during the process.
*/
ERROR, ERROR,
/**
* The import or export task is finished.
*/
FINISHED, FINISHED,
/**
* The task is still running.
*/
RUNNING, RUNNING,
} }

View File

@ -29,6 +29,8 @@ import javax.inject.Inject;
import javax.transaction.Transactional; import javax.transaction.Transactional;
/** /**
* Listens for CDI events fired by {@link org.libreccm.ui.admin.imexport.ImportExportTaskManager}
* and executes tasks.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -38,7 +40,12 @@ public class ImExportTasks {
@Inject @Inject
private ImportExport importExport; private ImportExport importExport;
/**
* Listens for {@link org.libreccm.ui.admin.imexport.ExportTask}s.
*
* @param task The task to execute.
* @return The task.
*/
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public ExportTask exportEntities(@ObservesAsync final ExportTask task) { public ExportTask exportEntities(@ObservesAsync final ExportTask task) {
final Collection<Exportable> entities = task.getEntities(); final Collection<Exportable> entities = task.getEntities();
@ -49,6 +56,12 @@ public class ImExportTasks {
return task; return task;
} }
/**
* Listens for {@link org.libreccm.ui.admin.imexport.ImportTask}s.
*
* @param task The task to execute.
* @return The task.
*/
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public void importEntitites(@ObservesAsync final ImportTask task) { public void importEntitites(@ObservesAsync final ImportTask task) {
final String importName = task.getName(); final String importName = task.getName();
@ -56,5 +69,4 @@ public class ImExportTasks {
importExport.importEntities(importName); importExport.importEntities(importName);
} }
} }

View File

@ -30,6 +30,7 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.concurrent.CompletionStage;
import javax.ejb.Schedule; import javax.ejb.Schedule;
import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.ApplicationScoped;
@ -43,6 +44,7 @@ import javax.persistence.criteria.Root;
import javax.transaction.Transactional; import javax.transaction.Transactional;
/** /**
* Provides the backend for importing and exporting entities.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -54,17 +56,34 @@ public class ImportExportTaskManager {
ImportExportTaskManager.class ImportExportTaskManager.class
); );
/**
* Entity manager used for some special queries. To execute import and
* export tasks concurrently CDI events are used which are processed by the
* {@link ImExportTasks} class.
*/
@Inject @Inject
private EntityManager entityManager; private EntityManager entityManager;
/**
* CDI event sender for export tasks.
*/
@Inject @Inject
private Event<ExportTask> exportTaskSender; private Event<ExportTask> exportTaskSender;
/**
* CDI event sender for import tasks.
*/
@Inject @Inject
private Event<ImportTask> importTaskSender; private Event<ImportTask> importTaskSender;
/**
* Status of all active export tasks.
*/
private final SortedSet<ExportTaskStatus> exportTasks; private final SortedSet<ExportTaskStatus> exportTasks;
/**
* Status of all active import tasks.
*/
private final SortedSet<ImportTaskStatus> importTasks; private final SortedSet<ImportTaskStatus> importTasks;
public ImportExportTaskManager() { public ImportExportTaskManager() {
@ -80,14 +99,31 @@ public class ImportExportTaskManager {
); );
} }
/**
* Returns the active export tasks.
*
* @return All active export tasks.
*/
public SortedSet<ExportTaskStatus> getExportTasks() { public SortedSet<ExportTaskStatus> getExportTasks() {
return Collections.unmodifiableSortedSet(exportTasks); return Collections.unmodifiableSortedSet(exportTasks);
} }
/**
* Returns the active import tasks.
*
* @return All active import tasks.
*/
public SortedSet<ImportTaskStatus> getImportTasks() { public SortedSet<ImportTaskStatus> getImportTasks() {
return Collections.unmodifiableSortedSet(importTasks); return Collections.unmodifiableSortedSet(importTasks);
} }
/**
* Export all entities of the selected entity types.
*
* @param exportTypes The entity types to export.
* @param exportName Name of the export archive.
*
*/
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public void exportEntities( public void exportEntities(
final Set<Class<? extends Exportable>> exportTypes, final Set<Class<? extends Exportable>> exportTypes,
@ -107,7 +143,7 @@ public class ImportExportTaskManager {
taskStatus.setStarted(LocalDateTime.now()); taskStatus.setStarted(LocalDateTime.now());
exportTaskSender.fireAsync( exportTaskSender.fireAsync(
new ExportTask(exportName, LocalDate.now(), entities, taskStatus) new ExportTask(exportName, LocalDate.now(), entities, taskStatus)
).handle((task , ex) -> handleExportTaskResult(task, ex, taskStatus)); ).handle((task, ex) -> handleExportTaskResult(task, ex, taskStatus));
taskStatus.setStatus(ImExportTaskStatus.RUNNING); taskStatus.setStatus(ImExportTaskStatus.RUNNING);
exportTasks.add(taskStatus); exportTasks.add(taskStatus);
@ -124,13 +160,27 @@ public class ImportExportTaskManager {
importTasks.add(taskStatus); importTasks.add(taskStatus);
} }
/**
* Called every 5 minutes to remove finished tasks from {@link #exportTasks}
* and and {@link #importTasks}.
*/
@Schedule(hour = "*", minute = "*/5", persistent = false) @Schedule(hour = "*", minute = "*/5", persistent = false)
protected void removeFinishedTasks() { protected void removeFinishedTasks() {
exportTasks.removeIf(taskStatus -> taskStatus.getStatus() == ImExportTaskStatus.FINISHED); exportTasks.removeIf(
// importTasks.removeIf(taskStatus -> taskStatus.getStatus() == ImExportTaskStatus.FINISHED); taskStatus -> taskStatus.getStatus() == ImExportTaskStatus.FINISHED
);
importTasks.removeIf(
taskStatus -> taskStatus.getStatus() == ImExportTaskStatus.FINISHED
);
} }
/**
* Collects the entities of the provided types for exporting.
*
* @param ofType The entity type.
*
* @return All entities of the provided type.
*/
private Set<? extends Exportable> collectEntities( private Set<? extends Exportable> collectEntities(
final Class<Exportable> ofType final Class<Exportable> ofType
) { ) {
@ -145,6 +195,19 @@ public class ImportExportTaskManager {
); );
} }
/**
* Handler function for processing the result of an export tasks.
*
* @param task The task.
* @param ex Exception thrown during the export process. If the export
* process run without errors, this parameter will be
* {@code null}.
* @param status The status of the task.
*
* @return The task.
*
* @see CompletionStage#handle(java.util.function.BiFunction)
*/
private Object handleExportTaskResult( private Object handleExportTaskResult(
final ExportTask task, final Throwable ex, final ExportTaskStatus status final ExportTask task, final Throwable ex, final ExportTaskStatus status
) { ) {
@ -159,6 +222,19 @@ public class ImportExportTaskManager {
return task; return task;
} }
/**
* Handler function for processing the result of an import tasks.
*
* @param task The task.
* @param ex Exception thrown during the import process. If the import
* process run without errors, this parameter will be
* {@code null}.
* @param status The status of the task.
*
* @return The task.
*
* @see CompletionStage#handle(java.util.function.BiFunction)
*/
private Object handleImportTaskResult( private Object handleImportTaskResult(
final ImportTask task, final Throwable ex, final ImportTaskStatus status final ImportTask task, final Throwable ex, final ImportTaskStatus status
) { ) {
@ -172,4 +248,5 @@ public class ImportExportTaskManager {
} }
return task; return task;
} }
} }

View File

@ -18,16 +18,26 @@
*/ */
package org.libreccm.ui.admin.imexport; package org.libreccm.ui.admin.imexport;
import org.libreccm.imexport.ImportManifest;
import java.util.Objects; import java.util.Objects;
/** /**
* Provides a preprocessed {@link ImportManifest} for easier use in a template.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
public class ImportOption implements Comparable<ImportOption> { public class ImportOption implements Comparable<ImportOption> {
/**
* Name of the import.
*/
private final String importName; private final String importName;
/**
* Label of the import, includes the relevant data from the
* {@link ImportManifest}.
*/
private final String label; private final String label;
public ImportOption( public ImportOption(

View File

@ -21,15 +21,25 @@ package org.libreccm.ui.admin.imexport;
import java.time.LocalDate; import java.time.LocalDate;
/** /**
* Data for an import task.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
public class ImportTask { public class ImportTask {
/**
* Name of the import archive.
*/
private final String name; private final String name;
/**
* When was the import task started?
*/
private final LocalDate started; private final LocalDate started;
/**
* The status of the import task.
*/
private final ImportTaskStatus status; private final ImportTaskStatus status;
public ImportTask( public ImportTask(

View File

@ -25,24 +25,36 @@ import java.util.Comparator;
import java.util.Objects; import java.util.Objects;
/** /**
* Status of an import task.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
public class ImportTaskStatus implements Comparable<ImportTaskStatus> { public class ImportTaskStatus implements Comparable<ImportTaskStatus> {
/**
* Name of the import archive.
*/
private String name; private String name;
/**
* When was the task started?
*/
private LocalDateTime started; private LocalDateTime started;
/**
* Status of the import task.
*/
private ImExportTaskStatus status; private ImExportTaskStatus status;
/**
* If the proces throw an exception, it is stored here.
*/
private Throwable exception; private Throwable exception;
public String getName() { public String getName() {
return name; return name;
} }
protected void setName(final String name) { protected void setName(final String name) {
this.name = name; this.name = name;
} }
@ -104,7 +116,6 @@ public class ImportTaskStatus implements Comparable<ImportTaskStatus> {
return status == other.getStatus(); return status == other.getStatus();
} }
public boolean canEqual(final Object obj) { public boolean canEqual(final Object obj) {
return obj instanceof ImportTaskStatus; return obj instanceof ImportTaskStatus;
} }

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2020 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
/**
* UI for importing and exporting entities.
*/
package org.libreccm.ui.admin.imexport;

View File

@ -22,7 +22,6 @@ import org.libreccm.sites.Site;
import org.libreccm.theming.ThemeInfo; import org.libreccm.theming.ThemeInfo;
import org.libreccm.ui.Message; import org.libreccm.ui.Message;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -33,6 +32,7 @@ import javax.enterprise.context.RequestScoped;
import javax.inject.Named; import javax.inject.Named;
/** /**
* Model providing the properties of a site for the UI.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -96,6 +96,12 @@ public class SiteDetailsModel {
messages.add(message); messages.add(message);
} }
/**
* Set the properties of this model to the values of the properties of the
* provided site.
*
* @param site The site.
*/
protected void setSite(final Site site) { protected void setSite(final Site site) {
Objects.requireNonNull(site); Objects.requireNonNull(site);

View File

@ -42,6 +42,8 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
/** /**
* Controller for processing the {@code POST} requests from the form for
* creating and editing sites.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -71,6 +73,11 @@ public class SiteFormController {
@FormParam("defaultTheme") @FormParam("defaultTheme")
private String defaultTheme; private String defaultTheme;
/**
* Create a new site.
*
* @return Redirect to the sites overview.
*/
@POST @POST
@Path("/new") @Path("/new")
@AuthorizationRequired @AuthorizationRequired
@ -90,6 +97,12 @@ public class SiteFormController {
return "redirect:sites"; return "redirect:sites";
} }
/**
* Update a site with the data from the form.
*
* @param siteIdentifierParam The identifier of the site to update.
* @return Redirect to the details page of the site.
*/
@POST @POST
@Path("/{siteIdentifier}/edit") @Path("/{siteIdentifier}/edit")
@AuthorizationRequired @AuthorizationRequired
@ -147,6 +160,9 @@ public class SiteFormController {
} }
} }
/**
* Helper method for resetting the default site of an installation.
*/
private void resetDefaultSite() { private void resetDefaultSite() {
final Optional<Site> result = siteRepository final Optional<Site> result = siteRepository
.findDefaultSite(); .findDefaultSite();

View File

@ -19,6 +19,7 @@
package org.libreccm.ui.admin.sites; package org.libreccm.ui.admin.sites;
/** /**
* Data for a row in the table showing all available sites.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */

View File

@ -47,6 +47,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
/** /**
* Primary controller for the UI for managing sites.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -73,6 +74,11 @@ public class SitesController {
@Inject @Inject
private Themes themes; private Themes themes;
/**
* Show all available sites.
*
* @return The template to use.
*/
@GET @GET
@Path("/") @Path("/")
@AuthorizationRequired @AuthorizationRequired
@ -91,6 +97,13 @@ public class SitesController {
return "org/libreccm/ui/admin/sites/sites.xhtml"; return "org/libreccm/ui/admin/sites/sites.xhtml";
} }
/**
* Show the details of a site.
*
* @param siteIdentifierParam Identifier of the site to show.
*
* @return The template to use.
*/
@GET @GET
@Path("/{siteIdentifier}/details") @Path("/{siteIdentifier}/details")
@AuthorizationRequired @AuthorizationRequired
@ -137,6 +150,11 @@ public class SitesController {
} }
} }
/**
* Show the form for creating a new site.
*
* @return The template to use.
*/
@GET @GET
@Path("/new") @Path("/new")
@AuthorizationRequired @AuthorizationRequired
@ -147,6 +165,13 @@ public class SitesController {
return "org/libreccm/ui/admin/sites/site-form.xhtml"; return "org/libreccm/ui/admin/sites/site-form.xhtml";
} }
/**
* Show the form for editing a site.
*
* @param siteIdentifierParam The identifier of the site to edit.
*
* @return The template to use.
*/
@GET @GET
@Path("/{siteIdentifier}/edit") @Path("/{siteIdentifier}/edit")
@AuthorizationRequired @AuthorizationRequired
@ -193,6 +218,14 @@ public class SitesController {
} }
} }
/**
* Delete a site.
*
* @param siteIdentifierParam The identifier of the site to delete.
* @param confirmed Was the deletion confirmed by the user?
*
* @return Redirect to the list of all available sites.
*/
@POST @POST
@Path("/{identifier}/delete") @Path("/{identifier}/delete")
@AuthorizationRequired @AuthorizationRequired
@ -229,6 +262,15 @@ public class SitesController {
return "redirect:sites"; return "redirect:sites";
} }
/**
* Helper method for building a
* {@link org.libreccm.ui.admin.sites.SiteTableRow} instance for a
* {@link Site}.
*
* @param site The site.
*
* @return A {@link SiteTableRow} instance for the site.
*/
private SiteTableRow buildSiteTableRow(final Site site) { private SiteTableRow buildSiteTableRow(final Site site) {
final SiteTableRow row = new SiteTableRow(); final SiteTableRow row = new SiteTableRow();
row.setSiteId(site.getObjectId()); row.setSiteId(site.getObjectId());

View File

@ -27,6 +27,7 @@ import java.util.Set;
import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.ApplicationScoped;
/** /**
* {@link AdminPage} implementation for the UI for managing sites.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2020 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
/**
* UI for managing sites.
*/
package org.libreccm.ui.admin.sites;

View File

@ -30,6 +30,7 @@ import javax.ws.rs.GET;
import javax.ws.rs.Path; import javax.ws.rs.Path;
/** /**
* Controller for the systeminformations page.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -38,9 +39,11 @@ import javax.ws.rs.Path;
@Path("/systeminformation") @Path("/systeminformation")
public class SystemInformationController { public class SystemInformationController {
@Inject /**
private MvcContext mvc; * Show the system information page.
*
* @return The template to use.
*/
@GET @GET
@Path("/") @Path("/")
@AuthorizationRequired @AuthorizationRequired

View File

@ -30,6 +30,7 @@ import javax.enterprise.context.RequestScoped;
import javax.inject.Named; import javax.inject.Named;
/** /**
* Model providing the date for the system information page.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -37,6 +38,12 @@ import javax.inject.Named;
@Named("SystemInformationModel") @Named("SystemInformationModel")
public class SystemInformationModel { public class SystemInformationModel {
/**
* Get some data about this LibreCCM installation, eg. version, application
* name, and homepage.
*
* @return The information about this CCM installation.
*/
public Map<String, String> getCcmSystemInformation() { public Map<String, String> getCcmSystemInformation() {
final Properties properties = new Properties(); final Properties properties = new Properties();
try { try {
@ -64,6 +71,11 @@ public class SystemInformationModel {
return sysInfo; return sysInfo;
} }
/**
* Get the Java System Properties from the runtime environment.
*
* @return The Java System Properties of the runtime environment.
*/
public Map<String, String> getJavaSystemProperties() { public Map<String, String> getJavaSystemProperties() {
final Properties systemProperties = System.getProperties(); final Properties systemProperties = System.getProperties();
final Map<String, String> result = new HashMap<>(); final Map<String, String> result = new HashMap<>();
@ -74,4 +86,5 @@ public class SystemInformationModel {
} }
return result; return result;
} }
} }

View File

@ -27,6 +27,7 @@ import org.libreccm.ui.admin.AdminPage;
import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.ApplicationScoped;
/** /**
* {@link AdminPage} implementaton for the system information page.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2020 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
/**
* UI for inspecting some information about LibreCCM and the runtime environment.
*/
package org.libreccm.ui.admin.systeminformation;

View File

@ -21,12 +21,7 @@ package org.libreccm.ui.admin.themes;
import org.libreccm.core.CoreConstants; import org.libreccm.core.CoreConstants;
import org.libreccm.security.AuthorizationRequired; import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.RequiresPrivilege; import org.libreccm.security.RequiresPrivilege;
import org.libreccm.theming.ThemeInfo;
import org.libreccm.theming.Themes; import org.libreccm.theming.Themes;
import org.libreccm.theming.manager.ThemeManager;
;
import java.util.List;
import javax.enterprise.context.RequestScoped; import javax.enterprise.context.RequestScoped;
import javax.inject.Inject; import javax.inject.Inject;
@ -40,11 +35,10 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
/** /**
* Primary controller for the UI for managing themes.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@RequestScoped @RequestScoped
@Controller @Controller
@Path("/themes") @Path("/themes")
@ -53,10 +47,14 @@ public class ThemesController {
@Inject @Inject
private Themes themes; private Themes themes;
@Inject @Inject
private Models models; private Models models;
/**
* Show all available themes.
*
* @return The template to use.
*/
@GET @GET
@Path("/") @Path("/")
@AuthorizationRequired @AuthorizationRequired
@ -66,6 +64,14 @@ public class ThemesController {
return "org/libreccm/ui/admin/themes/themes.xhtml"; return "org/libreccm/ui/admin/themes/themes.xhtml";
} }
/**
* Create a new theme.
*
* @param themeName The name of the new theme.
* @param providerName The provider of the new theme.
*
* @return Redirect to the list of available themes.
*/
@POST @POST
@Path("/new") @Path("/new")
@AuthorizationRequired @AuthorizationRequired
@ -80,6 +86,13 @@ public class ThemesController {
return "redirect:themes/"; return "redirect:themes/";
} }
/**
* (Re-)Publish a theme.
*
* @param themeName The theme to (re-)publish.
*
* @return Redirect to the list of themes.
*/
@POST @POST
@Path("/{themeName}/publish") @Path("/{themeName}/publish")
@AuthorizationRequired @AuthorizationRequired
@ -91,6 +104,13 @@ public class ThemesController {
return "redirect:themes/"; return "redirect:themes/";
} }
/**
* Unpublish a theme.
*
* @param themeName The theme to unpublish.
*
* @return Redirect to the list of themes.
*/
@POST @POST
@Path("/{themeName}/unpublish") @Path("/{themeName}/unpublish")
@AuthorizationRequired @AuthorizationRequired
@ -102,6 +122,13 @@ public class ThemesController {
return "redirect:themes/"; return "redirect:themes/";
} }
/**
* Delete a theme.
*
* @param themeName The theme to delete.
*
* @return Redirect to the list of themes.
*/
@POST @POST
@Path("/{themeName}/delete") @Path("/{themeName}/delete")
@AuthorizationRequired @AuthorizationRequired
@ -113,5 +140,4 @@ public class ThemesController {
return "redirect:themes/"; return "redirect:themes/";
} }
} }

View File

@ -34,12 +34,11 @@ import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.enterprise.context.RequestScoped; import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Instance;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
/** /**
* Model for the themes page.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -53,6 +52,11 @@ public class ThemesModel {
@Inject @Inject
private Themes themes; private Themes themes;
/**
* Get all available themes.
*
* @return A list of all available themes.
*/
public List<ThemesTableRow> getThemes() { public List<ThemesTableRow> getThemes() {
return themes return themes
.getAvailableThemes() .getAvailableThemes()
@ -61,6 +65,12 @@ public class ThemesModel {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
/**
* Get all available {@link org.libreccm.theming.ThemeProvider}s which
* support changes and draft themes.
*
* @return
*/
public Map<String, String> getProviderOptions() { public Map<String, String> getProviderOptions() {
return themes return themes
.getThemeProviders() .getThemeProviders()
@ -75,8 +85,15 @@ public class ThemesModel {
); );
} }
/**
* Helper function for mapping a {@link ThemeInfo} instance to a
* {@link ThemesTableRow} instance.
*
* @param themeInfo The {@link ThemeInfo} instance to map.
*
* @return A {@link ThemesTableRow} instance for the theme.
*/
private ThemesTableRow mapThemeInfo(final ThemeInfo themeInfo) { private ThemesTableRow mapThemeInfo(final ThemeInfo themeInfo) {
final LocalizedTextsUtil textsUtil = globalizationHelper final LocalizedTextsUtil textsUtil = globalizationHelper
.getLocalizedTextsUtil(AdminConstants.ADMIN_BUNDLE); .getLocalizedTextsUtil(AdminConstants.ADMIN_BUNDLE);

View File

@ -27,6 +27,7 @@ import java.util.Set;
import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.ApplicationScoped;
/** /**
* {@link AdminPage} implementation for the UI for managing themes.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */

View File

@ -24,6 +24,7 @@ import java.io.Serializable;
import java.util.Comparator; import java.util.Comparator;
/** /**
* Data of theme for displaying in the table of available themes.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2020 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
/**
* UI for managing themes.
*/
package org.libreccm.ui.admin.themes;