mirror of
https://github.com/HangarMC/Hangar.git
synced 2024-11-21 01:21:54 +08:00
project notes backend
This commit is contained in:
parent
027b5b0bb2
commit
fd3a882507
@ -497,7 +497,7 @@ const msgs: LocaleMessageObject = {
|
||||
notes: {
|
||||
header: 'Notes for',
|
||||
noNotes: 'No notes found',
|
||||
addNote: 'Add notes',
|
||||
addNote: 'Add note',
|
||||
notes: 'Notes',
|
||||
placeholder: 'Add a note...',
|
||||
},
|
||||
|
@ -7,15 +7,21 @@
|
||||
</NuxtLink>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-text-field v-model="text" :placeholder="$t('notes.placeholder')">
|
||||
<v-text-field v-model.trim="text" filled :placeholder="$t('notes.placeholder')" dense hide-details @keyup.enter="addNote">
|
||||
<template #append-outer>
|
||||
<v-btn @click="addNote">{{ $t('notes.addNote') }}</v-btn>
|
||||
<v-btn class="input-append-btn" color="primary" :disabled="!text" :loading="loading" @click="addNote">{{ $t('notes.addNote') }}</v-btn>
|
||||
</template>
|
||||
</v-text-field>
|
||||
<h2>{{ $t('notes.notes') }}</h2>
|
||||
<v-data-table v-if="notes && notes.length > 0" :headers="headers" :items="notes" disable-filtering disable-sort hide-default-footer>
|
||||
<template #item.message="{ item }">{{ item.message }}</template>
|
||||
<template #item.user="{ item }">{{ item.user.name }}</template>
|
||||
<h2 class="mt-2">{{ $t('notes.notes') }}</h2>
|
||||
<v-data-table
|
||||
v-if="notes && notes.length > 0"
|
||||
:headers="headers"
|
||||
:items="notes"
|
||||
:loading="$fetchState.pending"
|
||||
disable-filtering
|
||||
disable-sort
|
||||
hide-default-footer
|
||||
>
|
||||
<template #item.createdAt="{ item }">{{ $util.prettyDate(item.createdAt) }}</template>
|
||||
</v-data-table>
|
||||
<v-alert v-else type="info" prominent v-text="$t('notes.noNotes')" />
|
||||
@ -24,42 +30,49 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'nuxt-property-decorator';
|
||||
import { Project } from 'hangar-api';
|
||||
import { Component } from 'nuxt-property-decorator';
|
||||
import { Note } from 'hangar-internal';
|
||||
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 ProjectNotesPage extends Vue {
|
||||
@Prop({ required: true })
|
||||
project!: Project;
|
||||
|
||||
// todo load notes
|
||||
notes: Array<Note> = [];
|
||||
|
||||
export default class ProjectNotesPage extends HangarProjectMixin {
|
||||
notes: Note[] = [];
|
||||
loading = false;
|
||||
text: string = '';
|
||||
|
||||
addNote() {
|
||||
const note = {
|
||||
id: -1,
|
||||
message: this.text,
|
||||
user: this.$util.getCurrentUser(),
|
||||
createdAt: new Date().toISOString(),
|
||||
} as Note;
|
||||
this.text = '';
|
||||
this.notes.push(note);
|
||||
// TODO add new note to server
|
||||
if (!this.text) {
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
this.$api
|
||||
.requestInternal(`projects/notes/${this.project.id}`, true, 'post', {
|
||||
content: this.text,
|
||||
})
|
||||
.then(() => {
|
||||
this.$nuxt.refresh();
|
||||
this.text = '';
|
||||
})
|
||||
.catch(this.$util.handleRequestError)
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
get headers() {
|
||||
return [
|
||||
{ text: 'Date', value: 'createdAt', width: '10%' },
|
||||
{ text: 'User', value: 'user', width: '10%' },
|
||||
{ text: 'User', value: 'userName', width: '10%' },
|
||||
{ text: 'Message', value: 'message', width: '80%' },
|
||||
];
|
||||
}
|
||||
|
||||
async fetch() {
|
||||
this.notes = (await this.$api.requestInternal<Note[]>(`projects/notes/${this.project.id}`, true).catch<any>(this.$util.handleRequestError)) || [];
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
6
frontend/types/internal/projects.d.ts
vendored
6
frontend/types/internal/projects.d.ts
vendored
@ -1,6 +1,6 @@
|
||||
declare module 'hangar-internal' {
|
||||
import { FlagReason, Joinable, Table } from 'hangar-internal';
|
||||
import { Project, User } from 'hangar-api';
|
||||
import { Project } from 'hangar-api';
|
||||
import { ProjectCategory, Visibility } from '~/types/enums';
|
||||
|
||||
interface ProjectOwner {
|
||||
@ -58,8 +58,10 @@ declare module 'hangar-internal' {
|
||||
}
|
||||
|
||||
interface Note extends Table {
|
||||
projectId: number;
|
||||
message: string;
|
||||
user: User;
|
||||
userId: number;
|
||||
userName: string | null;
|
||||
}
|
||||
|
||||
interface ProjectSettingsForm {
|
||||
|
@ -12,12 +12,14 @@ import io.papermc.hangar.model.internal.api.requests.projects.NewProjectForm;
|
||||
import io.papermc.hangar.model.internal.api.requests.projects.ProjectSettingsForm;
|
||||
import io.papermc.hangar.model.internal.api.responses.PossibleProjectOwner;
|
||||
import io.papermc.hangar.model.internal.projects.HangarProject;
|
||||
import io.papermc.hangar.model.internal.projects.HangarProjectNote;
|
||||
import io.papermc.hangar.security.annotations.permission.PermissionRequired;
|
||||
import io.papermc.hangar.security.annotations.unlocked.Unlocked;
|
||||
import io.papermc.hangar.security.annotations.visibility.VisibilityRequired;
|
||||
import io.papermc.hangar.security.annotations.visibility.VisibilityRequired.Type;
|
||||
import io.papermc.hangar.service.internal.organizations.OrganizationService;
|
||||
import io.papermc.hangar.service.internal.projects.ProjectFactory;
|
||||
import io.papermc.hangar.service.internal.projects.ProjectNoteService;
|
||||
import io.papermc.hangar.service.internal.projects.ProjectService;
|
||||
import io.papermc.hangar.service.internal.users.UserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -48,13 +50,15 @@ public class ProjectController extends HangarController {
|
||||
private final ProjectService projectService;
|
||||
private final UserService userService;
|
||||
private final OrganizationService organizationService;
|
||||
private final ProjectNoteService projectNoteService;
|
||||
|
||||
@Autowired
|
||||
public ProjectController(ProjectFactory projectFactory, ProjectService projectService, UserService userService, OrganizationService organizationService) {
|
||||
public ProjectController(ProjectFactory projectFactory, ProjectService projectService, UserService userService, OrganizationService organizationService, ProjectNoteService projectNoteService) {
|
||||
this.projectFactory = projectFactory;
|
||||
this.projectService = projectService;
|
||||
this.userService = userService;
|
||||
this.organizationService = organizationService;
|
||||
this.projectNoteService = projectNoteService;
|
||||
}
|
||||
|
||||
@GetMapping("/validateName")
|
||||
@ -139,8 +143,17 @@ public class ProjectController extends HangarController {
|
||||
userService.toggleWatching(projectId, state);
|
||||
}
|
||||
|
||||
// @GetMapping("/project/{author}/{name}/flags")
|
||||
// public void getProjectFlags(@PathVariable String author, @PathVariable String name) {
|
||||
//
|
||||
// }
|
||||
@PermissionRequired(type = PermissionType.PROJECT, perms = NamedPermission.MOD_NOTES_AND_FLAGS, args = "{#projectId}")
|
||||
@GetMapping(path = "/notes/{projectId}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public ResponseEntity<List<HangarProjectNote>> getProjectNotes(@PathVariable long projectId) {
|
||||
return ResponseEntity.ok(projectNoteService.getNotes(projectId));
|
||||
}
|
||||
|
||||
@Unlocked
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
@PermissionRequired(type = PermissionType.PROJECT, perms = NamedPermission.MOD_NOTES_AND_FLAGS, args = "{#projectId}")
|
||||
@PostMapping(path = "/notes/{projectId}", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
public void addProjectNote(@PathVariable long projectId, @RequestBody @Valid StringContent content) {
|
||||
projectNoteService.addNote(projectId, content.getContent());
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,5 @@
|
||||
package io.papermc.hangar.controllerold;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import io.papermc.hangar.config.hangar.HangarConfig;
|
||||
import io.papermc.hangar.db.customtypes.LoggedActionType;
|
||||
import io.papermc.hangar.db.customtypes.LoggedActionType.ProjectContext;
|
||||
@ -15,11 +12,9 @@ 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.generated.Note;
|
||||
import io.papermc.hangar.modelold.viewhelpers.ProjectData;
|
||||
import io.papermc.hangar.modelold.viewhelpers.ScopedOrganizationData;
|
||||
import io.papermc.hangar.modelold.viewhelpers.ScopedProjectData;
|
||||
import io.papermc.hangar.modelold.viewhelpers.UserData;
|
||||
import io.papermc.hangar.securityold.annotations.GlobalPermission;
|
||||
import io.papermc.hangar.securityold.annotations.ProjectPermission;
|
||||
import io.papermc.hangar.securityold.annotations.UserLock;
|
||||
@ -36,7 +31,6 @@ import io.papermc.hangar.util.Routes;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -49,8 +43,6 @@ import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -212,44 +204,6 @@ public class ProjectsController extends HangarController {
|
||||
return Routes.PROJECTS_SHOW.getRedirect(author, slug);
|
||||
}
|
||||
|
||||
@GlobalPermission(NamedPermission.MOD_NOTES_AND_FLAGS)
|
||||
@Secured("ROLE_USER")
|
||||
@GetMapping("/{author}/{slug}/notes")
|
||||
public ModelAndView showNotes(@PathVariable String author, @PathVariable String slug) {
|
||||
ModelAndView mv = new ModelAndView("projects/admin/notes");
|
||||
ProjectsTable project = projectsTable.get();
|
||||
|
||||
List<Note> notes = new ArrayList<>();
|
||||
ArrayNode messages = (ArrayNode) project.getNotes().getJson().get("messages");
|
||||
if (messages != null) {
|
||||
for (JsonNode message : messages) {
|
||||
Note note = new Note().message(message.get("message").asText());
|
||||
notes.add(note);
|
||||
UserData user = userService.getUserData(message.get("user").asLong());
|
||||
note.user(user.getUser().getName());
|
||||
}
|
||||
}
|
||||
|
||||
mv.addObject("project", project);
|
||||
mv.addObject("notes", notes);
|
||||
return fillModel(mv);
|
||||
}
|
||||
|
||||
@GlobalPermission(NamedPermission.MOD_NOTES_AND_FLAGS)
|
||||
@Secured("ROLE_USER")
|
||||
@PostMapping("/{author}/{slug}/notes/addmessage")
|
||||
public ResponseEntity<String> addMessage(@PathVariable String author, @PathVariable String slug, @RequestParam String content) {
|
||||
ProjectsTable project = projectsTable.get();
|
||||
ArrayNode messages = project.getNotes().getJson().withArray("messages");
|
||||
ObjectNode note = messages.addObject();
|
||||
note.put("message", content);
|
||||
note.put("user", getCurrentUser().getId());
|
||||
|
||||
String json = project.getNotes().getJson().toString();
|
||||
projectDao.get().updateNotes(json, project.getId());
|
||||
return ResponseEntity.ok("Review");
|
||||
}
|
||||
|
||||
@GlobalPermission(NamedPermission.REVIEWER)
|
||||
@UserLock(route = Routes.PROJECTS_SHOW, args = "{#author, #slug}")
|
||||
@Secured("ROLE_USER")
|
||||
|
@ -1,5 +1,7 @@
|
||||
package io.papermc.hangar.db.dao.internal;
|
||||
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;
|
||||
@ -11,11 +13,8 @@ import org.springframework.stereotype.Repository;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import io.papermc.hangar.model.db.projects.ProjectFlagTable;
|
||||
import io.papermc.hangar.model.internal.projects.HangarProjectFlag;
|
||||
|
||||
@Repository
|
||||
public interface HangarFlagsDAO {
|
||||
public interface HangarProjectFlagsDAO {
|
||||
|
||||
@Timestamped
|
||||
@GetGeneratedKeys
|
@ -0,0 +1,19 @@
|
||||
package io.papermc.hangar.db.dao.internal.projects;
|
||||
|
||||
import io.papermc.hangar.model.internal.projects.HangarProjectNote;
|
||||
import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper;
|
||||
import org.jdbi.v3.sqlobject.statement.SqlQuery;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
@RegisterConstructorMapper(HangarProjectNote.class)
|
||||
public interface HangarProjectNotesDAO {
|
||||
|
||||
@SqlQuery("SELECT pn.*, u.name" +
|
||||
" FROM project_notes pn" +
|
||||
" LEFT JOIN users u ON pn.user_id = u.id" +
|
||||
" WHERE pn.project_id = :projectId")
|
||||
List<HangarProjectNote> getProjectNotes(long projectId);
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package io.papermc.hangar.db.dao.internal;
|
||||
package io.papermc.hangar.db.dao.internal.projects;
|
||||
|
||||
import io.papermc.hangar.model.internal.projects.HangarViewProjectPage;
|
||||
import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper;
|
@ -1,4 +1,4 @@
|
||||
package io.papermc.hangar.db.dao.internal;
|
||||
package io.papermc.hangar.db.dao.internal.projects;
|
||||
|
||||
import io.papermc.hangar.db.mappers.PromotedVersionMapper;
|
||||
import io.papermc.hangar.db.mappers.factories.JoinableMemberFactory;
|
||||
@ -74,16 +74,17 @@ public interface HangarProjectsDAO {
|
||||
List<JoinableMember<ProjectRoleTable>> getProjectMembers(long projectId, Long userId, @Define boolean canSeePending);
|
||||
|
||||
@RegisterConstructorMapper(HangarProjectInfo.class)
|
||||
@SqlQuery("SELECT count(pv.*) public_versions," +
|
||||
" count(pf.*) flag_count," +
|
||||
" count(ps.*) star_count," +
|
||||
" count(pw.*) watcher_count," +
|
||||
" coalesce(jsonb_array_length(p.notes->'messages'), 0) note_count" +
|
||||
@SqlQuery("SELECT count(DISTINCT pv.id) public_versions," +
|
||||
" count(DISTINCT pf.id) flag_count," +
|
||||
" count(DISTINCT ps.user_id) star_count," +
|
||||
" count(DISTINCT pw.user_id) watcher_count," +
|
||||
" count(DISTINCT pn.id) note_count" +
|
||||
" FROM projects p" +
|
||||
" LEFT JOIN project_versions pv ON p.id = pv.project_id AND pv.visibility = 0" +
|
||||
" LEFT JOIN project_stars ps ON p.id = ps.project_id" +
|
||||
" LEFT JOIN project_watchers pw ON p.id = pw.project_id" +
|
||||
" LEFT JOIN project_flags pf ON p.id = pf.project_id" +
|
||||
" LEFT JOIN project_notes pn ON p.id = pn.project_id" +
|
||||
" WHERE p.id = :projectId" +
|
||||
" GROUP BY p.id")
|
||||
HangarProjectInfo getHangarProjectInfo(long projectId);
|
@ -0,0 +1,17 @@
|
||||
package io.papermc.hangar.db.dao.internal.table.projects;
|
||||
|
||||
import io.papermc.hangar.model.db.projects.ProjectNoteTable;
|
||||
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.SqlUpdate;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
@RegisterConstructorMapper(ProjectNoteTable.class)
|
||||
public interface ProjectNotesDAO {
|
||||
|
||||
@Timestamped
|
||||
@SqlUpdate("INSERT INTO project_notes (created_at, project_id, message, user_id) VALUES (:now, :projectId, :message, :userId)")
|
||||
void insert(@BindBean ProjectNoteTable projectNoteTable);
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package io.papermc.hangar.model.db.projects;
|
||||
|
||||
import io.papermc.hangar.model.db.Table;
|
||||
import org.jdbi.v3.core.mapper.reflect.JdbiConstructor;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
public class ProjectNoteTable extends Table {
|
||||
|
||||
private final long projectId;
|
||||
private final String message;
|
||||
private final Long userId;
|
||||
|
||||
@JdbiConstructor
|
||||
public ProjectNoteTable(OffsetDateTime createdAt, long id, long projectId, String message, Long userId) {
|
||||
super(createdAt, id);
|
||||
this.projectId = projectId;
|
||||
this.message = message;
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public ProjectNoteTable(long projectId, String message, Long userId) {
|
||||
this.projectId = projectId;
|
||||
this.message = message;
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public long getProjectId() {
|
||||
return projectId;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public Long getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProjectNoteTable{" +
|
||||
"projectId=" + projectId +
|
||||
", message='" + message + '\'' +
|
||||
", userId=" + userId +
|
||||
"} " + super.toString();
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package io.papermc.hangar.model.db.projects;
|
||||
|
||||
import io.papermc.hangar.db.customtypes.JSONB;
|
||||
import io.papermc.hangar.model.ModelVisible;
|
||||
import io.papermc.hangar.model.Visitable;
|
||||
import io.papermc.hangar.model.common.projects.Category;
|
||||
@ -26,7 +25,6 @@ public class ProjectTable extends Table implements Visitable, ModelVisible, Proj
|
||||
private Category category;
|
||||
private String description;
|
||||
private Visibility visibility;
|
||||
private JSONB notes;
|
||||
private Collection<String> keywords;
|
||||
private String homepage;
|
||||
private String issues;
|
||||
@ -63,7 +61,6 @@ public class ProjectTable extends Table implements Visitable, ModelVisible, Proj
|
||||
this.category = other.category;
|
||||
this.description = other.description;
|
||||
this.visibility = other.visibility;
|
||||
this.notes = other.notes;
|
||||
this.keywords = other.keywords;
|
||||
this.homepage = other.homepage;
|
||||
this.issues = other.issues;
|
||||
@ -75,7 +72,7 @@ public class ProjectTable extends Table implements Visitable, ModelVisible, Proj
|
||||
}
|
||||
|
||||
@JdbiConstructor
|
||||
public ProjectTable(OffsetDateTime createdAt, long id, String name, String slug, String ownerName, long ownerId, long topicId, long postId, @EnumByOrdinal Category category, String description, @EnumByOrdinal Visibility visibility, JSONB notes, Collection<String> keywords, String homepage, String issues, String source, String support, String licenseName, String licenseUrl, boolean forumSync) {
|
||||
public ProjectTable(OffsetDateTime createdAt, long id, String name, String slug, String ownerName, long ownerId, long topicId, long postId, @EnumByOrdinal Category category, String description, @EnumByOrdinal Visibility visibility, Collection<String> keywords, String homepage, String issues, String source, String support, String licenseName, String licenseUrl, boolean forumSync) {
|
||||
super(createdAt, id);
|
||||
this.name = name;
|
||||
this.slug = slug;
|
||||
@ -86,7 +83,6 @@ public class ProjectTable extends Table implements Visitable, ModelVisible, Proj
|
||||
this.category = category;
|
||||
this.description = description;
|
||||
this.visibility = visibility;
|
||||
this.notes = notes;
|
||||
this.keywords = keywords;
|
||||
this.homepage = homepage;
|
||||
this.issues = issues;
|
||||
@ -168,14 +164,6 @@ public class ProjectTable extends Table implements Visitable, ModelVisible, Proj
|
||||
this.visibility = visibility;
|
||||
}
|
||||
|
||||
public JSONB getNotes() {
|
||||
return notes;
|
||||
}
|
||||
|
||||
public void setNotes(JSONB notes) {
|
||||
this.notes = notes;
|
||||
}
|
||||
|
||||
public Collection<String> getKeywords() {
|
||||
return keywords;
|
||||
}
|
||||
@ -262,7 +250,6 @@ public class ProjectTable extends Table implements Visitable, ModelVisible, Proj
|
||||
", category=" + category +
|
||||
", description='" + description + '\'' +
|
||||
", visibility=" + visibility +
|
||||
", notes=" + notes +
|
||||
", keywords=" + keywords +
|
||||
", homepage='" + homepage + '\'' +
|
||||
", issues='" + issues + '\'' +
|
||||
|
@ -0,0 +1,29 @@
|
||||
package io.papermc.hangar.model.internal.projects;
|
||||
|
||||
import io.papermc.hangar.model.db.projects.ProjectNoteTable;
|
||||
import org.jdbi.v3.core.mapper.reflect.JdbiConstructor;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
public class HangarProjectNote extends ProjectNoteTable {
|
||||
|
||||
private final String userName;
|
||||
|
||||
@JdbiConstructor
|
||||
public HangarProjectNote(OffsetDateTime createdAt, long id, long projectId, String message, Long userId, @Nullable String name) {
|
||||
super(createdAt, id, projectId, message, userId);
|
||||
this.userName = name;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HangarProjectNote{" +
|
||||
"userName='" + userName + '\'' +
|
||||
"} " + super.toString();
|
||||
}
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
package io.papermc.hangar.modelold.generated;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Objects;
|
||||
|
||||
@Validated
|
||||
public class Note {
|
||||
@JsonProperty("message")
|
||||
private String message = null;
|
||||
|
||||
@JsonProperty("user")
|
||||
private String user = null;
|
||||
|
||||
@JsonProperty("time")
|
||||
private Long time = System.currentTimeMillis();
|
||||
|
||||
/**
|
||||
* Get message
|
||||
*
|
||||
* @return message
|
||||
**/
|
||||
@ApiModelProperty(required = true, value = "")
|
||||
@NotNull
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public Note message(String message) {
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get user
|
||||
*
|
||||
* @return user
|
||||
**/
|
||||
@ApiModelProperty(required = true, value = "")
|
||||
@NotNull
|
||||
public String getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(String user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public Note user(String user) {
|
||||
this.user = user;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Get time
|
||||
*
|
||||
* @return time
|
||||
**/
|
||||
@ApiModelProperty(required = true, value = "")
|
||||
@NotNull
|
||||
public Long getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTime(Long time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public Note slug(Long time) {
|
||||
this.time = time;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OffsetDateTime toDateTime() {
|
||||
return OffsetDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Note note = (Note) o;
|
||||
return Objects.equals(this.message, note.message) &&
|
||||
Objects.equals(this.user, note.user) &&
|
||||
Objects.equals(this.time, note.time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(message, user, time);
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package io.papermc.hangar.service.internal.admin;
|
||||
|
||||
import io.papermc.hangar.db.dao.HangarDao;
|
||||
import io.papermc.hangar.db.dao.internal.HangarFlagsDAO;
|
||||
import io.papermc.hangar.db.dao.internal.projects.HangarProjectFlagsDAO;
|
||||
import io.papermc.hangar.model.common.projects.FlagReason;
|
||||
import io.papermc.hangar.model.db.projects.ProjectFlagTable;
|
||||
import io.papermc.hangar.model.internal.projects.HangarProjectFlag;
|
||||
@ -14,28 +14,28 @@ import java.util.List;
|
||||
@Service
|
||||
public class FlagService extends HangarService {
|
||||
|
||||
private final HangarFlagsDAO flagsDAO;
|
||||
private final HangarProjectFlagsDAO hangarProjectFlagsDAO;
|
||||
|
||||
public FlagService(HangarDao<HangarFlagsDAO> flagsDAO) {
|
||||
this.flagsDAO = flagsDAO.get();
|
||||
public FlagService(HangarDao<HangarProjectFlagsDAO> hangarProjectFlagsDAO) {
|
||||
this.hangarProjectFlagsDAO = hangarProjectFlagsDAO.get();
|
||||
}
|
||||
|
||||
public void createFlag(long projectId, FlagReason reason, String comment) {
|
||||
// TODO idk, we prolly need more checking here, plus notification? logs?
|
||||
flagsDAO.insert(new ProjectFlagTable( projectId, getHangarPrincipal().getId(), reason, comment));
|
||||
hangarProjectFlagsDAO.insert(new ProjectFlagTable( projectId, getHangarPrincipal().getId(), reason, comment));
|
||||
}
|
||||
|
||||
public ProjectFlagTable markAsResolved(long flagId, boolean resolved) {
|
||||
Long resolvedBy = resolved ? getHangarPrincipal().getId() : null;
|
||||
OffsetDateTime resolvedAt = resolved ? OffsetDateTime.now() : null;
|
||||
return flagsDAO.markAsResolved(flagId, resolved, resolvedBy, resolvedAt);
|
||||
return hangarProjectFlagsDAO.markAsResolved(flagId, resolved, resolvedBy, resolvedAt);
|
||||
}
|
||||
|
||||
public List<HangarProjectFlag> getFlags(String author, String slug) {
|
||||
return flagsDAO.getFlags(author, slug);
|
||||
return hangarProjectFlagsDAO.getFlags(author, slug);
|
||||
}
|
||||
|
||||
public List<HangarProjectFlag> getFlags() {
|
||||
return flagsDAO.getFlags();
|
||||
return hangarProjectFlagsDAO.getFlags();
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package io.papermc.hangar.service.internal.projects;
|
||||
|
||||
import io.papermc.hangar.db.dao.HangarDao;
|
||||
import io.papermc.hangar.db.dao.internal.HangarProjectsDAO;
|
||||
import io.papermc.hangar.db.dao.internal.projects.HangarProjectsDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.projects.ProjectChannelsDAO;
|
||||
import io.papermc.hangar.exceptions.HangarApiException;
|
||||
import io.papermc.hangar.model.common.Color;
|
||||
|
@ -0,0 +1,33 @@
|
||||
package io.papermc.hangar.service.internal.projects;
|
||||
|
||||
import io.papermc.hangar.db.dao.HangarDao;
|
||||
import io.papermc.hangar.db.dao.internal.projects.HangarProjectNotesDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.projects.ProjectNotesDAO;
|
||||
import io.papermc.hangar.model.db.projects.ProjectNoteTable;
|
||||
import io.papermc.hangar.model.internal.projects.HangarProjectNote;
|
||||
import io.papermc.hangar.service.HangarService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class ProjectNoteService extends HangarService {
|
||||
|
||||
private final ProjectNotesDAO projectNotesDAO;
|
||||
private final HangarProjectNotesDAO hangarProjectNotesDAO;
|
||||
|
||||
@Autowired
|
||||
public ProjectNoteService(HangarDao<ProjectNotesDAO> projectNotesDAO, HangarDao<HangarProjectNotesDAO> hangarProjectNotesDAO) {
|
||||
this.projectNotesDAO = projectNotesDAO.get();
|
||||
this.hangarProjectNotesDAO = hangarProjectNotesDAO.get();
|
||||
}
|
||||
|
||||
public List<HangarProjectNote> getNotes(long projectId) {
|
||||
return hangarProjectNotesDAO.getProjectNotes(projectId);
|
||||
}
|
||||
|
||||
public void addNote(long projectId, String msg) {
|
||||
projectNotesDAO.insert(new ProjectNoteTable(projectId, msg, getHangarPrincipal().getId()));
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ package io.papermc.hangar.service.internal.projects;
|
||||
import io.papermc.hangar.db.customtypes.LoggedActionType;
|
||||
import io.papermc.hangar.db.customtypes.LoggedActionType.ProjectPageContext;
|
||||
import io.papermc.hangar.db.dao.HangarDao;
|
||||
import io.papermc.hangar.db.dao.internal.HangarProjectPagesDAO;
|
||||
import io.papermc.hangar.db.dao.internal.projects.HangarProjectPagesDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.projects.ProjectPagesDAO;
|
||||
import io.papermc.hangar.exceptions.HangarApiException;
|
||||
import io.papermc.hangar.model.db.projects.ProjectHomePageTable;
|
||||
|
@ -3,8 +3,8 @@ package io.papermc.hangar.service.internal.projects;
|
||||
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.HangarProjectsDAO;
|
||||
import io.papermc.hangar.db.dao.internal.HangarUsersDAO;
|
||||
import io.papermc.hangar.db.dao.internal.projects.HangarProjectsDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.UserDAO;
|
||||
import io.papermc.hangar.db.dao.internal.table.projects.ProjectsDAO;
|
||||
import io.papermc.hangar.exceptions.HangarApiException;
|
||||
|
@ -0,0 +1,27 @@
|
||||
ALTER TABLE project_visibility_changes DROP CONSTRAINT project_visibility_changes_created_by_fkey;
|
||||
ALTER TABLE project_visibility_changes ADD CONSTRAINT project_visibility_changes_created_by_fkey FOREIGN KEY (created_by) REFERENCES users ON DELETE SET NULL;
|
||||
|
||||
ALTER TABLE project_visibility_changes DROP CONSTRAINT project_visibility_changes_resolved_by_fkey;
|
||||
ALTER TABLE project_visibility_changes ADD CONSTRAINT project_visibility_changes_resolved_by_fkey FOREIGN KEY (resolved_by) REFERENCES users ON DELETE SET NULL;
|
||||
|
||||
ALTER TABLE project_version_visibility_changes DROP CONSTRAINT project_version_visibility_changes_created_by_fkey;
|
||||
ALTER TABLE project_version_visibility_changes ADD CONSTRAINT project_version_visibility_changes_created_by_fkey FOREIGN KEY (created_by) REFERENCES users ON DELETE SET NULL;
|
||||
|
||||
ALTER TABLE project_version_visibility_changes DROP CONSTRAINT project_version_visibility_changes_resolved_by_fkey;
|
||||
ALTER TABLE project_version_visibility_changes ADD CONSTRAINT project_version_visibility_changes_resolved_by_fkey FOREIGN KEY (resolved_by) REFERENCES users ON DELETE SET NULL;
|
||||
|
||||
CREATE TABLE project_notes
|
||||
(
|
||||
id bigserial NOT NULL
|
||||
CONSTRAINT notes_pkey PRIMARY KEY,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
project_id bigint NOT NULL
|
||||
CONSTRAINT notes_project_id_fkey
|
||||
REFERENCES projects ON DELETE CASCADE,
|
||||
message text NOT NULL,
|
||||
user_id bigint
|
||||
CONSTRAINT notes_user_id
|
||||
REFERENCES users ON DELETE SET NULL
|
||||
);
|
||||
|
||||
ALTER TABLE projects DROP COLUMN notes;
|
@ -1,59 +0,0 @@
|
||||
<#import "/spring.ftl" as spring />
|
||||
<#import "*/utils/hangar.ftlh" as hangar />
|
||||
<#import "*/layout/base.ftlh" as base />
|
||||
|
||||
<#assign scriptsVar>
|
||||
<script type="text/javascript" src="${hangar.url("js/showNotes.js")}"></script>
|
||||
<script nonce="${nonce}">
|
||||
<#outputformat "JavaScript">
|
||||
window.resourcePath = '${project.ownerName}/${project.slug}'
|
||||
</#outputformat>
|
||||
</script>
|
||||
</#assign>
|
||||
|
||||
<#assign message><@spring.message "notes" /></#assign>
|
||||
<@base.base title="${message}" additionalScripts=scriptsVar>
|
||||
<div class="row">
|
||||
<div class="col-md-12 header-flags">
|
||||
<div class="clearfix">
|
||||
<h1 class="float-left"><@spring.message "notes" /> <a href="${Routes.PROJECTS_SHOW.getRouteUrl(project.ownerName, project.slug)}">${project.ownerName}/${project.slug}</a></h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="input-group" style="width: 100%;
|
||||
margin-top: 1em;">
|
||||
<textarea type="text" class="form-control textarea-addmessage" placeholder="Message"></textarea>
|
||||
<div class="input-group-addon btn btn-note-addmessage-submit btn-primary"><i class="fas fa-clipboard"></i> <@spring.message "notes.addmessage" /></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row version-description">
|
||||
<div class="col-md-12">
|
||||
<h2><@spring.message "notes" /></h2>
|
||||
</div>
|
||||
<#if !notes?has_content>
|
||||
<div class="col-md-12">
|
||||
<div class="alert-notes alert alert-info" role="alert">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
This project does not have notes
|
||||
</div>
|
||||
</div>
|
||||
</#if>
|
||||
|
||||
<div class="col-md-12">
|
||||
<table class="table table-sm setting-no-border table-notes-log">
|
||||
<tbody>
|
||||
<#list notes as note>
|
||||
<tr>
|
||||
<td class="note-fixed-with">${utils.prettifyDateTime(note.toDateTime())}</td>
|
||||
<td class="note-fixed-with"><strong>${note.getUser()!"Unknown"}</strong></td>
|
||||
<td><#outputformat "plainText">${markdownService.render(note.getMessage())}</#outputformat></td>
|
||||
</tr>
|
||||
</#list>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</@base.base>
|
Loading…
Reference in New Issue
Block a user