diff --git a/backend/pom.xml b/backend/pom.xml index 8d2e95409..b8b6cdc03 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -37,9 +37,10 @@ 4.5 20220924 7.6.0 - + 1.6.0 3.12.0 4.2.1 + 1.17.5 @@ -226,6 +227,13 @@ ${spring-cloud-aws.version} + + + net.datafaker + datafaker + ${datafaker.version} + + org.springframework.boot diff --git a/backend/src/main/java/io/papermc/hangar/controller/internal/FakeDataController.java b/backend/src/main/java/io/papermc/hangar/controller/internal/FakeDataController.java new file mode 100644 index 000000000..e43eeb0c4 --- /dev/null +++ b/backend/src/main/java/io/papermc/hangar/controller/internal/FakeDataController.java @@ -0,0 +1,31 @@ +package io.papermc.hangar.controller.internal; + +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import io.papermc.hangar.model.common.NamedPermission; +import io.papermc.hangar.security.annotations.permission.PermissionRequired; +import io.papermc.hangar.security.annotations.ratelimit.RateLimit; +import io.papermc.hangar.service.internal.FakeDataService; + +@Controller +@RateLimit(path = "admin") +@RequestMapping("/api/internal/fakeData") +public class FakeDataController { + + private final FakeDataService fakeDataService; + + public FakeDataController(FakeDataService fakeDataService) { + this.fakeDataService = fakeDataService; + } + + @ResponseStatus(HttpStatus.OK) + @GetMapping("/") + @PermissionRequired(NamedPermission.MANUAL_VALUE_CHANGES) + public void generateFakeData(@RequestParam int users, @RequestParam int projectsPerUser) { + fakeDataService.generate(users, projectsPerUser); + } +} diff --git a/backend/src/main/java/io/papermc/hangar/model/Model.java b/backend/src/main/java/io/papermc/hangar/model/Model.java index 8d26e3f00..f294f1e0c 100644 --- a/backend/src/main/java/io/papermc/hangar/model/Model.java +++ b/backend/src/main/java/io/papermc/hangar/model/Model.java @@ -15,6 +15,10 @@ public abstract class Model { return this.createdAt; } + public void setCreatedAt(OffsetDateTime createdAt) { + this.createdAt = createdAt; + } + @Override public boolean equals(final Object o) { if (this == o) return true; diff --git a/backend/src/main/java/io/papermc/hangar/model/common/roles/GlobalRole.java b/backend/src/main/java/io/papermc/hangar/model/common/roles/GlobalRole.java index b5e205c73..79773192f 100644 --- a/backend/src/main/java/io/papermc/hangar/model/common/roles/GlobalRole.java +++ b/backend/src/main/java/io/papermc/hangar/model/common/roles/GlobalRole.java @@ -20,6 +20,8 @@ public enum GlobalRole implements Role { PAPERMC_CORE("PaperMC_Core", 4, Permission.All, "PaperMC Core", Color.AMBER, 10), PAPERMC_STAFF("PaperMC_Staff", 5, Permission.IsStaff, "Paper Staff", Color.AMBER, 50), + DUMMY("Dummy", 42, Permission.ViewPublicInfo, "Dummy", Color.CHARTREUSE, 42), + ORGANIZATION("Organization", 100, OrganizationRole.ORGANIZATION_OWNER.getPermissions(), "Organization", Color.PURPLE); private final String value; diff --git a/backend/src/main/java/io/papermc/hangar/service/internal/FakeDataService.java b/backend/src/main/java/io/papermc/hangar/service/internal/FakeDataService.java new file mode 100644 index 000000000..1e41340e1 --- /dev/null +++ b/backend/src/main/java/io/papermc/hangar/service/internal/FakeDataService.java @@ -0,0 +1,116 @@ +package io.papermc.hangar.service.internal; + +import net.datafaker.Faker; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; +import java.time.ZoneOffset; +import java.util.HashSet; +import java.util.Set; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import io.papermc.hangar.HangarComponent; +import io.papermc.hangar.db.dao.internal.table.UserDAO; +import io.papermc.hangar.db.dao.internal.table.projects.ProjectsDAO; +import io.papermc.hangar.model.api.project.ProjectDonationSettings; +import io.papermc.hangar.model.api.project.ProjectLicense; +import io.papermc.hangar.model.api.project.ProjectSettings; +import io.papermc.hangar.model.common.Permission; +import io.papermc.hangar.model.common.projects.Category; +import io.papermc.hangar.model.common.projects.Visibility; +import io.papermc.hangar.model.common.roles.GlobalRole; +import io.papermc.hangar.model.db.UserTable; +import io.papermc.hangar.model.db.projects.ProjectTable; +import io.papermc.hangar.model.db.roles.GlobalRoleTable; +import io.papermc.hangar.model.internal.api.requests.projects.NewProjectForm; +import io.papermc.hangar.security.authentication.HangarAuthenticationToken; +import io.papermc.hangar.security.authentication.HangarPrincipal; +import io.papermc.hangar.service.internal.perms.roles.GlobalRoleService; +import io.papermc.hangar.service.internal.projects.ProjectFactory; +import io.papermc.hangar.service.internal.projects.ProjectService; + +@Service +public class FakeDataService extends HangarComponent { + + private final Faker faker = new Faker(); + + private final UserDAO userDAO; + private final GlobalRoleService globalRoleService; + private final ProjectService projectService; + private final ProjectFactory projectFactory; + private final ProjectsDAO projectsDAO; + + public FakeDataService(UserDAO userDAO, GlobalRoleService globalRoleService, ProjectService projectService, ProjectFactory projectFactory, ProjectsDAO projectsDAO) { + this.userDAO = userDAO; + this.globalRoleService = globalRoleService; + this.projectService = projectService; + this.projectFactory = projectFactory; + this.projectsDAO = projectsDAO; + } + + public void generate(int users, int projectsPerUser) { + HangarAuthenticationToken oldAuth = (HangarAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); + try { + for (int udx = 0; udx < users; udx++) { + UserTable user = createUser(); + SecurityContextHolder.getContext().setAuthentication(HangarAuthenticationToken.createVerifiedToken(new HangarPrincipal(user.getUserId(), user.getName(), false, Permission.All), oldAuth.getCredentials())); + for (int pdx = 0; pdx < projectsPerUser; pdx++) { + createProject(user.getUserId()); + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + SecurityContextHolder.getContext().setAuthentication(oldAuth); + projectService.refreshHomeProjects(); + } + } + + public UserTable createUser() { + UserTable userTable = userDAO.create(UUID.randomUUID(), + normalize(faker.simpsons().character()) + faker.random().nextInt(500), + faker.internet().safeEmailAddress(), + faker.chuckNorris().fact(), + "en", + List.of(), + false, + "dark"); + globalRoleService.addRole(new GlobalRoleTable(userTable.getId(), GlobalRole.DUMMY)); + return userTable; + } + + public void createProject(long ownerId) { + ProjectLicense licence = new ProjectLicense(config.getLicenses().get(faker.random().nextInt(config.getLicenses().size())), null); + Set keyWords = new HashSet<>(); + for (int i = 0; i < faker.random().nextInt(2, 5); i++) { + keyWords.add(faker.marketing().buzzwords()); + } + ProjectSettings settings = new ProjectSettings(faker.internet().domainName(), + null, + null, + null, + null, + licence, + new ProjectDonationSettings(false, "d"), + keyWords, + false, + "# Sponsored by " + faker.beer().style() + " " + faker.beer().name()); + String projectName = normalize(faker.funnyName().name() + "_" + faker.minecraft().animalName()); + String quote = faker.theItCrowd().quotes(); + NewProjectForm newProject = new NewProjectForm(settings, + Category.values()[faker.random().nextInt(Category.values().length)], + quote.substring(0, Math.min(quote.length(), 254)), + ownerId, + projectName.substring(0, Math.min(projectName.length(), 24)), + "# " + projectName + "\n\n" + "> " + faker.leagueOfLegends().quote()); + ProjectTable projectTable = projectFactory.createProject(newProject); + + projectTable.setVisibility(Visibility.PUBLIC); + projectTable.setCreatedAt(faker.date().past(100 * 365, TimeUnit.DAYS).toLocalDateTime().atOffset(ZoneOffset.UTC)); + projectsDAO.update(projectTable); + } + + private String normalize(String input) { + return input.replace(" ", "_").replace("\"", "").replace("'", "").replace(".", ""); + } +} diff --git a/frontend/src/lib b/frontend/src/lib index 4dc74966a..6343bfe7d 160000 --- a/frontend/src/lib +++ b/frontend/src/lib @@ -1 +1 @@ -Subproject commit 4dc74966aa6df91a73adb2876662cefc5d5aeb79 +Subproject commit 6343bfe7d2e0bc9cdb2d14b345d0814a3bb431f3 diff --git a/frontend/src/pages/index.vue b/frontend/src/pages/index.vue index aa930d327..6f6aa01b7 100644 --- a/frontend/src/pages/index.vue +++ b/frontend/src/pages/index.vue @@ -52,8 +52,7 @@ const loggedOut = ref("loggedOut" in route.query); const projects = ref | null>(); const requestParams = computed(() => { - // TODO change the limit back to something larger - const limit = 4; + const limit = 10; const params: Record = { limit: limit, offset: page.value * limit,