mirror of
https://github.com/HangarMC/Hangar.git
synced 2025-01-24 14:24:47 +08:00
feat: improve project icon changing experience
This commit is contained in:
parent
309b9f278f
commit
d6d9319fc4
@ -9,6 +9,7 @@ trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
ij_any_block_comment_at_first_column = false
|
||||
ij_any_line_comment_at_first_column = false
|
||||
ij_any_line_comment_add_space_on_reformat = true
|
||||
ij_any_block_comment_add_space = true
|
||||
max_line_length = 160
|
||||
ij_visual_guides = 160
|
||||
@ -19,8 +20,11 @@ ij_html_quote_style = double
|
||||
[*.java]
|
||||
ij_java_insert_inner_class_imports = false
|
||||
ij_java_use_fq_class_names = false
|
||||
ij_java_use_single_class_imports = true
|
||||
ij_java_class_count_to_use_import_on_demand = 99999
|
||||
ij_java_names_count_to_use_import_on_demand = 99999
|
||||
ij_java_keep_simple_lambdas_in_one_line = true
|
||||
ij_java_keep_simple_classes_in_one_line = true
|
||||
ij_java_imports_layout = *,|,$*
|
||||
ij_java_generate_final_locals = true
|
||||
ij_java_generate_final_parameters = true
|
||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -18,7 +18,7 @@ work/
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
.idea/*
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
@ -33,3 +33,7 @@ build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
|
||||
### Unignore Inspection Profiles ###
|
||||
!/.idea/inspectionProfiles
|
||||
|
58
.idea/inspectionProfiles/Project_Default.xml
Normal file
58
.idea/inspectionProfiles/Project_Default.xml
Normal file
@ -0,0 +1,58 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="BoundedWildcard" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="REPORT_INVARIANT_CLASSES" value="false" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="ClassInitializer" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ClassNameDiffersFromFileName" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ClassWithOnlyPrivateConstructors" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="CommentedOutCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="minLines" value="8" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="DeclareCollectionAsInterface" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoreLocalVariables" value="false" />
|
||||
<option name="ignorePrivateMethodsAndFields" value="false" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ExtendsUtilityClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="LocalCanBeFinal" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="REPORT_VARIABLES" value="true" />
|
||||
<option name="REPORT_PARAMETERS" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="MissortedModifiers" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="m_requireAnnotationsFirst" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="NonFinalUtilityClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ObsoleteCollection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoreRequiredObsoleteCollectionTypes" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="SimplifiableAnnotation" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SizeReplaceableByIsEmpty" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SystemOutErr" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnnecessarilyQualifiedStaticUsage" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="m_ignoreStaticFieldAccesses" value="false" />
|
||||
<option name="m_ignoreStaticMethodCalls" value="false" />
|
||||
<option name="m_ignoreStaticAccessFromStaticContext" value="false" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="UnnecessarilyQualifiedStaticallyImportedElement" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnnecessaryConstructor" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoreAnnotations" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="UnnecessarySuperConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnnecessarySuperQualifier" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnqualifiedFieldAccess" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UnqualifiedInnerClassAccess" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoreReferencesToLocalInnerClasses" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="UnqualifiedMethodAccess" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UseOfObsoleteDateTimeApi" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UtilityClassWithPublicConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="UtilityClassWithoutPrivateConstructor" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignorableAnnotations">
|
||||
<value />
|
||||
</option>
|
||||
<option name="ignoreClassesWithOnlyMain" value="false" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
@ -32,8 +32,9 @@ public class HangarProject extends Project implements Joinable<ProjectRoleTable>
|
||||
private final Collection<HangarProjectPage> pages;
|
||||
private final List<PinnedVersion> pinnedVersions;
|
||||
private final Map<Platform, HangarVersion> mainChannelVersions;
|
||||
private final boolean customIcon;
|
||||
|
||||
public HangarProject(final Project project, final long id, final ProjectOwner owner, final List<JoinableMember<ProjectRoleTable>> members, final String lastVisibilityChangeComment, final String lastVisibilityChangeUserName, final HangarProjectInfo info, final Collection<HangarProjectPage> pages, final List<PinnedVersion> pinnedVersions, final Map<Platform, HangarVersion> mainChannelVersions) {
|
||||
public HangarProject(final Project project, final long id, final ProjectOwner owner, final List<JoinableMember<ProjectRoleTable>> members, final String lastVisibilityChangeComment, final String lastVisibilityChangeUserName, final HangarProjectInfo info, final Collection<HangarProjectPage> pages, final List<PinnedVersion> pinnedVersions, final Map<Platform, HangarVersion> mainChannelVersions, final boolean customIcon) {
|
||||
super(project);
|
||||
this.id = id;
|
||||
this.owner = owner;
|
||||
@ -44,20 +45,21 @@ public class HangarProject extends Project implements Joinable<ProjectRoleTable>
|
||||
this.pages = pages;
|
||||
this.pinnedVersions = pinnedVersions;
|
||||
this.mainChannelVersions = mainChannelVersions;
|
||||
this.customIcon = customIcon;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getProjectId() {
|
||||
return id;
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectOwner getOwner() {
|
||||
return owner;
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -67,23 +69,23 @@ public class HangarProject extends Project implements Joinable<ProjectRoleTable>
|
||||
|
||||
@Override
|
||||
public List<JoinableMember<ProjectRoleTable>> getMembers() {
|
||||
return members;
|
||||
return this.members;
|
||||
}
|
||||
|
||||
public String getLastVisibilityChangeComment() {
|
||||
return lastVisibilityChangeComment;
|
||||
return this.lastVisibilityChangeComment;
|
||||
}
|
||||
|
||||
public String getLastVisibilityChangeUserName() {
|
||||
return lastVisibilityChangeUserName;
|
||||
return this.lastVisibilityChangeUserName;
|
||||
}
|
||||
|
||||
public HangarProjectInfo getInfo() {
|
||||
return info;
|
||||
return this.info;
|
||||
}
|
||||
|
||||
public Collection<HangarProjectPage> getPages() {
|
||||
return pages;
|
||||
return this.pages;
|
||||
}
|
||||
|
||||
public List<PinnedVersion> getPinnedVersions() {
|
||||
@ -91,7 +93,7 @@ public class HangarProject extends Project implements Joinable<ProjectRoleTable>
|
||||
}
|
||||
|
||||
public Map<Platform, HangarVersion> getMainChannelVersions() {
|
||||
return mainChannelVersions;
|
||||
return this.mainChannelVersions;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -105,9 +107,14 @@ public class HangarProject extends Project implements Joinable<ProjectRoleTable>
|
||||
", info=" + this.info +
|
||||
", pages=" + this.pages +
|
||||
", pinnedVersions=" + this.pinnedVersions +
|
||||
", customIcon=" + this.customIcon +
|
||||
"} " + super.toString();
|
||||
}
|
||||
|
||||
public boolean isCustomIcon() {
|
||||
return customIcon;
|
||||
}
|
||||
|
||||
public static class HangarProjectInfo {
|
||||
|
||||
private final int publicVersions;
|
||||
@ -125,35 +132,35 @@ public class HangarProject extends Project implements Joinable<ProjectRoleTable>
|
||||
}
|
||||
|
||||
public int getPublicVersions() {
|
||||
return publicVersions;
|
||||
return this.publicVersions;
|
||||
}
|
||||
|
||||
@RequiresPermission(NamedPermission.MOD_NOTES_AND_FLAGS)
|
||||
public int getFlagCount() {
|
||||
return flagCount;
|
||||
return this.flagCount;
|
||||
}
|
||||
|
||||
@RequiresPermission(NamedPermission.MOD_NOTES_AND_FLAGS)
|
||||
public int getNoteCount() {
|
||||
return noteCount;
|
||||
return this.noteCount;
|
||||
}
|
||||
|
||||
public long getStarCount() {
|
||||
return starCount;
|
||||
return this.starCount;
|
||||
}
|
||||
|
||||
public long getWatcherCount() {
|
||||
return watcherCount;
|
||||
return this.watcherCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HangarProjectInfo{" +
|
||||
"publicVersions=" + publicVersions +
|
||||
", flagCount=" + flagCount +
|
||||
", noteCount=" + noteCount +
|
||||
", starCount=" + starCount +
|
||||
", watcherCount=" + watcherCount +
|
||||
"publicVersions=" + this.publicVersions +
|
||||
", flagCount=" + this.flagCount +
|
||||
", noteCount=" + this.noteCount +
|
||||
", starCount=" + this.starCount +
|
||||
", watcherCount=" + this.watcherCount +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@ -167,7 +174,7 @@ public class HangarProject extends Project implements Joinable<ProjectRoleTable>
|
||||
private final Map<Platform, String> platformDependenciesFormatted;
|
||||
private final Map<Platform, PlatformVersionDownload> downloads;
|
||||
|
||||
public PinnedVersion(long versionId, Type type, String name, @Nested("pc") ProjectChannel channel) {
|
||||
public PinnedVersion(final long versionId, final Type type, final String name, @Nested("pc") final ProjectChannel channel) {
|
||||
this.versionId = versionId;
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
@ -177,38 +184,38 @@ public class HangarProject extends Project implements Joinable<ProjectRoleTable>
|
||||
}
|
||||
|
||||
public long getVersionId() {
|
||||
return versionId;
|
||||
return this.versionId;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public Map<Platform, String> getPlatformDependenciesFormatted() {
|
||||
return platformDependenciesFormatted;
|
||||
return this.platformDependenciesFormatted;
|
||||
}
|
||||
|
||||
public ProjectChannel getChannel() {
|
||||
return channel;
|
||||
return this.channel;
|
||||
}
|
||||
|
||||
public Map<Platform, PlatformVersionDownload> getDownloads() {
|
||||
return downloads;
|
||||
return this.downloads;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PinnedVersion{" +
|
||||
"versionId=" + versionId +
|
||||
", type=" + type +
|
||||
", name='" + name + '\'' +
|
||||
", channel=" + channel +
|
||||
", platformDependenciesFormatted=" + platformDependenciesFormatted +
|
||||
", downloads=" + downloads +
|
||||
"versionId=" + this.versionId +
|
||||
", type=" + this.type +
|
||||
", name='" + this.name + '\'' +
|
||||
", channel=" + this.channel +
|
||||
", platformDependenciesFormatted=" + this.platformDependenciesFormatted +
|
||||
", downloads=" + this.downloads +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
@ -21,49 +21,49 @@ public class LocalStorageFileService implements FileService {
|
||||
private final StorageConfig config;
|
||||
private final HangarConfig hangarConfig;
|
||||
|
||||
public LocalStorageFileService(StorageConfig config, HangarConfig hangarConfig) {
|
||||
public LocalStorageFileService(final StorageConfig config, final HangarConfig hangarConfig) {
|
||||
this.config = config;
|
||||
this.hangarConfig = hangarConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource getResource(String path) {
|
||||
public Resource getResource(final String path) {
|
||||
return new FileSystemResource(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(String path) {
|
||||
public boolean exists(final String path) {
|
||||
return Files.exists(Path.of(path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteDirectory(String dir) {
|
||||
public void deleteDirectory(final String dir) {
|
||||
FileUtils.deleteDirectory(Path.of(dir));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete(String path) {
|
||||
public boolean delete(final String path) {
|
||||
return FileUtils.delete(Path.of(path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] bytes(String path) throws IOException {
|
||||
public byte[] bytes(final String path) throws IOException {
|
||||
return Files.readAllBytes(Path.of(path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(InputStream inputStream, String path) throws IOException {
|
||||
Path p = Path.of(path);
|
||||
public void write(final InputStream inputStream, final String path) throws IOException {
|
||||
final Path p = Path.of(path);
|
||||
if (Files.notExists(p)) {
|
||||
Files.createDirectories(p.getParent());
|
||||
}
|
||||
Files.copy(inputStream, p);
|
||||
Files.copy(inputStream, p, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(String oldPathString, String newPathString) throws IOException {
|
||||
Path oldPath = Path.of(oldPathString);
|
||||
Path newPath = Path.of(newPathString);
|
||||
public void move(final String oldPathString, final String newPathString) throws IOException {
|
||||
final Path oldPath = Path.of(oldPathString);
|
||||
final Path newPath = Path.of(newPathString);
|
||||
if (Files.notExists(newPath)) {
|
||||
Files.createDirectories(newPath.getParent());
|
||||
}
|
||||
@ -75,9 +75,9 @@ public class LocalStorageFileService implements FileService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void link(String existingPathString, String newPathString) throws IOException {
|
||||
Path existingPath = Path.of(existingPathString);
|
||||
Path newPath = Path.of(newPathString);
|
||||
public void link(final String existingPathString, final String newPathString) throws IOException {
|
||||
final Path existingPath = Path.of(existingPathString);
|
||||
final Path newPath = Path.of(newPathString);
|
||||
if (Files.notExists(newPath)) {
|
||||
Files.createDirectories(newPath.getParent());
|
||||
}
|
||||
@ -85,17 +85,17 @@ public class LocalStorageFileService implements FileService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolve(String path, String fileName) {
|
||||
public String resolve(final String path, final String fileName) {
|
||||
return Path.of(path).resolve(fileName).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRoot() {
|
||||
return config.workDir();
|
||||
return this.config.workDir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDownloadUrl(String user, String project, String version, Platform platform, String fileName) {
|
||||
return hangarConfig.getBaseUrl() + "/api/v1/projects/" + user + "/" + project + "/versions/" + version + "/" + platform.name() + "/download";
|
||||
public String getDownloadUrl(final String user, final String project, final String version, final Platform platform, final String fileName) {
|
||||
return this.hangarConfig.getBaseUrl() + "/api/v1/projects/" + user + "/" + project + "/versions/" + version + "/" + platform.name() + "/download";
|
||||
}
|
||||
}
|
||||
|
@ -154,7 +154,7 @@ public class ProjectService extends HangarComponent {
|
||||
}
|
||||
}
|
||||
|
||||
return new HangarProject(project.getRight(), project.getLeft(), projectOwner, members, lastVisibilityChangeComment, lastVisibilityChangeUserName, info, pages.values(), pinnedVersions, mainChannelVersions);
|
||||
return new HangarProject(project.getRight(), project.getLeft(), projectOwner, members, lastVisibilityChangeComment, lastVisibilityChangeUserName, info, pages.values(), pinnedVersions, mainChannelVersions, this.fileService.exists(this.projectFiles.getIconPath(author, slug)));
|
||||
}
|
||||
|
||||
public @Nullable HangarVersion getLastVersion(String author, String slug, Platform platform, @Nullable String channel) {
|
||||
|
@ -4,16 +4,13 @@ import io.papermc.hangar.HangarComponent;
|
||||
import io.papermc.hangar.exceptions.HangarApiException;
|
||||
import io.papermc.hangar.exceptions.InternalHangarException;
|
||||
import io.papermc.hangar.service.internal.file.FileService;
|
||||
import java.io.IOException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Service
|
||||
public class ImageService extends HangarComponent {
|
||||
|
||||
@ -21,27 +18,25 @@ public class ImageService extends HangarComponent {
|
||||
private final FileService fileService;
|
||||
|
||||
@Autowired
|
||||
public ImageService(ProjectFiles projectFiles, FileService fileService) {
|
||||
public ImageService(final ProjectFiles projectFiles, final FileService fileService) {
|
||||
this.projectFiles = projectFiles;
|
||||
this.fileService = fileService;
|
||||
}
|
||||
|
||||
public ResponseEntity<byte[]> getProjectIcon(String author, String slug) {
|
||||
String iconPath = projectFiles.getIconPath(author, slug);
|
||||
if (iconPath == null || !fileService.exists(iconPath)) {
|
||||
public ResponseEntity<byte[]> getProjectIcon(final String author, final String slug) {
|
||||
final String iconPath = this.projectFiles.getIconPath(author, slug);
|
||||
if (iconPath == null || !this.fileService.exists(iconPath)) {
|
||||
throw new InternalHangarException("Default to avatar url");
|
||||
}
|
||||
try {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setCacheControl(CacheControl.maxAge(3600, TimeUnit.SECONDS).getHeaderValue());
|
||||
return ResponseEntity.ok().headers(headers).body(fileService.bytes(iconPath));
|
||||
} catch (IOException e) {
|
||||
return ResponseEntity.ok().cacheControl(CacheControl.noCache()).body(this.fileService.bytes(iconPath));
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new HangarApiException(HttpStatus.INTERNAL_SERVER_ERROR, "Unable to fetch project icon");
|
||||
}
|
||||
}
|
||||
|
||||
public String getUserIcon(String author) {
|
||||
return String.format(config.security.api().avatarUrl(), author);
|
||||
public String getUserIcon(final String author) {
|
||||
return String.format(this.config.security.api().avatarUrl(), author);
|
||||
}
|
||||
}
|
||||
|
@ -4,15 +4,14 @@ import io.papermc.hangar.config.hangar.StorageConfig;
|
||||
import io.papermc.hangar.model.common.Platform;
|
||||
import io.papermc.hangar.service.internal.file.FileService;
|
||||
import io.papermc.hangar.util.FileUtils;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
@Component
|
||||
public class ProjectFiles {
|
||||
|
||||
@ -23,77 +22,77 @@ public class ProjectFiles {
|
||||
private final FileService fileService;
|
||||
|
||||
@Autowired
|
||||
public ProjectFiles(StorageConfig storageConfig, FileService fileService) {
|
||||
public ProjectFiles(final StorageConfig storageConfig, final FileService fileService) {
|
||||
this.fileService = fileService;
|
||||
Path uploadsDir = Path.of(storageConfig.workDir());
|
||||
pluginsDir = fileService.resolve(fileService.getRoot(), "plugins");
|
||||
tmpDir = uploadsDir.resolve("tmp");
|
||||
if (Files.exists(tmpDir)) {
|
||||
FileUtils.deleteDirectory(tmpDir);
|
||||
final Path uploadsDir = Path.of(storageConfig.workDir());
|
||||
this.pluginsDir = fileService.resolve(fileService.getRoot(), "plugins");
|
||||
this.tmpDir = uploadsDir.resolve("tmp");
|
||||
if (Files.exists(this.tmpDir)) {
|
||||
FileUtils.deleteDirectory(this.tmpDir);
|
||||
}
|
||||
logger.info("Cleaned up tmp files and inited work dir {} ", uploadsDir);
|
||||
}
|
||||
|
||||
public String getProjectDir(String owner, String name) {
|
||||
return fileService.resolve(getUserDir(owner), name);
|
||||
public String getProjectDir(final String owner, final String slug) {
|
||||
return this.fileService.resolve(this.getUserDir(owner), slug);
|
||||
}
|
||||
|
||||
public String getVersionDir(String owner, String name, String version) {
|
||||
return fileService.resolve(fileService.resolve(getProjectDir(owner, name), "versions"), version);
|
||||
public String getVersionDir(final String owner, final String slug, final String version) {
|
||||
return this.fileService.resolve(this.fileService.resolve(this.getProjectDir(owner, slug), "versions"), version);
|
||||
}
|
||||
|
||||
public String getVersionDir(String owner, String name, String version, Platform platform) {
|
||||
return fileService.resolve(getVersionDir(owner, name, version), platform.name());
|
||||
public String getVersionDir(final String owner, final String slug, final String version, final Platform platform) {
|
||||
return this.fileService.resolve(this.getVersionDir(owner, slug, version), platform.name());
|
||||
}
|
||||
|
||||
public String getVersionDir(String owner, String name, String version, Platform platform, String fileName) {
|
||||
return fileService.resolve(getVersionDir(owner, name, version, platform), fileName);
|
||||
public String getVersionDir(final String owner, final String name, final String version, final Platform platform, final String fileName) {
|
||||
return this.fileService.resolve(this.getVersionDir(owner, name, version, platform), fileName);
|
||||
}
|
||||
|
||||
public String getUserDir(String user) {
|
||||
return fileService.resolve(pluginsDir, user);
|
||||
public String getUserDir(final String user) {
|
||||
return this.fileService.resolve(this.pluginsDir, user);
|
||||
}
|
||||
|
||||
public void transferProject(String owner, String newOwner, String slug) {
|
||||
final String oldProjectDir = getProjectDir(owner, slug);
|
||||
final String newProjectDir = getProjectDir(newOwner, slug);
|
||||
public void transferProject(final String owner, final String newOwner, final String slug) {
|
||||
final String oldProjectDir = this.getProjectDir(owner, slug);
|
||||
final String newProjectDir = this.getProjectDir(newOwner, slug);
|
||||
try {
|
||||
fileService.move(oldProjectDir, newProjectDir);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void renameProject(String owner, String slug, String newSlug) {
|
||||
final String oldProjectDir = getProjectDir(owner, slug);
|
||||
final String newProjectDir = getProjectDir(owner, newSlug);
|
||||
try {
|
||||
fileService.move(oldProjectDir, newProjectDir);
|
||||
this.fileService.move(oldProjectDir, newProjectDir);
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void renameVersion(String owner, String slug, String version, String newVersionName) {
|
||||
final String oldVersionDir = getVersionDir(owner, slug, version);
|
||||
final String newVersionDir = getVersionDir(owner, slug, newVersionName);
|
||||
public void renameProject(final String owner, final String slug, final String newSlug) {
|
||||
final String oldProjectDir = this.getProjectDir(owner, slug);
|
||||
final String newProjectDir = this.getProjectDir(owner, newSlug);
|
||||
try {
|
||||
fileService.move(oldVersionDir, newVersionDir);
|
||||
this.fileService.move(oldProjectDir, newProjectDir);
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public String getIconsDir(String owner, String name) {
|
||||
return fileService.resolve(getProjectDir(owner, name), "icons");
|
||||
public void renameVersion(final String owner, final String slug, final String version, final String newVersionName) {
|
||||
final String oldVersionDir = this.getVersionDir(owner, slug, version);
|
||||
final String newVersionDir = this.getVersionDir(owner, slug, newVersionName);
|
||||
try {
|
||||
this.fileService.move(oldVersionDir, newVersionDir);
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public String getIconPath(String owner, String name) {
|
||||
return fileService.resolve(getIconsDir(owner, name), "icon.png");
|
||||
public String getIconsDir(final String owner, final String slug) {
|
||||
return this.fileService.resolve(this.getProjectDir(owner, slug), "icons");
|
||||
}
|
||||
|
||||
public Path getTempDir(String owner) {
|
||||
return tmpDir.resolve(owner);
|
||||
public String getIconPath(final String owner, final String slug) {
|
||||
return this.fileService.resolve(this.getIconsDir(owner, slug), "icon.png");
|
||||
}
|
||||
|
||||
public Path getTempDir(final String owner) {
|
||||
return this.tmpDir.resolve(owner);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import { useVuelidate } from "@vuelidate/core";
|
||||
import { Cropper, type CropperResult } from "vue-advanced-cropper";
|
||||
import { PaginatedResult, User } from "hangar-api";
|
||||
import { useSeo } from "~/composables/useSeo";
|
||||
import { projectIconUrl } from "~/composables/useUrlHelper";
|
||||
import { avatarUrl, projectIconUrl } from "~/composables/useUrlHelper";
|
||||
import Card from "~/lib/components/design/Card.vue";
|
||||
import MemberList from "~/components/projects/MemberList.vue";
|
||||
import { hasPerms } from "~/composables/usePerm";
|
||||
@ -65,11 +65,13 @@ if (!form.settings.license.type) {
|
||||
form.settings.license.type = "Unspecified";
|
||||
}
|
||||
|
||||
const hasCustomIcon = ref(props.project.customIcon);
|
||||
const projectIcon = ref<File | null>(null);
|
||||
const cropperInput = ref();
|
||||
const cropperResult = ref();
|
||||
const imgSrc = ref(projectIconUrl(props.project.namespace.owner, props.project.namespace.slug));
|
||||
let reader: FileReader | null = null;
|
||||
onMounted(async () => {
|
||||
onMounted(() => {
|
||||
reader = new FileReader();
|
||||
reader.addEventListener(
|
||||
"load",
|
||||
@ -78,7 +80,6 @@ onMounted(async () => {
|
||||
},
|
||||
false
|
||||
);
|
||||
await loadIconIntoCropper();
|
||||
});
|
||||
|
||||
watch(projectIcon, (newValue) => {
|
||||
@ -93,16 +94,6 @@ function changeImage({ canvas }: CropperResult) {
|
||||
});
|
||||
}
|
||||
|
||||
async function loadIconIntoCropper() {
|
||||
const response = await fetch(projectIconUrl(props.project.namespace.owner, props.project.namespace.slug, false), {
|
||||
headers: {
|
||||
"Cache-Control": "no-cache",
|
||||
},
|
||||
});
|
||||
const data = await response.blob();
|
||||
reader?.readAsDataURL(data);
|
||||
}
|
||||
|
||||
const newName = ref<string | null>("");
|
||||
const newNameField = ref<InstanceType<typeof InputText> | null>(null);
|
||||
const loading = reactive({
|
||||
@ -210,8 +201,11 @@ async function uploadIcon() {
|
||||
loading.uploadIcon = true;
|
||||
try {
|
||||
const response = await useInternalApi<string | null>(`projects/project/${route.params.user}/${route.params.project}/saveIcon`, "post", data);
|
||||
imgSrc.value = URL.createObjectURL(cropperResult.value); // set temporary source so it changes right away
|
||||
projectIcon.value = null;
|
||||
cropperInput.value = null;
|
||||
cropperResult.value = null;
|
||||
await loadIconIntoCropper();
|
||||
hasCustomIcon.value = true;
|
||||
if (response) {
|
||||
useNotificationStore().success(i18n.t("project.settings.success.changedIconWarn", [response]));
|
||||
} else {
|
||||
@ -232,8 +226,11 @@ async function resetIcon() {
|
||||
} else {
|
||||
useNotificationStore().success(i18n.t("project.settings.success.resetIcon"));
|
||||
}
|
||||
imgSrc.value = avatarUrl(props.project.owner.name); // set temporary source so it changes right away
|
||||
projectIcon.value = null;
|
||||
await loadIconIntoCropper();
|
||||
cropperInput.value = null;
|
||||
cropperResult.value = null;
|
||||
hasCustomIcon.value = false;
|
||||
} catch (e: any) {
|
||||
handleRequestError(e);
|
||||
}
|
||||
@ -305,11 +302,11 @@ useHead(
|
||||
<IconMdiUpload />
|
||||
{{ i18n.t("project.settings.iconUpload") }}
|
||||
</Button>
|
||||
<Button :loading="loading.resetIcon" @click="resetIcon">
|
||||
<IconMdiUpload />
|
||||
<Button :disabled="!hasCustomIcon" :loading="loading.resetIcon" @click="resetIcon">
|
||||
<IconMdiCached />
|
||||
{{ i18n.t("project.settings.iconReset") }}
|
||||
</Button>
|
||||
<div class="col-span-1 col-start-3 row-start-1 row-span-3">
|
||||
<div class="col-span-1 col-start-3 row-start-1 row-span-3" :class="{ 'justify-self-center': !cropperInput }">
|
||||
<cropper
|
||||
v-if="cropperInput"
|
||||
:src="cropperInput"
|
||||
@ -332,14 +329,7 @@ useHead(
|
||||
image-restriction="stencil"
|
||||
@change="changeImage"
|
||||
/>
|
||||
<img
|
||||
v-else
|
||||
id="project-icon-preview"
|
||||
width="150"
|
||||
height="150"
|
||||
alt="Project Icon"
|
||||
:src="projectIconUrl(project.namespace.owner, project.namespace.slug)"
|
||||
/>
|
||||
<img v-else id="project-icon-preview" width="150" height="150" alt="Project Icon" :src="imgSrc" />
|
||||
</div>
|
||||
</div>
|
||||
</ProjectSettingsSection>
|
||||
|
1
frontend/src/types/generated/icons.d.ts
vendored
1
frontend/src/types/generated/icons.d.ts
vendored
@ -14,6 +14,7 @@ declare module "@vue/runtime-core" {
|
||||
IconMdiAlertOutline: typeof import("~icons/mdi/alert-outline")["default"];
|
||||
IconMdiBell: typeof import("~icons/mdi/bell")["default"];
|
||||
IconMdiBellOutline: typeof import("~icons/mdi/bell-outline")["default"];
|
||||
IconMdiCached: typeof import("~icons/mdi/cached")["default"];
|
||||
IconMdiCalendar: typeof import("~icons/mdi/calendar")["default"];
|
||||
IconMdiCancel: typeof import("~icons/mdi/cancel")["default"];
|
||||
IconMdiCashMultiple: typeof import("~icons/mdi/cash-multiple")["default"];
|
||||
|
1
frontend/src/types/internal/projects.d.ts
vendored
1
frontend/src/types/internal/projects.d.ts
vendored
@ -44,6 +44,7 @@ declare module "hangar-internal" {
|
||||
pages: HangarProjectPage[];
|
||||
pinnedVersions: PinnedVersion[];
|
||||
mainChannelVersions: Record<Platform, HangarVersion>;
|
||||
customIcon: boolean;
|
||||
}
|
||||
|
||||
interface ProjectPage extends Table {
|
||||
|
Loading…
Reference in New Issue
Block a user