page name duplicate check

This commit is contained in:
Jake Potrebic 2021-04-09 18:40:21 -07:00
parent 50bf015fc2
commit a3c59c1075
No known key found for this signature in database
GPG Key ID: 7C58557EC9C421F8
5 changed files with 49 additions and 5 deletions

View File

@ -12,12 +12,14 @@
<v-text-field
v-model.trim="form.name"
filled
:loading="validateLoading"
:rules="[
$util.$vc.require($t('page.new.name')),
$util.$vc.regex($t('page.new.name'), validations.project.pageName.regex),
$util.$vc.maxLength(validations.project.pageName.max),
$util.$vc.minLength(validations.project.pageName.min),
]"
:error-messages="nameErrorMessages"
:label="$t('page.new.name')"
/>
<v-select
@ -41,13 +43,17 @@
</template>
<script lang="ts">
import { Component, Prop } from 'nuxt-property-decorator';
import { Component, Prop, Watch } from 'nuxt-property-decorator';
import { PropType } from 'vue';
import { HangarProjectPage } from 'hangar-internal';
import { TranslateResult } from 'vue-i18n';
import { AxiosError } from 'axios';
import { HangarFormModal } from '~/components/mixins';
@Component
export default class NewPageModal extends HangarFormModal {
validateLoading = false;
nameErrorMessages: TranslateResult[] = [];
form = {
name: '',
parent: null as number | null,
@ -92,5 +98,27 @@ export default class NewPageModal extends HangarFormModal {
this.loading = false;
});
}
@Watch('form', { deep: true })
checkName(val: NewPageModal['form']) {
if (!val.name) return;
this.validateLoading = true;
this.nameErrorMessages = [];
this.$api
.requestInternal('pages/checkName', true, 'get', {
projectId: this.projectId,
name: val.name,
parentId: val.parent,
})
.catch((err: AxiosError) => {
if (!err.response?.data.isHangarApiException) {
return this.$util.handleRequestError(err);
}
this.nameErrorMessages.push(this.$t(err.response.data.message));
})
.finally(() => {
this.validateLoading = false;
});
}
}
</script>

View File

@ -120,7 +120,6 @@ export default class AuthorSettingsApiKeysPage extends HangarForm {
};
create() {
// TODO check that name isn't in current keys
this.loading = true;
this.$api
.requestInternal<string>(`api-keys/create-key/${this.$route.params.user}`, true, 'post', {

View File

@ -13,6 +13,7 @@ import io.papermc.hangar.security.annotations.visibility.VisibilityRequired;
import io.papermc.hangar.security.annotations.visibility.VisibilityRequired.Type;
import io.papermc.hangar.service.internal.MarkdownService;
import io.papermc.hangar.service.internal.projects.ProjectPageService;
import io.papermc.hangar.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@ -23,6 +24,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import javax.validation.Valid;
@ -46,6 +48,12 @@ public class ProjectPageController extends HangarComponent {
return ResponseEntity.ok(markdownService.render(content.getContent()));
}
@ResponseStatus(HttpStatus.OK)
@GetMapping("/checkName")
public void checkName(@RequestParam long projectId, @RequestParam String name, @RequestParam(required = false) Long parentId) {
projectPageService.checkDuplicateName(projectId, StringUtils.slugify(name), parentId);
}
@VisibilityRequired(type = Type.PROJECT, args = "{#author, #slug}")
@GetMapping(path = "/page/{author}/{slug}/**", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ExtendedProjectPage> getProjectPage(@PathVariable String author, @PathVariable String slug) {

View File

@ -42,6 +42,9 @@ public interface ProjectPagesDAO {
@SqlQuery("SELECT * FROM project_pages WHERE project_id = :projectId AND parent_id = :parentId AND slug = :slug")
ProjectPageTable getChildPage(long projectId, long parentId, String slug);
@SqlQuery("SELECT * FROM project_pages WHERE project_id = :projectId AND parent_id IS NULL AND slug = :slug")
ProjectPageTable getRootPage(long projectId, String slug);
@SqlQuery("SELECT * FROM project_pages WHERE project_id = :projectId AND id = :pageId")
ProjectPageTable getProjectPage(long projectId, long pageId);
}

View File

@ -33,6 +33,14 @@ public class ProjectPageService extends HangarComponent {
this.hangarProjectPagesDAO = hangarProjectPagesDAO.get();
}
public void checkDuplicateName(long projectId, String slug, @Nullable Long parentId) {
if (parentId != null && projectPagesDAO.getChildPage(projectId, parentId, slug) != null) {
throw new HangarApiException("page.new.error.duplicateName");
} else if (parentId == null && projectPagesDAO.getRootPage(projectId, slug) != null){
throw new HangarApiException("page.new.error.duplicateName");
}
}
@Transactional
public ProjectPageTable createPage(long projectId, String name, String slug, String contents, boolean deletable, @Nullable Long parentId, boolean isHome) {
if (!isHome && contents.length() < config.pages.getMinLen()) {
@ -45,9 +53,7 @@ public class ProjectPageService extends HangarComponent {
config.pages.testPageName(name);
if (parentId != null && projectPagesDAO.getChildPage(projectId, parentId, slug) != null) {
throw new HangarApiException(HttpStatus.BAD_REQUEST, "page.new.error.duplicateName");
}
checkDuplicateName(projectId, slug, parentId);
ProjectPageTable projectPageTable = new ProjectPageTable(
projectId,