mirror of
https://github.com/HangarMC/Hangar.git
synced 2024-11-21 01:21:54 +08:00
work on project flags
This commit is contained in:
parent
70709c0873
commit
783cde2c87
@ -41,7 +41,7 @@ export default class FlagModal extends mixins(HangarFormModal, HangarProjectMixi
|
||||
this.loading = true;
|
||||
this.$api
|
||||
.requestInternal('flags/', true, 'POST', {
|
||||
project_id: this.project.id,
|
||||
projectId: this.project.id,
|
||||
reason: this.form.selection,
|
||||
comment: this.form.comment,
|
||||
})
|
||||
|
@ -103,6 +103,17 @@ const msgs: LocaleMessageObject = {
|
||||
flag: {
|
||||
flagProject: 'Flag {0}?',
|
||||
flagSend: 'Successfully flagged, thanks for making this community a better place!',
|
||||
flags: {
|
||||
inappropriateContent: 'Inappropriate Content',
|
||||
impersonation: 'Impersonation or Deception',
|
||||
spam: 'Spam',
|
||||
malIntent: 'Malicious Intent',
|
||||
other: 'Other',
|
||||
},
|
||||
error: {
|
||||
alreadyOpen: 'You can only have 1 unresolved flag on a project',
|
||||
alreadyResolved: 'This flag is already resolved',
|
||||
},
|
||||
},
|
||||
tabs: {
|
||||
docs: 'Docs',
|
||||
@ -592,7 +603,8 @@ const msgs: LocaleMessageObject = {
|
||||
markResolved: 'Mark resolved',
|
||||
visibilityActions: 'Visibility actions',
|
||||
line1: '{0} reported {1} on {2}',
|
||||
line2: 'Reason: {0}, Comment: {1}',
|
||||
line2: 'Reason: {0}',
|
||||
line3: 'Comment: {0}',
|
||||
},
|
||||
userAdmin: {
|
||||
title: 'Edit User',
|
||||
|
@ -5,35 +5,33 @@
|
||||
<NuxtLink :to="'/' + project.namespace.owner + '/' + project.namespace.slug">{{ project.namespace.owner + '/' + project.namespace.slug }}</NuxtLink>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-data-table v-if="flags && flags.length > 0" :headers="headers" :items="flags" disable-filtering disable-sort hide-default-footer>
|
||||
<v-data-table :loading="$fetchState.pending" :headers="headers" :items="flags" disable-filtering disable-sort hide-default-footer>
|
||||
<template #no-data>
|
||||
<v-alert type="info" class="mt-2">{{ $t('flags.noFlags') }}</v-alert>
|
||||
</template>
|
||||
<template #item.user="{ item }">{{ item.reportedByName }}</template>
|
||||
<template #item.reason="{ item }">{{ item.reason }}</template>
|
||||
<template #item.reason="{ item }">{{ $t(item.reason) }}</template>
|
||||
<template #item.createdAt="{ item }">{{ $util.prettyDateTime(item.createdAt) }}</template>
|
||||
<template #item.resolved="{ item }">
|
||||
<span v-if="item.resolved">{{ $t('flags.resolved', [item.resolvedByName, $util.prettyDate(item.resolvedAt)]) }}</span>
|
||||
<span v-else v-text="$t('flags.notResolved')"></span>
|
||||
</template>
|
||||
</v-data-table>
|
||||
<v-alert v-else type="info" prominent>{{ $t('flags.noFlags') }}</v-alert>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'nuxt-property-decorator';
|
||||
import { Project } from 'hangar-api';
|
||||
import { Component } from 'nuxt-property-decorator';
|
||||
import { Flag } from 'hangar-internal';
|
||||
import { Context } from '@nuxt/types';
|
||||
import { GlobalPermission } from '~/utils/perms';
|
||||
import { NamedPermission } from '~/types/enums';
|
||||
import { HangarProjectMixin } from '~/components/mixins';
|
||||
|
||||
@Component
|
||||
@GlobalPermission(NamedPermission.MOD_NOTES_AND_FLAGS)
|
||||
export default class ProjectFlagsPage extends Vue {
|
||||
@Prop({ required: true })
|
||||
project!: Project;
|
||||
|
||||
flags!: Flag[];
|
||||
export default class ProjectFlagsPage extends HangarProjectMixin {
|
||||
flags: Flag[] = [];
|
||||
|
||||
get headers() {
|
||||
return [
|
||||
@ -45,9 +43,8 @@ export default class ProjectFlagsPage extends Vue {
|
||||
];
|
||||
}
|
||||
|
||||
async asyncData({ $api, $util, params }: Context) {
|
||||
const flags = await $api.requestInternal<Flag[]>(`flags/${params.author}/${params.slug}`, false).catch<any>($util.handlePageRequestError);
|
||||
return { flags };
|
||||
async fetch() {
|
||||
this.flags = (await this.$api.requestInternal<Flag[]>(`flags/${this.project.id}`, false).catch<any>(this.$util.handlePageRequestError)) || [];
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -2,31 +2,50 @@
|
||||
<v-card>
|
||||
<v-card-title>{{ $t('flagReview.title') }}</v-card-title>
|
||||
<v-card-text>
|
||||
<!-- TODO link to project -->
|
||||
<v-list v-if="flags.length > 0">
|
||||
<v-list-item v-for="flag in flags" :key="flag.id">
|
||||
<v-list-item-avatar>
|
||||
<UserAvatar :username="flag.reportedByName" clazz="user-avatar-xs"></UserAvatar>
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>{{
|
||||
$t('flagReview.line1', [flag.reportedByName, flag.projectNamespace, $util.prettyDateTime(flag.createdAt)])
|
||||
}}</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ $t('flagReview.line2', [flag.reason, flag.comment]) }}</v-list-item-subtitle>
|
||||
<v-list-item-title>
|
||||
{{
|
||||
$t('flagReview.line1', [
|
||||
flag.reportedByName,
|
||||
`${flag.projectNamespace.owner}/${flag.projectNamespace.slug}`,
|
||||
$util.prettyDateTime(flag.createdAt),
|
||||
])
|
||||
}}
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ $t('flagReview.line2', [$t(flag.reason)]) }}</v-list-item-subtitle>
|
||||
<v-list-item-subtitle>{{ $t('flagReview.line3', [flag.comment]) }}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
<v-list-item-action>
|
||||
<v-btn small :href="$util.forumUrl(flag.reportedByName)"><v-icon>mdi-reply</v-icon>{{ $t('flagReview.msgUser') }}</v-btn>
|
||||
<v-btn small :href="$util.forumUrl(flag.projectOwnerName)"><v-icon>mdi-reply</v-icon>{{ $t('flagReview.msgProjectOwner') }}</v-btn>
|
||||
<v-btn small :href="$util.forumUrl(flag.reportedByName)" class="mr-1">
|
||||
<v-icon small left>mdi-reply</v-icon>
|
||||
{{ $t('flagReview.msgUser') }}
|
||||
</v-btn>
|
||||
<v-btn small :href="$util.forumUrl(flag.projectNamespace.owner)" class="mr-1">
|
||||
<v-icon small left>mdi-reply</v-icon>
|
||||
{{ $t('flagReview.msgProjectOwner') }}
|
||||
</v-btn>
|
||||
<v-menu offset-y>
|
||||
<template #activator="{ on, attrs }">
|
||||
<v-btn small v-bind="attrs" v-on="on"><v-icon>mdi-eye</v-icon>{{ $t('flagReview.visibilityActions') }}</v-btn>
|
||||
<v-btn small v-bind="attrs" color="warning" class="mr-1" v-on="on">
|
||||
<v-icon small left>mdi-eye</v-icon>
|
||||
{{ $t('flagReview.visibilityActions') }}
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-list>
|
||||
<v-list-item v-for="(v, index) in visibilities" :key="index">
|
||||
<v-list-item-title @click="visibility(flag, v)">{{ v }}</v-list-item-title>
|
||||
<v-list-item v-for="(v, index) in visibilities" :key="index" @click="visibility(flag, v)">
|
||||
<v-list-item-title>{{ v }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
<v-btn small color="primary" @click="resolve(flag)"><v-icon>mdi-check</v-icon>{{ $t('flagReview.markResolved') }}</v-btn>
|
||||
<v-btn small color="success" :loading="loading[flag.id]" @click="resolve(flag)"
|
||||
><v-icon small left>mdi-check</v-icon>{{ $t('flagReview.markResolved') }}</v-btn
|
||||
>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
@ -49,11 +68,7 @@ import { GlobalPermission } from '~/utils/perms';
|
||||
@GlobalPermission(NamedPermission.MOD_NOTES_AND_FLAGS)
|
||||
export default class AdminFlagsPage extends Vue {
|
||||
flags!: Flag[];
|
||||
|
||||
async asyncData({ $api, $util }: Context) {
|
||||
const flags = await $api.requestInternal<Flag[]>(`flags/`, false).catch<any>($util.handlePageRequestError);
|
||||
return { flags };
|
||||
}
|
||||
loading: { [key: number]: boolean } = {};
|
||||
|
||||
get visibilities(): Visibility[] {
|
||||
return Object.keys(Visibility) as Visibility[];
|
||||
@ -65,13 +80,29 @@ export default class AdminFlagsPage extends Vue {
|
||||
}
|
||||
|
||||
resolve(flag: Flag) {
|
||||
this.loading[flag.id] = true;
|
||||
this.$api
|
||||
.requestInternal<Flag[]>(`flags/${flag.id}/resolve/true`, false, 'POST')
|
||||
.catch<any>(this.$util.handlePageRequestError)
|
||||
.catch<any>(this.$util.handleRequestError)
|
||||
.then(() => {
|
||||
this.flags = this.flags.filter((f) => f.id !== flag.id);
|
||||
this.$nuxt.refresh();
|
||||
this.$auth.refreshUser();
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading[flag.id] = false;
|
||||
});
|
||||
}
|
||||
|
||||
created() {
|
||||
for (const flag of this.flags) {
|
||||
this.loading[flag.id] = false;
|
||||
}
|
||||
}
|
||||
|
||||
async asyncData({ $api, $util }: Context) {
|
||||
const flags = await $api.requestInternal<Flag[]>(`flags/`, false).catch<any>($util.handlePageRequestError);
|
||||
return { flags };
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
26
frontend/types/internal/projects.d.ts
vendored
26
frontend/types/internal/projects.d.ts
vendored
@ -1,6 +1,6 @@
|
||||
declare module 'hangar-internal' {
|
||||
import { FlagReason, Joinable, Table } from 'hangar-internal';
|
||||
import { Project } from 'hangar-api';
|
||||
import { Joinable, Table } from 'hangar-internal';
|
||||
import { Project, ProjectNamespace } from 'hangar-api';
|
||||
import { ProjectCategory, Visibility } from '~/types/enums';
|
||||
|
||||
interface ProjectOwner {
|
||||
@ -42,18 +42,16 @@ declare module 'hangar-internal' {
|
||||
}
|
||||
|
||||
interface Flag extends Table {
|
||||
userId: number;
|
||||
reportedByName: string;
|
||||
reason: FlagReason;
|
||||
isResolved: boolean;
|
||||
comment: string;
|
||||
resolvedAt: string;
|
||||
resolvedBy: number;
|
||||
resolvedByName: string;
|
||||
projectId: number;
|
||||
projectOwnerName: string;
|
||||
projectSlug: string;
|
||||
projectNamespace: string;
|
||||
userId: number; //
|
||||
reportedByName: string; //
|
||||
reason: string; //
|
||||
resolved: boolean; //
|
||||
comment: string; //
|
||||
resolvedAt: string | null; //
|
||||
resolvedBy: number | null; //
|
||||
resolvedByName: string | null; //
|
||||
projectId: number; //
|
||||
projectNamespace: ProjectNamespace;
|
||||
projectVisibility: Visibility;
|
||||
}
|
||||
|
||||
|
@ -32,8 +32,8 @@ public class FlagController extends HangarController {
|
||||
this.flagService = flagService;
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
@PostMapping(value = "/", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
@PostMapping(path = "/", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
public void flag(@RequestBody @Valid FlagForm form) {
|
||||
flagService.createFlag(form.getProjectId(), form.getReason(), form.getComment());
|
||||
}
|
||||
@ -46,14 +46,14 @@ public class FlagController extends HangarController {
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@GetMapping(value = "/{author}/{slug}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@GetMapping(path = "/{projectId}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@PermissionRequired(perms = NamedPermission.MOD_NOTES_AND_FLAGS)
|
||||
public List<HangarProjectFlag> getFlags(@PathVariable String author, @PathVariable String slug) {
|
||||
return flagService.getFlags(author, slug);
|
||||
public List<HangarProjectFlag> getFlags(@PathVariable long projectId) {
|
||||
return flagService.getFlags(projectId);
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@GetMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@GetMapping(path = "/", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@PermissionRequired(perms = NamedPermission.MOD_NOTES_AND_FLAGS)
|
||||
public List<HangarProjectFlag> getFlags() {
|
||||
return flagService.getFlags();
|
||||
|
@ -7,8 +7,6 @@ import com.vladsch.flexmark.ext.admonition.AdmonitionExtension;
|
||||
import io.papermc.hangar.config.hangar.HangarConfig;
|
||||
import io.papermc.hangar.controllerold.forms.UserAdminForm;
|
||||
import io.papermc.hangar.controllerold.util.StatusZ;
|
||||
import io.papermc.hangar.db.customtypes.LoggedActionType;
|
||||
import io.papermc.hangar.db.customtypes.LoggedActionType.ProjectContext;
|
||||
import io.papermc.hangar.db.customtypes.RoleCategory;
|
||||
import io.papermc.hangar.db.dao.HangarDao;
|
||||
import io.papermc.hangar.db.daoold.PlatformVersionsDao;
|
||||
@ -25,7 +23,6 @@ import io.papermc.hangar.modelold.Role;
|
||||
import io.papermc.hangar.modelold.viewhelpers.Activity;
|
||||
import io.papermc.hangar.modelold.viewhelpers.LoggedActionViewModel;
|
||||
import io.papermc.hangar.modelold.viewhelpers.OrganizationData;
|
||||
import io.papermc.hangar.modelold.viewhelpers.ProjectFlag;
|
||||
import io.papermc.hangar.modelold.viewhelpers.ReviewQueueEntry;
|
||||
import io.papermc.hangar.modelold.viewhelpers.UnhealthyProject;
|
||||
import io.papermc.hangar.modelold.viewhelpers.UserData;
|
||||
@ -38,7 +35,6 @@ import io.papermc.hangar.serviceold.StatsService;
|
||||
import io.papermc.hangar.serviceold.UserActionLogService;
|
||||
import io.papermc.hangar.serviceold.UserService;
|
||||
import io.papermc.hangar.serviceold.VersionService;
|
||||
import io.papermc.hangar.serviceold.project.FlagService;
|
||||
import io.papermc.hangar.serviceold.project.ProjectService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
@ -75,7 +71,6 @@ public class ApplicationController extends HangarController {
|
||||
private final HangarDao<PlatformVersionsDao> platformVersionsDao;
|
||||
private final UserService userService;
|
||||
private final ProjectService projectService;
|
||||
private final FlagService flagService;
|
||||
private final OrgService orgService;
|
||||
private final UserActionLogService userActionLogService;
|
||||
private final VersionService versionService;
|
||||
@ -91,12 +86,11 @@ public class ApplicationController extends HangarController {
|
||||
private final Supplier<UserData> userData;
|
||||
|
||||
@Autowired
|
||||
public ApplicationController(HangarDao<PlatformVersionsDao> platformVersionsDao, UserService userService, ProjectService projectService, OrgService orgService, VersionService versionService, FlagService flagService, UserActionLogService userActionLogService, JobService jobService, SitemapService sitemapService, StatsService statsService, RoleService roleService, StatusZ statusZ, ObjectMapper mapper, HangarConfig hangarConfig, HttpServletRequest request, Supplier<UserData> userData) {
|
||||
public ApplicationController(HangarDao<PlatformVersionsDao> platformVersionsDao, UserService userService, ProjectService projectService, OrgService orgService, VersionService versionService, UserActionLogService userActionLogService, JobService jobService, SitemapService sitemapService, StatsService statsService, RoleService roleService, StatusZ statusZ, ObjectMapper mapper, HangarConfig hangarConfig, HttpServletRequest request, Supplier<UserData> userData) {
|
||||
this.platformVersionsDao = platformVersionsDao;
|
||||
this.userService = userService;
|
||||
this.projectService = projectService;
|
||||
this.orgService = orgService;
|
||||
this.flagService = flagService;
|
||||
this.userActionLogService = userActionLogService;
|
||||
this.versionService = versionService;
|
||||
this.jobService = jobService;
|
||||
@ -151,31 +145,6 @@ public class ApplicationController extends HangarController {
|
||||
return fillModel(mv);
|
||||
}
|
||||
|
||||
@GlobalPermission(NamedPermission.MOD_NOTES_AND_FLAGS)
|
||||
@Secured("ROLE_USER")
|
||||
@GetMapping("/admin/flags")
|
||||
public ModelAndView showFlags() {
|
||||
ModelAndView mav = new ModelAndView("users/admin/flags");
|
||||
mav.addObject("flags", flagService.getAllProjectFlags());
|
||||
return fillModel(mav);
|
||||
}
|
||||
|
||||
@GlobalPermission(NamedPermission.MOD_NOTES_AND_FLAGS)
|
||||
@Secured("ROLE_USER")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@GetMapping("/admin/flags/{id}/resolve/{resolved}")
|
||||
public void setFlagResolved(@PathVariable long id, @PathVariable boolean resolved) {
|
||||
ProjectFlag flag = flagService.getProjectFlag(id);
|
||||
if (flag == null) {
|
||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
if (flag.getFlag().getIsResolved() == resolved) return; // No change
|
||||
|
||||
flagService.markAsResolved(id, resolved);
|
||||
String userName = getCurrentUser().getName();
|
||||
userActionLogService.project(request, LoggedActionType.PROJECT_FLAG_RESOLVED.with(ProjectContext.of(flag.getFlag().getProjectId())), "Flag resovled by " + userName, "Flagged by " + flag.getReportedBy());
|
||||
}
|
||||
|
||||
@GlobalPermission(NamedPermission.VIEW_HEALTH)
|
||||
@Secured("ROLE_USER")
|
||||
@GetMapping("/admin/health")
|
||||
|
@ -1,16 +1,12 @@
|
||||
package io.papermc.hangar.controllerold;
|
||||
|
||||
import io.papermc.hangar.config.hangar.HangarConfig;
|
||||
import io.papermc.hangar.db.customtypes.LoggedActionType;
|
||||
import io.papermc.hangar.db.customtypes.LoggedActionType.ProjectContext;
|
||||
import io.papermc.hangar.db.dao.HangarDao;
|
||||
import io.papermc.hangar.db.daoold.ProjectDao;
|
||||
import io.papermc.hangar.db.modelold.OrganizationsTable;
|
||||
import io.papermc.hangar.db.modelold.ProjectsTable;
|
||||
import io.papermc.hangar.db.modelold.UserProjectRolesTable;
|
||||
import io.papermc.hangar.model.common.NamedPermission;
|
||||
import io.papermc.hangar.model.common.Permission;
|
||||
import io.papermc.hangar.model.common.projects.FlagReason;
|
||||
import io.papermc.hangar.model.common.projects.Visibility;
|
||||
import io.papermc.hangar.modelold.viewhelpers.ProjectData;
|
||||
import io.papermc.hangar.modelold.viewhelpers.ScopedOrganizationData;
|
||||
@ -22,8 +18,6 @@ import io.papermc.hangar.serviceold.OrgService;
|
||||
import io.papermc.hangar.serviceold.RoleService;
|
||||
import io.papermc.hangar.serviceold.StatsService;
|
||||
import io.papermc.hangar.serviceold.UserActionLogService;
|
||||
import io.papermc.hangar.serviceold.UserService;
|
||||
import io.papermc.hangar.serviceold.project.FlagService;
|
||||
import io.papermc.hangar.serviceold.project.ProjectFactory;
|
||||
import io.papermc.hangar.serviceold.project.ProjectService;
|
||||
import io.papermc.hangar.util.AlertUtil;
|
||||
@ -55,33 +49,25 @@ public class ProjectsController extends HangarController {
|
||||
private static final String STATUS_ACCEPT = "accept";
|
||||
private static final String STATUS_UNACCEPT = "unaccept";
|
||||
|
||||
private final HangarConfig hangarConfig;
|
||||
private final UserService userService;
|
||||
private final OrgService orgService;
|
||||
private final FlagService flagService;
|
||||
private final ProjectService projectService;
|
||||
private final ProjectFactory projectFactory;
|
||||
private final RoleService roleService;
|
||||
private final UserActionLogService userActionLogService;
|
||||
private final StatsService statsService;
|
||||
private final HangarDao<ProjectDao> projectDao;
|
||||
|
||||
private final HttpServletRequest request;
|
||||
private final Supplier<ProjectsTable> projectsTable;
|
||||
private final Supplier<ProjectData> projectData;
|
||||
|
||||
@Autowired
|
||||
public ProjectsController(HangarConfig hangarConfig, UserService userService, OrgService orgService, FlagService flagService, ProjectService projectService, ProjectFactory projectFactory, RoleService roleService, UserActionLogService userActionLogService, StatsService statsService, HangarDao<ProjectDao> projectDao, HttpServletRequest request, Supplier<ProjectsTable> projectsTable, Supplier<ProjectData> projectData) {
|
||||
this.hangarConfig = hangarConfig;
|
||||
this.userService = userService;
|
||||
public ProjectsController(OrgService orgService, ProjectService projectService, ProjectFactory projectFactory, RoleService roleService, UserActionLogService userActionLogService, StatsService statsService, HttpServletRequest request, Supplier<ProjectsTable> projectsTable, Supplier<ProjectData> projectData) {
|
||||
this.orgService = orgService;
|
||||
this.flagService = flagService;
|
||||
this.projectService = projectService;
|
||||
this.projectFactory = projectFactory;
|
||||
this.roleService = roleService;
|
||||
this.userActionLogService = userActionLogService;
|
||||
this.statsService = statsService;
|
||||
this.projectDao = projectDao;
|
||||
this.request = request;
|
||||
this.projectsTable = projectsTable;
|
||||
this.projectData = projectData;
|
||||
@ -140,30 +126,6 @@ public class ProjectsController extends HangarController {
|
||||
return null; // TODO implement postDiscussionReply request controller
|
||||
}
|
||||
|
||||
@Secured("ROLE_USER")
|
||||
@PostMapping(value = "/{author}/{slug}/flag", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public ModelAndView flag(@PathVariable String author, @PathVariable String slug, @RequestParam("flag-reason") FlagReason flagReason, @RequestParam String comment) {
|
||||
ProjectsTable project = projectsTable.get();
|
||||
if (flagService.hasUnresolvedFlag(project.getId())) {
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Only 1 flag at a time per project per user");
|
||||
} else if (comment.isBlank()) {
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Comment must not be blank");
|
||||
}
|
||||
flagService.flagProject(project.getId(), flagReason, comment);
|
||||
String userName = getCurrentUser().getName();
|
||||
userActionLogService.project(request, LoggedActionType.PROJECT_FLAGGED.with(ProjectContext.of(project.getId())), "Flagged by " + userName, "Not flagged by " + userName);
|
||||
return Routes.PROJECTS_SHOW.getRedirect(author, slug); // TODO flashing
|
||||
}
|
||||
|
||||
@GlobalPermission(NamedPermission.MOD_NOTES_AND_FLAGS)
|
||||
@Secured("ROLE_USER")
|
||||
@GetMapping("/{author}/{slug}/flags")
|
||||
public ModelAndView showFlags(@PathVariable String author, @PathVariable String slug) {
|
||||
ModelAndView mav = new ModelAndView("projects/admin/flags");
|
||||
mav.addObject("p", projectData.get());
|
||||
return fillModel(mav);
|
||||
}
|
||||
|
||||
@ProjectPermission(NamedPermission.DELETE_PROJECT)
|
||||
@UserLock(route = Routes.PROJECTS_SHOW, args = "{#author, #slug}")
|
||||
@Secured("ROLE_USER")
|
||||
|
@ -1,38 +1,35 @@
|
||||
package io.papermc.hangar.db.dao.internal.projects;
|
||||
|
||||
import io.papermc.hangar.model.db.projects.ProjectFlagTable;
|
||||
import io.papermc.hangar.model.internal.projects.HangarProjectFlag;
|
||||
import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper;
|
||||
import org.jdbi.v3.sqlobject.customizer.BindBean;
|
||||
import org.jdbi.v3.sqlobject.customizer.Timestamped;
|
||||
import org.jdbi.v3.sqlobject.statement.GetGeneratedKeys;
|
||||
import org.jdbi.v3.sqlobject.statement.SqlQuery;
|
||||
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
@RegisterConstructorMapper(HangarProjectFlag.class)
|
||||
public interface HangarProjectFlagsDAO {
|
||||
|
||||
@Timestamped
|
||||
@GetGeneratedKeys
|
||||
@RegisterConstructorMapper(ProjectFlagTable.class)
|
||||
@SqlUpdate("INSERT INTO project_flags (created_at, project_id, user_id, reason, comment) VALUES (:now, :projectId, :userId, :reason, :comment)")
|
||||
ProjectFlagTable insert(@BindBean ProjectFlagTable projectFlagsTable);
|
||||
|
||||
@RegisterConstructorMapper(HangarProjectFlag.class)
|
||||
@SqlQuery("SELECT pf.*, fu.name reported_by_name, ru.name resolved_by_name, p.owner_name project_owner_name, p.slug project_slug, p.visibility project_visibility " +
|
||||
"FROM project_flags pf " +
|
||||
" JOIN projects p ON pf.project_id = p.id " +
|
||||
" JOIN users fu ON pf.user_id = fu.id " +
|
||||
" LEFT JOIN users ru ON ru.id = pf.resolved_by " +
|
||||
"WHERE pf.id = :flagId " +
|
||||
"GROUP BY pf.id, fu.id, ru.id, p.id")
|
||||
HangarProjectFlag getById(long flagId);
|
||||
|
||||
@SqlQuery("SELECT pf.*, fu.name reported_by_name, ru.name resolved_by_name, p.owner_name project_owner_name, p.slug project_slug, p.visibility project_visibility " +
|
||||
"FROM project_flags pf " +
|
||||
" JOIN projects p ON pf.project_id = p.id " +
|
||||
" JOIN users fu ON pf.user_id = fu.id " +
|
||||
" LEFT OUTER JOIN users ru ON ru.id = pf.resolved_by " +
|
||||
"WHERE lower(p.owner_name) = lower(:author) AND lower(p.slug) = lower(:slug)" +
|
||||
"WHERE pf.project_id = :projectId " +
|
||||
"GROUP BY pf.id, fu.id, ru.id, p.id")
|
||||
List<HangarProjectFlag> getFlags(String author, String slug);
|
||||
List<HangarProjectFlag> getFlags(long projectId);
|
||||
|
||||
@RegisterConstructorMapper(HangarProjectFlag.class)
|
||||
@SqlQuery("SELECT pf.*, fu.name reported_by_name, ru.name resolved_by_name, p.owner_name project_owner_name, p.slug project_slug, p.visibility project_visibility " +
|
||||
"FROM project_flags pf " +
|
||||
" JOIN projects p ON pf.project_id = p.id " +
|
||||
@ -41,9 +38,4 @@ public interface HangarProjectFlagsDAO {
|
||||
"WHERE NOT pf.resolved " +
|
||||
"GROUP BY pf.id, fu.id, ru.id, p.id")
|
||||
List<HangarProjectFlag> getFlags();
|
||||
|
||||
@SqlUpdate("UPDATE project_flags SET resolved = :resolved, resolved_by = :resolvedBy, resolved_at = :resolvedAt WHERE id = :flagId")
|
||||
@GetGeneratedKeys
|
||||
@RegisterConstructorMapper(ProjectFlagTable.class)
|
||||
ProjectFlagTable markAsResolved(long flagId, boolean resolved, Long resolvedBy, OffsetDateTime resolvedAt);
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
package io.papermc.hangar.db.dao.internal.table.projects;
|
||||
|
||||
import io.papermc.hangar.model.db.projects.ProjectFlagTable;
|
||||
import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper;
|
||||
import org.jdbi.v3.sqlobject.customizer.BindBean;
|
||||
import org.jdbi.v3.sqlobject.customizer.Timestamped;
|
||||
import org.jdbi.v3.sqlobject.statement.GetGeneratedKeys;
|
||||
import org.jdbi.v3.sqlobject.statement.SqlQuery;
|
||||
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
@Repository
|
||||
@RegisterConstructorMapper(ProjectFlagTable.class)
|
||||
public interface ProjectFlagsDAO {
|
||||
|
||||
@Timestamped
|
||||
@GetGeneratedKeys
|
||||
@SqlUpdate("INSERT INTO project_flags (created_at, project_id, user_id, reason, comment) VALUES (:now, :projectId, :userId, :reason, :comment)")
|
||||
ProjectFlagTable insert(@BindBean ProjectFlagTable projectFlagsTable);
|
||||
|
||||
@SqlUpdate("UPDATE project_flags SET resolved = :resolved, resolved_by = :resolvedBy, resolved_at = :resolvedAt WHERE id = :flagId")
|
||||
void markAsResolved(long flagId, boolean resolved, Long resolvedBy, OffsetDateTime resolvedAt);
|
||||
|
||||
@SqlQuery("SELECT * FROM project_flags WHERE project_id = :projectId AND user_id = :userId AND resolved IS FALSE")
|
||||
ProjectFlagTable getUnresolvedFlag(long projectId, long userId);
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
package io.papermc.hangar.db.daoold;
|
||||
|
||||
import io.papermc.hangar.modelold.viewhelpers.ProjectFlag;
|
||||
import io.papermc.hangar.db.modelold.ProjectFlagsTable;
|
||||
|
||||
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
|
||||
import org.jdbi.v3.sqlobject.customizer.BindBean;
|
||||
import org.jdbi.v3.sqlobject.customizer.Timestamped;
|
||||
import org.jdbi.v3.sqlobject.statement.GetGeneratedKeys;
|
||||
import org.jdbi.v3.sqlobject.statement.SqlQuery;
|
||||
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
@Repository
|
||||
@RegisterBeanMapper(ProjectFlagsTable.class)
|
||||
public interface FlagDao {
|
||||
|
||||
@Timestamped
|
||||
@GetGeneratedKeys
|
||||
@SqlUpdate("INSERT INTO project_flags (created_at, project_id, user_id, reason, comment) VALUES (:now, :projectId, :userId, :reason, :comment)")
|
||||
ProjectFlagsTable insert(@BindBean ProjectFlagsTable projectFlagsTable);
|
||||
|
||||
@RegisterBeanMapper(value = ProjectFlagsTable.class, prefix = "p")
|
||||
@RegisterBeanMapper(value = ProjectFlag.class, prefix = "pf")
|
||||
@SqlQuery("SELECT pf.id p_id, pf.created_at p_created_at, pf.project_id p_project_id, pf.user_id p_user_id, pf.reason p_reason, pf.is_resolved p_is_resolved, pf.comment p_comment, pf.resolved_at p_resolved_at, pf.resolved_by p_resolved_by, " +
|
||||
"fu.name pf_reported_by, ru.name pf_resolved_by, p.owner_name pf_project_owner_name, p.slug pf_project_slug, p.visibility pf_project_visibility " +
|
||||
"FROM project_flags pf " +
|
||||
" JOIN projects p ON pf.project_id = p.id " +
|
||||
" JOIN users fu ON pf.user_id = fu.id " +
|
||||
" LEFT OUTER JOIN users ru ON ru.id = pf.resolved_by " +
|
||||
"WHERE pf.id = :flagId")
|
||||
Map<ProjectFlag, ProjectFlagsTable> getById(long flagId);
|
||||
|
||||
@SqlUpdate("UPDATE project_flags SET is_resolved = :resolved, resolved_by = :resolvedBy, resolved_at = :resolvedAt WHERE id = :flagId")
|
||||
@GetGeneratedKeys
|
||||
ProjectFlagsTable markAsResolved(long flagId, boolean resolved, Long resolvedBy, OffsetDateTime resolvedAt);
|
||||
|
||||
@SqlQuery("SELECT * FROM project_flags WHERE user_id = :userId AND project_id = :projectId AND is_resolved = false")
|
||||
ProjectFlagsTable getUnresolvedFlag(long projectId, long userId);
|
||||
|
||||
@RegisterBeanMapper(value = ProjectFlagsTable.class, prefix = "p")
|
||||
@RegisterBeanMapper(value = ProjectFlag.class, prefix = "pf")
|
||||
@SqlQuery("SELECT pf.id p_id, pf.created_at p_created_at, pf.project_id p_project_id, pf.user_id p_user_id, pf.reason p_reason, pf.is_resolved p_is_resolved, pf.comment p_comment, pf.resolved_at p_resolved_at, pf.resolved_by p_resolved_by, " +
|
||||
"u.name pf_reported_by, ru.name pf_resolved_by, p.owner_name pf_project_owner_name, p.slug pf_project_slug, p.visibility pf_project_visibility " +
|
||||
"FROM project_flags pf " +
|
||||
" JOIN users u ON u.id = pf.user_id " +
|
||||
" JOIN projects p ON pf.project_id = p.id" +
|
||||
" LEFT OUTER JOIN users ru ON ru.id = pf.resolved_by " +
|
||||
"WHERE pf.project_id = :projectId " +
|
||||
"ORDER BY pf.created_at")
|
||||
Map<ProjectFlag, ProjectFlagsTable> getProjectFlags(long projectId);
|
||||
|
||||
@RegisterBeanMapper(value = ProjectFlagsTable.class, prefix = "p")
|
||||
@RegisterBeanMapper(value = ProjectFlag.class, prefix = "pf")
|
||||
@SqlQuery("SELECT pf.id p_id, pf.created_at p_created_at, pf.project_id p_project_id, pf.user_id p_user_id, pf.reason p_reason, pf.is_resolved p_is_resolved, pf.comment p_comment, pf.resolved_at p_resolved_at, pf.resolved_by p_resolved_by, " +
|
||||
"fu.name pf_reported_by, ru.name pf_resolved_by, p.owner_name pf_project_owner_name, p.slug pf_project_slug, p.visibility pf_project_visibility " +
|
||||
"FROM project_flags pf " +
|
||||
" JOIN projects p ON pf.project_id = p.id " +
|
||||
" JOIN users fu ON pf.user_id = fu.id " +
|
||||
" LEFT OUTER JOIN users ru ON ru.id = pf.resolved_by " +
|
||||
"WHERE NOT pf.is_resolved " +
|
||||
"GROUP BY pf.id, fu.id, ru.id, p.id")
|
||||
Map<ProjectFlag, ProjectFlagsTable> getFlags();
|
||||
|
||||
|
||||
}
|
@ -1,18 +1,22 @@
|
||||
package io.papermc.hangar.model.common.projects;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
|
||||
public enum FlagReason {
|
||||
|
||||
INAPPROPRIATE_CONTENT("Inappropriate Content"),
|
||||
IMPERSONATION("Impersonation or Deception"),
|
||||
SPAM("Spam"),
|
||||
MAL_INTENT("Malicious Intent"),
|
||||
OTHER("Other");
|
||||
INAPPROPRIATE_CONTENT("project.flag.flags.inappropriateContent"),
|
||||
IMPERSONATION("project.flag.flags.impersonation"),
|
||||
SPAM("project.flag.flags.spam"),
|
||||
MAL_INTENT("project.flag.flags.malIntent"),
|
||||
OTHER("project.flag.flags.other");
|
||||
|
||||
private final String title;
|
||||
|
||||
FlagReason(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@JsonValue
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
@ -15,10 +15,10 @@ public class ProjectFlagTable extends Table {
|
||||
private boolean resolved;
|
||||
private final String comment;
|
||||
private OffsetDateTime resolvedAt;
|
||||
private long resolvedBy;
|
||||
private Long resolvedBy;
|
||||
|
||||
@JdbiConstructor
|
||||
public ProjectFlagTable(OffsetDateTime createdAt, long id, long projectId, long userId, @EnumByOrdinal FlagReason reason, boolean resolved, String comment, OffsetDateTime resolvedAt, long resolvedBy) {
|
||||
public ProjectFlagTable(OffsetDateTime createdAt, long id, long projectId, long userId, @EnumByOrdinal FlagReason reason, boolean resolved, String comment, OffsetDateTime resolvedAt, Long resolvedBy) {
|
||||
super(createdAt, id);
|
||||
this.projectId = projectId;
|
||||
this.userId = userId;
|
||||
@ -69,11 +69,11 @@ public class ProjectFlagTable extends Table {
|
||||
this.resolvedAt = resolvedAt;
|
||||
}
|
||||
|
||||
public long getResolvedBy() {
|
||||
public Long getResolvedBy() {
|
||||
return resolvedBy;
|
||||
}
|
||||
|
||||
public void setResolvedBy(long resolvedBy) {
|
||||
public void setResolvedBy(Long resolvedBy) {
|
||||
this.resolvedBy = resolvedBy;
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
package io.papermc.hangar.model.internal.projects;
|
||||
|
||||
import io.papermc.hangar.model.api.project.ProjectNamespace;
|
||||
import io.papermc.hangar.model.common.projects.FlagReason;
|
||||
import io.papermc.hangar.model.common.projects.Visibility;
|
||||
import io.papermc.hangar.model.db.projects.ProjectFlagTable;
|
||||
import org.jdbi.v3.core.enums.EnumByOrdinal;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
@ -11,16 +13,14 @@ public class HangarProjectFlag extends ProjectFlagTable {
|
||||
|
||||
private final String reportedByName;
|
||||
private final String resolvedByName;
|
||||
private final String projectOwnerName;
|
||||
private final String projectSlug;
|
||||
private final ProjectNamespace projectNamespace;
|
||||
private final Visibility projectVisibility;
|
||||
|
||||
public HangarProjectFlag(OffsetDateTime createdAt, long id, long projectId, long userId, @EnumByOrdinal FlagReason reason, boolean resolved, String comment, OffsetDateTime resolvedAt, long resolvedBy, String reportedByName, String resolvedByName, String projectOwnerName, String projectSlug, @EnumByOrdinal Visibility projectVisibility) {
|
||||
public HangarProjectFlag(OffsetDateTime createdAt, long id, long projectId, long userId, @EnumByOrdinal FlagReason reason, boolean resolved, String comment, OffsetDateTime resolvedAt, Long resolvedBy, String reportedByName, @Nullable String resolvedByName, String projectOwnerName, String projectSlug, @EnumByOrdinal Visibility projectVisibility) {
|
||||
super(createdAt, id, projectId, userId, reason, resolved, comment, resolvedAt, resolvedBy);
|
||||
this.reportedByName = reportedByName;
|
||||
this.resolvedByName = resolvedByName;
|
||||
this.projectOwnerName = projectOwnerName;
|
||||
this.projectSlug = projectSlug;
|
||||
this.projectNamespace = new ProjectNamespace(projectOwnerName, projectSlug);
|
||||
this.projectVisibility = projectVisibility;
|
||||
}
|
||||
|
||||
@ -32,29 +32,20 @@ public class HangarProjectFlag extends ProjectFlagTable {
|
||||
return resolvedByName;
|
||||
}
|
||||
|
||||
public String getProjectOwnerName() {
|
||||
return projectOwnerName;
|
||||
}
|
||||
|
||||
public String getProjectSlug() {
|
||||
return projectSlug;
|
||||
public ProjectNamespace getProjectNamespace() {
|
||||
return projectNamespace;
|
||||
}
|
||||
|
||||
public Visibility getProjectVisibility() {
|
||||
return projectVisibility;
|
||||
}
|
||||
|
||||
public String getProjectNamespace() {
|
||||
return projectOwnerName + "/" + projectSlug;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HangarProjectFlag{" +
|
||||
"reportedByName='" + reportedByName + '\'' +
|
||||
", resolvedByName='" + resolvedByName + '\'' +
|
||||
", projectOwnerName='" + projectOwnerName + '\'' +
|
||||
", projectSlug='" + projectSlug + '\'' +
|
||||
", projectNamespace=" + projectNamespace +
|
||||
", projectVisibility=" + projectVisibility +
|
||||
"} " + super.toString();
|
||||
}
|
||||
|
@ -1,11 +1,17 @@
|
||||
package io.papermc.hangar.service.internal.admin;
|
||||
|
||||
import io.papermc.hangar.db.customtypes.LoggedActionType;
|
||||
import io.papermc.hangar.db.customtypes.LoggedActionType.ProjectContext;
|
||||
import io.papermc.hangar.db.dao.HangarDao;
|
||||
import io.papermc.hangar.db.dao.internal.projects.HangarProjectFlagsDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.projects.ProjectFlagsDAO;
|
||||
import io.papermc.hangar.exceptions.HangarApiException;
|
||||
import io.papermc.hangar.model.common.projects.FlagReason;
|
||||
import io.papermc.hangar.model.db.projects.ProjectFlagTable;
|
||||
import io.papermc.hangar.model.internal.projects.HangarProjectFlag;
|
||||
import io.papermc.hangar.service.HangarService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
@ -14,25 +20,43 @@ import java.util.List;
|
||||
@Service
|
||||
public class FlagService extends HangarService {
|
||||
|
||||
private final ProjectFlagsDAO projectFlagsDAO;
|
||||
private final HangarProjectFlagsDAO hangarProjectFlagsDAO;
|
||||
|
||||
public FlagService(HangarDao<HangarProjectFlagsDAO> hangarProjectFlagsDAO) {
|
||||
@Autowired
|
||||
public FlagService(HangarDao<ProjectFlagsDAO> projectFlagsDAO, HangarDao<HangarProjectFlagsDAO> hangarProjectFlagsDAO) {
|
||||
this.projectFlagsDAO = projectFlagsDAO.get();
|
||||
this.hangarProjectFlagsDAO = hangarProjectFlagsDAO.get();
|
||||
}
|
||||
|
||||
public void createFlag(long projectId, FlagReason reason, String comment) {
|
||||
// TODO idk, we prolly need more checking here, plus notification? logs?
|
||||
hangarProjectFlagsDAO.insert(new ProjectFlagTable( projectId, getHangarPrincipal().getId(), reason, comment));
|
||||
if (hasUnresolvedFlag(projectId, getHangarPrincipal().getId())) {
|
||||
throw new HangarApiException("project.flag.error.alreadyOpen");
|
||||
}
|
||||
projectFlagsDAO.insert(new ProjectFlagTable( projectId, getHangarPrincipal().getId(), reason, comment));
|
||||
userActionLogService.project(LoggedActionType.PROJECT_FLAGGED.with(ProjectContext.of(projectId)), "Flagged by " + getHangarPrincipal().getName(), "");
|
||||
}
|
||||
|
||||
public ProjectFlagTable markAsResolved(long flagId, boolean resolved) {
|
||||
public boolean hasUnresolvedFlag(long projectId, long userId) {
|
||||
return projectFlagsDAO.getUnresolvedFlag(projectId, userId) != null;
|
||||
}
|
||||
|
||||
public void markAsResolved(long flagId, boolean resolved) {
|
||||
HangarProjectFlag hangarProjectFlag = hangarProjectFlagsDAO.getById(flagId);
|
||||
if (hangarProjectFlag == null) {
|
||||
throw new HangarApiException(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
if (hangarProjectFlag.isResolved()) {
|
||||
throw new HangarApiException("project.flag.error.alreadyResolved");
|
||||
}
|
||||
Long resolvedBy = resolved ? getHangarPrincipal().getId() : null;
|
||||
OffsetDateTime resolvedAt = resolved ? OffsetDateTime.now() : null;
|
||||
return hangarProjectFlagsDAO.markAsResolved(flagId, resolved, resolvedBy, resolvedAt);
|
||||
projectFlagsDAO.markAsResolved(flagId, resolved, resolvedBy, resolvedAt);
|
||||
userActionLogService.project(LoggedActionType.PROJECT_FLAG_RESOLVED.with(ProjectContext.of(hangarProjectFlag.getProjectId())), "Flag resolved by " + getHangarPrincipal().getName(), "Flag reported by " + hangarProjectFlag.getReportedByName());
|
||||
}
|
||||
|
||||
public List<HangarProjectFlag> getFlags(String author, String slug) {
|
||||
return hangarProjectFlagsDAO.getFlags(author, slug);
|
||||
public List<HangarProjectFlag> getFlags(long projectId) {
|
||||
return hangarProjectFlagsDAO.getFlags(projectId);
|
||||
}
|
||||
|
||||
public List<HangarProjectFlag> getFlags() {
|
||||
|
@ -1,60 +0,0 @@
|
||||
package io.papermc.hangar.serviceold.project;
|
||||
|
||||
import io.papermc.hangar.db.dao.HangarDao;
|
||||
import io.papermc.hangar.db.daoold.FlagDao;
|
||||
import io.papermc.hangar.db.modelold.ProjectFlagsTable;
|
||||
import io.papermc.hangar.model.common.projects.FlagReason;
|
||||
import io.papermc.hangar.modelold.viewhelpers.ProjectFlag;
|
||||
import io.papermc.hangar.serviceold.HangarService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Service("flagServiceOld")
|
||||
public class FlagService extends HangarService {
|
||||
|
||||
private final HangarDao<FlagDao> flagDao;
|
||||
|
||||
@Autowired
|
||||
public FlagService(HangarDao<FlagDao> flagDao) {
|
||||
this.flagDao = flagDao;
|
||||
}
|
||||
|
||||
public boolean hasUnresolvedFlag(long projectId) {
|
||||
return flagDao.get().getUnresolvedFlag(projectId, getCurrentUser().getId()) != null;
|
||||
}
|
||||
|
||||
public void flagProject(long projectId, FlagReason flagReason, String comment) {
|
||||
ProjectFlagsTable flag = new ProjectFlagsTable(
|
||||
projectId,
|
||||
getCurrentUser().getId(),
|
||||
flagReason,
|
||||
comment
|
||||
);
|
||||
flagDao.get().insert(flag);
|
||||
}
|
||||
|
||||
public ProjectFlagsTable markAsResolved(long flagId, boolean resolved) {
|
||||
Long resolvedBy = resolved ? getCurrentUser().getId() : null;
|
||||
OffsetDateTime resolvedAt = resolved ? OffsetDateTime.now() : null;
|
||||
return flagDao.get().markAsResolved(flagId, resolved, resolvedBy, resolvedAt);
|
||||
}
|
||||
|
||||
public List<ProjectFlag> getProjectFlags(long projectId) {
|
||||
return flagDao.get().getProjectFlags(projectId).entrySet().stream().map(entry -> entry.getKey().with(entry.getValue())).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public ProjectFlag getProjectFlag(long flagId) {
|
||||
List<ProjectFlag> flags = flagDao.get().getById(flagId).entrySet().stream().map(entry -> entry.getKey().with(entry.getValue())).collect(Collectors.toList());
|
||||
if (flags.size() != 1) return null;
|
||||
return flags.get(0);
|
||||
}
|
||||
|
||||
public List<ProjectFlag> getAllProjectFlags() {
|
||||
return flagDao.get().getFlags().entrySet().stream().map(entry -> entry.getKey().with(entry.getValue())).collect(Collectors.toList());
|
||||
}
|
||||
}
|
@ -35,6 +35,7 @@ import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -51,21 +52,19 @@ public class ProjectService extends HangarService {
|
||||
private final HangarDao<UserDao> userDao;
|
||||
private final HangarDao<VisibilityDao> visibilityDao;
|
||||
private final HangarDao<GeneralDao> generalDao;
|
||||
private final FlagService flagService;
|
||||
private final PermissionService permissionService;
|
||||
private final ProjectFiles projectFiles;
|
||||
|
||||
private final HttpServletRequest request;
|
||||
|
||||
@Autowired
|
||||
public ProjectService(HangarConfig hangarConfig, HangarDao<ProjectDao> projectDao, HangarDao<UserDao> userDao, HangarDao<VisibilityDao> visibilityDao, HangarDao<GeneralDao> generalDao, ProjectFiles projectFiles, FlagService flagService, PermissionService permissionService, HttpServletRequest request) {
|
||||
public ProjectService(HangarConfig hangarConfig, HangarDao<ProjectDao> projectDao, HangarDao<UserDao> userDao, HangarDao<VisibilityDao> visibilityDao, HangarDao<GeneralDao> generalDao, ProjectFiles projectFiles, PermissionService permissionService, HttpServletRequest request) {
|
||||
this.hangarConfig = hangarConfig;
|
||||
this.projectDao = projectDao;
|
||||
this.userDao = userDao;
|
||||
this.visibilityDao = visibilityDao;
|
||||
this.generalDao = generalDao;
|
||||
this.projectFiles = projectFiles;
|
||||
this.flagService = flagService;
|
||||
this.permissionService = permissionService;
|
||||
this.request = request;
|
||||
}
|
||||
@ -106,7 +105,7 @@ public class ProjectService extends HangarService {
|
||||
|
||||
int publicVersions = 0;
|
||||
Map<UserProjectRolesTable, UsersTable> projectMembers = projectDao.get().getProjectMembers(projectsTable.getId());
|
||||
List<ProjectFlag> flags = flagService.getProjectFlags(projectsTable.getId());
|
||||
List<ProjectFlag> flags = /*flagService.getProjectFlags(projectsTable.getId());*/ new ArrayList<>();
|
||||
ArrayNode messages = (ArrayNode) projectsTable.getNotes().getJson().get("messages");
|
||||
int noteCount;
|
||||
if (messages == null) {
|
||||
|
@ -1,55 +0,0 @@
|
||||
<#import "/spring.ftl" as spring />
|
||||
<#import "*/utils/hangar.ftlh" as hangar />
|
||||
<#import "*/layout/base.ftlh" as base />
|
||||
|
||||
<#assign message><@spring.message "project.flag.plural" /></#assign>
|
||||
<@base.base title="${message}">
|
||||
<div class="row">
|
||||
<div class="col-md-12 header-flags">
|
||||
<div class="clearfix">
|
||||
<h1 class="float-left"><@spring.message "project.flag.plural" /> for <a href="${Routes.PROJECTS_SHOW.getRouteUrl(p.project.ownerName, p.project.slug)}">${p.project.ownerName}/${p.project.slug}</a></h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<#if p.flagCount == 0>
|
||||
<div class="alert-review alert alert-info" role="alert">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
No flags found
|
||||
</div>
|
||||
<#else>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title float-left"><@spring.message "project.flag.plural" /></h4>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<table class="table table-sm setting-no-border table-review-log">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Submitter</th>
|
||||
<th>Reason</th>
|
||||
<th>When</th>
|
||||
<th>Resolved</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<#list p.flags as flag>
|
||||
<tr>
|
||||
<td>${flag.reportedBy}</td>
|
||||
<td>${flag.flag.reason.title}, ${flag.flag.comment}</td>
|
||||
<td>${utils.prettifyDateTime(flag.flag.createdAt)}</td>
|
||||
<#if flag.flag.isResolved>
|
||||
<td>${flag.resolvedBy} at ${utils.prettifyDateTime(flag.flag.resolvedAt)}</td>
|
||||
<#else>
|
||||
<td>-not resolved-</td>
|
||||
</#if>
|
||||
</tr>
|
||||
</#list>
|
||||
</tbody>
|
||||
</table>
|
||||
</#if>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</@base.base>
|
@ -1,86 +0,0 @@
|
||||
<#import "/spring.ftl" as spring />
|
||||
<#import "*/utils/hangar.ftlh" as hangar />
|
||||
<#import "*/layout/base.ftlh" as base />
|
||||
<#import "*/projects/helper/btnHide.ftlh" as hide />
|
||||
|
||||
<#assign scriptsVar>
|
||||
<script type="text/javascript" src="${hangar.url("js/adminFlags.js")}"></script>
|
||||
<script type="text/javascript" src="${hangar.url("js/hideProject.js")}"></script>
|
||||
</#assign>
|
||||
|
||||
<@base.base title="Flags" additionalScripts=scriptsVar>
|
||||
<div class="row">
|
||||
<div class="col-md-12 header-flags">
|
||||
<h2>Flags</h2>
|
||||
<h3 class="minor no-flags" <#if flags?has_content>style="display: none;"</#if>>
|
||||
<i class="far fa-thumbs-up"></i> <@spring.message "user.flags.none" />
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<ul class="list-group list-flags-admin">
|
||||
<#list flags as flag>
|
||||
<li data-flag-id="${flag.flag.id}" class="list-group-item">
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-1" style="width: 40px;">
|
||||
<a href="${Routes.USERS_SHOW_PROJECTS.getRouteUrl(flag.reportedBy)}">
|
||||
<#import "*/utils/userAvatar.ftlh" as userAvatar>
|
||||
<@userAvatar.userAvatar userName=flag.reportedBy avatarUrl=utils.format(config.security.api.avatarUrl, flag.reportedBy) clazz="user-avatar-xs"></@userAvatar.userAvatar>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-12 col-md-11">
|
||||
<span class="description">
|
||||
<strong>${flag.reportedBy}</strong>
|
||||
<span class="minor"> reported </span>
|
||||
<a href="${Routes.PROJECTS_SHOW.getRouteUrl(flag.projectOwnerName, flag.projectSlug)}">
|
||||
${flag.projectNamespace}
|
||||
</a>
|
||||
<span class="minor"> for </span>
|
||||
<strong>${flag.flag.reason.title}</strong>
|
||||
<span class="minor"> at </span>
|
||||
<strong>${utils.prettifyDateTime(flag.flag.createdAt)}</strong>
|
||||
<br><i class="minor">${flag.flag.comment}</i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<span class="float-right btn-group-sm">
|
||||
<a target="_blank" rel="noopener" href="https://papermc.io/forums/users/${flag.reportedBy}" class="btn btn-default">
|
||||
<i class="fas fa-reply"></i> <@spring.message "user.flags.messageUser" />
|
||||
</a>
|
||||
<a target="_blank" rel="noopener" href="https://papermc.io/forums/users/${flag.projectOwnerName}" class="btn btn-default">
|
||||
<i class="fas fa-reply"></i> <@spring.message "user.flags.messageOwner" />
|
||||
</a>
|
||||
<@hide.btnHide flag.projectNamespace flag.projectVisibility />
|
||||
<button type="submit" class="btn btn-primary btn-resolve">
|
||||
<i class="fas fa-check"></i> <strong><@spring.message "user.flags.markResolved" /></strong>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</#list>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="modal-visibility-needschanges" tabindex="-1" role="dialog" aria-labelledby="modal-visibility-needschanges">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="<@spring.message "general.close" />">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="modal-title">Needs Changes</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<textarea class="textarea-needschanges form-control" rows="3"></textarea>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-default" data-dismiss="modal"><@spring.message "general.close" /></button>
|
||||
<button class="btn btn-visibility-needschanges-submit btn-primary"><i class="fa fa-pencil-alt"></i> Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</@base.base>
|
Loading…
Reference in New Issue
Block a user