mirror of
https://github.com/HangarMC/Hangar.git
synced 2025-01-06 13:56:14 +08:00
works™️
This commit is contained in:
parent
a55ca6ca1c
commit
018e23a2be
@ -2,7 +2,7 @@ import $ from 'jquery';
|
||||
|
||||
//=====> EXTERNAL CONSTANTS
|
||||
|
||||
var namespace = window.namespace;
|
||||
var namespace = window.NAMESPACE;
|
||||
var keyGenText = window.keyGenText;
|
||||
var keyRevokeText = window.keyRevokeText;
|
||||
|
||||
|
@ -2,7 +2,6 @@ import $ from 'jquery';
|
||||
|
||||
//=====> EXTERNAL CONSTANTS
|
||||
|
||||
var PLUGIN_ID = window.PLUGIN_ID;
|
||||
var NAMESPACE = window.NAMESPACE;
|
||||
|
||||
//=====> HELPER FUNCTIONS
|
||||
@ -14,7 +13,7 @@ function bindExpand(e) {
|
||||
var $this = $(this);
|
||||
$.ajax({
|
||||
method: 'get',
|
||||
url: '/api/v1/projects/' + namespace + '/pages?parentId=' + pageId,
|
||||
url: '/api/v1/projects/' + NAMESPACE + '/pages?parentId=' + pageId,
|
||||
dataType: 'json',
|
||||
success: function(childPages) {
|
||||
console.log(childPages);
|
||||
|
@ -225,7 +225,7 @@ public class VersionsController extends HangarController {
|
||||
return _showCreator(author, slug, pendingVersion);
|
||||
}
|
||||
|
||||
private final Pattern URL_PATTERN = Pattern.compile("(https?://(?:www\\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|www\\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|https?://(?:www\\.|(?!www))[a-zA-Z0-9]+\\.[^\\s]{2,}|www\\.[a-zA-Z0-9]+\\.[^\\s]{2,})");
|
||||
private static final Pattern URL_PATTERN = Pattern.compile("(https?://(?:www\\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|www\\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|https?://(?:www\\.|(?!www))[a-zA-Z0-9]+\\.[^\\s]{2,}|www\\.[a-zA-Z0-9]+\\.[^\\s]{2,})");
|
||||
|
||||
@ProjectPermission(NamedPermission.CREATE_VERSION)
|
||||
@UserLock(route = Routes.PROJECTS_SHOW, args = "{#author, #slug}")
|
||||
@ -370,9 +370,8 @@ public class VersionsController extends HangarController {
|
||||
if (channelOptional.isEmpty()) {
|
||||
if (projectChannels.size() >= hangarConfig.projects.getMaxChannels()) {
|
||||
alertMsg = "error.channel.maxChannels";
|
||||
alertArgs = new String[] {String.valueOf(hangarConfig.projects.getMaxChannels())};
|
||||
}
|
||||
else if (projectChannels.stream().anyMatch(ch -> ch.getColor() == channelColor)) {
|
||||
alertArgs = new String[]{String.valueOf(hangarConfig.projects.getMaxChannels())};
|
||||
} else if (projectChannels.stream().anyMatch(ch -> ch.getColor() == channelColor)) {
|
||||
alertMsg = "error.channel.duplicateColor";
|
||||
}
|
||||
if (alertMsg != null) {
|
||||
@ -518,9 +517,9 @@ public class VersionsController extends HangarController {
|
||||
String curlInstruction;
|
||||
CsrfToken csrfToken = (CsrfToken) request.getAttribute("_csrf");
|
||||
if (csrfToken == null) {
|
||||
curlInstruction = messageSource.getMessage("version.download.confirm.curl.nocsrf", new String[] {Routes.VERSIONS_CONFIRM_DOWNLOAD.getRouteUrl(author, slug, version, downloadType.ordinal() + "", token, null)}, LocaleContextHolder.getLocale());
|
||||
curlInstruction = messageSource.getMessage("version.download.confirm.curl.nocsrf", new String[]{Routes.VERSIONS_CONFIRM_DOWNLOAD.getRouteUrl(author, slug, version, downloadType.ordinal() + "", token, null)}, LocaleContextHolder.getLocale());
|
||||
} else {
|
||||
curlInstruction = messageSource.getMessage("version.download.confirm.curl", new String[] {Routes.VERSIONS_CONFIRM_DOWNLOAD.getRouteUrl(author, slug, version, downloadType.ordinal() + "", token, null), csrfToken.getToken()}, LocaleContextHolder.getLocale());
|
||||
curlInstruction = messageSource.getMessage("version.download.confirm.curl", new String[]{Routes.VERSIONS_CONFIRM_DOWNLOAD.getRouteUrl(author, slug, version, downloadType.ordinal() + "", token, null), csrfToken.getToken()}, LocaleContextHolder.getLocale());
|
||||
}
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.set(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"README.txt\"");
|
||||
|
@ -1,6 +1,5 @@
|
||||
package io.papermc.hangar.controller.api;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.papermc.hangar.model.ApiAuthInfo;
|
||||
import io.papermc.hangar.model.NamedPermission;
|
||||
import io.papermc.hangar.model.Permission;
|
||||
@ -15,7 +14,6 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Controller;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
@ -24,17 +22,12 @@ import java.util.function.BiPredicate;
|
||||
public class PermissionsApiController implements PermissionsApi {
|
||||
|
||||
private final PermissionService permissionService;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private final ApiAuthInfo apiAuthInfo;
|
||||
private final HttpServletRequest request;
|
||||
|
||||
@Autowired
|
||||
public PermissionsApiController(PermissionService permissionService, ObjectMapper objectMapper, ApiAuthInfo apiAuthInfo, HttpServletRequest request) {
|
||||
public PermissionsApiController(PermissionService permissionService, ApiAuthInfo apiAuthInfo) {
|
||||
this.permissionService = permissionService;
|
||||
this.objectMapper = objectMapper;
|
||||
this.apiAuthInfo = apiAuthInfo;
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -60,7 +53,7 @@ public class PermissionsApiController implements PermissionsApi {
|
||||
Permission perms = permissionService.getProjectPermissions(apiAuthInfo.getUser(), author, slug);
|
||||
return new ImmutablePair<>(PermissionType.PROJECT, perms);
|
||||
} else {
|
||||
Permission perms = permissionService.getOrganizationPermissions(apiAuthInfo.getUser(), slug);
|
||||
Permission perms = permissionService.getOrganizationPermissions(apiAuthInfo.getUser(), author);
|
||||
return new ImmutablePair<>(PermissionType.ORGANIZATION, perms);
|
||||
}
|
||||
}
|
||||
|
@ -8,13 +8,13 @@ public class ApiScope {
|
||||
private final String owner;
|
||||
private final String slug;
|
||||
|
||||
private ApiScope(ApiScopeType apiScopeType, String owner, @Nullable String slug) {
|
||||
private ApiScope(ApiScopeType apiScopeType, @Nullable String owner, @Nullable String slug) {
|
||||
this.type = apiScopeType;
|
||||
this.owner = owner;
|
||||
this.slug = slug;
|
||||
}
|
||||
|
||||
private ApiScope(ApiScopeType apiScopeType, String owner) {
|
||||
private ApiScope(ApiScopeType apiScopeType, @Nullable String owner) {
|
||||
this(apiScopeType, owner, null);
|
||||
}
|
||||
|
||||
|
@ -23,12 +23,11 @@ import java.util.Map;
|
||||
@Repository
|
||||
public interface V1ApiDao {
|
||||
|
||||
//TODO plugin_id
|
||||
@UseStringTemplateEngine
|
||||
@SqlQuery("SELECT p.id " +
|
||||
" FROM home_projects p" +
|
||||
" WHERE true" +
|
||||
" <if(q)>AND p.name ILIKE '<q>' OR p.description ILIKE '<q>' OR p.owner_name ILIKE '<q>' OR p.plugin_id ILIKE '<q>' <endif>" +
|
||||
" <if(q)>AND p.name ILIKE '<q>' OR p.description ILIKE '<q>' OR p.owner_name ILIKE '<q>' <endif>" +
|
||||
" <if(categories)>AND p.category IN (<categories>) <endif>" +
|
||||
" ORDER BY :strategyFragment" +
|
||||
" LIMIT :limit OFFSET :offset")
|
||||
@ -38,9 +37,9 @@ public interface V1ApiDao {
|
||||
@RegisterBeanMapper(ProjectsTable.class)
|
||||
@SqlQuery("SELECT pr.* " +
|
||||
" FROM home_projects p" +
|
||||
" JOIN projects pr ON p.plugin_id = pr.plugin_id" +
|
||||
" JOIN projects pr ON p.project_id = pr.project_id" +
|
||||
" WHERE true" +
|
||||
" <if(q)>AND p.name ILIKE '<q>' OR p.description ILIKE '<q>' OR p.owner_name ILIKE '<q>' OR p.plugin_id ILIKE '<q>' <endif>" +
|
||||
" <if(q)>AND p.name ILIKE '<q>' OR p.description ILIKE '<q>' OR p.owner_name ILIKE '<q>' <endif>" +
|
||||
" <if(categories)>AND p.category IN (<categories>) <endif>" +
|
||||
" ORDER BY :strategyFragment" +
|
||||
" LIMIT :limit OFFSET :offset")
|
||||
|
@ -62,7 +62,7 @@ public class ProjectData extends JoinableData<UserProjectRolesTable, ProjectsTab
|
||||
}
|
||||
|
||||
public String getFullSlug() {
|
||||
return "/" + getProject().getOwnerName() + "/" + getProject().getSlug();
|
||||
return getProject().getOwnerName() + "/" + getProject().getSlug();
|
||||
}
|
||||
|
||||
public UsersTable getProjectOwner() {
|
||||
|
@ -63,7 +63,6 @@ public class AuthenticationService extends HangarService {
|
||||
private final HangarDao<ApiKeyDao> apiKeyDao;
|
||||
private final AuthenticationManager authenticationManager;
|
||||
private final RoleService roleService;
|
||||
private final SessionService sessionService;
|
||||
private final PermissionService permissionService;
|
||||
private final RestTemplate restTemplate;
|
||||
private final ObjectMapper objectMapper;
|
||||
@ -74,7 +73,7 @@ public class AuthenticationService extends HangarService {
|
||||
private static final Pattern API_KEY_PATTERN = Pattern.compile("(" + UUID_REGEX + ").(" + UUID_REGEX + ")");
|
||||
|
||||
@Autowired
|
||||
public AuthenticationService(HttpServletRequest request, ApiAuthInfo apiAuthInfo, HangarConfig hangarConfig, HangarDao<UserDao> userDao, HangarDao<SessionsDao> sessionsDao, HangarDao<ApiKeyDao> apiKeyDao, AuthenticationManager authenticationManager, RoleService roleService, SessionService sessionService, PermissionService permissionService, RestTemplate restTemplate, ObjectMapper objectMapper, Supplier<Optional<UsersTable>> currentUser) {
|
||||
public AuthenticationService(HttpServletRequest request, ApiAuthInfo apiAuthInfo, HangarConfig hangarConfig, HangarDao<UserDao> userDao, HangarDao<SessionsDao> sessionsDao, HangarDao<ApiKeyDao> apiKeyDao, AuthenticationManager authenticationManager, RoleService roleService, PermissionService permissionService, RestTemplate restTemplate, ObjectMapper objectMapper, Supplier<Optional<UsersTable>> currentUser) {
|
||||
this.request = request;
|
||||
this.apiAuthInfo = apiAuthInfo;
|
||||
this.hangarConfig = hangarConfig;
|
||||
@ -83,7 +82,6 @@ public class AuthenticationService extends HangarService {
|
||||
this.apiKeyDao = apiKeyDao;
|
||||
this.authenticationManager = authenticationManager;
|
||||
this.roleService = roleService;
|
||||
this.sessionService = sessionService;
|
||||
this.permissionService = permissionService;
|
||||
this.restTemplate = restTemplate;
|
||||
this.objectMapper = objectMapper;
|
||||
|
@ -87,15 +87,14 @@ public class PluginUploadService {
|
||||
throw new HangarException("error.version.illegalVersion");
|
||||
}
|
||||
|
||||
|
||||
ProjectChannelsTable channel = channelService.getFirstChannel(project);
|
||||
|
||||
PendingVersion pendingVersion = startVersion(plugin, project.getId(), project.getForumSync(), channel.getName());
|
||||
|
||||
boolean exists = versionService.exists(pendingVersion);
|
||||
if (exists && hangarConfig.projects.isFileValidate()) {
|
||||
throw new HangarException("error.version.duplicate");
|
||||
}
|
||||
|
||||
cacheManager.getCache(CacheConfig.PENDING_VERSION_CACHE).put(project.getId() + "/" + pendingVersion.getVersionString(), pendingVersion);
|
||||
return pendingVersion;
|
||||
}
|
||||
|
@ -138,7 +138,6 @@ public class ProjectFactory {
|
||||
|
||||
public ProjectVersionsTable createVersion(HttpServletRequest request, ProjectData project, PendingVersion pendingVersion) {
|
||||
ProjectChannelsTable channel = projectChannelDao.get().getProjectChannel(project.getProject().getId(), pendingVersion.getChannelName(), null);
|
||||
|
||||
if (versionService.exists(pendingVersion) && hangarConfig.projects.isFileValidate()) {
|
||||
throw new HangarException("error.version.duplicate");
|
||||
}
|
||||
@ -163,6 +162,7 @@ public class ProjectFactory {
|
||||
pendingVersion.isCreateForumPost(),
|
||||
pendingVersion.getExternalUrl()
|
||||
));
|
||||
|
||||
if (pendingVersion.getPlugin() != null) {
|
||||
pendingVersion.getPlugin().getData().createTags(version.getId(), versionService); // TODO not sure what this is for
|
||||
}
|
||||
@ -178,6 +178,7 @@ public class ProjectFactory {
|
||||
new String[]{"notification.project.newVersion", project.getProject().getName(), version.getVersionString()},
|
||||
project.getNamespace() + "/versions/" + version.getVersionString()
|
||||
));
|
||||
|
||||
if (pendingVersion.getPlugin() != null) {
|
||||
try {
|
||||
uploadPlugin(project, pendingVersion.getPlugin(), version);
|
||||
@ -187,13 +188,11 @@ public class ProjectFactory {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// first project upload
|
||||
if (project.getVisibility() == Visibility.NEW) {
|
||||
projectService.changeVisibility(project.getProject(), Visibility.PUBLIC, "First upload");
|
||||
userActionLogService.project(request, LoggedActionType.PROJECT_VISIBILITY_CHANGE.with(ProjectContext.of(project.getProject().getId())), Visibility.PUBLIC.getName(), Visibility.NEW.getName());
|
||||
// TODO Add forum job
|
||||
|
||||
}
|
||||
|
||||
projectService.refreshHomePage();
|
||||
@ -206,13 +205,12 @@ public class ProjectFactory {
|
||||
Path oldPath = plugin.getPath();
|
||||
Path versionDir = projectFiles.getVersionDir(project.getProjectOwner().getName(), project.getProject().getName(), version.getVersionString());
|
||||
Path newPath = versionDir.resolve(oldPath.getFileName());
|
||||
|
||||
if (Files.notExists(newPath)) {
|
||||
Files.createDirectories(newPath.getParent());
|
||||
}
|
||||
|
||||
Files.move(oldPath, newPath, StandardCopyOption.REPLACE_EXISTING); // TODO maybe remove the replace_existing in prod?
|
||||
Files.deleteIfExists(oldPath);
|
||||
|
||||
if (Files.notExists(newPath)) {
|
||||
throw new HangarException("error.plugin.fileName");
|
||||
}
|
||||
|
@ -38,6 +38,11 @@ public class AlertUtil {
|
||||
return mav;
|
||||
}
|
||||
|
||||
public static ModelAndView showAlert(ModelAndView mav, AlertType alertType, String alertMessage, String... args) {
|
||||
applyAlert(mav.getModelMap(), alertType, alertMessage, (Object[]) args);
|
||||
return mav;
|
||||
}
|
||||
|
||||
public static RedirectAttributes showAlert(RedirectAttributes attributes, AlertType alertType, String alertMsg, String...args) {
|
||||
attributes.addFlashAttribute(TYPE, alertType);
|
||||
attributes.addFlashAttribute(MSG, alertMsg);
|
||||
|
@ -135,8 +135,8 @@ public enum Routes {
|
||||
APIV1_SHOW_STATUS_Z("apiv1.showStatusZ", Paths.APIV1_SHOW_STATUS_Z, of(), of()),
|
||||
APIV1_SHOW_USER("apiv1.showUser", Paths.APIV1_SHOW_USER, of("user"), of()),
|
||||
APIV1_LIST_PAGES("apiv1.listPages", Paths.APIV1_LIST_PAGES, of("author", "slug"), of("parentId")),
|
||||
APIV1_DEPLOY_VERSION("apiv1.deployVersion", Paths.APIV1_DEPLOY_VERSION, of("author", "slugt", "name"), of()),
|
||||
APIV1_LIST_TAGS("apiv1.listTags", Paths.APIV1_LIST_TAGS, of("plugin", "versionName"), of()),
|
||||
APIV1_DEPLOY_VERSION("apiv1.deployVersion", Paths.APIV1_DEPLOY_VERSION, of("author", "slug", "name"), of()),
|
||||
APIV1_LIST_TAGS("apiv1.listTags", Paths.APIV1_LIST_TAGS, of("author", "slug", "versionName"), of()),
|
||||
APIV1_LIST_PLATFORMS("apiv1.listPlatforms", Paths.APIV1_LIST_PLATFORMS, of(), of());
|
||||
|
||||
private static final Map<String, Routes> ROUTES = new HashMap<>();
|
||||
|
@ -250,7 +250,7 @@ version.create.selectFile = Select file
|
||||
version.create.externalUrl = External download URL
|
||||
version.create.publish = Publish
|
||||
version.create.tos = By clicking "Publish" you are agreeing to Hangar's <a href="https://docs.spongepowered.org/stable/en/about/tos.html">Terms of Service</a>.
|
||||
version.create.info = Release a new version for <strong>{0}</strong> (slug: {1}).
|
||||
version.create.info = Release a new version for <strong>{0}</strong>.
|
||||
version.create.unstable = Mark this version as unstable
|
||||
version.recommended = Recommended version
|
||||
version.approved = Approved
|
||||
|
@ -18,7 +18,6 @@
|
||||
window.PROJECT_NAME = "${p.project.name}";
|
||||
window.PROJECT_OWNER = "${p.project.ownerName}";
|
||||
window.PROJECT_SLUG = "${p.project.slug}";
|
||||
window.pluginId = "${p.project.pluginId}";
|
||||
window.keyGenText = "<@spring.message "project.settings.genKey" />";
|
||||
window.keyRevokeText = "<@spring.message "project.settings.revokeKey" />";
|
||||
</script>
|
||||
|
@ -37,7 +37,7 @@
|
||||
|
||||
<div class="create-body card-body">
|
||||
<div class="minor create-blurb">
|
||||
<span><@spring.messageArgs code="version.create.info" args=[projectName, projectSlug] /></span>
|
||||
<span><@spring.messageArgs code="version.create.info" args=[projectName] /></span>
|
||||
</div>
|
||||
|
||||
<#if pending??>
|
||||
@ -203,18 +203,7 @@
|
||||
<@alertFile.alertFile />
|
||||
</@form.form>
|
||||
|
||||
<#if !pending??>
|
||||
<@form.form action=Routes.VERSIONS_CREATE_EXTERNAL_URL.getRouteUrl(ownerName, projectSlug) method="POST" id="form-url-upload" class="form-inline">
|
||||
<@csrf.formField />
|
||||
<div class="input-group float-right" style="width: 50%">
|
||||
<input type="text" class="form-control" id="externalUrl" name="externalUrl" placeholder="<@spring.message "version.create.externalUrl" />" style="width: 70%">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-info" type="submit">Create Version</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</@form.form>
|
||||
<#else>
|
||||
<#if pending??>
|
||||
<#assign version = pending>
|
||||
<#assign formAction>
|
||||
<#if version.versionString??>${Routes.VERSIONS_PUBLISH.getRouteUrl(ownerName, projectSlug, version.versionString)}<#else>${Routes.VERSIONS_PUBLISH_URL.getRouteUrl(ownerName, projectSlug)}</#if>
|
||||
@ -224,8 +213,17 @@
|
||||
<input type="hidden" class="channel-color-input" name="channel-color-input" value="${config.channels.colorDefault.hex}">
|
||||
<div><input type="submit" name="create" value="<@spring.message "version.create.publish" />" class="btn btn-primary"></div>
|
||||
</@form.form>
|
||||
<#else>
|
||||
<@form.form action=Routes.VERSIONS_CREATE_EXTERNAL_URL.getRouteUrl(ownerName, projectSlug) method="POST" id="form-url-upload" class="form-inline">
|
||||
<@csrf.formField />
|
||||
<div class="input-group float-right" style="width: 50%">
|
||||
<input type="text" class="form-control" id="externalUrl" name="externalUrl" placeholder="<@spring.message "version.create.externalUrl" />" style="width: 70%">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-info" type="submit">Create Version</button>
|
||||
</div>
|
||||
</div>
|
||||
</@form.form>
|
||||
</#if>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<span class="float-left tos"><i><@spring.messageArgs code="version.create.tos" args=["#"] /></i></span>
|
||||
|
@ -43,7 +43,7 @@ Base template for Project overview.
|
||||
<div class="alert alert-danger" role="alert" style="margin: 0.2em 0 0 0">
|
||||
<#if p.visibility == Visibility.NEEDSCHANGES>
|
||||
<#if sp.perms(Permission.EditPage)>
|
||||
<a class="btn btn-success float-right" href="${p.fullSlug}/manage/sendforapproval">Send for approval</a>
|
||||
<a class="btn btn-success float-right" href="/${p.fullSlug}/manage/sendforapproval">Send for approval</a>
|
||||
</#if>
|
||||
<strong><@spring.message "visibility.notice." + p.visibility.getName() /></strong>
|
||||
<br>
|
||||
|
@ -19,9 +19,8 @@ class RouteHelperTest {
|
||||
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", ""));
|
||||
|
||||
assertEquals("/api/v1/projects/Essentials/EssentialsX/tags/1.33.7", Routes.getRouteUrlOf("apiv1.listTags", "Essentials", "EssentialsX", "1.33.7"));
|
||||
assertEquals("/api/v1/projects/Essentials/EssentialsX/pages?parentId=2", Routes.getRouteUrlOf("apiv1.listPages", "Essentials", "EssentialsX", "2"));
|
||||
assertEquals("/api/v1/projects/Essentials/EssentialsX/pages", Routes.getRouteUrlOf("apiv1.listPages", "Essentials", "EssentialsX", ""));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user