SEBSERV-133 added deletion for user activity logs for SEB server admins
This commit is contained in:
		
							parent
							
								
									9438206c9d
								
							
						
					
					
						commit
						a2d2ca6751
					
				
					 17 changed files with 439 additions and 28 deletions
				
			
		|  | @ -323,28 +323,32 @@ public class ExamForm implements TemplateComposer { | ||||||
|                         .withInputSpan(3) |                         .withInputSpan(3) | ||||||
|                         .withEmptyCellSeparation(false)) |                         .withEmptyCellSeparation(false)) | ||||||
| 
 | 
 | ||||||
|                 .addField(FormBuilder.text( |  | ||||||
|                         Domain.EXAM.ATTR_EXTERNAL_ID, |  | ||||||
|                         FORM_QUIZ_ID_TEXT_KEY, |  | ||||||
|                         exam.externalId) |  | ||||||
|                         .readonly(true) |  | ||||||
|                         .withEmptyCellSeparation(false)) |  | ||||||
|                 .addField(FormBuilder.text( |                 .addField(FormBuilder.text( | ||||||
|                         QuizData.QUIZ_ATTR_START_URL, |                         QuizData.QUIZ_ATTR_START_URL, | ||||||
|                         FORM_QUIZ_URL_TEXT_KEY, |                         FORM_QUIZ_URL_TEXT_KEY, | ||||||
|                         exam.startURL) |                         exam.startURL) | ||||||
|                         .readonly(true) |                         .readonly(true) | ||||||
|                         .withInputSpan(7)) |                         .withInputSpan(7) | ||||||
|  |                         .withEmptyCellSeparation(false)) | ||||||
| 
 | 
 | ||||||
|                 .addField(FormBuilder.text( |                 .addField(FormBuilder.text( | ||||||
|                         QuizData.QUIZ_ATTR_DESCRIPTION, |                         QuizData.QUIZ_ATTR_DESCRIPTION, | ||||||
|                         FORM_DESCRIPTION_TEXT_KEY, |                         FORM_DESCRIPTION_TEXT_KEY, | ||||||
|                         exam.description) |                         exam.description) | ||||||
|                         .asHTML() |                         .asHTML(50) | ||||||
|                         .readonly(true) |                         .readonly(true) | ||||||
|                         .withInputSpan(6) |                         .withInputSpan(6) | ||||||
|                         .withEmptyCellSeparation(false)) |                         .withEmptyCellSeparation(false)) | ||||||
| 
 | 
 | ||||||
|  |                 .addField(FormBuilder.text( | ||||||
|  |                         Domain.EXAM.ATTR_EXTERNAL_ID, | ||||||
|  |                         FORM_QUIZ_ID_TEXT_KEY, | ||||||
|  |                         exam.externalId) | ||||||
|  |                         .readonly(true) | ||||||
|  |                         .withLabelSpan(2) | ||||||
|  |                         .withInputSpan(6) | ||||||
|  |                         .withEmptyCellSeparation(false)) | ||||||
|  | 
 | ||||||
|                 .addField(FormBuilder.text( |                 .addField(FormBuilder.text( | ||||||
|                         Domain.EXAM.ATTR_STATUS + "_display", |                         Domain.EXAM.ATTR_STATUS + "_display", | ||||||
|                         FORM_STATUS_TEXT_KEY, |                         FORM_STATUS_TEXT_KEY, | ||||||
|  | @ -352,7 +356,8 @@ public class ExamForm implements TemplateComposer { | ||||||
|                         .readonly(true) |                         .readonly(true) | ||||||
|                         .withLabelSpan(2) |                         .withLabelSpan(2) | ||||||
|                         .withInputSpan(4) |                         .withInputSpan(4) | ||||||
|                         .withEmptyCellSpan(1)) |                         .withEmptyCellSeparation(false)) | ||||||
|  | 
 | ||||||
|                 .addField(FormBuilder.singleSelection( |                 .addField(FormBuilder.singleSelection( | ||||||
|                         Domain.EXAM.ATTR_TYPE, |                         Domain.EXAM.ATTR_TYPE, | ||||||
|                         FORM_TYPE_TEXT_KEY, |                         FORM_TYPE_TEXT_KEY, | ||||||
|  | @ -400,11 +405,6 @@ public class ExamForm implements TemplateComposer { | ||||||
|                 .withExec(this.cancelModifyFunction()) |                 .withExec(this.cancelModifyFunction()) | ||||||
|                 .publishIf(() -> !readonly) |                 .publishIf(() -> !readonly) | ||||||
| 
 | 
 | ||||||
|                 .newAction(ActionDefinition.EXAM_DELETE) |  | ||||||
|                 .withEntityKey(entityKey) |  | ||||||
|                 .withExec(this.examDeletePopup.deleteWizardFunction(pageContext)) |  | ||||||
|                 .publishIf(() -> writeGrant && readonly) |  | ||||||
| 
 |  | ||||||
|                 .newAction(ActionDefinition.EXAM_MODIFY_SEB_RESTRICTION_DETAILS) |                 .newAction(ActionDefinition.EXAM_MODIFY_SEB_RESTRICTION_DETAILS) | ||||||
|                 .withEntityKey(entityKey) |                 .withEntityKey(entityKey) | ||||||
|                 .withExec(this.examSEBRestrictionSettings.settingsFunction(this.pageService)) |                 .withExec(this.examSEBRestrictionSettings.settingsFunction(this.pageService)) | ||||||
|  | @ -428,7 +428,12 @@ public class ExamForm implements TemplateComposer { | ||||||
|                 .withEntityKey(entityKey) |                 .withEntityKey(entityKey) | ||||||
|                 .withExec(action -> this.examSEBRestrictionSettings.setSEBRestriction(action, false, this.restService)) |                 .withExec(action -> this.examSEBRestrictionSettings.setSEBRestriction(action, false, this.restService)) | ||||||
|                 .publishIf(() -> sebRestrictionAvailable && readonly && modifyGrant && !importFromQuizData |                 .publishIf(() -> sebRestrictionAvailable && readonly && modifyGrant && !importFromQuizData | ||||||
|                         && BooleanUtils.isTrue(isRestricted)); |                         && BooleanUtils.isTrue(isRestricted)) | ||||||
|  | 
 | ||||||
|  |                 .newAction(ActionDefinition.EXAM_DELETE) | ||||||
|  |                 .withEntityKey(entityKey) | ||||||
|  |                 .withExec(this.examDeletePopup.deleteWizardFunction(pageContext)) | ||||||
|  |                 .publishIf(() -> writeGrant && readonly); | ||||||
| 
 | 
 | ||||||
|         // additional data in read-only view |         // additional data in read-only view | ||||||
|         if (readonly && !importFromQuizData) { |         if (readonly && !importFromQuizData) { | ||||||
|  |  | ||||||
|  | @ -38,7 +38,7 @@ import ch.ethz.seb.sebserver.gui.service.page.impl.ModelInputWizard.WizardAction | ||||||
| import ch.ethz.seb.sebserver.gui.service.page.impl.ModelInputWizard.WizardPage; | import ch.ethz.seb.sebserver.gui.service.page.impl.ModelInputWizard.WizardPage; | ||||||
| import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; | import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.DeleteAllClientEvents; | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.DeleteAllClientEvents; | ||||||
| import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; | import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; | ||||||
| 
 | 
 | ||||||
| @Lazy | @Lazy | ||||||
|  |  | ||||||
|  | @ -42,8 +42,8 @@ import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder; | ||||||
| import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; | import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; | ||||||
| import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; | import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetClientEventNames; | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetExtendedClientEventPage; | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetExtendedClientEventPage; | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetClientEventNames; |  | ||||||
| import ch.ethz.seb.sebserver.gui.table.ColumnDefinition; | import ch.ethz.seb.sebserver.gui.table.ColumnDefinition; | ||||||
| import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute; | import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute; | ||||||
| import ch.ethz.seb.sebserver.gui.table.EntityTable; | import ch.ethz.seb.sebserver.gui.table.EntityTable; | ||||||
|  |  | ||||||
|  | @ -8,18 +8,27 @@ | ||||||
| 
 | 
 | ||||||
| package ch.ethz.seb.sebserver.gui.content; | package ch.ethz.seb.sebserver.gui.content; | ||||||
| 
 | 
 | ||||||
|  | import java.util.List; | ||||||
| import java.util.function.BooleanSupplier; | import java.util.function.BooleanSupplier; | ||||||
|  | import java.util.function.Consumer; | ||||||
| import java.util.function.Function; | import java.util.function.Function; | ||||||
|  | import java.util.stream.Collectors; | ||||||
| 
 | 
 | ||||||
|  | import org.apache.tomcat.util.buf.StringUtils; | ||||||
| import org.eclipse.swt.widgets.Composite; | import org.eclipse.swt.widgets.Composite; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
| import org.springframework.beans.factory.annotation.Value; | import org.springframework.beans.factory.annotation.Value; | ||||||
| import org.springframework.context.annotation.Lazy; | import org.springframework.context.annotation.Lazy; | ||||||
| import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||||
|  | import org.springframework.util.MultiValueMap; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.Constants; | import ch.ethz.seb.sebserver.gbl.Constants; | ||||||
| import ch.ethz.seb.sebserver.gbl.api.API; | import ch.ethz.seb.sebserver.gbl.api.API; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.EntityType; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Domain; | import ch.ethz.seb.sebserver.gbl.model.Domain; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Entity; | import ch.ethz.seb.sebserver.gbl.model.Entity; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.model.EntityName; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; | import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; | import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserRole; | import ch.ethz.seb.sebserver.gbl.model.user.UserRole; | ||||||
|  | @ -37,6 +46,7 @@ import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; | ||||||
| import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputDialog; | import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputDialog; | ||||||
| import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; | import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetUserLogNames; | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetUserLogPage; | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetUserLogPage; | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount; | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount; | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; | import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; | ||||||
|  | @ -51,6 +61,8 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; | ||||||
| @GuiProfile | @GuiProfile | ||||||
| public class UserActivityLogs implements TemplateComposer { | public class UserActivityLogs implements TemplateComposer { | ||||||
| 
 | 
 | ||||||
|  |     private static final Logger log = LoggerFactory.getLogger(UserActivityLogs.class); | ||||||
|  | 
 | ||||||
|     private static final LocTextKey DETAILS_TITLE_TEXT_KEY = |     private static final LocTextKey DETAILS_TITLE_TEXT_KEY = | ||||||
|             new LocTextKey("sebserver.userlogs.details.title"); |             new LocTextKey("sebserver.userlogs.details.title"); | ||||||
|     private static final LocTextKey TITLE_TEXT_KEY = |     private static final LocTextKey TITLE_TEXT_KEY = | ||||||
|  | @ -93,16 +105,19 @@ public class UserActivityLogs implements TemplateComposer { | ||||||
|     private final ResourceService resourceService; |     private final ResourceService resourceService; | ||||||
|     private final I18nSupport i18nSupport; |     private final I18nSupport i18nSupport; | ||||||
|     private final WidgetFactory widgetFactory; |     private final WidgetFactory widgetFactory; | ||||||
|  |     private final UserActivityLogsDeletePopup userActivityLogsDeletePopup; | ||||||
|     private final int pageSize; |     private final int pageSize; | ||||||
| 
 | 
 | ||||||
|     public UserActivityLogs( |     public UserActivityLogs( | ||||||
|             final PageService pageService, |             final PageService pageService, | ||||||
|  |             final UserActivityLogsDeletePopup userActivityLogsDeletePopup, | ||||||
|             @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { |             @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { | ||||||
| 
 | 
 | ||||||
|         this.pageService = pageService; |         this.pageService = pageService; | ||||||
|         this.resourceService = pageService.getResourceService(); |         this.resourceService = pageService.getResourceService(); | ||||||
|         this.i18nSupport = this.resourceService.getI18nSupport(); |         this.i18nSupport = this.resourceService.getI18nSupport(); | ||||||
|         this.widgetFactory = pageService.getWidgetFactory(); |         this.widgetFactory = pageService.getWidgetFactory(); | ||||||
|  |         this.userActivityLogsDeletePopup = userActivityLogsDeletePopup; | ||||||
|         this.pageSize = pageSize; |         this.pageSize = pageSize; | ||||||
| 
 | 
 | ||||||
|         this.institutionFilter = new TableFilterAttribute( |         this.institutionFilter = new TableFilterAttribute( | ||||||
|  | @ -152,6 +167,17 @@ public class UserActivityLogs implements TemplateComposer { | ||||||
|                             } |                             } | ||||||
|                         }); |                         }); | ||||||
| 
 | 
 | ||||||
|  |         final Consumer<Boolean> deleteActionActivation = this.pageService.getActionActiviationPublisher( | ||||||
|  |                 pageContext, | ||||||
|  |                 ActionDefinition.LOGS_USER_ACTIVITY_DELETE_ALL); | ||||||
|  |         final Consumer<Boolean> detailsActionActivation = this.pageService.getActionActiviationPublisher( | ||||||
|  |                 pageContext, | ||||||
|  |                 ActionDefinition.LOGS_USER_ACTIVITY_SHOW_DETAILS); | ||||||
|  |         final Consumer<Integer> contentChangeListener = contentSize -> { | ||||||
|  |             deleteActionActivation.accept(contentSize > 0); | ||||||
|  |             detailsActionActivation.accept(contentSize > 0); | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|         // table |         // table | ||||||
|         final EntityTable<UserActivityLog> table = this.pageService.entityTableBuilder( |         final EntityTable<UserActivityLog> table = this.pageService.entityTableBuilder( | ||||||
|                 restService.getRestCall(GetUserLogPage.class)) |                 restService.getRestCall(GetUserLogPage.class)) | ||||||
|  | @ -207,6 +233,8 @@ public class UserActivityLogs implements TemplateComposer { | ||||||
|                 .withSelectionListener(this.pageService.getSelectionPublisher( |                 .withSelectionListener(this.pageService.getSelectionPublisher( | ||||||
|                         pageContext, |                         pageContext, | ||||||
|                         ActionDefinition.LOGS_USER_ACTIVITY_SHOW_DETAILS)) |                         ActionDefinition.LOGS_USER_ACTIVITY_SHOW_DETAILS)) | ||||||
|  | 
 | ||||||
|  |                 .withContentChangeListener(contentChangeListener) | ||||||
|                 .compose(pageContext.copyOf(content)); |                 .compose(pageContext.copyOf(content)); | ||||||
| 
 | 
 | ||||||
|         actionBuilder |         actionBuilder | ||||||
|  | @ -216,8 +244,40 @@ public class UserActivityLogs implements TemplateComposer { | ||||||
|                         action -> this.showDetails(action, table.getSingleSelectedROWData()), |                         action -> this.showDetails(action, table.getSingleSelectedROWData()), | ||||||
|                         EMPTY_SELECTION_TEXT) |                         EMPTY_SELECTION_TEXT) | ||||||
|                 .noEventPropagation() |                 .noEventPropagation() | ||||||
|                 .publishIf(table::hasAnyContent, false); |                 .publish(false) | ||||||
| 
 | 
 | ||||||
|  |                 .newAction(ActionDefinition.LOGS_USER_ACTIVITY_DELETE_ALL) | ||||||
|  |                 .withExec(action -> this.getOpenDelete(action, table.getFilterCriteria())) | ||||||
|  |                 .noEventPropagation() | ||||||
|  |                 .publishIf(isSEBAdmin, table.hasAnyContent()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private PageAction getOpenDelete(final PageAction pageAction, final MultiValueMap<String, String> filterCriteria) { | ||||||
|  |         try { | ||||||
|  |             final List<String> ids = this.pageService | ||||||
|  |                     .getRestService() | ||||||
|  |                     .getBuilder(GetUserLogNames.class) | ||||||
|  |                     .withQueryParams(filterCriteria) | ||||||
|  |                     .call() | ||||||
|  |                     .getOrThrow() | ||||||
|  |                     .stream() | ||||||
|  |                     .map(EntityName::getModelId) | ||||||
|  |                     .collect(Collectors.toList()); | ||||||
|  | 
 | ||||||
|  |             final PageAction deleteAction = pageAction.withAttribute( | ||||||
|  |                     PageContext.AttributeKeys.ENTITY_ID_LIST, | ||||||
|  |                     StringUtils.join(ids, Constants.COMMA)) | ||||||
|  |                     .withAttribute( | ||||||
|  |                             PageContext.AttributeKeys.ENTITY_LIST_TYPE, | ||||||
|  |                             EntityType.CLIENT_EVENT.name()); | ||||||
|  | 
 | ||||||
|  |             return this.userActivityLogsDeletePopup | ||||||
|  |                     .deleteWizardFunction(deleteAction.pageContext()) | ||||||
|  |                     .apply(deleteAction); | ||||||
|  |         } catch (final Exception e) { | ||||||
|  |             log.error("Unexpected error while try to open user activity log delete popup", e); | ||||||
|  |             return pageAction; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private String getLogTime(final UserActivityLog log) { |     private String getLogTime(final UserActivityLog log) { | ||||||
|  |  | ||||||
|  | @ -0,0 +1,152 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.content; | ||||||
|  | 
 | ||||||
|  | import java.util.function.BiFunction; | ||||||
|  | import java.util.function.Function; | ||||||
|  | import java.util.function.Predicate; | ||||||
|  | import java.util.function.Supplier; | ||||||
|  | 
 | ||||||
|  | import org.apache.commons.lang3.StringUtils; | ||||||
|  | import org.eclipse.swt.layout.GridData; | ||||||
|  | import org.eclipse.swt.widgets.Composite; | ||||||
|  | import org.eclipse.swt.widgets.Label; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  | import org.springframework.context.annotation.Lazy; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.Constants; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.API; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.util.Utils; | ||||||
|  | import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageService; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.impl.ModelInputWizard; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.impl.ModelInputWizard.WizardAction; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.impl.ModelInputWizard.WizardPage; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.DeleteAllUserLogs; | ||||||
|  | import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; | ||||||
|  | 
 | ||||||
|  | @Lazy | ||||||
|  | @Component | ||||||
|  | @GuiProfile | ||||||
|  | public class UserActivityLogsDeletePopup { | ||||||
|  | 
 | ||||||
|  |     private static final Logger log = LoggerFactory.getLogger(UserActivityLogsDeletePopup.class); | ||||||
|  | 
 | ||||||
|  |     private final static LocTextKey FORM_TITLE = | ||||||
|  |             new LocTextKey("sebserver.userlogs.delete.form.title"); | ||||||
|  |     private final static LocTextKey ACTION_DELETE = | ||||||
|  |             new LocTextKey("sebserver.userlogs.delete.action.delete"); | ||||||
|  |     private final static LocTextKey DELETE_CONFIRM_TITLE = | ||||||
|  |             new LocTextKey("sebserver.userlogs.delete.confirm.title"); | ||||||
|  | 
 | ||||||
|  |     private final PageService pageService; | ||||||
|  | 
 | ||||||
|  |     protected UserActivityLogsDeletePopup(final PageService pageService) { | ||||||
|  |         this.pageService = pageService; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Function<PageAction, PageAction> deleteWizardFunction(final PageContext pageContext) { | ||||||
|  |         return action -> { | ||||||
|  | 
 | ||||||
|  |             final ModelInputWizard<PageContext> wizard = | ||||||
|  |                     new ModelInputWizard<PageContext>( | ||||||
|  |                             action.pageContext().getParent().getShell(), | ||||||
|  |                             this.pageService.getWidgetFactory()) | ||||||
|  |                                     .setVeryLargeDialogWidth(); | ||||||
|  | 
 | ||||||
|  |             final String page1Id = "DELETE_PAGE"; | ||||||
|  |             final Predicate<PageContext> callback = pc -> doDelete(this.pageService, pc); | ||||||
|  |             final BiFunction<PageContext, Composite, Supplier<PageContext>> composePage1 = | ||||||
|  |                     (prefPageContext, content) -> composeDeleteDialog(content, | ||||||
|  |                             (prefPageContext != null) ? prefPageContext : pageContext); | ||||||
|  | 
 | ||||||
|  |             final WizardPage<PageContext> page1 = new WizardPage<>( | ||||||
|  |                     page1Id, | ||||||
|  |                     true, | ||||||
|  |                     composePage1, | ||||||
|  |                     new WizardAction<>(ACTION_DELETE, callback)); | ||||||
|  | 
 | ||||||
|  |             wizard.open(FORM_TITLE, Utils.EMPTY_EXECUTION, page1); | ||||||
|  | 
 | ||||||
|  |             return action; | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private boolean doDelete( | ||||||
|  |             final PageService pageService, | ||||||
|  |             final PageContext pageContext) { | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             final String idsToDelete = pageContext.getAttribute(PageContext.AttributeKeys.ENTITY_ID_LIST); | ||||||
|  | 
 | ||||||
|  |             final RestCall<EntityProcessingReport>.RestCallBuilder restCallBuilder = this.pageService.getRestService() | ||||||
|  |                     .getBuilder(DeleteAllUserLogs.class) | ||||||
|  |                     .withFormParam(API.PARAM_MODEL_ID_LIST, idsToDelete) | ||||||
|  |                     .withFormParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.HARD_DELETE.name()); | ||||||
|  | 
 | ||||||
|  |             final EntityProcessingReport report = restCallBuilder.call().getOrThrow(); | ||||||
|  | 
 | ||||||
|  |             final PageAction action = this.pageService.pageActionBuilder(pageContext) | ||||||
|  |                     .newAction(ActionDefinition.LOGS_USER_ACTIVITY_LIST) | ||||||
|  |                     .create(); | ||||||
|  | 
 | ||||||
|  |             this.pageService.firePageEvent( | ||||||
|  |                     new ActionEvent(action), | ||||||
|  |                     action.pageContext()); | ||||||
|  | 
 | ||||||
|  |             pageContext.publishPageMessage( | ||||||
|  |                     DELETE_CONFIRM_TITLE, | ||||||
|  |                     new LocTextKey( | ||||||
|  |                             "sebserver.userlogs.delete.confirm.message", | ||||||
|  |                             report.results.size(), | ||||||
|  |                             (report.errors.isEmpty()) ? "no" : String.valueOf((report.errors.size())))); | ||||||
|  | 
 | ||||||
|  |             return true; | ||||||
|  |         } catch (final Exception e) { | ||||||
|  |             log.error("Unexpected error while trying to delete user activity logs:", e); | ||||||
|  |             pageContext.notifyUnexpectedError(e); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private Supplier<PageContext> composeDeleteDialog( | ||||||
|  |             final Composite parent, | ||||||
|  |             final PageContext pageContext) { | ||||||
|  | 
 | ||||||
|  |         final String idsToDelete = pageContext.getAttribute(PageContext.AttributeKeys.ENTITY_ID_LIST); | ||||||
|  |         final int number = (StringUtils.isNotBlank(idsToDelete)) | ||||||
|  |                 ? idsToDelete.split(Constants.LIST_SEPARATOR).length | ||||||
|  |                 : 0; | ||||||
|  | 
 | ||||||
|  |         final Composite grid = this.pageService.getWidgetFactory() | ||||||
|  |                 .createPopupScrollComposite(parent); | ||||||
|  | 
 | ||||||
|  |         final Label title = this.pageService.getWidgetFactory().labelLocalized( | ||||||
|  |                 grid, | ||||||
|  |                 CustomVariant.TEXT_H3, | ||||||
|  |                 new LocTextKey("sebserver.userlogs.delete.form.info", number)); | ||||||
|  |         final GridData gridData = new GridData(); | ||||||
|  |         gridData.horizontalIndent = 10; | ||||||
|  |         gridData.verticalIndent = 10; | ||||||
|  |         title.setLayoutData(gridData); | ||||||
|  | 
 | ||||||
|  |         return () -> pageContext; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -675,6 +675,11 @@ public enum ActionDefinition { | ||||||
|             new LocTextKey("sebserver.logs.activity.userlogs.details"), |             new LocTextKey("sebserver.logs.activity.userlogs.details"), | ||||||
|             ImageIcon.SHOW, |             ImageIcon.SHOW, | ||||||
|             ActionCategory.LOGS_USER_ACTIVITY_LIST), |             ActionCategory.LOGS_USER_ACTIVITY_LIST), | ||||||
|  |     LOGS_USER_ACTIVITY_DELETE_ALL( | ||||||
|  |             new LocTextKey("sebserver.userlogs.action.delete"), | ||||||
|  |             ImageIcon.DELETE, | ||||||
|  |             PageStateDefinitionImpl.USER_ACTIVITY_LOGS, | ||||||
|  |             ActionCategory.LOGS_USER_ACTIVITY_LIST), | ||||||
| 
 | 
 | ||||||
|     LOGS_SEB_CLIENT( |     LOGS_SEB_CLIENT( | ||||||
|             new LocTextKey("sebserver.logs.activity.seblogs"), |             new LocTextKey("sebserver.logs.activity.seblogs"), | ||||||
|  | @ -687,7 +692,7 @@ public enum ActionDefinition { | ||||||
|             new LocTextKey("sebserver.seblogs.action.delete"), |             new LocTextKey("sebserver.seblogs.action.delete"), | ||||||
|             ImageIcon.DELETE, |             ImageIcon.DELETE, | ||||||
|             PageStateDefinitionImpl.SEB_CLIENT_LOGS, |             PageStateDefinitionImpl.SEB_CLIENT_LOGS, | ||||||
|             ActionCategory.FORM), |             ActionCategory.LOGS_SEB_CLIENT_LIST), | ||||||
| 
 | 
 | ||||||
|     ; |     ; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -10,13 +10,11 @@ package ch.ethz.seb.sebserver.gui.form; | ||||||
| 
 | 
 | ||||||
| import java.util.function.Consumer; | import java.util.function.Consumer; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gui.service.page.PageService; |  | ||||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||||
| import org.eclipse.rap.rwt.RWT; | import org.eclipse.rap.rwt.RWT; | ||||||
| import org.eclipse.swt.SWT; | import org.eclipse.swt.SWT; | ||||||
| import org.eclipse.swt.browser.Browser; | import org.eclipse.swt.browser.Browser; | ||||||
| import org.eclipse.swt.graphics.Color; | import org.eclipse.swt.graphics.Color; | ||||||
| import org.eclipse.swt.graphics.RGB; |  | ||||||
| import org.eclipse.swt.layout.GridData; | import org.eclipse.swt.layout.GridData; | ||||||
| import org.eclipse.swt.widgets.Composite; | import org.eclipse.swt.widgets.Composite; | ||||||
| import org.eclipse.swt.widgets.Control; | import org.eclipse.swt.widgets.Control; | ||||||
|  | @ -25,6 +23,7 @@ import org.eclipse.swt.widgets.Text; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.Constants; | import ch.ethz.seb.sebserver.gbl.Constants; | ||||||
| import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; | import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageService; | ||||||
| import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; | import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; | ||||||
| 
 | 
 | ||||||
| public final class TextFieldBuilder extends FieldBuilder<String> { | public final class TextFieldBuilder extends FieldBuilder<String> { | ||||||
|  | @ -77,6 +76,12 @@ public final class TextFieldBuilder extends FieldBuilder<String> { | ||||||
|         return this; |         return this; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public TextFieldBuilder asHTML(final int minHeight) { | ||||||
|  |         this.isHTML = true; | ||||||
|  |         this.areaMinHeight = minHeight; | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public FieldBuilder<?> asHTML(final boolean html) { |     public FieldBuilder<?> asHTML(final boolean html) { | ||||||
|         this.isHTML = html; |         this.isHTML = html; | ||||||
|         return this; |         return this; | ||||||
|  | @ -97,7 +102,7 @@ public final class TextFieldBuilder extends FieldBuilder<String> { | ||||||
|             final Browser browser = new Browser(fieldGrid, SWT.NONE); |             final Browser browser = new Browser(fieldGrid, SWT.NONE); | ||||||
|             final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, true); |             final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, true); | ||||||
|             gridData.minimumHeight = this.areaMinHeight; |             gridData.minimumHeight = this.areaMinHeight; | ||||||
|             browser.setBackground(new Color(builder.formParent.getDisplay(), new RGB(250, 250, 250))); |             browser.setBackground(new Color(builder.formParent.getDisplay(), 250, 250, 250)); | ||||||
|             browser.setLayoutData(gridData); |             browser.setLayoutData(gridData); | ||||||
|             if (StringUtils.isNoneBlank(this.value)) { |             if (StringUtils.isNoneBlank(this.value)) { | ||||||
|                 browser.setText(createHTMLText(this.value)); |                 browser.setText(createHTMLText(this.value)); | ||||||
|  |  | ||||||
|  | @ -178,6 +178,20 @@ public interface PageService { | ||||||
|                         .get(); |                         .get(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** Use this to get an action activation publisher that processes the action activation. | ||||||
|  |      * | ||||||
|  |      * @param pageContext the current PageContext | ||||||
|  |      * @param actionDefinitions list of action definitions that activity should be toggled on table selection | ||||||
|  |      * @return the action activation publisher that can be used to control the activity of an certain action */ | ||||||
|  |     default Consumer<Boolean> getActionActiviationPublisher( | ||||||
|  |             final PageContext pageContext, | ||||||
|  |             final ActionDefinition... actionDefinitions) { | ||||||
|  | 
 | ||||||
|  |         return avtivate -> firePageEvent( | ||||||
|  |                 new ActionActivationEvent(avtivate, actionDefinitions), | ||||||
|  |                 pageContext); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** Use this to get an table selection action publisher that processes the action |     /** Use this to get an table selection action publisher that processes the action | ||||||
|      * activation on table selection. |      * activation on table selection. | ||||||
|      * |      * | ||||||
|  |  | ||||||
|  | @ -6,7 +6,7 @@ | ||||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session; | package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs; | ||||||
| 
 | 
 | ||||||
| import org.springframework.context.annotation.Lazy; | import org.springframework.context.annotation.Lazy; | ||||||
| import org.springframework.http.HttpMethod; | import org.springframework.http.HttpMethod; | ||||||
|  | @ -0,0 +1,40 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs; | ||||||
|  | 
 | ||||||
|  | import org.springframework.context.annotation.Lazy; | ||||||
|  | import org.springframework.http.HttpMethod; | ||||||
|  | import org.springframework.http.MediaType; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.core.type.TypeReference; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.API; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.EntityType; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; | ||||||
|  | 
 | ||||||
|  | @Lazy | ||||||
|  | @Component | ||||||
|  | @GuiProfile | ||||||
|  | public class DeleteAllUserLogs extends RestCall<EntityProcessingReport> { | ||||||
|  | 
 | ||||||
|  |     public DeleteAllUserLogs() { | ||||||
|  |         super(new TypeKey<>( | ||||||
|  |                 CallType.DELETE, | ||||||
|  |                 EntityType.USER_ACTIVITY_LOG, | ||||||
|  |                 new TypeReference<EntityProcessingReport>() { | ||||||
|  |                 }), | ||||||
|  |                 HttpMethod.DELETE, | ||||||
|  |                 MediaType.APPLICATION_FORM_URLENCODED, | ||||||
|  |                 API.USER_ACTIVITY_LOG_ENDPOINT); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -6,7 +6,7 @@ | ||||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session; | package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs; | ||||||
| 
 | 
 | ||||||
| import java.util.List; | import java.util.List; | ||||||
| 
 | 
 | ||||||
|  | @ -6,7 +6,7 @@ | ||||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session; | package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs; | ||||||
| 
 | 
 | ||||||
| import org.springframework.context.annotation.Lazy; | import org.springframework.context.annotation.Lazy; | ||||||
| import org.springframework.http.HttpMethod; | import org.springframework.http.HttpMethod; | ||||||
|  | @ -0,0 +1,42 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs; | ||||||
|  | 
 | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | import org.springframework.context.annotation.Lazy; | ||||||
|  | import org.springframework.http.HttpMethod; | ||||||
|  | import org.springframework.http.MediaType; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.core.type.TypeReference; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.API; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.EntityType; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.model.EntityName; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; | ||||||
|  | 
 | ||||||
|  | @Lazy | ||||||
|  | @Component | ||||||
|  | @GuiProfile | ||||||
|  | public class GetUserLogNames extends RestCall<List<EntityName>> { | ||||||
|  | 
 | ||||||
|  |     public GetUserLogNames() { | ||||||
|  |         super(new TypeKey<>( | ||||||
|  |                 CallType.GET_NAMES, | ||||||
|  |                 EntityType.USER_ACTIVITY_LOG, | ||||||
|  |                 new TypeReference<List<EntityName>>() { | ||||||
|  |                 }), | ||||||
|  |                 HttpMethod.GET, | ||||||
|  |                 MediaType.APPLICATION_FORM_URLENCODED, | ||||||
|  |                 API.USER_ACTIVITY_LOG_ENDPOINT + API.NAMES_PATH_SEGMENT); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -95,6 +95,7 @@ public class EntityTable<ROW> { | ||||||
|     private final MultiValueMap<String, String> staticQueryParams; |     private final MultiValueMap<String, String> staticQueryParams; | ||||||
|     private final BiConsumer<TableItem, ROW> rowDecorator; |     private final BiConsumer<TableItem, ROW> rowDecorator; | ||||||
|     private final Consumer<Set<ROW>> selectionListener; |     private final Consumer<Set<ROW>> selectionListener; | ||||||
|  |     private final Consumer<Integer> contentChangeListener; | ||||||
| 
 | 
 | ||||||
|     int pageNumber; |     int pageNumber; | ||||||
|     int pageSize; |     int pageSize; | ||||||
|  | @ -118,7 +119,8 @@ public class EntityTable<ROW> { | ||||||
|             final boolean hideNavigation, |             final boolean hideNavigation, | ||||||
|             final MultiValueMap<String, String> staticQueryParams, |             final MultiValueMap<String, String> staticQueryParams, | ||||||
|             final BiConsumer<TableItem, ROW> rowDecorator, |             final BiConsumer<TableItem, ROW> rowDecorator, | ||||||
|             final Consumer<Set<ROW>> selectionListener) { |             final Consumer<Set<ROW>> selectionListener, | ||||||
|  |             final Consumer<Integer> contentChangeListener) { | ||||||
| 
 | 
 | ||||||
|         this.name = name; |         this.name = name; | ||||||
|         this.filterAttrName = name + "_filter"; |         this.filterAttrName = name + "_filter"; | ||||||
|  | @ -149,6 +151,7 @@ public class EntityTable<ROW> { | ||||||
|         this.staticQueryParams = staticQueryParams; |         this.staticQueryParams = staticQueryParams; | ||||||
|         this.rowDecorator = rowDecorator; |         this.rowDecorator = rowDecorator; | ||||||
|         this.selectionListener = selectionListener; |         this.selectionListener = selectionListener; | ||||||
|  |         this.contentChangeListener = contentChangeListener; | ||||||
|         this.pageSize = pageSize; |         this.pageSize = pageSize; | ||||||
|         this.filter = columns |         this.filter = columns | ||||||
|                 .stream() |                 .stream() | ||||||
|  | @ -492,6 +495,7 @@ public class EntityTable<ROW> { | ||||||
| 
 | 
 | ||||||
|         this.composite.getParent().layout(true, true); |         this.composite.getParent().layout(true, true); | ||||||
|         PageService.updateScrolledComposite(this.composite); |         PageService.updateScrolledComposite(this.composite); | ||||||
|  |         this.notifyContentChange(); | ||||||
|         this.notifySelectionChange(); |         this.notifySelectionChange(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -753,4 +757,10 @@ public class EntityTable<ROW> { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private void notifyContentChange() { | ||||||
|  |         if (this.contentChangeListener != null) { | ||||||
|  |             this.contentChangeListener.accept(this.table.getItemCount()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -47,6 +47,7 @@ public class TableBuilder<ROW> { | ||||||
|     private Function<PageSupplier.Builder<ROW>, PageSupplier.Builder<ROW>> restCallAdapter; |     private Function<PageSupplier.Builder<ROW>, PageSupplier.Builder<ROW>> restCallAdapter; | ||||||
|     private BiConsumer<TableItem, ROW> rowDecorator; |     private BiConsumer<TableItem, ROW> rowDecorator; | ||||||
|     private Consumer<Set<ROW>> selectionListener; |     private Consumer<Set<ROW>> selectionListener; | ||||||
|  |     private Consumer<Integer> contentChangeListener; | ||||||
|     private boolean markupEnabled = false; |     private boolean markupEnabled = false; | ||||||
| 
 | 
 | ||||||
|     public TableBuilder( |     public TableBuilder( | ||||||
|  | @ -128,6 +129,11 @@ public class TableBuilder<ROW> { | ||||||
|         return this; |         return this; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public TableBuilder<ROW> withContentChangeListener(final Consumer<Integer> contentChangeListener) { | ||||||
|  |         this.contentChangeListener = contentChangeListener; | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public TableBuilder<ROW> withStaticFilter(final String name, final String value) { |     public TableBuilder<ROW> withStaticFilter(final String name, final String value) { | ||||||
|         this.staticQueryParams.add(name, value); |         this.staticQueryParams.add(name, value); | ||||||
|         return this; |         return this; | ||||||
|  | @ -171,7 +177,7 @@ public class TableBuilder<ROW> { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public EntityTable<ROW> compose(final PageContext pageContext) { |     public EntityTable<ROW> compose(final PageContext pageContext) { | ||||||
|         return new EntityTable<ROW>( |         return new EntityTable<>( | ||||||
|                 this.name, |                 this.name, | ||||||
|                 this.markupEnabled, |                 this.markupEnabled, | ||||||
|                 this.type, |                 this.type, | ||||||
|  | @ -188,7 +194,8 @@ public class TableBuilder<ROW> { | ||||||
|                 this.hideNavigation, |                 this.hideNavigation, | ||||||
|                 this.staticQueryParams, |                 this.staticQueryParams, | ||||||
|                 this.rowDecorator, |                 this.rowDecorator, | ||||||
|                 this.selectionListener); |                 this.selectionListener, | ||||||
|  |                 this.contentChangeListener); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -8,19 +8,37 @@ | ||||||
| 
 | 
 | ||||||
| package ch.ethz.seb.sebserver.webservice.weblayer.api; | package ch.ethz.seb.sebserver.webservice.weblayer.api; | ||||||
| 
 | 
 | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.Collection; | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Set; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | 
 | ||||||
| import org.mybatis.dynamic.sql.SqlTable; | import org.mybatis.dynamic.sql.SqlTable; | ||||||
|  | import org.springframework.http.MediaType; | ||||||
| import org.springframework.web.bind.annotation.RequestMapping; | import org.springframework.web.bind.annotation.RequestMapping; | ||||||
|  | import org.springframework.web.bind.annotation.RequestMethod; | ||||||
|  | import org.springframework.web.bind.annotation.RequestParam; | ||||||
| import org.springframework.web.bind.annotation.RestController; | import org.springframework.web.bind.annotation.RestController; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.api.API; | import ch.ethz.seb.sebserver.gbl.api.API; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.APIMessage; | ||||||
| import ch.ethz.seb.sebserver.gbl.api.EntityType; | import ch.ethz.seb.sebserver.gbl.api.EntityType; | ||||||
| import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType; | import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.model.EntityKey; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport.ErrorEntry; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; | import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.model.user.UserRole; | ||||||
| import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | ||||||
| import ch.ethz.seb.sebserver.gbl.util.Result; | import ch.ethz.seb.sebserver.gbl.util.Result; | ||||||
| import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserActivityLogRecordDynamicSqlSupport; | import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserActivityLogRecordDynamicSqlSupport; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService; | import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService; | import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService; | ||||||
|  | import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PermissionDeniedException; | ||||||
|  | import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService; | ||||||
|  | import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.SEBServerUser; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService; | import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.dao.EntityDAO; | import ch.ethz.seb.sebserver.webservice.servicelayer.dao.EntityDAO; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO; | import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO; | ||||||
|  | @ -48,6 +66,53 @@ public class UserActivityLogController extends ReadonlyEntityController<UserActi | ||||||
|                 beanValidationService); |                 beanValidationService); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Override | ||||||
|  |     @RequestMapping( | ||||||
|  |             method = RequestMethod.DELETE, | ||||||
|  |             consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, | ||||||
|  |             produces = MediaType.APPLICATION_JSON_UTF8_VALUE) | ||||||
|  |     public EntityProcessingReport hardDeleteAll( | ||||||
|  |             @RequestParam(name = API.PARAM_MODEL_ID_LIST) final List<String> ids, | ||||||
|  |             @RequestParam(name = API.PARAM_BULK_ACTION_ADD_INCLUDES, defaultValue = "false") final boolean addIncludes, | ||||||
|  |             @RequestParam(name = API.PARAM_BULK_ACTION_INCLUDES, required = false) final List<String> includes, | ||||||
|  |             @RequestParam( | ||||||
|  |                     name = API.PARAM_INSTITUTION_ID, | ||||||
|  |                     required = true, | ||||||
|  |                     defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId) { | ||||||
|  | 
 | ||||||
|  |         // check user has SEB Server administrator role | ||||||
|  |         final SEBServerUser currentUser = this.authorization.getUserService() | ||||||
|  |                 .getCurrentUser(); | ||||||
|  |         if (!currentUser.getUserRoles().contains(UserRole.SEB_SERVER_ADMIN)) { | ||||||
|  |             throw new PermissionDeniedException( | ||||||
|  |                     EntityType.USER_ACTIVITY_LOG, | ||||||
|  |                     PrivilegeType.WRITE, | ||||||
|  |                     currentUser.getUserInfo()); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (ids == null || ids.isEmpty()) { | ||||||
|  |             return EntityProcessingReport.ofEmptyError(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         final Set<EntityKey> sources = ids.stream() | ||||||
|  |                 .map(id -> new EntityKey(id, EntityType.USER_ACTIVITY_LOG)) | ||||||
|  |                 .collect(Collectors.toSet()); | ||||||
|  | 
 | ||||||
|  |         final Result<Collection<EntityKey>> delete = this.entityDAO.delete(sources); | ||||||
|  | 
 | ||||||
|  |         if (delete.hasError()) { | ||||||
|  |             return new EntityProcessingReport( | ||||||
|  |                     Collections.emptyList(), | ||||||
|  |                     Collections.emptyList(), | ||||||
|  |                     Arrays.asList(new ErrorEntry(null, APIMessage.ErrorMessage.UNEXPECTED.of(delete.getError())))); | ||||||
|  |         } else { | ||||||
|  |             return new EntityProcessingReport( | ||||||
|  |                     sources, | ||||||
|  |                     delete.get(), | ||||||
|  |                     Collections.emptyList()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Override |     @Override | ||||||
|     protected void checkReadPrivilege(final Long institutionId) { |     protected void checkReadPrivilege(final Long institutionId) { | ||||||
|         checkRead(institutionId); |         checkRead(institutionId); | ||||||
|  |  | ||||||
|  | @ -1448,6 +1448,12 @@ sebserver.userlogs.info.pleaseSelect=At first please select a User Log from the | ||||||
| sebserver.userlogs.list.actions= | sebserver.userlogs.list.actions= | ||||||
| sebserver.userlogs.list.empty=No User activity logs can be found. Please adapt or clear the filter | sebserver.userlogs.list.empty=No User activity logs can be found. Please adapt or clear the filter | ||||||
| 
 | 
 | ||||||
|  | sebserver.userlogs.action.delete=Delete Logs | ||||||
|  | sebserver.userlogs.delete.form.title=Delete User Logs | ||||||
|  | sebserver.userlogs.delete.form.info=This will delete all user activity logs from the current filtered list.<br/>Please check carefully if all user activity logs from the list shall be deleted.<br/><br/>There are currently {0} logs within the list. | ||||||
|  | sebserver.userlogs.delete.action.delete=Delete All Logs | ||||||
|  | sebserver.userlogs.delete.confirm.title=Deletion Successful | ||||||
|  | sebserver.userlogs.delete.confirm.message={0} User activity logs where successfully deleted.<br/><br/>And there where {1} errors. | ||||||
| 
 | 
 | ||||||
| sebserver.seblogs.list.title=SEB Client Logs | sebserver.seblogs.list.title=SEB Client Logs | ||||||
| sebserver.seblogs.list.actions= | sebserver.seblogs.list.actions= | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 anhefti
						anhefti