2
0
mirror of https://github.com/HangarMC/Hangar.git synced 2025-03-19 15:40:50 +08:00

Route constants, add helper method for redirects

Closes 
This commit is contained in:
KennyTV 2020-09-05 10:14:19 +02:00
parent ce21e8215a
commit f82a8bdaee
No known key found for this signature in database
GPG Key ID: 6BE3B555EBC5982B
52 changed files with 459 additions and 472 deletions

@ -5,8 +5,8 @@
[#-- @ftlvariable name="utils" type="io.papermc.hangar.util.TemplateHelper" --]
[#-- @ftlvariable name="@helper" type="freemarker.template.TemplateHashModel" --]
[#-- @ftlvariable name="alerts" type="java.util.Map" --]
[#-- @ftlvariable name="routes" type="io.papermc.hangar.util.RouteHelper" --]
[#-- @ftlvariable name="rand" type="java.util.Random" --]
[#-- @ftlvariable name="headerData" type="io.papermc.hangar.model.viewhelpers.HeaderData" --]
[#-- @ftlvariable name="rc" type="org.springframework.web.servlet.support.RequestContext" --]
[#-- @ftlvariable name="config" type="io.papermc.hangar.config.hangar.HangarConfig" --]
[#-- @ftlvariable name="Routes" type="io.papermc.hangar.util.Routes" --]

@ -6,7 +6,7 @@ import io.papermc.hangar.controller.converters.StringToEnumConverterFactory;
import io.papermc.hangar.controller.interceptors.ProjectsInterceptor;
import io.papermc.hangar.service.PermissionService;
import io.papermc.hangar.service.project.ProjectService;
import io.papermc.hangar.util.RouteHelper;
import io.papermc.hangar.util.Routes;
import no.api.freemarker.java8.Java8ObjectWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver;
@ -37,13 +37,11 @@ import java.util.concurrent.TimeUnit;
@Configuration
public class MvcConfig implements WebMvcConfigurer {
private final RouteHelper routeHelper;
private final ProjectService projectService;
private final PermissionService permissionService;
@Autowired
public MvcConfig(RouteHelper routeHelper, ProjectService projectService, PermissionService permissionService) {
this.routeHelper = routeHelper;
public MvcConfig(ProjectService projectService, PermissionService permissionService) {
this.projectService = projectService;
this.permissionService = permissionService;
}
@ -108,7 +106,7 @@ public class MvcConfig implements WebMvcConfigurer {
} else if (status == HttpStatus.NOT_FOUND) {
return new ModelAndView("errors/notFound");
} else if (status == HttpStatus.FORBIDDEN) {
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("users.login", "", "", request.getRequestURI()));
return Routes.USERS_LOGIN.getRedirect("", "", request.getRequestURI());
} else {
return new ModelAndView("errors/error");
}

@ -4,7 +4,7 @@ import io.papermc.hangar.filter.HangarAuthenticationFilter;
import io.papermc.hangar.security.HangarAuthenticationProvider;
import io.papermc.hangar.security.voters.GlobalPermissionVoter;
import io.papermc.hangar.service.PermissionService;
import io.papermc.hangar.util.RouteHelper;
import io.papermc.hangar.util.Routes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -28,13 +28,11 @@ import java.util.List;
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final HangarAuthenticationProvider authProvider;
private final RouteHelper routeHelper;
private final PermissionService permissionService;
@Autowired
public SecurityConfig(HangarAuthenticationProvider authProvider, RouteHelper routeHelper, PermissionService permissionService) {
public SecurityConfig(HangarAuthenticationProvider authProvider, PermissionService permissionService) {
this.authProvider = authProvider;
this.routeHelper = routeHelper;
this.permissionService = permissionService;
}
@ -46,7 +44,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
http.addFilter(new HangarAuthenticationFilter());
http.exceptionHandling().authenticationEntryPoint((request, response, e) -> response.sendRedirect(routeHelper.getRouteUrl("users.login", "", "", request.getRequestURI())));
http.exceptionHandling().authenticationEntryPoint((request, response, e) -> response.sendRedirect(Routes.getRouteUrlOf("users.login", "", "", request.getRequestURI())));
http.authorizeRequests().anyRequest().permitAll().accessDecisionManager(accessDecisionManager()); // we use method security
}

@ -110,7 +110,8 @@ public class Apiv1Controller extends HangarController {
pages.stream().filter(p -> {
if (parentId != null) {
return parentId.equals(p.getParentId());
} else return true;
}
return true;
}).forEach(page -> {
ObjectNode pageObj = mapper.createObjectNode();
pageObj.set("createdAt", mapper.valueToTree(page.getCreatedAt()));
@ -201,7 +202,7 @@ public class Apiv1Controller extends HangarController {
Map<Long, ProjectVersionsTable> recommendedVersions = v1ApiService.getProjectsRecommendedVersion(projectIds);
Map<Long, ProjectChannelsTable> recommendedVersionChannels = v1ApiService.getProjectsRecommendedVersionChannel(projectIds);
Map<Long, List<ProjectVersionTagsTable>> vTags = v1ApiService.getVersionsTags(recommendedVersions.entrySet().stream().map(entry -> entry.getValue().getId()).collect(Collectors.toList()));
Map<Long, List<ProjectVersionTagsTable>> vTags = v1ApiService.getVersionsTags(recommendedVersions.values().stream().map(ProjectVersionsTable::getId).collect(Collectors.toList()));
projectsTables.forEach(project -> {
ObjectNode projectObj = mapper.createObjectNode();
@ -296,22 +297,22 @@ public class Apiv1Controller extends HangarController {
return membersArray;
}
@PostMapping(value = "/sync_sso")
@PostMapping("/sync_sso")
public ResponseEntity<MultiValueMap<String, String>> syncSso(@RequestParam String sso, @RequestParam String sig, @RequestParam("api_key") String apiKey) {
if (!apiKey.equals(hangarConfig.sso.getApiKey())) {
log.warn("SSO sync failed: bad API key (" + apiKey + " provided, " + hangarConfig.sso.getApiKey() + " expected)");
log.warn("SSO sync failed: bad API key ({} provided, {} expected)", apiKey, hangarConfig.sso.getApiKey());
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
try {
Map<String, String> map = ssoService.decode(sso, sig);
SsoSyncData data = SsoSyncData.fromSignedPayload(map);
userService.ssoSyncUser(data);
log.debug("SSO sync successful: " + map.toString());
log.debug("SSO sync successful: {}", map.toString());
MultiValueMap<String, String> ssoResponse = new LinkedMultiValueMap<>();
ssoResponse.set("status", "success");
return new ResponseEntity<>(ssoResponse, HttpStatus.OK);
} catch (SignatureException e) {
log.warn("SSO sync failed: invalid signature (" + sig + " for data " + sso + ")");
log.warn("SSO sync failed: invalid signature ({} for data {})", sig, sso);
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}

@ -4,7 +4,7 @@ import io.papermc.hangar.model.Color;
import io.papermc.hangar.model.viewhelpers.ProjectData;
import io.papermc.hangar.service.project.ChannelService;
import io.papermc.hangar.service.project.ProjectService;
import io.papermc.hangar.util.RouteHelper;
import io.papermc.hangar.util.Routes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
@ -19,13 +19,11 @@ public class ChannelsController extends HangarController {
private final ProjectService projectService;
private final ChannelService channelService;
private final RouteHelper routeHelper;
@Autowired
public ChannelsController(ProjectService projectService, ChannelService channelService, RouteHelper routeHelper) {
public ChannelsController(ProjectService projectService, ChannelService channelService) {
this.projectService = projectService;
this.channelService = channelService;
this.routeHelper = routeHelper;
}
@Secured("ROLE_USER")
@ -43,7 +41,7 @@ public class ChannelsController extends HangarController {
public ModelAndView create(@PathVariable String author, @PathVariable String slug, @RequestParam("channel-input") String channelId, @RequestParam("channel-color-input") String channelHex) {
ProjectData projectData = projectService.getProjectData(author, slug);
channelService.addProjectChannel(projectData.getProject().getId(), channelId, Color.getByHexStr(channelHex));
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("channels.showList", author, slug));
return Routes.CHANNELS_SHOW_LIST.getRedirect(author, slug);
}
@Secured("ROLE_USER")
@ -52,14 +50,14 @@ public class ChannelsController extends HangarController {
@RequestParam("channel-input") String newChannelName, @RequestParam("channel-color-input") String newChannelHex) {
ProjectData projectData = projectService.getProjectData(author, slug);
channelService.updateProjectChannel(projectData.getProject().getId(), channel, newChannelName, Color.getByHexStr(newChannelHex));
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("channels.showList", author, slug));
return Routes.CHANNELS_SHOW_LIST.getRedirect(author, slug);
}
@Secured("ROLE_USER")
@PostMapping("/{author}/{slug}/channels/{channel}/delete")
public ModelAndView delete(@PathVariable String author, @PathVariable String slug, @PathVariable String channel) {
// TODO implement delete request controller
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("channels.showList", author, slug));
return Routes.CHANNELS_SHOW_LIST.getRedirect(author, slug);
}
}

@ -3,6 +3,8 @@ package io.papermc.hangar.controller;
import freemarker.ext.beans.BeansWrapperBuilder;
import freemarker.template.Configuration;
import freemarker.template.TemplateHashModel;
import freemarker.template.TemplateModelException;
import io.papermc.hangar.config.hangar.HangarConfig;
import io.papermc.hangar.service.MarkdownService;
import io.papermc.hangar.service.UserService;
@ -14,12 +16,10 @@ import org.springframework.web.servlet.ModelAndView;
import java.util.HashMap;
import java.util.concurrent.ThreadLocalRandom;
import io.papermc.hangar.util.RouteHelper;
import io.papermc.hangar.util.Routes;
public abstract class HangarController {
@Autowired
private RouteHelper routeHelper;
@Autowired
private UserService userService;
@Autowired
@ -31,16 +31,22 @@ public abstract class HangarController {
protected ModelAndView fillModel(ModelAndView mav) {
// helpers
mav.addObject("routes", routeHelper);
BeansWrapperBuilder builder = new BeansWrapperBuilder(Configuration.VERSION_2_3_30);
builder.setExposeFields(true);
builder.setUseModelCache(true);
mav.addObject("@helper", builder.build().getStaticModels());
TemplateHashModel staticModels = builder.build().getStaticModels();
mav.addObject("@helper", staticModels);
mav.addObject("config", hangarConfig);
mav.addObject("markdownService", markdownService);
mav.addObject("rand", ThreadLocalRandom.current());
mav.addObject("utils", templateHelper);
try {
mav.addObject("Routes", staticModels.get("io.papermc.hangar.util.Routes"));
} catch (TemplateModelException e) {
e.printStackTrace();
}
// alerts
if (mav.getModelMap().getAttribute("alerts") == null) {
mav.addObject("alerts", new HashMap<>());

@ -17,7 +17,7 @@ import io.papermc.hangar.service.UserService;
import io.papermc.hangar.util.AlertUtil;
import io.papermc.hangar.util.AlertUtil.AlertType;
import io.papermc.hangar.util.HangarException;
import io.papermc.hangar.util.RouteHelper;
import io.papermc.hangar.util.Routes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@ -42,6 +42,10 @@ import java.util.Map;
@Controller
public class OrgController extends HangarController {
private static final String STATUS_DECLINE = "decline";
private static final String STATUS_ACCEPT = "accept";
private static final String STATUS_UNACCEPT = "unaccept";
private final AuthenticationService authenticationService;
private final OrgService orgService;
private final OrgFactory orgFactory;
@ -49,10 +53,9 @@ public class OrgController extends HangarController {
private final RoleService roleService;
private final NotificationService notificationService;
private final HangarConfig hangarConfig;
private final RouteHelper routeHelper;
@Autowired
public OrgController(AuthenticationService authenticationService, OrgService orgService, OrgFactory orgFactory, UserService userService, RoleService roleService, NotificationService notificationService, HangarConfig hangarConfig, RouteHelper routeHelper) {
public OrgController(AuthenticationService authenticationService, OrgService orgService, OrgFactory orgFactory, UserService userService, RoleService roleService, NotificationService notificationService, HangarConfig hangarConfig) {
this.authenticationService = authenticationService;
this.orgService = orgService;
this.orgFactory = orgFactory;
@ -60,13 +63,8 @@ public class OrgController extends HangarController {
this.roleService = roleService;
this.notificationService = notificationService;
this.hangarConfig = hangarConfig;
this.routeHelper = routeHelper;
}
private final String STATUS_DECLINE = "decline";
private final String STATUS_ACCEPT = "accept";
private final String STATUS_UNACCEPT = "unaccept";
@Secured("ROLE_USER")
@PostMapping("/organizations/invite/{id}/{status}")
@ResponseStatus(HttpStatus.OK)
@ -97,7 +95,7 @@ public class OrgController extends HangarController {
public ModelAndView showCreator(RedirectAttributes attributes, ModelMap modelMap) {
if (orgService.getUserOwnedOrgs(userService.getCurrentUser().getId()).size() >= hangarConfig.org.getCreateLimit()) {
AlertUtil.showAlert(attributes, AlertUtil.AlertType.ERROR, "error.org.createLimit", String.valueOf(hangarConfig.org.getCreateLimit()));
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("showHome"));
return Routes.SHOW_HOME.getRedirect();
}
return fillModel(AlertUtil.transferAlerts(new ModelAndView("createOrganization"), modelMap));
}
@ -111,7 +109,7 @@ public class OrgController extends HangarController {
if (userService.getCurrentUser().isLocked()) throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
if (!hangarConfig.org.isEnabled()) {
AlertUtil.showAlert(attributes, AlertType.ERROR, "error.org.disabled");
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("org.showCreator"));
return Routes.ORG_SHOW_CREATOR.getRedirect();
} else {
Map<Long, Role> userRoles = zip(users, roles);
@ -120,9 +118,9 @@ public class OrgController extends HangarController {
org = orgFactory.createOrganization(name, userService.getCurrentUser().getId(), userRoles);
} catch (HangarException e) {
AlertUtil.showAlert(attributes, AlertType.ERROR, e.getMessageKey(), e.getArgs());
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("org.showCreator"));
return Routes.ORG_SHOW_CREATOR.getRedirect();
}
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("users.showProjects", org.getName()));
return Routes.USERS_SHOW_PROJECTS.getRedirect(org.getName());
}
}
@ -134,7 +132,7 @@ public class OrgController extends HangarController {
URI uri = authenticationService.changeAvatarUri(userService.getCurrentUser().getName(), organization);
return new ModelAndView("redirect:" + uri.toString());
} catch (JsonProcessingException e) {
ModelAndView mav = new ModelAndView("redirect:" + routeHelper.getRouteUrl("users.showProjects", organization));
ModelAndView mav = Routes.USERS_SHOW_PROJECTS.getRedirect(organization);
AlertUtil.showAlert(mav, AlertType.ERROR, "organization.avatarFailed");
return mav;
}
@ -160,7 +158,7 @@ public class OrgController extends HangarController {
roleService.updateRole(org, user.getId(), role);
});
// TODO user action logging for orgs
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("users.showProjects", organization));
return Routes.USERS_SHOW_PROJECTS.getRedirect(organization);
}
@Secured("ROLE_USER")
@ -172,7 +170,7 @@ public class OrgController extends HangarController {
if (roleService.removeMember(org, user.getUser().getId()) != 0) {
// TODO org logging
}
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("users.showProjects", organization));
return Routes.USERS_SHOW_PROJECTS.getRedirect(organization);
}
private <K, V> Map<K, V> zip(List<K> keys, List<V> values) {

@ -14,7 +14,7 @@ import io.papermc.hangar.service.UserActionLogService;
import io.papermc.hangar.service.project.PagesFactory;
import io.papermc.hangar.service.project.PagesSerivce;
import io.papermc.hangar.service.project.ProjectService;
import io.papermc.hangar.util.RouteHelper;
import io.papermc.hangar.util.Routes;
import org.springframework.boot.configurationprocessor.json.JSONException;
import org.springframework.boot.configurationprocessor.json.JSONObject;
@ -38,7 +38,6 @@ import javax.servlet.http.HttpServletRequest;
@Controller
public class PagesController extends HangarController {
private final RouteHelper routeHelper;
private final UserActionLogService userActionLogService;
private final ProjectService projectService;
private final MarkdownService markdownService;
@ -48,8 +47,7 @@ public class PagesController extends HangarController {
private final HttpServletRequest request;
public PagesController(RouteHelper routeHelper, UserActionLogService userActionLogService, ProjectService projectService, MarkdownService markdownService, PagesSerivce pagesSerivce, PagesFactory pagesFactory, HangarDao<ProjectPageDao> projectPageDao, HttpServletRequest request) {
this.routeHelper = routeHelper;
public PagesController(UserActionLogService userActionLogService, ProjectService projectService, MarkdownService markdownService, PagesSerivce pagesSerivce, PagesFactory pagesFactory, HangarDao<ProjectPageDao> projectPageDao, HttpServletRequest request) {
this.userActionLogService = userActionLogService;
this.projectService = projectService;
this.markdownService = markdownService;
@ -102,7 +100,7 @@ public class PagesController extends HangarController {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Cannot delete this page");
}
projectPageDao.get().delete(projectPage);
return new RedirectView(routeHelper.getRouteUrl("projects.show", author, slug));
return new RedirectView(Routes.getRouteUrlOf("projects.show", author, slug));
}
@Secured("ROLE_USER")
@ -136,7 +134,7 @@ public class PagesController extends HangarController {
oldContents = projectPage.getContents();
projectPage.setContents(pageContent);
projectPageDao.get().update(projectPage);
toReturn = new RedirectView(routeHelper.getRouteUrl("pages.show", author, slug, StringUtils.slugify(pageName)));
toReturn = new RedirectView(Routes.getRouteUrlOf("pages.show", author, slug, StringUtils.slugify(pageName)));
}
userActionLogService.projectPage(request, LoggedActionType.PROJECT_PAGE_EDITED.with(ProjectPageContext.of(projectData.getProject().getId(), projectPage.getId())), pageContent, oldContents);
return toReturn;

@ -43,7 +43,7 @@ import io.papermc.hangar.util.AlertUtil;
import io.papermc.hangar.util.AlertUtil.AlertType;
import io.papermc.hangar.util.FileUtils;
import io.papermc.hangar.util.HangarException;
import io.papermc.hangar.util.RouteHelper;
import io.papermc.hangar.util.Routes;
import io.papermc.hangar.util.StringUtils;
import io.papermc.hangar.util.TemplateHelper;
import io.papermc.hangar.util.TriFunction;
@ -85,9 +85,11 @@ import java.util.stream.Collectors;
public class ProjectsController extends HangarController {
public static final Pattern ID_PATTERN = Pattern.compile("[a-z][a-z0-9-_]{0,63}");
private static final String STATUS_DECLINE = "decline";
private static final String STATUS_ACCEPT = "accept";
private static final String STATUS_UNACCEPT = "unaccept";
private final HangarConfig hangarConfig;
private final RouteHelper routeHelper;
private final UserService userService;
private final OrgService orgService;
private final FlagService flagService;
@ -107,9 +109,8 @@ public class ProjectsController extends HangarController {
private final HttpServletRequest request;
@Autowired
public ProjectsController(HangarConfig hangarConfig, RouteHelper routeHelper, UserService userService, OrgService orgService, FlagService flagService, ProjectService projectService, ProjectFactory projectFactory, PagesSerivce pagesSerivce, ApiKeyService apiKeyService, RoleService roleService, NotificationService notificationService, UserActionLogService userActionLogService, ProjectFiles projectFiles, TemplateHelper templateHelper, HangarDao<UserDao> userDao, HangarDao<ProjectDao> projectDao, HangarDao<GeneralDao> generalDao, HttpServletRequest request) {
public ProjectsController(HangarConfig hangarConfig, UserService userService, OrgService orgService, FlagService flagService, ProjectService projectService, ProjectFactory projectFactory, PagesSerivce pagesSerivce, ApiKeyService apiKeyService, RoleService roleService, NotificationService notificationService, UserActionLogService userActionLogService, ProjectFiles projectFiles, TemplateHelper templateHelper, HangarDao<UserDao> userDao, HangarDao<ProjectDao> projectDao, HangarDao<GeneralDao> generalDao, HttpServletRequest request) {
this.hangarConfig = hangarConfig;
this.routeHelper = routeHelper;
this.userService = userService;
this.orgService = orgService;
this.flagService = flagService;
@ -177,13 +178,9 @@ public class ProjectsController extends HangarController {
// refresh home page
generalDao.get().refreshHomeProjects();
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("projects.show", project.getOwnerName(), project.getSlug()));
return Routes.PROJECTS_SHOW.getRedirect(project.getOwnerName(), project.getSlug());
}
private final String STATUS_DECLINE = "decline";
private final String STATUS_ACCEPT = "accept";
private final String STATUS_UNACCEPT = "unaccept";
@Secured("ROLE_USER")
@PostMapping("/invite/{id}/{status}")
@ResponseStatus(HttpStatus.OK)
@ -264,7 +261,7 @@ public class ProjectsController extends HangarController {
flagService.flagProject(projectData.getProject().getId(), flagReason, comment);
String userName = userService.getCurrentUser().getName();
userActionLogService.project(request, LoggedActionType.PROJECT_FLAGGED.with(ProjectContext.of(projectData.getProject().getId())), "Flagged by " + userName, "Not flagged by " + userName);
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("projects.show", author, slug)); // TODO flashing
return Routes.PROJECTS_SHOW.getRedirect(author, slug); // TODO flashing
}
@Secured("ROLE_USER")
@ -282,11 +279,11 @@ public class ProjectsController extends HangarController {
ProjectsTable project = projectService.getProjectData(author, slug).getProject();
if (icon.getContentType() == null || (!icon.getContentType().equals(MediaType.IMAGE_PNG_VALUE) && !icon.getContentType().equals(MediaType.IMAGE_JPEG_VALUE))) {
AlertUtil.showAlert(attributes, AlertUtil.AlertType.ERROR, "error.invalidFile");
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("projects.showSettings", author, slug));
return Routes.PROJECTS_SHOW_SETTINGS.getRedirect(author, slug);
}
if (icon.getOriginalFilename() == null || icon.getOriginalFilename().isBlank()) {
AlertUtil.showAlert(attributes, AlertUtil.AlertType.ERROR, "error.noFile");
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("projects.showSettings", author, slug));
return Routes.PROJECTS_SHOW_SETTINGS.getRedirect(author, slug);
}
try {
Path pendingDir = projectFiles.getPendingIconDir(author, slug);
@ -367,7 +364,7 @@ public class ProjectsController extends HangarController {
userActionLogService.project(request, LoggedActionType.PROJECT_VISIBILITY_CHANGE.with(ProjectContext.of(projectData.getProject().getId())), Visibility.SOFTDELETE.getName(), oldVisibility.getName());
projectFactory.softDeleteProject(projectData, comment);
AlertUtil.showAlert(ra, AlertUtil.AlertType.SUCCESS, "project.deleted", projectData.getProject().getName());
return new RedirectView(routeHelper.getRouteUrl("showHome"));
return new RedirectView(Routes.getRouteUrlOf("showHome"));
}
@Secured("ROLE_USER")
@ -377,7 +374,7 @@ public class ProjectsController extends HangarController {
projectFactory.hardDeleteProject(projectData);
userActionLogService.project(request, LoggedActionType.PROJECT_VISIBILITY_CHANGE.with(ProjectContext.of(projectData.getProject().getId())), "deleted", projectData.getVisibility().getName());
AlertUtil.showAlert(ra, AlertUtil.AlertType.SUCCESS, "project.deleted", projectData.getProject().getName());
return new RedirectView(routeHelper.getRouteUrl("showHome"));
return new RedirectView(Routes.getRouteUrlOf("showHome"));
}
@Secured("ROLE_USER")
@ -394,7 +391,7 @@ public class ProjectsController extends HangarController {
user.getUser().getName() + " is not a member of " + projectData.getNamespace(),
user.getUser().getName() + " is a member of " + projectData.getNamespace());
}
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("projects.showSettings", author, slug));
return Routes.PROJECTS_SHOW_SETTINGS.getRedirect(author, slug);
}
@Secured("ROLE_USER")
@ -417,7 +414,7 @@ public class ProjectsController extends HangarController {
projectData.getProject().setSlug(StringUtils.slugify(compactNewName));
projectDao.get().update(projectData.getProject());
userActionLogService.project(request, LoggedActionType.PROJECT_RENAMED.with(ProjectContext.of(projectData.getProject().getId())), author + "/" + compactNewName, author + "/" + oldName);
return new RedirectView(routeHelper.getRouteUrl("projects.show", author, newName));
return new RedirectView(Routes.getRouteUrlOf("projects.show", author, newName));
}
@Secured("ROLE_USER")
@ -492,7 +489,7 @@ public class ProjectsController extends HangarController {
userActionLogService.project(request, LoggedActionType.PROJECT_SETTINGS_CHANGED.with(ProjectContext.of(projectsTable.getId())), "", "");
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("projects.show", author, slug));
return Routes.PROJECTS_SHOW.getRedirect(author, slug);
}
@Secured("ROLE_USER")
@ -503,7 +500,7 @@ public class ProjectsController extends HangarController {
projectService.changeVisibility(projectData.getProject(), Visibility.NEEDSAPPROVAL, "");
userActionLogService.project(request, LoggedActionType.PROJECT_VISIBILITY_CHANGE.with(ProjectContext.of(projectData.getProject().getId())), Visibility.NEEDSAPPROVAL.getName(), Visibility.NEEDSCHANGES.getName());
}
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("projects.show", author, slug));
return Routes.PROJECTS_SHOW.getRedirect(author, slug);
}
@GlobalPermission(NamedPermission.MOD_NOTES_AND_FLAGS)

@ -20,7 +20,7 @@ import io.papermc.hangar.service.UserActionLogService;
import io.papermc.hangar.service.UserService;
import io.papermc.hangar.service.VersionService;
import io.papermc.hangar.service.project.ProjectService;
import io.papermc.hangar.util.RouteHelper;
import io.papermc.hangar.util.Routes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@ -48,19 +48,17 @@ public class ReviewsController extends HangarController {
private final NotificationService notificationService;
private final UserActionLogService userActionLogService;
private final UserService userService;
private final RouteHelper routeHelper;
private final HttpServletRequest request;
@Autowired
public ReviewsController(ProjectService projectService, VersionService versionService, ReviewService reviewService, NotificationService notificationService, UserActionLogService userActionLogService, UserService userService, RouteHelper routeHelper, HttpServletRequest request) {
public ReviewsController(ProjectService projectService, VersionService versionService, ReviewService reviewService, NotificationService notificationService, UserActionLogService userActionLogService, UserService userService, HttpServletRequest request) {
this.projectService = projectService;
this.versionService = versionService;
this.reviewService = reviewService;
this.notificationService = notificationService;
this.userActionLogService = userActionLogService;
this.userService = userService;
this.routeHelper = routeHelper;
this.request = request;
}
@ -114,7 +112,7 @@ public class ReviewsController extends HangarController {
notificationService.sendNotification(user.getId(), null, NotificationType.VERSION_REVIEWED, new String[]{"notification.project.reviewed", slug, version});
}
});
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("reviews.showReviews", author, slug, version));
return Routes.REVIEWS_SHOW_REVIEWS.getRedirect(author, slug, version);
}
@GlobalPermission(NamedPermission.REVIEWER)
@ -141,7 +139,7 @@ public class ReviewsController extends HangarController {
new JSONB("{}")
);
reviewService.insert(review);
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("reviews.showReviews", author, slug, version));
return Routes.REVIEWS_SHOW_REVIEWS.getRedirect(author, slug, version);
}
@GlobalPermission(NamedPermission.REVIEWER)
@ -161,7 +159,7 @@ public class ReviewsController extends HangarController {
review.addMessage(new VersionReviewMessage("Reopened the review", System.currentTimeMillis(), "start"), reviewService);
reviewService.update(review);
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("reviews.showReviews", author, slug, version));
return Routes.REVIEWS_SHOW_REVIEWS.getRedirect(author, slug, version);
}
@GlobalPermission(NamedPermission.REVIEWER)
@ -178,7 +176,7 @@ public class ReviewsController extends HangarController {
userActionLogService.version(request, LoggedActionType.VERSION_REVIEW_STATE_CHANGED.with(VersionContext.of(versionsTable.getProjectId(), versionsTable.getId())), newState.name(), oldState.name());
versionService.update(versionsTable);
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("reviews.showReviews", author, slug, version));
return Routes.REVIEWS_SHOW_REVIEWS.getRedirect(author, slug, version);
}
@GlobalPermission(NamedPermission.REVIEWER)
@ -193,7 +191,7 @@ public class ReviewsController extends HangarController {
review.setEndedAt(OffsetDateTime.now());
review.addMessage(new VersionReviewMessage(content, System.currentTimeMillis(), "stop"), reviewService);
reviewService.update(review);
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("reviews.showReviews", author, slug, version));
return Routes.REVIEWS_SHOW_REVIEWS.getRedirect(author, slug, version);
}
@GlobalPermission(NamedPermission.REVIEWER)
@ -213,7 +211,7 @@ public class ReviewsController extends HangarController {
userService.getCurrentUser().getId(),
new JSONB("{}")
));
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("reviews.showReviews", author, slug, version));
return Routes.REVIEWS_SHOW_REVIEWS.getRedirect(author, slug, version);
}
}

@ -27,7 +27,7 @@ import io.papermc.hangar.service.sso.AuthUser;
import io.papermc.hangar.service.sso.UrlWithNonce;
import io.papermc.hangar.util.AlertUtil;
import io.papermc.hangar.util.HangarException;
import io.papermc.hangar.util.RouteHelper;
import io.papermc.hangar.util.Routes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@ -57,7 +57,6 @@ import java.util.Optional;
public class UsersController extends HangarController {
private final HangarConfig hangarConfig;
private final RouteHelper routeHelper;
private final AuthenticationService authenticationService;
private final UserService userService;
private final OrgService orgService;
@ -75,9 +74,8 @@ public class UsersController extends HangarController {
@Autowired
public UsersController(HangarConfig hangarConfig, RouteHelper routeHelper, AuthenticationService authenticationService, UserService userService, OrgService orgService, RoleService roleService, ApiKeyService apiKeyService, PermissionService permissionService, NotificationService notificationService, SsoService ssoService, UserActionLogService userActionLogService, HangarDao<UserDao> userDao, SitemapService sitemapService, HttpServletRequest request, HttpServletResponse response) {
public UsersController(HangarConfig hangarConfig, AuthenticationService authenticationService, UserService userService, OrgService orgService, RoleService roleService, ApiKeyService apiKeyService, PermissionService permissionService, NotificationService notificationService, SsoService ssoService, UserActionLogService userActionLogService, HangarDao<UserDao> userDao, SitemapService sitemapService, HttpServletRequest request, HttpServletResponse response) {
this.hangarConfig = hangarConfig;
this.routeHelper = routeHelper;
this.authenticationService = authenticationService;
this.userService = userService;
this.orgService = orgService;
@ -118,14 +116,14 @@ public class UsersController extends HangarController {
return redirectToSso(ssoService.getLoginUrl(hangarConfig.getBaseUrl() + "/login"), attributes);
} catch (HangarException e) {
AlertUtil.showAlert(attributes, AlertUtil.AlertType.ERROR, e.getMessageKey(), e.getArgs());
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("showHome"));
return Routes.SHOW_HOME.getRedirect();
}
} else {
AuthUser authUser = ssoService.authenticate(sso, sig);
if (authUser == null) {
AlertUtil.showAlert(attributes, AlertUtil.AlertType.ERROR, "error.loginFailed");
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("showHome"));
return Routes.SHOW_HOME.getRedirect();
}
UsersTable user = userService.getOrCreate(authUser.getUsername(), authUser);
@ -133,7 +131,7 @@ public class UsersController extends HangarController {
authUser.getGlobalRoles().forEach(role -> roleService.addGlobalRole(user.getId(), role.getRoleId()));
authenticationService.setAuthenticatedUser(user);
String redirectPath = redirectUrl != null ? redirectUrl : routeHelper.getRouteUrl("showHome");
String redirectPath = redirectUrl != null ? redirectUrl : Routes.getRouteUrlOf("showHome");
return new ModelAndView("redirect:" + redirectPath);
}
}
@ -141,7 +139,7 @@ public class UsersController extends HangarController {
private ModelAndView redirectToSso(UrlWithNonce urlWithNonce, RedirectAttributes attributes) {
if (!hangarConfig.sso.isEnabled()) {
AlertUtil.showAlert(attributes, AlertUtil.AlertType.ERROR, "error.noLogin");
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("showHome"));
return Routes.SHOW_HOME.getRedirect();
}
ssoService.insert(urlWithNonce.getNonce());
return new ModelAndView("redirect:" + urlWithNonce.getUrl());
@ -194,7 +192,7 @@ public class UsersController extends HangarController {
return redirectToSso(ssoService.getSignupUrl(returnUrl), attributes);
} catch (HangarException e) {
AlertUtil.showAlert(attributes, AlertUtil.AlertType.ERROR, e.getMessageKey(), e.getArgs());
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("showHome"));
return Routes.SHOW_HOME.getRedirect();
}
}
@ -214,7 +212,7 @@ public class UsersController extends HangarController {
return redirectToSso(ssoService.getVerifyUrl(returnPath), attributes);
} catch (HangarException e) {
AlertUtil.showAlert(attributes, AlertUtil.AlertType.ERROR, e.getMessageKey(), e.getArgs());
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("showHome"));
return Routes.SHOW_HOME.getRedirect();
}
}
@ -247,7 +245,7 @@ public class UsersController extends HangarController {
public RedirectView setLocked(@PathVariable String user, @PathVariable boolean locked, @RequestParam String sso, @RequestParam String sig) {
// TODO auth
userService.setLocked(user, locked);
return new RedirectView(routeHelper.getRouteUrl("users.showProjects", user));
return new RedirectView(Routes.getRouteUrlOf("users.showProjects", user));
}
@Secured("ROLE_USER")
@ -256,13 +254,13 @@ public class UsersController extends HangarController {
if (tagline.length() > hangarConfig.user.getMaxTaglineLen()) {
ModelAndView mav = showProjects(user);
AlertUtil.showAlert(mav, AlertUtil.AlertType.ERROR, "error.tagline.tooLong", String.valueOf(hangarConfig.user.getMaxTaglineLen()));
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("users.showProjects", user));
return Routes.USERS_SHOW_PROJECTS.getRedirect(user);
}
UsersTable usersTable = userDao.get().getByName(user);
userActionLogService.user(request, LoggedActionType.USER_TAGLINE_CHANGED.with(LoggedActionType.UserContext.of(usersTable.getId())), tagline, Optional.ofNullable(usersTable.getTagline()).orElse(""));
usersTable.setTagline(tagline);
userDao.get().update(usersTable);
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("users.showProjects", user));
return Routes.USERS_SHOW_PROJECTS.getRedirect(user);
}
@GetMapping(value = "/{user}/sitemap.xml", produces = MediaType.APPLICATION_XML_VALUE)

@ -32,7 +32,7 @@ import io.papermc.hangar.service.project.ProjectService;
import io.papermc.hangar.util.AlertUtil;
import io.papermc.hangar.util.HangarException;
import io.papermc.hangar.util.RequestUtil;
import io.papermc.hangar.util.RouteHelper;
import io.papermc.hangar.util.Routes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.core.io.FileSystemResource;
@ -71,7 +71,6 @@ public class VersionsController extends HangarController {
private final ChannelService channelService;
private final UserActionLogService userActionLogService;
private final CacheManager cacheManager;
private final RouteHelper routeHelper;
private final HangarConfig hangarConfig;
private final HangarDao<ProjectDao> projectDao;
private final ProjectFiles projectFiles;
@ -81,7 +80,7 @@ public class VersionsController extends HangarController {
private final HttpServletResponse response;
@Autowired
public VersionsController(ProjectService projectService, VersionService versionService, ProjectFactory projectFactory, UserService userService, PluginUploadService pluginUploadService, ChannelService channelService, UserActionLogService userActionLogService, CacheManager cacheManager, RouteHelper routeHelper, HangarConfig hangarConfig, HangarDao<ProjectDao> projectDao, ProjectFiles projectFiles, HangarDao<ProjectVersionDownloadWarningDao> downloadWarningDao, HttpServletRequest request, HttpServletResponse response) {
public VersionsController(ProjectService projectService, VersionService versionService, ProjectFactory projectFactory, UserService userService, PluginUploadService pluginUploadService, ChannelService channelService, UserActionLogService userActionLogService, CacheManager cacheManager, HangarConfig hangarConfig, HangarDao<ProjectDao> projectDao, ProjectFiles projectFiles, HangarDao<ProjectVersionDownloadWarningDao> downloadWarningDao, HttpServletRequest request, HttpServletResponse response) {
this.projectService = projectService;
this.versionService = versionService;
this.projectFactory = projectFactory;
@ -90,7 +89,6 @@ public class VersionsController extends HangarController {
this.channelService = channelService;
this.userActionLogService = userActionLogService;
this.cacheManager = cacheManager;
this.routeHelper = routeHelper;
this.hangarConfig = hangarConfig;
this.projectDao = projectDao;
this.projectFiles = projectFiles;
@ -260,7 +258,7 @@ public class VersionsController extends HangarController {
PendingVersion pendingVersion = cacheManager.getCache(CacheConfig.PENDING_VERSION_CACHE).get(projectData.getProject().getId() + "/" + versionName, PendingVersion.class);
if (pendingVersion == null) {
AlertUtil.showAlert(attributes, AlertUtil.AlertType.ERROR, "error.plugin.timeout");
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("versions.showCreator", author, slug));
return Routes.VERSIONS_SHOW_CREATOR.getRedirect(author, slug);
}
List<ProjectChannelsTable> projectChannels = channelService.getProjectChannels(projectData.getProject().getId());
@ -278,7 +276,7 @@ public class VersionsController extends HangarController {
}
if (alertMsg != null) {
AlertUtil.showAlert(attributes, AlertUtil.AlertType.ERROR, alertMsg, alertArgs);
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("versions.showCreator", author, slug));
return Routes.VERSIONS_SHOW_CREATOR.getRedirect(author, slug);
}
channel = channelService.addProjectChannel(projectData.getProject().getId(), channelInput.trim(), channelColor);
} else {
@ -294,7 +292,7 @@ public class VersionsController extends HangarController {
if (versionService.exists(newPendingVersion)) {
AlertUtil.showAlert(attributes, AlertUtil.AlertType.ERROR, "error.plugin.versionExists");
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("versions.showCreator", author, slug));
return Routes.VERSIONS_SHOW_CREATOR.getRedirect(author, slug);
}
ProjectVersionsTable version;
@ -302,7 +300,7 @@ public class VersionsController extends HangarController {
version = newPendingVersion.complete(request, projectData, projectFactory);
} catch (HangarException e) {
AlertUtil.showAlert(attributes, AlertUtil.AlertType.ERROR, e.getMessage(), e.getArgs());
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("versions.showCreator", author, slug));
return Routes.VERSIONS_SHOW_CREATOR.getRedirect(author, slug);
}
if (recommended) {
@ -316,7 +314,7 @@ public class VersionsController extends HangarController {
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));
return Routes.VERSIONS_SHOW.getRedirect(author, slug, versionName);
}
@GetMapping("/{author}/{slug}/versions/{version:.*}")
@ -354,7 +352,7 @@ public class VersionsController extends HangarController {
versionsTable.setVisibility(Visibility.PUBLIC);
versionService.update(versionsTable);
userActionLogService.version(request, LoggedActionType.VERSION_REVIEW_STATE_CHANGED.with(VersionContext.of(versionsTable.getProjectId(), versionsTable.getId())), newState.name(), oldState.name());
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("versions.show", author, slug, version));
return Routes.VERSIONS_SHOW.getRedirect(author, slug, version);
}
@GetMapping("/{author}/{slug}/versions/{version}/confirm")
@ -376,13 +374,13 @@ public class VersionsController extends HangarController {
projectFactory.prepareDeleteVersion(versionData);
} catch (HangarException e) {
AlertUtil.showAlert(ra, AlertUtil.AlertType.ERROR, e.getMessage());
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("versions.show", author, slug, version));
return Routes.VERSIONS_SHOW.getRedirect(author, slug, version);
}
Visibility oldVisibility = versionData.getV().getVisibility();
versionService.changeVisibility(versionData, Visibility.SOFTDELETE, comment, userService.getCurrentUser().getId());
userActionLogService.version(request, LoggedActionType.VERSION_DELETED.with(VersionContext.of(versionData.getP().getProject().getId(), versionData.getV().getId())), "SoftDelete: " + comment, oldVisibility.getName());
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("versions.showList", author, slug));
return Routes.VERSIONS_SHOW_LIST.getRedirect(author, slug);
}
@GetMapping(value = "/{author}/{slug}/versions/{version}/download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@ -398,7 +396,7 @@ public class VersionsController extends HangarController {
if (passed || confirm) {
return _sendVersion(project, version);
} else {
return new RedirectView(routeHelper.getRouteUrl("versions.showDownloadConfirm",
return new RedirectView(Routes.getRouteUrlOf("versions.showDownloadConfirm",
project.getOwnerName(),
project.getSlug(),
version.getVersionString(),
@ -460,7 +458,7 @@ public class VersionsController extends HangarController {
boolean passed = checkConfirmation(version, token);
if (!passed) {
return new RedirectView(routeHelper.getRouteUrl("versions.showDownloadConfirm",
return new RedirectView(Routes.getRouteUrlOf("versions.showDownloadConfirm",
project.getOwnerName(),
project.getSlug(),
version.getVersionString(),
@ -492,7 +490,7 @@ public class VersionsController extends HangarController {
VersionData versionData = versionService.getVersionData(author, slug, version);
versionData.getP().getProject().setRecommendedVersionId(versionData.getV().getId());
projectDao.get().update(versionData.getP().getProject());
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("versions.show", author, slug, version));
return Routes.VERSIONS_SHOW.getRedirect(author, slug, version);
}
@GlobalPermission(NamedPermission.REVIEWER)
@ -502,7 +500,7 @@ public class VersionsController extends HangarController {
VersionData versionData = versionService.getVersionData(author, slug, version);
versionService.changeVisibility(versionData, Visibility.PUBLIC, comment, userService.getCurrentUser().getId());
userActionLogService.version(request, LoggedActionType.VERSION_DELETED.with(VersionContext.of(versionData.getP().getProject().getId(), versionData.getV().getId())), "Restore: " + comment, "");
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("versions.show", author, slug, version));
return Routes.VERSIONS_SHOW.getRedirect(author, slug, version);
}
@Secured("ROLE_USER")
@ -514,7 +512,7 @@ public class VersionsController extends HangarController {
versionData.getV().setDescription(newDesc);
versionService.update(versionData.getV());
userActionLogService.version(request, LoggedActionType.VERSION_DESCRIPTION_CHANGED.with(VersionContext.of(versionData.getP().getProject().getId(), versionData.getV().getId())), newDesc, oldDesc);
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("versions.show", author, slug, version));
return Routes.VERSIONS_SHOW.getRedirect(author, slug, version);
}
}

@ -11,7 +11,7 @@ import io.papermc.hangar.model.generated.ProjectStatsDay;
import io.papermc.hangar.model.generated.Tag;
import io.papermc.hangar.service.pluginupload.ProjectFiles;
import io.papermc.hangar.util.ApiUtil;
import io.papermc.hangar.util.RouteHelper;
import io.papermc.hangar.util.Routes;
import io.papermc.hangar.util.TemplateHelper;
import org.springframework.stereotype.Service;
@ -27,14 +27,12 @@ public class ProjectApiService {
private final HangarConfig hangarConfig;
private final HangarDao<ProjectsApiDao> projectApiDao;
private final ProjectFiles projectFiles;
private final RouteHelper routeHelper;
private final TemplateHelper templateHelper;
public ProjectApiService(HangarConfig hangarConfig, HangarDao<ProjectsApiDao> projectApiDao, ProjectFiles projectFiles, RouteHelper routeHelper, TemplateHelper templateHelper) {
public ProjectApiService(HangarConfig hangarConfig, HangarDao<ProjectsApiDao> projectApiDao, ProjectFiles projectFiles, TemplateHelper templateHelper) {
this.hangarConfig = hangarConfig;
this.projectApiDao = projectApiDao;
this.projectFiles = projectFiles;
this.routeHelper = routeHelper;
this.templateHelper = templateHelper;
}
@ -79,7 +77,7 @@ public class ProjectApiService {
private void setProjectIconUrl(Project project) {
Path iconPath = projectFiles.getIconPath(project.getNamespace().getOwner(), project.getNamespace().getSlug());
if (iconPath != null) {
project.setIconUrl(hangarConfig.getBaseUrl() + routeHelper.getRouteUrl("projects.showIcon", project.getNamespace().getOwner(), project.getNamespace().getSlug()));
project.setIconUrl(hangarConfig.getBaseUrl() + Routes.getRouteUrlOf("projects.showIcon", project.getNamespace().getOwner(), project.getNamespace().getSlug()));
} else {
project.setIconUrl(templateHelper.avatarUrl(project.getNamespace().getOwner()));
}

@ -1,206 +0,0 @@
package io.papermc.hangar.util;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.util.List.of;
@Component
public class RouteHelper {
private final Map<String, Route> routes = new HashMap<>();
public RouteHelper() {
register("showProjectVisibility", "/admin/approval/projects", of(), of());
register("updateUser", "/admin/user/{user}/update", of("user"), of());
register("showQueue", "/admin/approval/versions", of(), of());
register("showLog", "/admin/log", of(), of("page", "userFilter", "projectFilter", "versionFilter", "pageFilter", "actionFilter", "subjectFilter"));
register("removeTrail", "/{path}/", of("path"), of());
register("faviconRedirect", "/favicon.ico", of(), of());
register("showFlags", "/admin/flags", of(), of());
register("sitemapIndex", "/sitemap.xml", of(), of());
register("globalSitemap", "/global-sitemap.xml", of(), of());
register("showStats", "/admin/stats", of(), of("from", "to"));
register("linkOut", "/linkout", of(), of("remoteUrl"));
register("showHealth", "/admin/health", of(), of());
register("showHome", "/", of(), of());
register("robots", "/robots.txt", of(), of());
register("setFlagResolved", "/admin/flags/{id}/resolve/{resolved}", of("id", "resolved"), of());
register("swagger", "/api", of(), of());
register("showActivities", "/admin/activities/{user}", of("user"), of());
register("userAdmin", "/admin/user/{user}", of("user"), of());
register("javaScriptRoutes", "/javascriptRoutes", of(), of());
register("projects.rename", "/{author}/{slug}/manage/rename", of("author", "slug"), of());
register("projects.setWatching", "/{author}/{slug}/watchers/{watching}", of("author", "slug", "watching"), of());
register("projects.showSettings", "/{author}/{slug}/manage", of("author", "slug"), of());
register("projects.setInviteStatus", "/invite/{id}/{status}", of("id", "status"), of());
register("projects.toggleStarred", "/{author}/{slug}/stars/toggle", of("author", "slug"), of());
register("projects.showCreator", "/new", of(), of());
register("projects.showStargazers", "/{author}/{slug}/stars", of("author", "slug"), of("page"));
register("projects.showWatchers", "/{author}/{slug}/watchers", of("author", "slug"), of("page"));
register("projects.uploadIcon", "/{author}/{slug}/icon", of("author", "slug"), of());
register("projects.showIcon", "/{author}/{slug}/icon", of("author", "slug"), of());
register("projects.sendForApproval", "/{author}/{slug}/manage/sendforapproval", of("author", "slug"), of());
register("projects.setInviteStatusOnBehalf", "/invite/{id}/{status}/{behalf}", of("id", "status", "behalf"), of());
register("projects.delete", "/{author}/{slug}/manage/hardDelete", of("author", "slug"), of());
register("projects.addMessage", "/{author}/{slug}/notes/addmessage", of("author", "slug"), of());
register("projects.showPendingIcon", "/{author}/{slug}/icon/pending", of("author", "slug"), of());
register("projects.postDiscussionReply", "/{author}/{slug}/discuss/reply", of("author", "slug"), of());
register("projects.show", "/{author}/{slug}", of("author", "slug"), of());
register("projects.showDiscussion", "/{author}/{slug}/discuss", of("author", "slug"), of());
register("projects.softDelete", "/{author}/{slug}/manage/delete", of("author", "slug"), of());
register("projects.showFlags", "/{author}/{slug}/flags", of("author", "slug"), of());
register("projects.flag", "/{author}/{slug}/flag", of("author", "slug"), of());
register("projects.createProject", "/new", of(), of());
register("projects.resetIcon", "/{author}/{slug}/icon/reset", of("author", "slug"), of());
register("projects.save", "/{author}/{slug}/manage/save", of("author", "slug"), of());
register("projects.showNotes", "/{author}/{slug}/notes", of("author", "slug"), of());
register("projects.setVisible", "/{author}/{slug}/visible/{visibility}", of("author", "slug", "visibility"), of());
register("projects.removeMember", "/{author}/{slug}/manage/members/remove", of("author", "slug"), of());
register("versions.restore", "/{author}/{slug}/versions/{version}/restore", of("author", "slug", "version"), of());
register("versions.downloadRecommendedJar", "/{author}/{slug}/versions/recommended/jar", of("author", "slug"), of("token"));
register("versions.publish", "/{author}/{slug}/versions/{version}", of("author", "slug", "version"), of());
register("versions.setRecommended", "/{author}/{slug}/versions/{version}/recommended", of("author", "slug", "version"), of());
register("versions.download", "/{author}/{slug}/versions/{version}/download", of("author", "slug", "version"), of("token", "confirm"));
register("versions.showLog", "/{author}/{slug}/versionLog", of("author", "slug"), of("versionString"));
register("versions.show", "/{author}/{slug}/versions/{version}", of("author", "slug", "version"), of());
register("versions.downloadJar", "/{author}/{slug}/versions/{version}/jar", of("author", "slug", "version"), of("token"));
register("versions.approve", "/{author}/{slug}/versions/{version}/approve", of("author", "slug", "version"), of());
register("versions.approvePartial", "/{author}/{slug}/versions/{version}/approvePartial", of("author", "slug", "version"), of());
register("versions.saveDescription", "/{author}/{slug}/versions/{version}/save", of("author", "slug", "version"), of());
register("versions.downloadRecommended", "/{author}/{slug}/versions/recommended/download", of("author", "slug"), of("token"));
register("versions.showList", "/{author}/{slug}/versions", of("author", "slug"), of());
register("versions.downloadJarById", "/api/project/{pluginId}/versions/{name}/download", of("pluginId", "name"), of("token"));
register("versions.downloadRecommendedJarById", "/api/project/{pluginId}/versions/recommended/download", of("pluginId"), of("token"));
register("versions.upload", "/{author}/{slug}/versions/new/upload", of("author", "slug"), of());
register("versions.softDelete", "/{author}/{slug}/versions/{version}/delete", of("author", "slug", "version"), of());
register("versions.showDownloadConfirm", "/{author}/{slug}/versions/{version}/confirm", of("author", "slug", "version"), of("downloadType", "api", "dummy"));
register("versions.showCreator", "/{author}/{slug}/versions/new", of("author", "slug"), of());
register("versions.delete", "/{author}/{slug}/versions/{version}/hardDelete", of("author", "slug", "version"), of());
register("versions.showCreatorWithMeta", "/{author}/{slug}/versions/new/{version}", of("author", "slug", "version"), of());
register("versions.confirmDownload", "/{author}/{slug}/versions/{version}/confirm", of("author", "slug", "version"), of("downloadType", "api", "dummy"));
register("pages.showPreview", "/pages/preview", of(), of());
register("pages.save", "/{author}/{slug}/pages/{page}/edit", of("author", "slug", "page"), of());
register("pages.showEditor", "/{author}/{slug}/pages/{page}/edit", of("author", "slug", "page"), of());
register("pages.show", "/{author}/{slug}/pages/{page}", of("author", "slug", "page"), of());
register("pages.delete", "/{author}/{slug}/pages/{page}/delete", of("author", "slug", "page"), of());
register("users.showAuthors", "/authors", of(), of("sort", "page"));
register("users.saveTagline", "/{user}/settings/tagline", of("user"), of());
register("users.signUp", "/signup", of(), of());
register("users.showNotifications", "/notifications", of(), of("notificationFilter", "inviteFilter"));
register("users.showProjects", "/{user}", of("user"), of());
register("users.verify", "/verify", of(), of("returnPath"));
register("users.markNotificationRead", "/notifications/read/{id}", of("id"), of());
register("users.login", "/login", of(), of("sso", "sig", "returnUrl"));
register("users.showStaff", "/staff", of(), of("sort", "page"));
register("users.setLocked", "/{user}/settings/lock/{locked}", of("user", "locked"), of("sso", "sig"));
register("users.markPromptRead", "/prompts/read/{id}", of("id"), of());
register("users.logout", "/logout", of(), of());
register("users.userSitemap", "/{user}/sitemap.xml", of("user"), of());
register("users.editApiKeys", "/{user}/settings/apiKeys", of("user"), of());
register("org.updateMembers", "/organizations/{organization}/settings/members", of("organization"), of());
register("org.updateAvatar", "/organizations/{organization}/settings/avatar", of("organization"), of());
register("org.setInviteStatus", "/organizations/invite/{id}/{status}", of("id", "status"), of());
register("org.showCreator", "/organizations/new", of(), of());
register("org.create", "/organizations/new", of(), of());
register("org.removeMember", "/organizations/{organization}/settings/members/remove", of("organization"), of());
register("reviews.addMessage", "/{author}/{slug}/versions/{version}/reviews/addmessage", of("author", "slug", "version"), of());
register("reviews.backlogToggle", "/{author}/{slug}/versions/{version}/reviews/reviewtoggle", of("author", "slug", "version"), of());
register("reviews.showReviews", "/{author}/{slug}/versions/{version}/reviews", of("author", "slug", "version"), of());
register("reviews.approveReview", "/{author}/{slug}/versions/{version}/reviews/approve", of("author", "slug", "version"), of());
register("reviews.editReview", "/{author}/{slug}/versions/{version}/reviews/edit/{review}", of("author", "slug", "version", "review"), of());
register("reviews.stopReview", "/{author}/{slug}/versions/{version}/reviews/stop", of("author", "slug", "version"), of());
register("reviews.createReview", "/{author}/{slug}/versions/{version}/reviews/init", of("author", "slug", "version"), of());
register("reviews.takeoverReview", "/{author}/{slug}/versions/{version}/reviews/takeover", of("author", "slug", "version"), of());
register("reviews.reopenReview", "/{author}/{slug}/versions/{version}/reviews/reopen", of("author", "slug", "version"), of());
register("channels.delete", "/{author}/{slug}/channels/{channel}/delete", of("author", "slug", "channel"), of());
register("channels.save", "/{author}/{slug}/channels/{channel}", of("author", "slug", "channel"), of());
register("channels.showList", "/{author}/{slug}/channels", of("author", "slug"), of());
register("channels.create", "/{author}/{slug}/channels", of("author", "slug"), of());
register("apiv1.showVersion", "/api/v1/projects/{pluginId}/versions/{name}", of("pluginId", "name"), of());
register("apiv1.listProjects", "/api/v1/projects", of(), of("categories", "sort", "q", "limit", "offset"));
register("apiv1.listUsers", "/api/v1/users", of(), of("limit", "offset"));
register("apiv1.listVersions", "/api/v1/projects/{pluginId}/versions", of("pluginId"), of("channels", "limit", "offset"));
register("apiv1.revokeKey", "/api/v1/projects/{pluginId}/keys/revoke", of("pluginId"), of());
register("apiv1.createKey", "/api/v1/projects/{pluginId}/keys/new", of("pluginId"), of());
register("apiv1.showProject", "/api/v1/projects/{pluginId}", of("pluginId"), of());
register("apiv1.syncSso", "/api/sync_sso", of(), of());
register("apiv1.tagColor", "/api/v1/tags/{tagId}", of("tagId"), of());
register("apiv1.showStatusZ", "/statusz", of(), of());
register("apiv1.showUser", "/api/v1/users/{user}", of("user"), of());
register("apiv1.listPages", "/api/v1/projects/{pluginId}/pages", of("pluginId"), of("parentId"));
register("apiv1.deployVersion", "/api/v1/projects/{pluginId}/versions/{name}", of("pluginId", "name"), of());
register("apiv1.listTags", "/api/v1/projects/{plugin}/tags/{versionName}", of("plugin", "versionName"), of());
}
// TODO support route params
public String getRouteUrl(String name, String... args) {
Route route = routes.get(name);
if (route == null) {
throw new RuntimeException("No Route " + name);
} else if ((route.pathParms.size() + route.queryParams.size()) != args.length) {
throw new RuntimeException("Args dont match for route " + name + " " + (route.pathParms.size() + route.queryParams.size()) + "!=" + args.length);
}
// path params first
String url = route.url;
for (int i = 0; i < route.pathParms.size(); i++) {
String value = args[i];
String key = route.pathParms.get(i);
url = url.replace("{" + key + "}", value);
}
// query params later
StringBuilder sb = new StringBuilder();
sb.append(url);
boolean first = true;
for (int i = 0; i < route.queryParams.size(); i++) {
String value = args[i + route.pathParms.size()];
if (value == null || value.length() == 0) {
continue;
}
if (first) {
sb.append("?");
first = false;
} else {
sb.append("&");
}
sb.append(route.queryParams.get(i));
sb.append("=");
sb.append(value);
}
return sb.toString();
}
private void register(String name, String url, List<String> pathParms, List<String> queryParams) {
Route route = new Route(name, url, pathParms, queryParams);
routes.put(route.name, route);
}
class Route {
String name;
String url;
List<String> pathParms;
List<String> queryParams;
public Route(String name, String url, List<String> pathParms, List<String> queryParams) {
this.name = name;
this.url = url;
this.pathParms = pathParms;
this.queryParams = queryParams;
}
}
}

@ -0,0 +1,213 @@
package io.papermc.hangar.util;
import org.springframework.web.servlet.ModelAndView;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.util.List.of;
public enum Routes {
SHOW_PROJECT_VISIBILITY("showProjectVisibility", "/admin/approval/projects", of(), of()),
ACTOR_COUNT("actorCount", "/pantopticon/actor-count", of(), of("timeoutMs")),
ACTOR_TREE("actorTree", "/pantopticon/actor-tree", of(), of("timeoutMs")),
UPDATE_USER("updateUser", "/admin/user/{user}/update", of("user"), of()),
SHOW_QUEUE("showQueue", "/admin/approval/versions", of(), of()),
SHOW_LOG("showLog", "/admin/log", of(), of("page", "userFilter", "projectFilter", "versionFilter", "pageFilter", "actionFilter", "subjectFilter")),
REMOVE_TRAIL("removeTrail", "/{path}/", of("path"), of()),
FAVICON_REDIRECT("faviconRedirect", "/favicon.ico", of(), of()),
SHOW_FLAGS("showFlags", "/admin/flags", of(), of()),
SITEMAP_INDEX("sitemapIndex", "/sitemap.xml", of(), of()),
GLOBAL_SITEMAP("globalSitemap", "/global-sitemap.xml", of(), of()),
SHOW_STATS("showStats", "/admin/stats", of(), of("from", "to")),
LINK_OUT("linkOut", "/linkout", of(), of("remoteUrl")),
SHOW_HEALTH("showHealth", "/admin/health", of(), of()),
SHOW_HOME("showHome", "/", of(), of()),
ROBOTS("robots", "/robots.txt", of(), of()),
SET_FLAG_RESOLVED("setFlagResolved", "/admin/flags/{id}/resolve/{resolved}", of("id", "resolved"), of()),
SWAGGER("swagger", "/api", of(), of()),
SHOW_ACTIVITIES("showActivities", "/admin/activities/{user}", of("user"), of()),
USER_ADMIN("userAdmin", "/admin/user/{user}", of("user"), of()),
JAVA_SCRIPT_ROUTES("javaScriptRoutes", "/javascriptRoutes", of(), of()),
PROJECTS_RENAME("projects.rename", "/{author}/{slug}/manage/rename", of("author", "slug"), of()),
PROJECTS_SET_WATCHING("projects.setWatching", "/{author}/{slug}/watchers/{watching}", of("author", "slug", "watching"), of()),
PROJECTS_SHOW_SETTINGS("projects.showSettings", "/{author}/{slug}/manage", of("author", "slug"), of()),
PROJECTS_SET_INVITE_STATUS("projects.setInviteStatus", "/invite/{id}/{status}", of("id", "status"), of()),
PROJECTS_TOGGLE_STARRED("projects.toggleStarred", "/{author}/{slug}/stars/toggle", of("author", "slug"), of()),
PROJECTS_SHOW_CREATOR("projects.showCreator", "/new", of(), of()),
PROJECTS_SHOW_STARGAZERS("projects.showStargazers", "/{author}/{slug}/stars", of("author", "slug"), of("page")),
PROJECTS_SHOW_WATCHERS("projects.showWatchers", "/{author}/{slug}/watchers", of("author", "slug"), of("page")),
PROJECTS_UPLOAD_ICON("projects.uploadIcon", "/{author}/{slug}/icon", of("author", "slug"), of()),
PROJECTS_SHOW_ICON("projects.showIcon", "/{author}/{slug}/icon", of("author", "slug"), of()),
PROJECTS_SEND_FOR_APPROVAL("projects.sendForApproval", "/{author}/{slug}/manage/sendforapproval", of("author", "slug"), of()),
PROJECTS_SET_INVITE_STATUS_ON_BEHALF("projects.setInviteStatusOnBehalf", "/invite/{id}/{status}/{behalf}", of("id", "status", "behalf"), of()),
PROJECTS_DELETE("projects.delete", "/{author}/{slug}/manage/hardDelete", of("author", "slug"), of()),
PROJECTS_ADD_MESSAGE("projects.addMessage", "/{author}/{slug}/notes/addmessage", of("author", "slug"), of()),
PROJECTS_SHOW_PENDING_ICON("projects.showPendingIcon", "/{author}/{slug}/icon/pending", of("author", "slug"), of()),
PROJECTS_POST_DISCUSSION_REPLY("projects.postDiscussionReply", "/{author}/{slug}/discuss/reply", of("author", "slug"), of()),
PROJECTS_SHOW("projects.show", "/{author}/{slug}", of("author", "slug"), of()),
PROJECTS_SHOW_DISCUSSION("projects.showDiscussion", "/{author}/{slug}/discuss", of("author", "slug"), of()),
PROJECTS_SOFT_DELETE("projects.softDelete", "/{author}/{slug}/manage/delete", of("author", "slug"), of()),
PROJECTS_SHOW_FLAGS("projects.showFlags", "/{author}/{slug}/flags", of("author", "slug"), of()),
PROJECTS_FLAG("projects.flag", "/{author}/{slug}/flag", of("author", "slug"), of()),
PROJECTS_CREATE_PROJECT("projects.createProject", "/new", of(), of()),
PROJECTS_RESET_ICON("projects.resetIcon", "/{author}/{slug}/icon/reset", of("author", "slug"), of()),
PROJECTS_SAVE("projects.save", "/{author}/{slug}/manage/save", of("author", "slug"), of()),
PROJECTS_SHOW_NOTES("projects.showNotes", "/{author}/{slug}/notes", of("author", "slug"), of()),
PROJECTS_SET_VISIBLE("projects.setVisible", "/{author}/{slug}/visible/{visibility}", of("author", "slug", "visibility"), of()),
PROJECTS_REMOVE_MEMBER("projects.removeMember", "/{author}/{slug}/manage/members/remove", of("author", "slug"), of()),
VERSIONS_RESTORE("versions.restore", "/{author}/{slug}/versions/{version}/restore", of("author", "slug", "version"), of()),
VERSIONS_DOWNLOAD_RECOMMENDED_JAR("versions.downloadRecommendedJar", "/{author}/{slug}/versions/recommended/jar", of("author", "slug"), of("token")),
VERSIONS_PUBLISH("versions.publish", "/{author}/{slug}/versions/{version}", of("author", "slug", "version"), of()),
VERSIONS_SET_RECOMMENDED("versions.setRecommended", "/{author}/{slug}/versions/{version}/recommended", of("author", "slug", "version"), of()),
VERSIONS_DOWNLOAD("versions.download", "/{author}/{slug}/versions/{version}/download", of("author", "slug", "version"), of("token", "confirm")),
VERSIONS_SHOW_LOG("versions.showLog", "/{author}/{slug}/versionLog", of("author", "slug"), of("versionString")),
VERSIONS_SHOW("versions.show", "/{author}/{slug}/versions/{version}", of("author", "slug", "version"), of()),
VERSIONS_DOWNLOAD_JAR("versions.downloadJar", "/{author}/{slug}/versions/{version}/jar", of("author", "slug", "version"), of("token")),
VERSIONS_APPROVE("versions.approve", "/{author}/{slug}/versions/{version}/approve", of("author", "slug", "version"), of()),
VERSIONS_APPROVE_PARTIAL("versions.approvePartial", "/{author}/{slug}/versions/{version}/approvePartial", of("author", "slug", "version"), of()),
VERSIONS_SAVE_DESCRIPTION("versions.saveDescription", "/{author}/{slug}/versions/{version}/save", of("author", "slug", "version"), of()),
VERSIONS_DOWNLOAD_RECOMMENDED("versions.downloadRecommended", "/{author}/{slug}/versions/recommended/download", of("author", "slug"), of("token")),
VERSIONS_SHOW_LIST("versions.showList", "/{author}/{slug}/versions", of("author", "slug"), of()),
VERSIONS_DOWNLOAD_JAR_BY_ID("versions.downloadJarById", "/api/project/{pluginId}/versions/{name}/download", of("pluginId", "name"), of("token")),
VERSIONS_DOWNLOAD_RECOMMENDED_JAR_BY_ID("versions.downloadRecommendedJarById", "/api/project/{pluginId}/versions/recommended/download", of("pluginId"), of("token")),
VERSIONS_UPLOAD("versions.upload", "/{author}/{slug}/versions/new/upload", of("author", "slug"), of()),
VERSIONS_SOFT_DELETE("versions.softDelete", "/{author}/{slug}/versions/{version}/delete", of("author", "slug", "version"), of()),
VERSIONS_SHOW_DOWNLOAD_CONFIRM("versions.showDownloadConfirm", "/{author}/{slug}/versions/{version}/confirm", of("author", "slug", "version"), of("downloadType", "api", "dummy")),
VERSIONS_SHOW_CREATOR("versions.showCreator", "/{author}/{slug}/versions/new", of("author", "slug"), of()),
VERSIONS_DELETE("versions.delete", "/{author}/{slug}/versions/{version}/hardDelete", of("author", "slug", "version"), of()),
VERSIONS_SHOW_CREATOR_WITH_META("versions.showCreatorWithMeta", "/{author}/{slug}/versions/new/{version}", of("author", "slug", "version"), of()),
VERSIONS_CONFIRM_DOWNLOAD("versions.confirmDownload", "/{author}/{slug}/versions/{version}/confirm", of("author", "slug", "version"), of("downloadType", "api", "dummy")),
PAGES_SHOW_PREVIEW("pages.showPreview", "/pages/preview", of(), of()),
PAGES_SAVE("pages.save", "/{author}/{slug}/pages/{page}/edit", of("author", "slug", "page"), of()),
PAGES_SHOW_EDITOR("pages.showEditor", "/{author}/{slug}/pages/{page}/edit", of("author", "slug", "page"), of()),
PAGES_SHOW("pages.show", "/{author}/{slug}/pages/{page}", of("author", "slug", "page"), of()),
PAGES_DELETE("pages.delete", "/{author}/{slug}/pages/{page}/delete", of("author", "slug", "page"), of()),
USERS_SHOW_AUTHORS("users.showAuthors", "/authors", of(), of("sort", "page")),
USERS_SAVE_TAGLINE("users.saveTagline", "/{user}/settings/tagline", of("user"), of()),
USERS_SIGN_UP("users.signUp", "/signup", of(), of()),
USERS_SHOW_NOTIFICATIONS("users.showNotifications", "/notifications", of(), of("notificationFilter", "inviteFilter")),
USERS_SHOW_PROJECTS("users.showProjects", "/{user}", of("user"), of()),
USERS_VERIFY("users.verify", "/verify", of(), of("returnPath")),
USERS_MARK_NOTIFICATION_READ("users.markNotificationRead", "/notifications/read/{id}", of("id"), of()),
USERS_LOGIN("users.login", "/login", of(), of("sso", "sig", "returnUrl")),
USERS_SHOW_STAFF("users.showStaff", "/staff", of(), of("sort", "page")),
USERS_SET_LOCKED("users.setLocked", "/{user}/settings/lock/{locked}", of("user", "locked"), of("sso", "sig")),
USERS_MARK_PROMPT_READ("users.markPromptRead", "/prompts/read/{id}", of("id"), of()),
USERS_LOGOUT("users.logout", "/logout", of(), of()),
USERS_USER_SITEMAP("users.userSitemap", "/{user}/sitemap.xml", of("user"), of()),
USERS_EDIT_API_KEYS("users.editApiKeys", "/{user}/settings/apiKeys", of("user"), of()),
ORG_UPDATE_MEMBERS("org.updateMembers", "/organizations/{organization}/settings/members", of("organization"), of()),
ORG_UPDATE_AVATAR("org.updateAvatar", "/organizations/{organization}/settings/avatar", of("organization"), of()),
ORG_SET_INVITE_STATUS("org.setInviteStatus", "/organizations/invite/{id}/{status}", of("id", "status"), of()),
ORG_SHOW_CREATOR("org.showCreator", "/organizations/new", of(), of()),
ORG_CREATE("org.create", "/organizations/new", of(), of()),
ORG_REMOVE_MEMBER("org.removeMember", "/organizations/{organization}/settings/members/remove", of("organization"), of()),
REVIEWS_ADD_MESSAGE("reviews.addMessage", "/{author}/{slug}/versions/{version}/reviews/addmessage", of("author", "slug", "version"), of()),
REVIEWS_BACKLOG_TOGGLE("reviews.backlogToggle", "/{author}/{slug}/versions/{version}/reviews/reviewtoggle", of("author", "slug", "version"), of()),
REVIEWS_SHOW_REVIEWS("reviews.showReviews", "/{author}/{slug}/versions/{version}/reviews", of("author", "slug", "version"), of()),
REVIEWS_APPROVE_REVIEW("reviews.approveReview", "/{author}/{slug}/versions/{version}/reviews/approve", of("author", "slug", "version"), of()),
REVIEWS_EDIT_REVIEW("reviews.editReview", "/{author}/{slug}/versions/{version}/reviews/edit/{review}", of("author", "slug", "version", "review"), of()),
REVIEWS_STOP_REVIEW("reviews.stopReview", "/{author}/{slug}/versions/{version}/reviews/stop", of("author", "slug", "version"), of()),
REVIEWS_CREATE_REVIEW("reviews.createReview", "/{author}/{slug}/versions/{version}/reviews/init", of("author", "slug", "version"), of()),
REVIEWS_TAKEOVER_REVIEW("reviews.takeoverReview", "/{author}/{slug}/versions/{version}/reviews/takeover", of("author", "slug", "version"), of()),
REVIEWS_REOPEN_REVIEW("reviews.reopenReview", "/{author}/{slug}/versions/{version}/reviews/reopen", of("author", "slug", "version"), of()),
CHANNELS_DELETE("channels.delete", "/{author}/{slug}/channels/{channel}/delete", of("author", "slug", "channel"), of()),
CHANNELS_SAVE("channels.save", "/{author}/{slug}/channels/{channel}", of("author", "slug", "channel"), of()),
CHANNELS_SHOW_LIST("channels.showList", "/{author}/{slug}/channels", of("author", "slug"), of()),
CHANNELS_CREATE("channels.create", "/{author}/{slug}/channels", of("author", "slug"), of()),
APIV1_SHOW_VERSION("apiv1.showVersion", "/api/v1/projects/{pluginId}/versions/{name}", of("pluginId", "name"), of()),
APIV1_LIST_PROJECTS("apiv1.listProjects", "/api/v1/projects", of(), of("categories", "sort", "q", "limit", "offset")),
APIV1_LIST_USERS("apiv1.listUsers", "/api/v1/users", of(), of("limit", "offset")),
APIV1_LIST_VERSIONS("apiv1.listVersions", "/api/v1/projects/{pluginId}/versions", of("pluginId"), of("channels", "limit", "offset")),
APIV1_REVOKE_KEY("apiv1.revokeKey", "/api/v1/projects/{pluginId}/keys/revoke", of("pluginId"), of()),
APIV1_CREATE_KEY("apiv1.createKey", "/api/v1/projects/{pluginId}/keys/new", of("pluginId"), of()),
APIV1_SHOW_PROJECT("apiv1.showProject", "/api/v1/projects/{pluginId}", of("pluginId"), of()),
APIV1_SYNC_SSO("apiv1.syncSso", "/api/sync_sso", of(), of()),
APIV1_TAG_COLOR("apiv1.tagColor", "/api/v1/tags/{tagId}", of("tagId"), of()),
APIV1_SHOW_STATUS_Z("apiv1.showStatusZ", "/statusz", of(), of()),
APIV1_SHOW_USER("apiv1.showUser", "/api/v1/users/{user}", of("user"), of()),
APIV1_LIST_PAGES("apiv1.listPages", "/api/v1/projects/{pluginId}/pages", of("pluginId"), of("parentId")),
APIV1_DEPLOY_VERSION("apiv1.deployVersion", "/api/v1/projects/{pluginId}/versions/{name}", of("pluginId", "name"), of()),
APIV1_LIST_TAGS("apiv1.listTags", "/api/v1/projects/{plugin}/tags/{versionName}", of("plugin", "versionName"), of());
private static final Map<String, Routes> ROUTES = new HashMap<>();
static {
for (Routes route : values()) {
ROUTES.put(route.name, route);
}
}
public static String getRouteUrlOf(String name, String... args) {
Routes route = ROUTES.get(name);
if (route == null) {
throw new RuntimeException("No Route " + name);
}
return route.getRouteUrl(args);
}
private final String name;
private final String url;
private final String[] pathParams;
private final String[] queryParams;
Routes(String name, String url, List<String> pathParams, List<String> queryParams) {
this.name = name;
this.url = url;
this.pathParams = pathParams.toArray(new String[0]);
this.queryParams = queryParams.toArray(new String[0]);
}
public String getRouteUrl(String... args) {
if ((pathParams.length + queryParams.length) != args.length) {
throw new RuntimeException("Args dont match for route " + name + " " + (pathParams.length + queryParams.length) + "!=" + args.length);
}
// path params first
String url = this.url;
for (int i = 0; i < pathParams.length; i++) {
String value = args[i];
String key = pathParams[i];
url = url.replace("{" + key + "}", value);
}
// query params later
StringBuilder sb = new StringBuilder();
sb.append(url);
boolean first = true;
for (int i = 0; i < queryParams.length; i++) {
String value = args[i + pathParams.length];
if (value == null || value.isEmpty()) {
continue;
}
if (first) {
sb.append('?');
first = false;
} else {
sb.append('&');
}
sb.append(queryParams[i]);
sb.append('=');
sb.append(value);
}
return sb.toString();
}
public ModelAndView getRedirect(String... args) {
return new ModelAndView("redirect:" + getRouteUrl(args));
}
}

@ -15,12 +15,10 @@ import java.time.format.FormatStyle;
@Component
public class TemplateHelper {
private final RouteHelper routeHelper;
private final HangarConfig hangarConfig;
@Autowired
public TemplateHelper(RouteHelper routeHelper, HangarConfig hangarConfig) {
this.routeHelper = routeHelper;
public TemplateHelper(HangarConfig hangarConfig) {
this.hangarConfig = hangarConfig;
}
@ -37,7 +35,7 @@ public class TemplateHelper {
}
public String projectAvatarUrl(ProjectsTable table) {
return routeHelper.getRouteUrl("projects.showIcon", table.getOwnerName(), table.getSlug());
return Routes.getRouteUrlOf("projects.showIcon", table.getOwnerName(), table.getSlug());
}
public String formatFileSize(Long size) {

@ -23,7 +23,7 @@
<p class="minor"> <@spring.message "org.info" /></p>
<#import "*/utils/form.ftlh" as form>
<@form.form action=routes.getRouteUrl("org.create") method="POST" id="form-continue">
<@form.form action=Routes.ORG_CREATE.getRouteUrl() method="POST" id="form-continue">
<#import "*/utils/csrf.ftlh" as csrf>
<@csrf.formField />
<div class="setting">

@ -103,7 +103,7 @@ showFooter: Boolean = true, noContainer: Boolean = false, additionalMeta: Html =
</script>
</#if>
<script type="text/javascript" src="${routes.getRouteUrl("javaScriptRoutes")}"></script>
<script type="text/javascript" src="${Routes.JAVA_SCRIPT_ROUTES.getRouteUrl()}"></script>
<script type="text/javascript" src="<@hangar.url "build/vendors.js" />"></script>
<script type="text/javascript" src="<@hangar.url "build/font-awesome.js" />"></script>
<script type="text/javascript" src="<@hangar.url "build/commons.js" />"></script>

@ -20,7 +20,7 @@
<div class="col-sm-2 col-xs-12">
<h5>Hangar API</h5>
<a class="btn dark"
href="${routes.getRouteUrl("swagger")}"><@spring.message "general.api" /></a>
href="${Routes.SWAGGER.getRouteUrl()}"><@spring.message "general.api" /></a>
</div>
<div class="col-sm-2 col-xs-12">
<h5>Help Needed?</h5>

@ -7,7 +7,7 @@
<#-- Left navbar -->
<div id="sp-logo-container">
<div class="logo">
<a href="${routes.getRouteUrl("showHome")}">
<a href="${Routes.SHOW_HOME.getRouteUrl()}">
<img src="https://papermc.io/images/logo-marker.svg" alt="Paper logo">
</a>
<i class="fas fa-fw fa-chevron-down"></i>
@ -30,7 +30,7 @@
<li><a href="https://papermc.io/javadocs">
<i class="fa-fw fas fa-graduation-cap"></i><@spring.message "general.javadocs" />
</a></li>
<li class="active"><a href="${routes.getRouteUrl("showHome")}">
<li class="active"><a href="${Routes.SHOW_HOME.getRouteUrl()}">
<img src="<@hangar.url "images/ore-nav.svg" />" alt=""
class="fa-fw ore-nav"><@spring.message "general.plugins" />
(<@spring.message "general.appName" />)
@ -56,11 +56,11 @@
</a>
<ul class="user-dropdown dropdown-menu" aria-label="Create new&hellip;">
<li>
<a href="${routes.getRouteUrl("projects.showCreator")}">
<a href="${Routes.PROJECTS_SHOW_CREATOR.getRouteUrl()}">
<i class="fas fa-book fa-fw mr-1"></i>
<span><@spring.message "project.create"/></span>
</a>
<a href="${routes.getRouteUrl("org.showCreator")}">
<a href="${Routes.ORG_SHOW_CREATOR.getRouteUrl()}">
<i class="fas fa-users fa-fw mr-1"></i>
<span><@spring.message "org.create" /></span>
</a>
@ -70,7 +70,7 @@
<#assign title><@spring.message "project.viewAuthors"/></#assign>
<li class="nav-icon authors-icon" <@tooltip title=title />>
<a href="${routes.getRouteUrl("users.showAuthors", "", "")}">
<a href="${Routes.USERS_SHOW_AUTHORS.getRouteUrl("", "")}">
<i class="icon fas fa-users"></i>
</a>
</li>
@ -78,7 +78,7 @@
<@hangar.hasPerm "IsStaff">
<#assign title><@spring.message "project.viewStaff"/></#assign>
<li class="nav-icon staff-icon" <@tooltip title=title />>
<a href="${routes.getRouteUrl("users.showStaff", "", "")}">
<a href="${Routes.USERS_SHOW_STAFF.getRouteUrl("", "")}">
<i class="icon fas fa-user-tie"></i>
</a>
</li>
@ -96,14 +96,14 @@
<ul class="user-dropdown dropdown-menu"
aria-label="<@spring.messageArgs code="aria.dropdown.menu" args=[1] />">
<li>
<a href="${routes.getRouteUrl("users.showProjects", "")}${cu.name}">
<a href="${Routes.USERS_SHOW_PROJECTS.getRouteUrl("")}${cu.name}">
<i class="fas fa-user mr-1"></i>
<span>${cu.name}</span>
</a>
</li>
<li>
<a href="${routes.getRouteUrl("users.showNotifications", "", "")}">
<a href="${Routes.USERS_SHOW_NOTIFICATIONS.getRouteUrl("", "")}">
<i class="fas fa-bell mr-1"></i>
<span>
<@spring.message "notification.plural" />
@ -116,7 +116,7 @@
<@hangar.hasPerm "ModNotesAndFlags">
<li>
<a href="${routes.getRouteUrl("showFlags")}">
<a href="${Routes.SHOW_FLAGS.getRouteUrl()}">
<i class="fas fa-flag mr-1"></i>
<span>
<@spring.message "project.flag.plural" />
@ -130,7 +130,7 @@
<@hangar.hasPerm "ModNotesAndFlags">
<li>
<a href="${routes.getRouteUrl("showProjectVisibility")}">
<a href="${Routes.SHOW_PROJECT_VISIBILITY.getRouteUrl()}">
<i class="fas fa-thumbs-up mr-1"></i>
<span>
Project approvals
@ -144,7 +144,7 @@
<@hangar.hasPerm "Reviewer">
<li>
<a href="${routes.getRouteUrl("showQueue")}">
<a href="${Routes.SHOW_QUEUE.getRouteUrl()}">
<i class="far fa-thumbs-up mr-1"></i>
<span>
<@spring.message "user.queue" />
@ -158,7 +158,7 @@
<@hangar.hasPerm "ViewStats">
<li>
<a href="${routes.getRouteUrl("showStats", "", "")}">
<a href="${Routes.SHOW_STATS.getRouteUrl("", "")}">
<i class="fas fa-chart-area mr-1"></i>
<span><@spring.message "user.stats" /></span>
</a>
@ -167,7 +167,7 @@
<@hangar.hasPerm "ViewHealth">
<li>
<a href="${routes.getRouteUrl("showHealth")}">
<a href="${Routes.SHOW_HEALTH.getRouteUrl()}">
<i class="fas fa-heartbeat mr-1"></i>
<span><@spring.message "admin.health.title" /></span>
</a>
@ -176,7 +176,7 @@
<@hangar.hasPerm "ViewLogs">
<li>
<a href="${routes.getRouteUrl("showLog", "", "", "", "", "", "", "")}">
<a href="${Routes.SHOW_LOG.getRouteUrl("", "", "", "", "", "", "")}">
<i class="fas fa-list mr-1"></i>
<span><@spring.message "admin.log.title" /></span>
</a>
@ -185,7 +185,7 @@
<li role="separator" class="divider"></li>
<li>
<a href="${routes.getRouteUrl("users.logout")}">
<a href="${Routes.USERS_LOGOUT.getRouteUrl()}">
<i class="fas fa-sign-out-alt mr-1"></i>
<span><@spring.message "general.signout" /></span>
</a>
@ -195,9 +195,9 @@
<#else>
<li>
<div class="btn-group-login">
<a href="${routes.getRouteUrl("users.signUp")}"
<a href="${Routes.USERS_SIGN_UP.getRouteUrl()}"
class="btn btn-primary navbar-btn"><@spring.message "general.signup" /></a>
<a href="${routes.getRouteUrl("users.login", "", "", rc.requestUri?url)}"
<a href="${Routes.USERS_LOGIN.getRouteUrl("", "", rc.requestUri?url)}"
class="btn btn-primary navbar-btn"><@spring.message "general.login" /></a>
</div>
</li>

@ -7,7 +7,7 @@
<div class="row">
<div class="col-md-12 header-flags">
<div class="clearfix">
<h1 class="pull-left"><@spring.message "project.flag.plural" /> for <a href="${routes.getRouteUrl("projects.show", p.project.ownerName, p.project.slug)}">${p.project.ownerName}/${p.project.slug}</a></h1>
<h1 class="pull-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>

@ -12,7 +12,7 @@
<div class="row">
<div class="col-md-12 header-flags">
<div class="clearfix">
<h1 class="pull-left"><@spring.message "notes" /> <a href="${routes.getRouteUrl("projects.show", project.ownerName, project.slug)}">${project.ownerName}/${project.slug}</a></h1>
<h1 class="pull-left"><@spring.message "notes" /> <a href="${Routes.PROJECTS_SHOW.getRouteUrl(project.ownerName, project.slug)}">${project.ownerName}/${project.slug}</a></h1>
</div>
</div>
</div>

@ -14,7 +14,7 @@
</button>
<h4 class="modal-title"></h4>
</div>
<@form.form action=routes.getRouteUrl("showHome") method="GET">
<@form.form action=Routes.SHOW_HOME.getRouteUrl() method="GET">
<@csrf.formField />
<div class="modal-body">
<div class="form-inline">

@ -13,7 +13,7 @@
$(function () {
initChannelManager(
"#channel-new", "", "${config.channels.colorDefault.hex}", "New channel",
"${routes.getRouteUrl("channels.create", p.project.ownerName, p.project.slug)}",
"${Routes.CHANNELS_CREATE.getRouteUrl(p.project.ownerName, p.project.slug)}",
"post", "Create channel", false
);
});
@ -56,7 +56,7 @@
id="channel-delete-${channel.id}" data-channel-delete="safe-delete"
data-channel-id="${channel.id}"
>
<@form.form method="POST" action=routes.getRouteUrl("channels.delete", p.project.ownerName, p.project.slug, channel.name)
<@form.form method="POST" action=Routes.CHANNELS_DELETE.getRouteUrl(p.project.ownerName, p.project.slug, channel.name)
id="form-delete-${channel.id}"
class="form-channel-delete">
<@csrf.formField />
@ -71,7 +71,7 @@
initChannelDelete('#channel-delete-${channel.id}', '${channel.name}', ${versions});
initChannelManager(
"#channel-edit-${channel.id}", "${channel.name}", "${channel.color.hex}",
"Edit channel", "${routes.getRouteUrl("channels.save"
"Edit channel", "${Routes.CHANNELS_SAVE.getRouteUrl(
p.project.ownerName, p.project.slug, channel.name)}",
"post", "Save changes", ${channel.isNonReviewed?string('true', 'false')}
);
@ -81,7 +81,7 @@
</#list>
</tbody>
</table>
<a href="${routes.getRouteUrl("versions.showList", p.project.ownerName, p.project.slug)}"
<a href="${Routes.VERSIONS_SHOW_LIST.getRouteUrl(p.project.ownerName, p.project.slug)}"
class="pull-left btn btn-default">
<i class="fas fa-arrow-left"></i>
</a>

@ -30,7 +30,7 @@ Page used for uploading and creating new projects.
<div>
<#import "*/utils/form.ftlh" as form>
<@form.form action=routes.getRouteUrl("projects.createProject") method="POST">
<@form.form action=Routes.PROJECTS_CREATE_PROJECT.getRouteUrl() method="POST">
<#import "*/utils/csrf.ftlh" as csrf>
<@csrf.formField />
<div class="form-group">

@ -37,7 +37,7 @@ Discussion page within Project overview.
</#if>
<div class="push-down">
<@editor.editor saveCall=routes.getRouteUrl("projects.postDiscussionReply", p.project.ownerName, p.project.slug) cancellable=false enabled=true/>
<@editor.editor saveCall=Routes.PROJECTS_POST_DISCUSSION_REPLY.getRouteUrl(p.project.ownerName, p.project.slug) cancellable=false enabled=true/>
</div>
</div>
<div class="reply-controls">
@ -49,7 +49,7 @@ Discussion page within Project overview.
</div>
<#else>
<div class="pull-right">
<a href="${routes.getRouteUrl("users.login", "", "", request.path)}"><@spring.message "general.login" /></a>
<a href="${Routes.USERS_LOGIN.getRouteUrl("", "", request.path)}"><@spring.message "general.login" /></a>
<span class="minor"> <@spring.message "general.toReply" /></span>
</div>
</#if>

@ -36,8 +36,8 @@ Documentation page within Project overview.
<div class="row">
<div class="col-md-12">
<@editor.editor
saveCall=routes.getRouteUrl("pages.save", p.project.ownerName, p.project.slug, projectPage.slug)
deleteCall=routes.getRouteUrl("pages.delete", p.project.ownerName, p.project.slug, projectPage.slug)
saveCall=Routes.PAGES_SAVE.getRouteUrl(p.project.ownerName, p.project.slug, projectPage.slug)
deleteCall=Routes.PAGES_DELETE.getRouteUrl(p.project.ownerName, p.project.slug, projectPage.slug)
deletable=projectPage.isDeletable
enabled=canEditPages()
raw=projectPage.contents
@ -51,7 +51,7 @@ Documentation page within Project overview.
<#if p.project.recommendedVersionId??>
<div class="btn-group btn-download">
<a href="${routes.getRouteUrl("versions.downloadRecommended", p.project.ownerName, p.project.slug, "")}"
<a href="${Routes.VERSIONS_DOWNLOAD_RECOMMENDED.getRouteUrl(p.project.ownerName, p.project.slug, "")}"
title="<@spring.message "project.download.recommend" />" data-toggle="tooltip"
data-placement="bottom" class="btn btn-primary">
<i class="fas fa-download"></i> <@spring.message "general.download" />
@ -61,8 +61,8 @@ Documentation page within Project overview.
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu dropdown-menu-right">
<li><a href="${routes.getRouteUrl("versions.downloadRecommended", p.project.ownerName, p.project.slug, "")}"><@spring.message "general.download" /></a></li>
<li><a href="#" class="copy-url" data-clipboard-text="${config.baseUrl}${routes.getRouteUrl("versions.downloadRecommended", p.project.ownerName, p.project.slug, "")}">Copy URL</a></li>
<li><a href="${Routes.VERSIONS_DOWNLOAD_RECOMMENDED.getRouteUrl(p.project.ownerName, p.project.slug, "")}"><@spring.message "general.download" /></a></li>
<li><a href="#" class="copy-url" data-clipboard-text="${config.baseUrl}${Routes.VERSIONS_DOWNLOAD_RECOMMENDED.getRouteUrl(p.project.ownerName, p.project.slug, "")}">Copy URL</a></li>
</ul>
</div>
</#if>
@ -71,8 +71,8 @@ Documentation page within Project overview.
<p><@spring.messageArgs code="project.category.info" args=[p.project.category.title] /></p>
<p><@spring.messageArgs code="project.publishDate" args=[utils.prettifyDate(p.project.createdAt)] /></p>
<p><span id="view-count"></span> views</p>
<p><span id="star-count"></span> <a href="${routes.getRouteUrl("projects.showStargazers", p.project.ownerName, p.project.slug, "")}">star<#if p.starCount != 1>s</#if></a></p>
<p><span id="watcher-count"></span> <a href="${routes.getRouteUrl("projects.showWatchers", p.project.ownerName, p.project.slug, "")}">watcher<#if p.watcherCount != 1>s</#if></a></p>
<p><span id="star-count"></span> <a href="${Routes.PROJECTS_SHOW_STARGAZERS.getRouteUrl(p.project.ownerName, p.project.slug, "")}">star<#if p.starCount != 1>s</#if></a></p>
<p><span id="watcher-count"></span> <a href="${Routes.PROJECTS_SHOW_WATCHERS.getRouteUrl(p.project.ownerName, p.project.slug, "")}">watcher<#if p.watcherCount != 1>s</#if></a></p>
<p><span id="download-count"></span> total downloads</p>
<#if p.project.licenseName?has_content && p.project.licenseUrl?has_content>
<p>
@ -104,7 +104,7 @@ Documentation page within Project overview.
</div>
<ul class="list-group">
<#-- <li class="list-group-item">-->
<#-- <a href="${routes.getRouteUrl("pages.show", p.project.ownerName, p.project.slug, config.pages.home.name)}">-->
<#-- <a href="${Routes.PAGES_SHOW.getRouteUrl(p.project.ownerName, p.project.slug, config.pages.home.name)}">-->
<#-- ${"Home"}-->
<#-- </a>-->
<#-- </li>-->
@ -123,7 +123,7 @@ Documentation page within Project overview.
</a>
</#if>
</#if>
<a href="${routes.getRouteUrl("pages.show", p.project.ownerName, p.project.slug, pg.slug)}" class="href">
<a href="${Routes.PAGES_SHOW.getRouteUrl(p.project.ownerName, p.project.slug, pg.slug)}" class="href">
${pg.name}
</a>
</li>
@ -132,7 +132,7 @@ Documentation page within Project overview.
<#-- @ftlvariable name="childPage" type="io.papermc.hangar.model.viewhelpers.ProjectPage" -->
<#list children as childPage>
<li class="list-group-item page-item-child">
<a href="${routes.getRouteUrl("pages.show", p.project.ownerName, p.project.slug, childPage.slug)}">
<a href="${Routes.PAGES_SHOW.getRouteUrl(p.project.ownerName, p.project.slug, childPage.slug)}">
${childPage.name}
</a>
</li>
@ -144,7 +144,7 @@ Documentation page within Project overview.
</div>
<!-- Member list -->
<@memberList.memberList project=p perms=sp.permissions settingsCall=routes.getRouteUrl("projects.showSettings", p.project.ownerName, p.project.slug) />
<@memberList.memberList project=p perms=sp.permissions settingsCall=Routes.PROJECTS_SHOW_SETTINGS.getRouteUrl(p.project.ownerName, p.project.slug) />
</div>
</div>
</@projectView.view>

@ -205,7 +205,7 @@
</div>
</#if>
<@form.form action=routes.getRouteUrl("projects.save", p.project.ownerName, p.project.slug) method="POST" id="save" class="pull-right">
<@form.form action=Routes.PROJECTS_SAVE.getRouteUrl(p.project.ownerName, p.project.slug) method="POST" id="save" class="pull-right">
<@csrf.formField />
<input type="hidden" id="update-icon" name="update-icon" value="false" />
<button type="submit" name="save" class="btn btn-success btn-spinner" data-icon="fa-check">
@ -229,7 +229,7 @@
<!-- Side panel -->
<div class="col-md-4">
<@memberList.memberList project=p perms=sp.permissions editable=true removeCall=routes.getRouteUrl("projects.removeMember", p.project.ownerName, p.project.slug) settingsCall=routes.getRouteUrl("projects.showSettings", p.project.ownerName, p.project.slug) />
<@memberList.memberList project=p perms=sp.permissions editable=true removeCall=Routes.PROJECTS_REMOVE_MEMBER.getRouteUrl(p.project.ownerName, p.project.slug) settingsCall=Routes.PROJECTS_SHOW_SETTINGS.getRouteUrl(p.project.ownerName, p.project.slug) />
</div>
</div>
</div>
@ -249,7 +249,7 @@
</div>
<div class="modal-footer">
<div class="form-inline">
<@form.form action=routes.getRouteUrl("projects.rename", p.project.ownerName, p.project.slug) method="POST" id="rename">
<@form.form action=Routes.PROJECTS_RENAME.getRouteUrl(p.project.ownerName, p.project.slug) method="POST" id="rename">
<@csrf.formField />
<button type="button" class="btn btn-default" data-dismiss="modal">
<@spring.message "channel.edit.close" />
@ -271,7 +271,7 @@
</button>
<h4 class="modal-title" id="label-delete"><@spring.message "project.delete.title" /></h4>
</div>
<@form.form action=routes.getRouteUrl("projects.softDelete", p.project.ownerName, p.project.slug) method="POST">
<@form.form action=Routes.PROJECTS_SOFT_DELETE.getRouteUrl(p.project.ownerName, p.project.slug) method="POST">
<div class="modal-body">
<@spring.message "project.delete.info" />
<br>

@ -34,7 +34,7 @@
<@userAvatar.userAvatar userName=gridUser.name avatarUrl=utils.avatarUrl(gridUser.name) clazz="user-avatar-sm media-object" />
</div>
<div class="media-body center-vertically">
<a class="media-heading mb-0" href="${routes.getRouteUrl("users.showProjects", gridUser.name)}">${gridUser.name}</a>
<a class="media-heading mb-0" href="${Routes.USERS_SHOW_PROJECTS.getRouteUrl(gridUser.name)}">${gridUser.name}</a>
</div>
</div>
</#list>

@ -148,7 +148,7 @@
<script <#--@CSPNonce.attr-->>$(function () { $('.btn-edit').click() });</script>
</#if>
<@form.form action=routes.getRouteUrl("versions.upload", ownerName, projectSlug) method="POST"
<@form.form action=Routes.VERSIONS_UPLOAD.getRouteUrl(ownerName, projectSlug) method="POST"
enctype="multipart/form-data" id="form-upload">
<@csrf.formField />
<label class="btn btn-default pull-left" for="pluginFile">
@ -162,7 +162,7 @@
<#if pending??>
<#-- Ready to go! -->
<#assign version = pending>
<@form.form method="POST" action=routes.getRouteUrl("versions.publish", ownerName, projectSlug, version.versionString)
<@form.form method="POST" action=Routes.VERSIONS_PUBLISH.getRouteUrl(ownerName, projectSlug, version.versionString)
id="form-publish" class="pull-right">
<@csrf.formField />
<input type="hidden" class="channel-color-input" name="channel-color-input"

@ -46,7 +46,7 @@ Versions page within Project overview.
<#assign Permission=@helper["io.papermc.hangar.model.Permission"]>
<#if sp.perms(Permission.EditTags)>
<li class="list-group-item text-right">
<a class="btn yellow btn-xs" href="${routes.getRouteUrl("channels.showList", p.project.ownerName, p.project.slug)}">
<a class="btn yellow btn-xs" href="${Routes.CHANNELS_SHOW_LIST.getRouteUrl(p.project.ownerName, p.project.slug)}">
Edit
</a>
</li>
@ -54,7 +54,7 @@ Versions page within Project overview.
</ul>
</div>
<#import "*/users/memberList.ftlh" as users>
<@users.memberList project=p perms=sp.permissions settingsCall=routes.getRouteUrl("projects.showSettings", p.project.ownerName, p.project.slug) />
<@users.memberList project=p perms=sp.permissions settingsCall=Routes.PROJECTS_SHOW_SETTINGS.getRouteUrl(p.project.ownerName, p.project.slug) />
</div>
</div>
</@projects.view>

@ -7,7 +7,7 @@
<div class="row">
<div class="col-md-12">
<h1><@spring.message "version.log.visibility.title" /> <a
href="${routes.getRouteUrl("versions.show", project.project.name, project.project.slug, version.versionString)}">${project.project.name}
href="${Routes.VERSIONS_SHOW.getRouteUrl(project.project.name, project.project.slug, version.versionString)}">${project.project.name}
/${project.project.slug}/versions/${version.versionString}</a></h1>
</div>
</div>

@ -49,7 +49,7 @@
</div>
<div class="col-xs-12 col-sm-6">
<form action="${routes.getRouteUrl("versions.confirmDownload", project.ownerName, project.slug, target.name, Some(downloadType.value), "", "dummy")}" method="post" id="form-download">
<form action="${Routes.VERSIONS_CONFIRM_DOWNLOAD.getRouteUrl(project.ownerName, project.slug, target.name, Some(downloadType.value), "", "dummy")}" method="post" id="form-download">
<@csrf.formField />
<button type="submit" form="form-download" class="btn btn-danger pull-right-sm">

@ -34,7 +34,7 @@
<!-- User info -->
<p class="user date pull-left">
<a href="${routes.getRouteUrl("users.showProjects", v.p.project.ownerName)}">
<a href="${Routes.USERS_SHOW_PROJECTS.getRouteUrl(v.p.project.ownerName)}">
<strong>${v.p.project.ownerName}</strong>
</a>
released this version on ${utils.prettifyDateTime(v.v.createdAt)}
@ -76,7 +76,7 @@
<div>
<#if !v.recommended && sp.perms(Permission.EditVersion) && v.v.visibility != Visibility.SOFTDELETE>
<@form.form method="POST" action=routes.getRouteUrl("versions.setRecommended", v.p.project.ownerName, v.p.project.slug, v.v.versionString) class="form-inline">
<@form.form method="POST" action=Routes.VERSIONS_SET_RECOMMENDED.getRouteUrl(v.p.project.ownerName, v.p.project.slug, v.v.versionString) class="form-inline">
<@csrf.formField />
<button type="submit" class="btn btn-info">
<i class="fas fa-gem"></i> Set recommended
@ -86,9 +86,9 @@
<#if headerData.globalPerm(Permission.Reviewer)>
<#if v.v.reviewState.checked>
<a href="${routes.getRouteUrl("reviews.showReviews", v.p.project.ownerName, v.p.project.slug, v.v.versionString)}" class="btn btn-info"><@spring.message "review.log" /></a>
<a href="${Routes.REVIEWS_SHOW_REVIEWS.getRouteUrl(v.p.project.ownerName, v.p.project.slug, v.v.versionString)}" class="btn btn-info"><@spring.message "review.log" /></a>
<#else>
<a href="${routes.getRouteUrl("reviews.showReviews", v.p.project.ownerName, v.p.project.slug, v.v.versionString)}" class="btn btn-success">
<a href="${Routes.REVIEWS_SHOW_REVIEWS.getRouteUrl(v.p.project.ownerName, v.p.project.slug, v.v.versionString)}" class="btn btn-success">
<i class="fas fa-play"></i> <@spring.message "review.start" />
</a>
</#if>
@ -115,7 +115,7 @@
</#if>
<div class="btn-group btn-download">
<a href="${routes.getRouteUrl("versions.download", v.p.project.ownerName, v.p.project.slug, v.v.versionString, "", "")}"
<a href="${Routes.VERSIONS_DOWNLOAD.getRouteUrl(v.p.project.ownerName, v.p.project.slug, v.v.versionString, "", "")}"
title="<@spring.message "project.download.recommend" />" data-toggle="tooltip"
data-placement="bottom" class="btn btn-primary">
<i class="fas fa-download"></i> <@spring.message "general.download" />
@ -125,8 +125,8 @@
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu dropdown-menu-right">
<li><a href="${routes.getRouteUrl("versions.download", v.p.project.ownerName, v.p.project.slug, v.v.versionString, "", "")}"><@spring.message "general.download" /></a></li>
<li><a href="#" class="copy-url" data-clipboard-text="${config.baseUrl}${routes.getRouteUrl("versions.download", v.p.project.ownerName, v.p.project.slug, v.v.versionString, "", "")}">Copy URL</a></li>
<li><a href="${Routes.VERSIONS_DOWNLOAD.getRouteUrl(v.p.project.ownerName, v.p.project.slug, v.v.versionString, "", "")}"><@spring.message "general.download" /></a></li>
<li><a href="#" class="copy-url" data-clipboard-text="${config.baseUrl}${Routes.VERSIONS_DOWNLOAD.getRouteUrl(v.p.project.ownerName, v.p.project.slug, v.v.versionString, "", "")}">Copy URL</a></li>
</ul>
</div>
@ -137,7 +137,7 @@
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="admin-version-actions">
<li><a href="${routes.getRouteUrl("showLog", "", "", "", v.v.versionString, "", "", "")}">User Action Logs</a></li>
<li><a href="${Routes.SHOW_LOG.getRouteUrl("", "", "", v.v.versionString, "", "", "")}">User Action Logs</a></li>
<#if headerData.globalPerm(Permission.Reviewer)>
<#if v.v.visibility == Visibility.SOFTDELETE>
<li><a href="#" data-toggle="modal" data-target="#modal-restore">Undo delete</a></li>
@ -171,7 +171,7 @@
</#if>
<div class="col-md-12">
<@editor.editor
saveCall=routes.getRouteUrl("versions.saveDescription", v.p.project.ownerName, v.p.project.slug, v.v.versionString)
saveCall=Routes.VERSIONS_SAVE_DESCRIPTION.getRouteUrl(v.p.project.ownerName, v.p.project.slug, v.v.versionString)
enabled=sp.perms(Permission.EditPage)
raw=v.v.description!""
cooked=markdownService.render(v.v.description)
@ -212,7 +212,7 @@
<#list v.filteredDependencies as depend, project>
<li class="list-group-item">
<#if project??>
<a href="${routes.getRouteUrl("projects.show", project.ownerName, project.slug)}">
<a href="${Routes.PROJECTS_SHOW.getRouteUrl(project.ownerName, project.slug)}">
<strong>${project.name}</strong>
</a>
<#else>
@ -246,7 +246,7 @@
</button>
<h4 class="modal-title" id="label-delete"><@spring.message "version.delete.title" /></h4>
</div>
<@form.form method="POST" action=routes.getRouteUrl("versions.softDelete", v.p.project.ownerName, v.p.project.slug, v.v.versionString)>
<@form.form method="POST" action=Routes.VERSIONS_SOFT_DELETE.getRouteUrl(v.p.project.ownerName, v.p.project.slug, v.v.versionString)>
<div class="modal-body">
<@spring.message "version.delete.info" />
<textarea name="comment" class="textarea-delete-comment form-control" rows="3"></textarea>
@ -277,7 +277,7 @@
</button>
<h4 class="modal-title" id="label-delete"><@spring.message "general.restore" /></h4>
</div>
<@form.form method="POST" action=routes.getRouteUrl("versions.restore", v.p.project.ownerName, v.p.project.slug, v.v.versionString)>
<@form.form method="POST" action=Routes.VERSIONS_RESTORE.getRouteUrl(v.p.project.ownerName, v.p.project.slug, v.v.versionString)>
<div class="modal-body">
<textarea name="comment" class="textarea-delete-comment form-control" rows="3"></textarea>
</div>
@ -305,7 +305,7 @@
</button>
<h4 class="modal-title" id="label-delete"><@spring.message "general.harddelete" /></h4>
</div>
<@form.form method="POST" action=routes.getRouteUrl("versions.delete", v.p.project.ownerName, v.p.project.slug, v.v.versionString)>
<@form.form method="POST" action=Routes.VERSIONS_DELETE.getRouteUrl(v.p.project.ownerName, v.p.project.slug, v.v.versionString)>
<div class="modal-body">
<textarea name="comment" class="textarea-delete-comment form-control" rows="3"></textarea>
</div>

@ -27,7 +27,7 @@ Base template for Project overview.
<#assign metaVar>
<meta property="og:title" content="${p.project.ownerName} / ${p.project.name}" />
<meta property="og:type" content="website" />
<meta property="og:url" content="${routes.getRouteUrl("projects.show", p.project.ownerName, p.project.slug)}" />
<meta property="og:url" content="${Routes.PROJECTS_SHOW.getRouteUrl(p.project.ownerName, p.project.slug)}" />
<meta property="og:image" content="${p.iconUrl}" />
<meta property="og:site_name" content="<@spring.message "general.appName" />" />
<meta property="og:description" content="${p.project.description!}" />
@ -64,9 +64,9 @@ Base template for Project overview.
<div class="col-md-6">
<div class="project-header">
<div class="project-path">
<a href="${routes.getRouteUrl("users.showProjects", p.project.ownerName)}">${p.project.ownerName}</a>
<a href="${Routes.USERS_SHOW_PROJECTS.getRouteUrl(p.project.ownerName)}">${p.project.ownerName}</a>
/
<a class="project-name" href="${routes.getRouteUrl("projects.show", p.project.ownerName, p.project.slug)}">${p.project.name}</a>
<a class="project-name" href="${Routes.PROJECTS_SHOW.getRouteUrl(p.project.ownerName, p.project.slug)}">${p.project.name}</a>
</div>
<div>
<#if p.project.description??>
@ -128,7 +128,7 @@ Base template for Project overview.
<h4 class="modal-title" id="label-flag">Flag project</h4>
</div>
<#import "*/utils/form.ftlh" as form>
<@form.form action=routes.getRouteUrl("projects.flag", p.project.ownerName, p.project.slug) method="POST">
<@form.form action=Routes.PROJECTS_FLAG.getRouteUrl(p.project.ownerName, p.project.slug) method="POST">
<#import "*/utils/csrf.ftlh" as csrf>
<@csrf.formField />
<div class="modal-body">
@ -166,15 +166,15 @@ Base template for Project overview.
</button>
<ul class="dropdown-menu" aria-labelledby="admin-actions">
<#if headerData.globalPerm(Permission.ModNotesAndFlags)>
<li><a href="${routes.getRouteUrl("projects.showFlags", p.project.ownerName, p.project.slug)}">
<li><a href="${Routes.PROJECTS_SHOW_FLAGS.getRouteUrl(p.project.ownerName, p.project.slug)}">
Flag history (${p.flagCount}) </a></li>
</#if>
<#if headerData.globalPerm(Permission.ModNotesAndFlags)>
<li><a href="${routes.getRouteUrl("projects.showNotes", p.project.ownerName, p.project.slug)}">
<li><a href="${Routes.PROJECTS_SHOW_NOTES.getRouteUrl(p.project.ownerName, p.project.slug)}">
Staff notes (${p.noteCount}) </a></li>
</#if>
<#if headerData.globalPerm(Permission.ViewLogs)>
<li><a href="${routes.getRouteUrl("showLog", "", "", p.project.pluginId, "", "", "", "")}">
<li><a href="${Routes.SHOW_LOG.getRouteUrl("", "", p.project.pluginId, "", "", "", "")}">
User Action Logs</a></li>
</#if>
<li><a href="https://papermc.io/forums/${p.project.ownerName}">Owner on forum <i class="fas fa-external-link-alt" aria-hidden="true"></i></a></li>
@ -193,19 +193,19 @@ Base template for Project overview.
<ul class="nav navbar-nav">
<!-- Tabs -->
<li id="docs" class="">
<a href="${routes.getRouteUrl("projects.show", p.project.ownerName, p.project.slug)}">
<a href="${Routes.PROJECTS_SHOW.getRouteUrl(p.project.ownerName, p.project.slug)}">
<i class="fas fa-book"></i> <@spring.message "project.docs" /></a>
</li>
<li id="versions" class="">
<a href="${routes.getRouteUrl("versions.showList", p.project.ownerName, p.project.slug)}">
<a href="${Routes.VERSIONS_SHOW_LIST.getRouteUrl(p.project.ownerName, p.project.slug)}">
<i class="fas fa-download"></i> <@spring.message "project.versions" />
</a>
</li>
<#if p.project.topicId??>
<li id="discussion" class="">
<a href="${routes.getRouteUrl("projects.showDiscussion", p.project.ownerName, p.project.slug)}">
<a href="${Routes.PROJECTS_SHOW_DISCUSSION.getRouteUrl(p.project.ownerName, p.project.slug)}">
<i class="fas fa-users"></i> <@spring.message "project.discuss" />
</a>
</li>
@ -214,7 +214,7 @@ Base template for Project overview.
<#if sp.perms(Permission.EditProjectSettings)>
<#-- Show manager if permitted -->
<li id="settings" class="">
<a href="${routes.getRouteUrl("projects.showSettings", p.project.ownerName, p.project.slug)}">
<a href="${Routes.PROJECTS_SHOW_SETTINGS.getRouteUrl(p.project.ownerName, p.project.slug)}">
<i class="fas fa-cog"></i> <@spring.message "project.settings" />
</a>
</li>

@ -32,7 +32,7 @@
<td>Review approved</td>
<td>${utils.prettifyDateTime(activity.endedAt!OffsetDateTime.MIN)}</td>
<td>for:
<a href="${routes.getRouteUrl("reviews.showReviews", activity.getProject().getOwner(), activity.getProject().getSlug(), activity.versionString)}" title="Go to reviews...">
<a href="${Routes.REVIEWS_SHOW_REVIEWS.getRouteUrl(activity.getProject().getOwner(), activity.getProject().getSlug(), activity.versionString)}" title="Go to reviews...">
${activity.getProject().getOwner()} / ${activity.getProject().getSlug()} / ${activity.versionString}
</a>
</td>
@ -43,7 +43,7 @@
<td>Flag resolved</td>
<td>${utils.prettifyDateTime(activity.resolvedAt!OffsetDateTime.MIN)}</td> <#--TODO: activity end datetime needs to be moved to abstract Activity-->
<td>for:
<a href="${routes.getRouteUrl("projects.show", activity.getProject().getSlug(), activity.getProject().getSlug())}">
<a href="${Routes.PROJECTS_SHOW.getRouteUrl(activity.getProject().getSlug(), activity.getProject().getSlug())}">
${activity.getProject().getOwner()} / ${activity.getProject().getSlug()}
</a>
</td>

@ -24,7 +24,7 @@
<li data-flag-id="${flag.flag.id}" class="list-group-item">
<div class="row">
<div class="col-xs-12 col-md-1" style="width: 40px;">
<a href="${routes.getRouteUrl("users.showProjects", flag.reportedBy)}">
<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>
@ -33,7 +33,7 @@
<span class="description">
<strong>${flag.reportedBy}</strong>
<span class="minor"> reported </span>
<a href="${routes.getRouteUrl("projects.show", flag.projectOwnerName, flag.projectSlug)}">
<a href="${Routes.PROJECTS_SHOW.getRouteUrl(flag.projectOwnerName, flag.projectSlug)}">
${flag.projectNamespace}
</a>
<span class="minor"> for </span>

@ -32,7 +32,7 @@
<div class="panel-body list-group list-group-health">
<#list noTopicProjects as project>
<div class="list-group-item">
<a class="pull-left" href="${routes.getRouteUrl("projects.show", project.getNamespace().getOwner(), project.getNamespace().getSlug())}">
<a class="pull-left" href="${Routes.PROJECTS_SHOW.getRouteUrl(project.getNamespace().getOwner(), project.getNamespace().getSlug())}">
<strong>${project.namespace}</strong>
</a>
<div class="clearfix"></div>
@ -66,7 +66,7 @@
<div class="panel-body list-group list-group-health">
<#list staleProjects as project>
<div class="list-group-item">
<a href="${routes.getRouteUrl("projects.show", project.getNamespace().getOwner(), project.getNamespace().getSlug())}">
<a href="${Routes.PROJECTS_SHOW.getRouteUrl(project.getNamespace().getOwner(), project.getNamespace().getSlug())}">
<strong>${project.namespace}</strong>
</a>
</div>
@ -82,7 +82,7 @@
<div class="panel-body list-group list-group-health">
<#list notPublicProjects as project>
<div class="list-group-item">
<a href="${routes.getRouteUrl("projects.show", project.getNamespace().getOwner(), project.getNamespace().getSlug())}">
<a href="${Routes.PROJECTS_SHOW.getRouteUrl(project.getNamespace().getOwner(), project.getNamespace().getSlug())}">
<strong>${project.namespace}</strong> <small><@spring.message "visibility.name." + project.getVisibility().getName() /></small>
</a>
</div>
@ -110,7 +110,7 @@
<div class="panel-body list-group list-group-health">
<#list missingFileProjects as missingFileProject>
<div class="list-group-item">
<a href="${routes.getRouteUrl("versions.show", missingFileProject.owner, missingFileProject.name, missingFileProject.getVersion().getVersionString())}">
<a href="${Routes.VERSIONS_SHOW.getRouteUrl(missingFileProject.owner, missingFileProject.name, missingFileProject.getVersion().getVersionString())}">
<strong>${missingFileProject.displayText}</strong>
</a>
</div>

@ -61,8 +61,8 @@
<tr>
<td><b>${offset + action?index + 1}</b></td>
<td>
<a href="${routes.getRouteUrl("users.showProjects", action.userName)}">${action.userName}</a>
<small class="filter-user">(<a href="${routes.getRouteUrl("showLog", page?string, action.userName, projectFilter, versionFilter, pageFilter, actionFilter, subjectFilter)}">${action.userName}</a>)</small>
<a href="${Routes.USERS_SHOW_PROJECTS.getRouteUrl(action.userName)}">${action.userName}</a>
<small class="filter-user">(<a href="${Routes.SHOW_LOG.getRouteUrl(page?string, action.userName, projectFilter, versionFilter, pageFilter, actionFilter, subjectFilter)}">${action.userName}</a>)</small>
</td>
<#if canViewIP>
@ -71,38 +71,38 @@
<td>${utils.prettifyDateTime(action.createdAt)}</td>
<td>
${action.action.description}
<small class="filter-action">(<a href="${routes.getRouteUrl("showLog", page?string, userFilter, projectFilter, versionFilter, pageFilter, action.action.value, subjectFilter)}">${action.action.value}</a>)</small>
<small class="filter-action">(<a href="${Routes.SHOW_LOG.getRouteUrl(page?string, userFilter, projectFilter, versionFilter, pageFilter, action.action.value, subjectFilter)}">${action.action.value}</a>)</small>
</td>
<#if action.actionContext.class.simpleName == "UserContext" || action.actionContext.class.simpleName == "OrganizationContext">
<td>
<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>
<a href="${Routes.USERS_SHOW_PROJECTS.getRouteUrl(action.subject.username!"Unknown")}">${action.subject.username}</a>
<small class="filter-subject">(<a href="${Routes.SHOW_LOG.getRouteUrl(page?string, userFilter, projectFilter, versionFilter, pageFilter, actionFilter, action.subject.username)}">${action.subject.username}</a>)</small>
</td>
<#elseif !action.project.id??>
<td>
Resource deleted
<#if action.actionContext.class.simpleName == "ProjectContext" || action.actionContext.class.simpleName == "ProjectPageContext">
<small class="filter-project">(<a href="${routes.getRouteUrl("showLog", page?string, userFilter, action.project.pluginId, versionFilter, pageFilter, actionFilter, subjectFilter)}">${action.project.pluginId}</a>)</small>
<small class="filter-project">(<a href="${Routes.SHOW_LOG.getRouteUrl(page?string, userFilter, action.project.pluginId, versionFilter, pageFilter, actionFilter, subjectFilter)}">${action.project.pluginId}</a>)</small>
<#else>
<small class="filter-version">(<a href="${routes.getRouteUrl("showLog", page?string, userFilter, projectFilter, action.version.versionString, pageFilter, actionFilter, subjectFilter)}">${action.version.versionString}</a>)</small>
<small class="filter-version">(<a href="${Routes.SHOW_LOG.getRouteUrl(page?string, userFilter, projectFilter, action.version.versionString, pageFilter, actionFilter, subjectFilter)}">${action.version.versionString}</a>)</small>
</#if>
</td>
<#elseif action.actionContext.class.simpleName == "ProjectContext">
<td>
<a href="${routes.getRouteUrl("projects.show", action.project.owner!"Unknown", action.project.slug!"Unknown")}">${action.project.owner}/${action.project.slug!"Unknown"}</a>
<small class="filter-project">(<a href="${routes.getRouteUrl("showLog", page?string, userFilter, action.project.pluginId, versionFilter, pageFilter, actionFilter, subjectFilter)}">${action.project.pluginId}</a>)</small>
<a href="${Routes.PROJECTS_SHOW.getRouteUrl(action.project.owner!"Unknown", action.project.slug!"Unknown")}">${action.project.owner}/${action.project.slug!"Unknown"}</a>
<small class="filter-project">(<a href="${Routes.SHOW_LOG.getRouteUrl(page?string, userFilter, action.project.pluginId, versionFilter, pageFilter, actionFilter, subjectFilter)}">${action.project.pluginId}</a>)</small>
</td>
<#elseif action.actionContext.class.simpleName == "ProjectPageContext">
<td>
<a href="${routes.getRouteUrl("pages.show", action.project.owner!"Unknown", action.project.slug!"Unknown", action.page.slug!"Unknown")}">${action.project.owner!"Unknown"}/${action.project.slug!"Unknown"}/${action.page.slug!"Unknown"}</a>
<small class="filter-project">(<a href="${routes.getRouteUrl("showLog", page?string, userFilter, action.project.pluginId, versionFilter, pageFilter, actionFilter, subjectFilter)}">${action.project.pluginId}</a>)</small>
<small class="filter-page">(<a href="${routes.getRouteUrl("showLog", page?string, userFilter, projectFilter, versionFilter, action.page.id?string, actionFilter, subjectFilter)}">${action.page.id}</a>)</small>
<a href="${Routes.PAGES_SHOW.getRouteUrl(action.project.owner!"Unknown", action.project.slug!"Unknown", action.page.slug!"Unknown")}">${action.project.owner!"Unknown"}/${action.project.slug!"Unknown"}/${action.page.slug!"Unknown"}</a>
<small class="filter-project">(<a href="${Routes.SHOW_LOG.getRouteUrl(page?string, userFilter, action.project.pluginId, versionFilter, pageFilter, actionFilter, subjectFilter)}">${action.project.pluginId}</a>)</small>
<small class="filter-page">(<a href="${Routes.SHOW_LOG.getRouteUrl(page?string, userFilter, projectFilter, versionFilter, action.page.id?string, actionFilter, subjectFilter)}">${action.page.id}</a>)</small>
</td>
<#elseif action.actionContext.class.simpleName == "VersionContext">
<td>
<a href="${routes.getRouteUrl("versions.show", action.project.owner!"Unknown", action.project.slug!"Unknown", action.version.versionString!"Unknown")}">${action.project.owner!"Unknown"}/${action.project.slug!"Unknown"}/${action.version.versionString!"Unknown"}</a>
<small class="filter-project">(<a href="${routes.getRouteUrl("showLog", page?string, userFilter, action.project.pluginId, versionFilter, pageFilter, actionFilter, subjectFilter)}">${action.project.pluginId}</a>)</small>
<small class="filter-version">(<a href="${routes.getRouteUrl("showLog", page?string, userFilter, projectFilter, action.version.versionString, pageFilter, actionFilter, subjectFilter)}">${action.version.versionString}</a>)</small>
<a href="${Routes.VERSIONS_SHOW.getRouteUrl(action.project.owner!"Unknown", action.project.slug!"Unknown", action.version.versionString!"Unknown")}">${action.project.owner!"Unknown"}/${action.project.slug!"Unknown"}/${action.version.versionString!"Unknown"}</a>
<small class="filter-project">(<a href="${Routes.SHOW_LOG.getRouteUrl(page?string, userFilter, action.project.pluginId, versionFilter, pageFilter, actionFilter, subjectFilter)}">${action.project.pluginId}</a>)</small>
<small class="filter-version">(<a href="${Routes.SHOW_LOG.getRouteUrl(page?string, userFilter, projectFilter, action.version.versionString, pageFilter, actionFilter, subjectFilter)}">${action.version.versionString}</a>)</small>
</td>
</#if>
<#-- Show diff only when page edit -->
@ -126,10 +126,10 @@
</div>
<div class="panel-heading" style="display:block">
<#if page gt 1>
<h4 class="panel-title pull-left"><a href="${routes.getRouteUrl("showLog", (page-1)?string, userFilter, projectFilter, versionFilter, pageFilter, actionFilter, subjectFilter)}">&leftarrow; ${page - 1}</a></h4>
<h4 class="panel-title pull-left"><a href="${Routes.SHOW_LOG.getRouteUrl((page-1)?string, userFilter, projectFilter, versionFilter, pageFilter, actionFilter, subjectFilter)}">&leftarrow; ${page - 1}</a></h4>
</#if>
<#if offset + limit < size>
<h4 class="panel-title pull-right"><a href="${routes.getRouteUrl("showLog", (page+1)?string, userFilter, projectFilter, versionFilter, pageFilter, actionFilter, subjectFilter)}">${page + 1} &rightarrow;</a></h4>
<h4 class="panel-title pull-right"><a href="${Routes.SHOW_LOG.getRouteUrl((page+1)?string, userFilter, projectFilter, versionFilter, pageFilter, actionFilter, subjectFilter)}">${page + 1} &rightarrow;</a></h4>
</#if>
<div class="clearfix"></div>
</div>

@ -56,7 +56,7 @@
<#list underReview as entry>
<tr <#if entry.unfinished && headerData.isCurrentUser(entry.reviewerId)>class="warning"</#if>>
<td>
<a href="${routes.getRouteUrl("versions.show", entry.author, entry.slug, entry.versionString)}">
<a href="${Routes.VERSIONS_SHOW.getRouteUrl(entry.author, entry.slug, entry.versionString)}">
${entry.namespace}
</a>
<br>
@ -144,7 +144,7 @@
<@userAvatar.userAvatar userName=entry.author avatarUrl=utils.avatarUrl(entry.author) clazz="user-avatar-xs"></@userAvatar.userAvatar>
</td>
<td>
<a href="${routes.getRouteUrl("versions.show", entry.author, entry.slug, entry.versionString)}">
<a href="${Routes.VERSIONS_SHOW.getRouteUrl(entry.author, entry.slug, entry.versionString)}">
${entry.namespace}
</a>
</td>

@ -17,7 +17,7 @@
<h1 class="pull-left">${project.project.name} <i>${version.v.versionString}</i></h1>
</div>
<p class="user date pull-left">
<a href="${routes.getRouteUrl("users.showProjects", project.project.ownerName)}">
<a href="${Routes.USERS_SHOW_PROJECTS.getRouteUrl(project.project.ownerName)}">
<strong>${project.project.ownerName}</strong>
</a>
released this version on ${utils.prettifyDateTime(version.v.createdAt)}
@ -26,8 +26,8 @@
<div class="pull-right">
<span class="btn-group-sm">
<a href="#" class="btn btn-info btn-skip-review"><#if version.v.reviewState != ReviewState.BACKLOG> Remove from queue <#else> Add to queue </#if></a>
<a href="${routes.getRouteUrl("projects.show", project.project.ownerName, project.project.slug)}" class="btn btn-info">Project Page</a>
<a href="${routes.getRouteUrl("versions.downloadJar", project.project.ownerName, project.project.slug, version.v.versionString, "")}" class="btn btn-info">Download File</a>
<a href="${Routes.PROJECTS_SHOW.getRouteUrl(project.project.ownerName, project.project.slug)}" class="btn btn-info">Project Page</a>
<a href="${Routes.VERSIONS_DOWNLOAD_JAR.getRouteUrl(project.project.ownerName, project.project.slug, version.v.versionString, "")}" class="btn btn-info">Download File</a>
</span>
<span class="btn-group-sm">
<#if mostRecentUnfinishedReview??>

@ -31,7 +31,7 @@
<div class="row">
<div class="col-md-12">
<h1>${prefix}<a href="${routes.getRouteUrl("users.showProjects", u.user.name)}">${u.user.name}</a></h1>
<h1>${prefix}<a href="${Routes.USERS_SHOW_PROJECTS.getRouteUrl(u.user.name)}">${u.user.name}</a></h1>
</div>
</div>
@ -42,7 +42,7 @@
<@panel "Organizations">
<@roleTable keyName="Organization" tableType="orgRole" withOwner=true roles=u.orgas roleTypes=orgRoles ; org, role>
<#-- @ftlvariable name="org" type="io.papermc.hangar.model.viewhelpers.OrganizationData" -->
<a href="${routes.getRouteUrl("userAdmin", org.org.name)}">
<a href="${Routes.USER_ADMIN.getRouteUrl(org.org.name)}">
${org.org.name}
</a>
</@roleTable>
@ -51,7 +51,7 @@
<@panel "Members">
<#-- TODO organization members map-->
<@roleTable keyName="User" tableType="memberRole" withOwner=false roles=orga.adminTable() roleTypes=orgRoles ; member, role>
<a href="${routes.getRouteUrl("userAdmin", member.user.name)}">
<a href="${Routes.USER_ADMIN.getRouteUrl(member.user.name)}">
${member.user.name}
</a>
</@roleTable>
@ -63,7 +63,7 @@
<@panel "Projects">
<@roleTable keyName="Project" tableType="projectRole" withOwner=true roles=userProjectRoles roleTypes=projectRoles ; project, role>
<#-- @ftlvariable name="project" type="io.papermc.hangar.model.viewhelpers.ProjectData" -->
<a href="${routes.getRouteUrl("projects.show", project.projectOwner.name, project.project.slug)}">
<a href="${Routes.PROJECTS_SHOW.getRouteUrl(project.projectOwner.name, project.project.slug)}">
${project.project.name}
</a>
</@roleTable>
@ -97,7 +97,7 @@
<td><#nested object, role /></td>
<#if withOwner>
<#-- @ftlvariable name="object" type="io.papermc.hangar.model.viewhelpers.JoinableData" -->
<td><a href="${routes.getRouteUrl("userAdmin", object.ownerName)}">${object.ownerName}</a></td>
<td><a href="${Routes.USER_ADMIN.getRouteUrl(object.ownerName)}">${object.ownerName}</a></td>
</#if>
<#if !role.role.assignable>
<td>

@ -18,7 +18,7 @@
<span class="description">
<strong>${project.changeRequester}</strong>
<span class="minor"> requested changes on </span>
<a href="${routes.getRouteUrl("projects.show", project.getNamespace().getOwner(), project.getNamespace().getSlug())}">
<a href="${Routes.PROJECTS_SHOW.getRouteUrl(project.getNamespace().getOwner(), project.getNamespace().getSlug())}">
${project.namespace}
</a>
</span>

@ -74,7 +74,7 @@
<#import "*/utils/userAvatar.ftlh" as userAvatar>
<td><@userAvatar.userAvatar userName=author.name avatarUrl=utils.avatarUrl(author.name) clazz="user-avatar-xs"></@userAvatar.userAvatar></td>
<td>
<a href="${routes.getRouteUrl("users.showProjects", author.name)}">${author.name}</a>
<a href="${Routes.USERS_SHOW_PROJECTS.getRouteUrl(author.name)}">${author.name}</a>
</td>
<td>
<#if author.donatorRole??>
@ -101,13 +101,13 @@
<td></td>
<td>
<#if authors?size gte pageSize>
<a href="${routes.getRouteUrl("users.showAuthors", ordering, page + 1)}" class="btn btn-default">
<a href="${Routes.USERS_SHOW_AUTHORS.getRouteUrl(ordering, page + 1)}" class="btn btn-default">
<i class="fas fa-arrow-right"></i>
</a>
</#if>
<#if page gt 1>
<a href="${routes.getRouteUrl("users.showAuthors", ordering, page - 1)}" class="btn btn-default">
<a href="${Routes.USERS_SHOW_AUTHORS.getRouteUrl(ordering, page - 1)}" class="btn btn-default">
<i class="fas fa-arrow-left"></i>
</a>
</#if>

@ -48,7 +48,7 @@
<td>
<input form="form-continue" type="hidden" value="${user.id}"/>
<@userAvatar.userAvatar userName=user.name avatarUrl=user.avatarUrl clazz="user-avatar-xs" />
<a target="_blank" rel="noopener" href="${routes.getRouteUrl("users.showProjects", user.name)}">
<a target="_blank" rel="noopener" href="${Routes.USERS_SHOW_PROJECTS.getRouteUrl(user.name)}">
${user.name}
</a>
<span><@roleSelect.roleSelect roleCategory=roleCategory /></span>

@ -91,7 +91,7 @@
<#-- @ftlvariable name="user" type="io.papermc.hangar.db.model.UsersTable" -->
<li class="list-group-item">
<@userAvatar.userAvatar userName=user.name avatarUrl=utils.avatarUrl(user.name) clazz="user-avatar-xs"></@userAvatar.userAvatar>
<a class="username" href="${routes.getRouteUrl("users.showProjects", user.name)}">
<a class="username" href="${Routes.USERS_SHOW_PROJECTS.getRouteUrl(user.name)}">
${user.name}
</a>
<p style="display: none;" class="role-id">${subjectRole.role.roleId}</p>

@ -3,8 +3,7 @@
<#import "*/users/view.ftlh" as users />
<#import "*/users/memberList.ftlh" as memberList />
<#--@import controllers.routes.{Users => userRoutes}
@import controllers.sugar.Requests.OreRequest
<#--@import controllers.Routes.IO_PAPERMC_HANGAR_MODEL__PERMISSION.getRouteUrl(.Requests.OreRequest
@import models.viewhelper.{OrganizationData, ScopedOrganizationData, UserData}
@import ore.OreConfig
@import ore.permission.Permission
@ -45,7 +44,7 @@
<#list o.projectRoles as role, project>
<tr>
<td>
<a href="${routes.getRouteUrl("projects.show", project.ownerName, project.slug)}">${project.ownerName}/${project.slug}</a>
<a href="${Routes.PROJECTS_SHOW.getRouteUrl(project.ownerName, project.slug)}">${project.ownerName}/${project.slug}</a>
<span class="minor">${role.role.title}</span>
</td>
<td>
@ -78,7 +77,7 @@
<td>
<#import "*/utils/userAvatar.ftlh" as userAvatar>
<@userAvatar.userAvatar userName=organization.org.name avatarUrl=utils.avatarUrl(organization.org.name) clazz="user-avatar-xxs"></@userAvatar.userAvatar>
<a href="${routes.getRouteUrl("users.showProjects", organization.org.name)}">
<a href="${Routes.USERS_SHOW_PROJECTS.getRouteUrl(organization.org.name)}">
${organization.org.name}
</a>
<div class="pull-right">
@ -134,8 +133,8 @@
<#else>
<#assign orgData=o> <#-- todo fix scopeddata -->
<@memberList.memberList project=orgData editable=true perms=so.permissions
saveCall=routes.getRouteUrl("org.updateMembers", orgData.org.name)
removeCall=routes.getRouteUrl("org.removeMember", orgData.org.name) />
saveCall=Routes.ORG_UPDATE_MEMBERS.getRouteUrl(orgData.org.name)
removeCall=Routes.ORG_REMOVE_MEMBER.getRouteUrl(orgData.org.name) />
</#if>
</div>
</div>

@ -51,7 +51,7 @@
<#import "*/utils/userAvatar.ftlh" as userAvatar>
<td><@userAvatar.userAvatar userName=staffUser.name avatarUrl=utils.avatarUrl(staffUser.name) clazz="user-avatar-xs"></@userAvatar.userAvatar></td>
<td>
<a href="${routes.getRouteUrl("showActivities", staffUser.name)}">${staffUser.name}</a>
<a href="${Routes.SHOW_ACTIVITIES.getRouteUrl(staffUser.name)}">${staffUser.name}</a>
</td>
<td>
<span class="user-role channel" style="background-color: ${staffUser.role.color.hex}">
@ -70,13 +70,13 @@
<td></td>
<td>
<#if staff?size gte pageSize>
<a href="${routes.getRouteUrl("users.showStaff", ordering, page + 1)}" class="btn btn-default">
<a href="${Routes.USERS_SHOW_STAFF.getRouteUrl(ordering, page + 1)}" class="btn btn-default">
<i class="fas fa-arrow-right"></i>
</a>
</#if>
<#if page gt 1>
<a href="${routes.getRouteUrl("users.showStaff", ordering, page - 1)}" class="btn btn-default">
<a href="${Routes.USERS_SHOW_STAFF.getRouteUrl(ordering, page - 1)}" class="btn btn-default">
<i class="fas fa-arrow-left"></i>
</a>
</#if>

@ -53,7 +53,7 @@
<#if canEditOrgSettings(u, o)>
<div class="edit-avatar" style="display: none;">
<a href="${routes.getRouteUrl("org.updateAvatar", u.user.name)}"><i class="fas fa-edit"></i> <@spring.message "user.editAvatar" /></a>
<a href="${Routes.ORG_UPDATE_AVATAR.getRouteUrl(u.user.name)}"><i class="fas fa-edit"></i> <@spring.message "user.editAvatar" /></a>
</div>
<#assign Prompt=@helper["io.papermc.hangar.model.Prompt"] />
@ -78,14 +78,14 @@
data-placement="top" title="<@spring.message "user.lock" />"></i>
</span>
<a class="action-api" href="${routes.getRouteUrl("users.editApiKeys", u.user.name)}">
<a class="action-api" href="${Routes.USERS_EDIT_API_KEYS.getRouteUrl(u.user.name)}">
<i class="fas fa-key" data-toggle="tooltip" data-placement="top" title="API Keys"></i>
</a>
</#if>
<#if u.hasUser()>
<#if u.userPerm.has(Permission.ModNotesAndFlags) || u.userPerm.has(Permission.Reviewer)>
<a class="user-settings" href="${routes.getRouteUrl("showActivities", u.user.name)}">
<a class="user-settings" href="${Routes.SHOW_ACTIVITIES.getRouteUrl(u.user.name)}">
<i class="fas fa-calendar" data-toggle="tooltip"
data-placement="top" title="Activity"></i>
</a>
@ -93,7 +93,7 @@
</#if>
<#if u.headerData.globalPerm(Permission.EditAllUserSettings)>
<a class="user-settings" href="${routes.getRouteUrl("userAdmin", u.user.name)}">
<a class="user-settings" href="${Routes.USER_ADMIN.getRouteUrl(u.user.name)}">
<i class="fas fa-wrench" data-toggle="tooltip"
data-placement="top" title="User Admin"></i>
</a>
@ -161,7 +161,7 @@
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal"><@spring.message "general.close" /></button>
<@form.form method="POST" action=routes.getRouteUrl("users.verify", routes.getRouteUrl("users.setLocked", u.user.name, (!u.user.isLocked())?string, "", "")) class="form-inline">
<@form.form method="POST" action=Routes.USERS_VERIFY.getRouteUrl(Routes.USERS_SET_LOCKED.getRouteUrl(u.user.name, (!u.user.isLocked())?string, "", "")) class="form-inline">
<@csrf.formField />
<button type="submit" class="btn btn-primary"><@spring.message "general.continue" /></button>
</@form.form>
@ -169,7 +169,7 @@
</@modal.modal>
<@modal.modal "user.tagline.edit" "modal-tagline" "label-tagline">
<@form.form action=routes.getRouteUrl("users.saveTagline", u.user.name) method="POST">
<@form.form action=Routes.USERS_SAVE_TAGLINE.getRouteUrl(u.user.name) method="POST">
<@csrf.formField />
<div class="modal-body">
<div class="setting setting-no-border">

@ -12,7 +12,7 @@
<#macro linkout url>
<#--noinspection FtlReferencesInspection-->
${routes.getRouteUrl("linkOut", url)}
${Routes.LINK_OUT.getRouteUrl(url)}
</#macro>
<#macro url path>

@ -21,7 +21,7 @@
<#if href?has_content>
${href}
<#elseif userName?has_content>
${routes.getRouteUrl("users.showProjects", userName)}
${Routes.USERS_SHOW_PROJECTS.getRouteUrl(userName)}
<#else>
#
</#if>

@ -9,25 +9,22 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {RouteHelper.class})
@ContextConfiguration(classes = {Routes.class})
class RouteHelperTest {
@Autowired
private RouteHelper classUnderTest;
@Test
void testSomeShit() throws Exception {
assertEquals("/", classUnderTest.getRouteUrl("showHome"));
assertEquals("/organizations/new", classUnderTest.getRouteUrl("org.showCreator"));
assertEquals("/linkout", classUnderTest.getRouteUrl("linkOut", ""));
assertEquals("/linkout?remoteUrl=TestUrl", classUnderTest.getRouteUrl("linkOut", "TestUrl"));
assertEquals("/staff", classUnderTest.getRouteUrl("users.showStaff", "", ""));
assertEquals("/staff?sort=ASC&page=1", classUnderTest.getRouteUrl("users.showStaff", "ASC", "1"));
assertEquals("/staff?page=1", classUnderTest.getRouteUrl("users.showStaff", "", "1"));
assertEquals("/staff?sort=ASC", classUnderTest.getRouteUrl("users.showStaff", "ASC", ""));
assertEquals("/api/v1/projects/Essentials/tags/1.33.7", classUnderTest.getRouteUrl("apiv1.listTags", "Essentials", "1.33.7"));
assertEquals("/api/v1/projects/Essentials/pages?parentId=2", classUnderTest.getRouteUrl("apiv1.listPages", "Essentials", "2"));
assertEquals("/api/v1/projects/Essentials/pages", classUnderTest.getRouteUrl("apiv1.listPages", "Essentials", ""));
assertEquals("/", Routes.getRouteUrlOf("showHome"));
assertEquals("/organizations/new", Routes.getRouteUrlOf("org.showCreator"));
assertEquals("/linkout", Routes.getRouteUrlOf("linkOut", ""));
assertEquals("/linkout?remoteUrl=TestUrl", Routes.getRouteUrlOf("linkOut", "TestUrl"));
assertEquals("/staff", Routes.getRouteUrlOf("users.showStaff", "", ""));
assertEquals("/staff?sort=ASC&page=1", Routes.getRouteUrlOf("users.showStaff", "ASC", "1"));
assertEquals("/staff?page=1", Routes.getRouteUrlOf("users.showStaff", "", "1"));
assertEquals("/staff?sort=ASC", Routes.getRouteUrlOf("users.showStaff", "ASC", ""));
assertEquals("/api/v1/projects/Essentials/tags/1.33.7", Routes.getRouteUrlOf("apiv1.listTags", "Essentials", "1.33.7"));
assertEquals("/api/v1/projects/Essentials/pages?parentId=2", Routes.getRouteUrlOf("apiv1.listPages", "Essentials", "2"));
assertEquals("/api/v1/projects/Essentials/pages", Routes.getRouteUrlOf("apiv1.listPages", "Essentials", ""));
}
}