finished admin log page

This commit is contained in:
Jake Potrebic 2020-09-04 00:05:37 -07:00
parent c4efbbc67a
commit 9949c3e6cc
No known key found for this signature in database
GPG Key ID: 7C58557EC9C421F8
12 changed files with 273 additions and 67 deletions

View File

@ -160,17 +160,17 @@ public class ApplicationController extends HangarController {
@Secured("ROLE_USER")
@GetMapping("/admin/log")
public ModelAndView showLog(@RequestParam(required = false) Integer oPage,
@RequestParam(required = false) Object userFilter,
@RequestParam(required = false) Object projectFilter,
@RequestParam(required = false) Object versionFilter,
@RequestParam(required = false) Object pageFilter,
@RequestParam(required = false) Object actionFilter,
@RequestParam(required = false) Object subjectFilter) {
@RequestParam(required = false) String userFilter,
@RequestParam(required = false) String projectFilter,
@RequestParam(required = false) String versionFilter,
@RequestParam(required = false) String pageFilter,
@RequestParam(required = false) String actionFilter,
@RequestParam(required = false) String subjectFilter) {
ModelAndView mv = new ModelAndView("users/admin/log");
int pageSize = 50;
int page = oPage != null ? oPage : 1;
int offset = (page - 1) * pageSize;
List<LoggedActionViewModel> log = userActionLogService.getLog(oPage, userFilter, projectFilter, versionFilter, pageFilter, actionFilter, subjectFilter);
List<LoggedActionViewModel<?>> log = userActionLogService.getLog(oPage, userFilter, projectFilter, versionFilter, pageFilter, actionFilter, subjectFilter);
mv.addObject("actions", log);
mv.addObject("limit", pageSize);
mv.addObject("offset", offset);

View File

@ -314,7 +314,7 @@ public class VersionsController extends HangarController {
versionService.addUnstableTag(version.getId());
}
userActionLogService.version(request, LoggedActionType.VERSION_UPLOADED.with(VersionContext.of(projectData.getProject().getId(), version.getId())), "published", "null");
userActionLogService.version(request, LoggedActionType.VERSION_UPLOADED.with(VersionContext.of(projectData.getProject().getId(), version.getId())), "published", "");
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("versions.show", author, slug, versionName));
}

View File

@ -34,6 +34,7 @@ public class LoggedActionType<C extends AbstractContext<C>> {
this.value = value;
this.name = name;
this.description = description;
loggedActionTypes.put(value.getValue(), this);
}
private LoggedActionType(LoggedActionType<C> actionType, C actionContext) {

View File

@ -1,17 +1,27 @@
package io.papermc.hangar.db.dao;
import io.papermc.hangar.db.mappers.LoggedActionViewModelMapper;
import io.papermc.hangar.db.model.LoggedActionsOrganizationTable;
import io.papermc.hangar.db.model.LoggedActionsPageTable;
import io.papermc.hangar.db.model.LoggedActionsProjectTable;
import io.papermc.hangar.db.model.LoggedActionsUserTable;
import io.papermc.hangar.db.model.LoggedActionsVersionTable;
import io.papermc.hangar.model.viewhelpers.LoggedActionViewModel;
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
import org.jdbi.v3.sqlobject.config.RegisterColumnMapper;
import org.jdbi.v3.sqlobject.config.RegisterRowMapper;
import org.jdbi.v3.sqlobject.customizer.BindBean;
import org.jdbi.v3.sqlobject.customizer.Define;
import org.jdbi.v3.sqlobject.customizer.DefineNamedBindings;
import org.jdbi.v3.sqlobject.customizer.Timestamped;
import org.jdbi.v3.sqlobject.statement.SqlQuery;
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
import org.jdbi.v3.stringtemplate4.UseStringTemplateEngine;
import org.springframework.stereotype.Repository;
import java.util.List;
@RegisterBeanMapper(LoggedActionsOrganizationTable.class)
@RegisterBeanMapper(LoggedActionsPageTable.class)
@RegisterBeanMapper(LoggedActionsVersionTable.class)
@ -39,4 +49,17 @@ public interface ActionsDao {
@Timestamped
@SqlUpdate("INSERT INTO logged_actions_organization (created_at, user_id, address, action, organization_id, new_state, old_state) VALUES (:now, :userId, :address, :action, :organizationId, :newState, :oldState)")
void insertOrganizationLog(@BindBean LoggedActionsOrganizationTable loggedActionsOrganizationTable);
@UseStringTemplateEngine
@RegisterRowMapper(LoggedActionViewModelMapper.class)
@SqlQuery("SELECT * FROM v_logged_actions la " +
" WHERE true " +
"<if(userFilter)>AND la.user_name = '<userFilter>'<endif> " +
"<if(projectFilter)>AND la.p_plugin_id = '<projectFilter>'<endif> " +
"<if(versionFilter)>AND la.pv_version_string = '<versionFilter>'<endif> " +
"<if(pageFilter)>AND la.pp_id = '<pageFilter>'<endif> " +
"<if(actionFilter)>AND la.action = '<actionFilter>'::LOGGED_ACTION_TYPE<endif> " +
"<if(subjectFilter)>AND la.s_name = '<subjectFilter>'<endif> " +
"ORDER BY la.created_at DESC OFFSET <offset> LIMIT <pageSize>")
List<LoggedActionViewModel<?>> getLog(@Define String userFilter, @Define String projectFilter, @Define String versionFilter, @Define String pageFilter, @Define String actionFilter, @Define String subjectFilter, @Define long offset, @Define long pageSize);
}

View File

@ -0,0 +1,130 @@
package io.papermc.hangar.db.mappers;
import io.papermc.hangar.db.customtypes.LoggedActionType;
import io.papermc.hangar.db.customtypes.LoggedActionType.AbstractContext;
import io.papermc.hangar.db.customtypes.LoggedActionType.OrganizationContext;
import io.papermc.hangar.db.customtypes.LoggedActionType.ProjectContext;
import io.papermc.hangar.db.customtypes.LoggedActionType.ProjectPageContext;
import io.papermc.hangar.db.customtypes.LoggedActionType.UserContext;
import io.papermc.hangar.db.customtypes.LoggedActionType.VersionContext;
import io.papermc.hangar.model.viewhelpers.LoggedActionViewModel;
import io.papermc.hangar.model.viewhelpers.LoggedProject;
import io.papermc.hangar.model.viewhelpers.LoggedProjectPage;
import io.papermc.hangar.model.viewhelpers.LoggedProjectVersion;
import io.papermc.hangar.model.viewhelpers.LoggedSubject;
import org.jdbi.v3.core.mapper.RowMapper;
import org.jdbi.v3.core.statement.StatementContext;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.OffsetDateTime;
public class LoggedActionViewModelMapper implements RowMapper<LoggedActionViewModel<?>> {
@Override
public LoggedActionViewModel<?> map(ResultSet rs, StatementContext ctx) throws SQLException {
long userId = rs.getLong("user_id");
String userName = rs.getString("user_name");
String address = rs.getString("address");
LoggedActionType<? extends AbstractContext<?>> action = LoggedActionType.getLoggedActionType(rs.getString("action"));
String newState = rs.getString("new_state");
String oldState = rs.getString("old_state");
OffsetDateTime createdAt = ctx.findColumnMapperFor(OffsetDateTime.class).get().map(rs, "created_at", ctx);
int contextType = rs.getInt("context_type");
switch (contextType) {
case 0:
return new LoggedActionViewModel<>(userId,
userName,
address,
(LoggedActionType<ProjectContext>) action,
ProjectContext.of(rs.getLong("p_id")),
newState,
oldState,
new LoggedProject(
rs.getLong("p_id"),
rs.getString("p_plugin_id"),
rs.getString("p_slug"),
rs.getString("p_owner_name")
),
null,
null,
null,
createdAt);
case 1:
return new LoggedActionViewModel<>(
userId,
userName,
address,
(LoggedActionType<VersionContext>) action,
VersionContext.of(rs.getLong("p_id"), rs.getLong("pv_id")),
newState,
oldState,
null,
new LoggedProjectVersion(
rs.getLong("pv_id"),
rs.getString("pv_version_string")
),
null,
null,
createdAt
);
case 2:
return new LoggedActionViewModel<>(
userId,
userName,
address,
(LoggedActionType<ProjectPageContext>) action,
ProjectPageContext.of(rs.getLong("p_id"), rs.getLong("pp_id")),
newState,
oldState,
null,
null,
new LoggedProjectPage(
rs.getLong("pp_id"),
rs.getString("pp_name"),
rs.getString("pp_slug")
),
null,
createdAt
);
case 3:
return new LoggedActionViewModel<>(
userId,
userName,
address,
(LoggedActionType<UserContext>) action,
UserContext.of(rs.getLong("s_id")),
newState,
oldState,
null,
null,
null,
new LoggedSubject(
rs.getLong("s_id"),
rs.getString("s_name")
),
createdAt
);
case 4:
return new LoggedActionViewModel<>(
userId,
userName,
address,
(LoggedActionType<OrganizationContext>) action,
OrganizationContext.of(rs.getLong("s_id")),
newState,
oldState,
null,
null,
null,
new LoggedSubject(
rs.getLong("s_id"),
rs.getString("s_name")
),
createdAt
);
default:
throw new IllegalArgumentException("Should be a value from 0 - 4");
}
}
}

View File

@ -1,25 +1,26 @@
package io.papermc.hangar.model.viewhelpers;
import io.papermc.hangar.db.customtypes.LoggedActionType;
import io.papermc.hangar.db.customtypes.LoggedActionType.AbstractContext;
import java.time.OffsetDateTime;
public class LoggedActionViewModel {
public class LoggedActionViewModel<C extends AbstractContext<C>> {
private long userId;
private String userName;
private String address;
private LoggedActionType action;
private LoggedActionType.AbstractContext actionContext;
private String newState;
private String oldState;
private LoggedProject project;
private LoggedProjectVersion version;
private LoggedProjectPage page;
private LoggedSubject subject;
private OffsetDateTime createdAt;
private final long userId;
private final String userName;
private final String address;
private final LoggedActionType<C> action;
private final C actionContext;
private final String newState;
private final String oldState;
private final LoggedProject project;
private final LoggedProjectVersion version;
private final LoggedProjectPage page;
private final LoggedSubject subject;
private final OffsetDateTime createdAt;
public LoggedActionViewModel(long userId, String userName, String address, LoggedActionType action, LoggedActionType.AbstractContext actionContext, String newState, String oldState, LoggedProject project, LoggedProjectVersion version, LoggedProjectPage page, LoggedSubject subject, OffsetDateTime createdAt) {
public LoggedActionViewModel(long userId, String userName, String address, LoggedActionType<C> action, C actionContext, String newState, String oldState, LoggedProject project, LoggedProjectVersion version, LoggedProjectPage page, LoggedSubject subject, OffsetDateTime createdAt) {
this.userId = userId;
this.userName = userName;
this.address = address;
@ -46,11 +47,11 @@ public class LoggedActionViewModel {
return address;
}
public LoggedActionType getAction() {
public LoggedActionType<C> getAction() {
return action;
}
public LoggedActionType.AbstractContext getActionContext() {
public C getActionContext() {
return actionContext;
}
@ -81,4 +82,22 @@ public class LoggedActionViewModel {
public OffsetDateTime getCreatedAt() {
return createdAt;
}
@Override
public String toString() {
return "LoggedActionViewModel{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", address='" + address + '\'' +
", action=" + action +
", actionContext=" + actionContext +
", newState='" + newState + '\'' +
", oldState='" + oldState + '\'' +
", project=" + project +
", version=" + version +
", page=" + page +
", subject=" + subject +
", createdAt=" + createdAt +
'}';
}
}

View File

@ -1,39 +1,44 @@
package io.papermc.hangar.model.viewhelpers;
import io.papermc.hangar.model.generated.Project;
import org.jetbrains.annotations.Nullable;
public class LoggedProject {
private Project project;
private String pluginId;
private String slug;
private String owner;
private final Long id;
private final String pluginId;
private final String slug;
private final String owner;
public LoggedProject(@Nullable Project project, @Nullable String pluginId, @Nullable String slug, @Nullable String owner) {
this.project = project;
public LoggedProject(@Nullable Long id, @Nullable String pluginId, @Nullable String slug, @Nullable String owner) {
this.id = id;
this.pluginId = pluginId;
this.slug = slug;
this.owner = owner;
}
@Nullable
public Project getProject() {
return project;
public Long getId() {
return id;
}
@Nullable
public String getPluginId() {
return pluginId;
}
@Nullable
public String getSlug() {
return slug;
}
@Nullable
public String getOwner() {
return owner;
}
@Override
public String toString() {
return "LoggedProject{" +
"id=" + id +
", pluginId='" + pluginId + '\'' +
", slug='" + slug + '\'' +
", owner='" + owner + '\'' +
'}';
}
}

View File

@ -4,28 +4,34 @@ import org.jetbrains.annotations.Nullable;
public class LoggedProjectPage {
private ProjectPage page;
private String name;
private String slug;
private final Long id;
private final String name;
private final String slug;
public LoggedProjectPage(@Nullable ProjectPage page, @Nullable String name, @Nullable String slug) {
this.page = page;
public LoggedProjectPage(@Nullable Long id, @Nullable String name, @Nullable String slug) {
this.id = id;
this.name = name;
this.slug = slug;
}
@Nullable
public ProjectPage getPage() {
return page;
public Long getId() {
return id;
}
@Nullable
public String getName() {
return name;
}
@Nullable
public String getSlug() {
return slug;
}
@Override
public String toString() {
return "LoggedProjectPage{" +
"id=" + id +
", name='" + name + '\'' +
", slug='" + slug + '\'' +
'}';
}
}

View File

@ -1,25 +1,30 @@
package io.papermc.hangar.model.viewhelpers;
import io.papermc.hangar.model.generated.Version;
import org.jetbrains.annotations.Nullable;
public class LoggedProjectVersion {
private Version version;
private String versionString;
private final Long id;
private final String versionString;
public LoggedProjectVersion(@Nullable Version version, @Nullable String versionString) {
this.version = version;
public LoggedProjectVersion(@Nullable Long id, @Nullable String versionString) {
this.id = id;
this.versionString = versionString;
}
@Nullable
public Version getVersion() {
return version;
public Long getId() {
return id;
}
@Nullable
public String getVersionString() {
return versionString;
}
@Override
public String toString() {
return "LoggedProjectVersion{" +
"id=" + id +
", versionString='" + versionString + '\'' +
'}';
}
}

View File

@ -4,23 +4,29 @@ import org.jetbrains.annotations.Nullable;
public class LoggedSubject {
private Long id;
private String username;
private final Long id;
private final String username;
public LoggedSubject(@Nullable Long id, @Nullable String username) {
this.id = id;
this.username = username;
}
@Nullable
public Long getId() {
return id;
}
@Nullable
public String getUsername() {
return username;
}
@Override
public String toString() {
return "LoggedSubject{" +
"id=" + id +
", username='" + username + '\'' +
'}';
}
}

View File

@ -94,8 +94,15 @@ public class UserActionLogService {
actionsDao.get().insertOrganizationLog(log);
}
public List<LoggedActionViewModel> getLog(Integer oPage, Object userFilter, Object projectFilter, Object versionFilter, Object pageFilter, Object actionFilter, Object subjectFilter) {
return new ArrayList<>(); //TODO See AppQueries.getLog(...)
public List<LoggedActionViewModel<?>> getLog(Integer oPage, String userFilter, String projectFilter, String versionFilter, String pageFilter, String actionFilter, String subjectFilter) {
long pageSize = 50L;
long offset;
if (oPage == null) {
offset = 0;
} else {
offset = oPage * pageSize;
}
return actionsDao.get().getLog(userFilter, projectFilter, versionFilter, pageFilter, actionFilter, subjectFilter, offset, pageSize);
}
private InetAddress getInetAddress(HttpServletRequest request) {

View File

@ -8,6 +8,11 @@
</#assign>
<#assign message><@spring.message "admin.log.title" /></#assign>
<#-- @ftlvariable name="canViewIP" type="java.lang.Boolean" -->
<#-- @ftlvariable name="limit" type="java.lang.Integer" -->
<#-- @ftlvariable name="offset" type="java.lang.Integer" -->
<#-- @ftlvariable name="page" type="java.lang.Integer" -->
<#-- @ftlvariable name="size" type="java.lang.Integer" -->
<@base.base title="${message}" additionalScripts=scriptsVar>
<div class="row">
<div class="col-md-12 header-flags">
@ -22,8 +27,7 @@
<tr><td class="filter-project">Project</td> <td>${projectFilter!"-"}</td></tr>
<tr><td class="filter-version">Version</td> <td>${versionFilter!"-"}</td></tr>
<tr><td class="filter-page">Page</td><td>${pageFilter!"-"} </td></tr>
<#assign LoggedActionType=@helper["io.papermc.hangar.db.customtypes.LoggedActionType"] />
<tr><td class="filter-action">Action</td><td>${LoggedActionType.getLoggedActionType(actionFilter!"")!"-"}</td></tr>
<tr><td class="filter-action">Action</td><td>${actionFilter!"-"}</td></tr>
<tr><td class="filter-subject">Subject</td><td>${subjectFilter!"-"}</td></tr>
</table>
</div>
@ -74,7 +78,7 @@
<a href="${routes.getRouteUrl("users.showProjects", action.subject.username!"Unknown")}">${action.subject.username}</a>
<small class="filter-subject">(<a href="${routes.getRouteUrl("showLog", page?string, userFilter, projectFilter, versionFilter, pageFilter, actionFilter, action.subject.username)}">${action.subject.username}</a>)</small>
</td>
<#elseif action.project.project??>
<#elseif !action.project?? || !action.project.id??>
<td>
Resource deleted
<#if action.actionContext.class.simpleName == "ProjectContext" || action.actionContext.class.simpleName == "ProjectPageContext">
@ -112,8 +116,8 @@
<textarea style="display: none" data-newstate="${offset + action?index}">${action.newState}</textarea>
</td>
<#else>
<td>${action.oldState}</td>
<td>${action.newState}</td>
<td>${action.oldState?has_content?string(action.oldState, "<i>none</i>")}</td>
<td>${action.newState?has_content?string(action.newState, "<i>none</i>")}</td>
</#if>
</tr>
</#list>