fully implemented v1 show user

This commit is contained in:
Jake Potrebic 2020-08-10 18:15:12 -07:00
parent 8b07f24e48
commit 0470c0bafa
No known key found for this signature in database
GPG Key ID: 7C58557EC9C421F8
5 changed files with 327 additions and 17 deletions

View File

@ -73,13 +73,13 @@ $(function() {
// hangar: user.name was username everywhere
var user = result.user;
// Check if user is already defined
if ($('.list-members').find('a[href="/' + user.name + '"]').length) {
if ($('.list-members').find('a[href="/' + user.username + '"]').length) {
return;
}
// Build result row
var resultRow = $('#row-user').clone().removeAttr('id').addClass('user-new');
resultRow.find('.username').attr('href', '/' + user.name).text(user.name);
resultRow.find('.username').attr('href', '/' + user.username).text(user.username);
resultRow.find('input').attr('form', 'save').val(user.id);
resultRow.find('select').attr('form', 'save');
resultRow.find('svg').click(function() {

View File

@ -1,14 +1,24 @@
package me.minidigger.hangar.controller;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import me.minidigger.hangar.db.dao.HangarDao;
import me.minidigger.hangar.db.dao.UserDao;
import me.minidigger.hangar.db.model.ProjectPagesTable;
import me.minidigger.hangar.db.model.ProjectChannelsTable;
import me.minidigger.hangar.db.model.ProjectVersionTagsTable;
import me.minidigger.hangar.db.model.ProjectVersionsTable;
import me.minidigger.hangar.db.model.ProjectsTable;
import me.minidigger.hangar.db.model.UserProjectRolesTable;
import me.minidigger.hangar.db.model.UsersTable;
import me.minidigger.hangar.model.Role;
import me.minidigger.hangar.model.Visibility;
import me.minidigger.hangar.model.generated.Dependency;
import me.minidigger.hangar.model.viewhelpers.ProjectPage;
import me.minidigger.hangar.model.viewhelpers.UserData;
import me.minidigger.hangar.service.UserService;
import me.minidigger.hangar.service.api.V1ApiService;
import me.minidigger.hangar.service.project.PagesSerivce;
import me.minidigger.hangar.util.TemplateHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@ -23,22 +33,34 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.server.ResponseStatusException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collector;
import java.util.stream.Collectors;
@Controller
public class Apiv1Controller extends HangarController {
private final ObjectMapper mapper;
private final TemplateHelper templateHelper;
private final PagesSerivce pagesSerivce;
private final HangarDao<UserDao> userDao;
private final UserService userService;
private final V1ApiService v1ApiService;
@Autowired
public Apiv1Controller(ObjectMapper mapper, PagesSerivce pagesSerivce, HangarDao<UserDao> userDao) {
public Apiv1Controller(ObjectMapper mapper, TemplateHelper templateHelper, PagesSerivce pagesSerivce, UserService userService, V1ApiService v1ApiService) {
this.mapper = mapper;
this.templateHelper = templateHelper;
this.pagesSerivce = pagesSerivce;
this.userDao = userDao;
this.userService = userService;
this.v1ApiService = v1ApiService;
}
@RequestMapping("/api/sync_sso")
@ -124,8 +146,13 @@ public class Apiv1Controller extends HangarController {
@RequestMapping("/api/v1/users/{user}")
@ResponseBody
public UsersTable showUser(@PathVariable String user) {
return userDao.get().getByName(user);
public ResponseEntity<ObjectNode> showUser(@PathVariable String user) {
UserData userData = userService.getUserData(user);
JsonNode userObj = writeUsers(List.of(userData.getUser())).get(0);
if (userObj == null || !userObj.isObject()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
return ResponseEntity.ok((ObjectNode) userObj);
}
@RequestMapping("/statusz")
@ -133,5 +160,124 @@ public class Apiv1Controller extends HangarController {
return null; // TODO implement showStatusZ request controller
}
}
private ArrayNode writeUsers(List<UsersTable> usersTables) {
ArrayNode usersArray = mapper.createArrayNode();
List<Long> userIds = usersTables.stream().map(UsersTable::getId).collect(Collectors.toList());
Map<Long, List<ProjectsTable>> usersProjects = v1ApiService.getUsersProjects(userIds);
Map<Long, List<String>> projectStars = v1ApiService.getStarredPlugins(userIds);
Map<Long, List<Role>> globalRoles = v1ApiService.getUsersGlobalRoles(userIds);
usersTables.forEach(user -> {
ObjectNode userObj = mapper.createObjectNode();
userObj.set("id", mapper.valueToTree(user.getId()));
userObj.set("createdAt", mapper.valueToTree(user.getCreatedAt()));
userObj.set("username", mapper.valueToTree(user.getName()));
userObj.set("roles", mapper.valueToTree(globalRoles.getOrDefault(user.getId(), new ArrayList<>()).stream().map(Role::getTitle)));
userObj.set("starred", mapper.valueToTree(projectStars.getOrDefault(user.getId(), new ArrayList<>())));
userObj.set("avatarUrl", mapper.valueToTree(templateHelper.avatarUrl(user.getName())));
userObj.set("projects", writeProjects(usersProjects.getOrDefault(user.getId(), new ArrayList<>())));
usersArray.add(userObj);
});
return usersArray;
}
private ArrayNode writeProjects(List<ProjectsTable> projectsTables) {
ArrayNode projectsArray = mapper.createArrayNode();
List<Long> projectIds = projectsTables.stream().map(ProjectsTable::getId).collect(Collectors.toList());
Map<Long, List<ProjectChannelsTable>> projectChannels = v1ApiService.getProjectsChannels(projectIds);
Map<Long, List<Entry<UserProjectRolesTable, UsersTable>>> members = v1ApiService.getProjectsMembers(projectIds);
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()));
projectsTables.forEach(project -> {
ObjectNode projectObj = mapper.createObjectNode();
projectObj.set("pluginId", mapper.valueToTree(project.getPluginId()));
projectObj.set("createdAt", mapper.valueToTree(project.getCreatedAt().toString()));
projectObj.set("name", mapper.valueToTree(project.getName()));
projectObj.set("owner", mapper.valueToTree(project.getOwnerName()));
projectObj.set("description", mapper.valueToTree(project.getDescription()));
projectObj.set("href", mapper.valueToTree(project.getOwnerName() + "/" + project.getSlug()));
projectObj.set("members", writeMembers(members.getOrDefault(project.getId(), new ArrayList<>())));
projectObj.set("channels", mapper.valueToTree( projectChannels.getOrDefault(project.getId(), new ArrayList<>())));
projectObj.set("recommended", writeVersion(recommendedVersions.get(project.getId()), project, recommendedVersionChannels.get(project.getId()), vTags.getOrDefault(recommendedVersions.get(project.getId()).getId(), new ArrayList<>())));
ObjectNode projectCategoryObj = mapper.createObjectNode();
projectCategoryObj.set("title", mapper.valueToTree(project.getCategory().getTitle()));
projectCategoryObj.set("icon", mapper.valueToTree(project.getCategory().getIcon()));
projectObj.set("category", projectCategoryObj);
projectObj.set("views", mapper.valueToTree(0));
projectObj.set("downloads", mapper.valueToTree(0));
projectObj.set("stars", mapper.valueToTree(0));
projectsArray.add(projectObj);
});
return projectsArray;
}
private ObjectNode writeVersion(ProjectVersionsTable version, ProjectsTable project, ProjectChannelsTable channel, List<ProjectVersionTagsTable> tags) {
ObjectNode objectNode = mapper.createObjectNode();
if (version == null) return objectNode;
objectNode.set("id", mapper.valueToTree(version.getId()));
objectNode.set("createdAt", mapper.valueToTree(version.getCreatedAt().toString()));
objectNode.set("name", mapper.valueToTree(version.getVersionString()));
objectNode.set("dependencies", Dependency.from(version.getDependencies()).stream().collect(Collector.of(mapper::createArrayNode, (array, dep) -> {
ObjectNode depObj = mapper.createObjectNode();
depObj.set("pluginId", mapper.valueToTree(dep.getPluginId()));
depObj.set("version", mapper.valueToTree(dep.getVersion()));
array.add(depObj);
}, (ignored1, ignored2) -> {
throw new UnsupportedOperationException();
})));
objectNode.set("pluginId", mapper.valueToTree(project.getPluginId()));
objectNode.set("channel", mapper.valueToTree(channel));
objectNode.set("fileSize", mapper.valueToTree(version.getFileSize()));
objectNode.set("md5", mapper.valueToTree(version.getHash()));
objectNode.set("staffApproved", mapper.valueToTree(version.getReviewState().isChecked()));
objectNode.set("reviewState", mapper.valueToTree(version.getReviewState().toString()));
objectNode.set("href", mapper.valueToTree("/" + project.getOwnerName() + "/" + project.getSlug() + "/versions/" + version.getVersionString()));
objectNode.set("tags", tags.stream().collect(Collector.of(mapper::createArrayNode, (array, tag) -> array.add(mapper.valueToTree(tag)), (t1, t2) -> {
throw new UnsupportedOperationException();
})));
objectNode.set("downloads", mapper.valueToTree(0));
objectNode.set("description", mapper.valueToTree(version.getDescription()));
if (version.getVisibility() != Visibility.PUBLIC) {
ObjectNode visObj = mapper.createObjectNode();
visObj.set("type", mapper.valueToTree(version.getVisibility().getName()));
visObj.set("css", mapper.valueToTree(version.getVisibility().getCssClass()));
objectNode.set("visibility", visObj);
}
return objectNode;
}
private ArrayNode writeMembers(List<Entry<UserProjectRolesTable, UsersTable>> members) {
ArrayNode membersArray = mapper.createArrayNode();
Map<Long, List<Role>> allRoles = new HashMap<>();
members.forEach(entry -> {
if (allRoles.containsKey(entry.getValue().getId())) {
allRoles.get(entry.getValue().getId()).add(Role.fromId(entry.getKey().getId()));
} else {
allRoles.put(entry.getValue().getId(), new ArrayList<>(Collections.singletonList(Role.fromId(entry.getKey().getId()))));
}
});
members.forEach(member -> {
List<Role> roles = allRoles.getOrDefault(member.getValue().getId(), new ArrayList<>());
ObjectNode memberObj = mapper.createObjectNode();
memberObj.set("userId", mapper.valueToTree(member.getValue().getId()));
memberObj.set("name", mapper.valueToTree(member.getValue().getName()));
memberObj.set("roles", mapper.valueToTree(roles.stream().map(Role::getTitle).collect(Collectors.toList())));
if (roles.isEmpty()) {
memberObj.set("headRole", mapper.valueToTree(null));
} else {
memberObj.set("headRole", mapper.valueToTree(roles.stream().max(Comparator.comparingLong(role -> role.getPermissions().getValue())).get().getTitle()));
}
membersArray.add(memberObj);
});
return membersArray;
}
}

View File

@ -1,5 +1,8 @@
package me.minidigger.hangar.db.dao.api;
import me.minidigger.hangar.model.Category;
import me.minidigger.hangar.model.generated.Project;
import me.minidigger.hangar.model.generated.Tag;
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
import org.jdbi.v3.sqlobject.customizer.AllowUnusedBindings;
import org.jdbi.v3.sqlobject.statement.SqlQuery;
@ -8,10 +11,6 @@ import org.springframework.stereotype.Repository;
import java.util.List;
import me.minidigger.hangar.model.Category;
import me.minidigger.hangar.model.generated.Project;
import me.minidigger.hangar.model.generated.Tag;
@Repository
@RegisterBeanMapper(Project.class)
public interface ProjectApiDao {

View File

@ -0,0 +1,65 @@
package me.minidigger.hangar.db.dao.api;
import me.minidigger.hangar.db.model.ProjectChannelsTable;
import me.minidigger.hangar.db.model.ProjectVersionTagsTable;
import me.minidigger.hangar.db.model.ProjectVersionsTable;
import me.minidigger.hangar.db.model.ProjectsTable;
import me.minidigger.hangar.db.model.RolesTable;
import me.minidigger.hangar.db.model.UserProjectRolesTable;
import me.minidigger.hangar.db.model.UsersTable;
import org.jdbi.v3.sqlobject.config.KeyColumn;
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
import org.jdbi.v3.sqlobject.config.ValueColumn;
import org.jdbi.v3.sqlobject.customizer.BindList;
import org.jdbi.v3.sqlobject.customizer.BindList.EmptyHandling;
import org.jdbi.v3.sqlobject.statement.SqlQuery;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
@Repository
public interface V1ApiDao {
@RegisterBeanMapper(ProjectsTable.class)
@SqlQuery("SELECT * FROM projects WHERE owner_id IN (<userIds>)")
List<ProjectsTable> getProjectsForUsers(@BindList(onEmpty = EmptyHandling.NULL_STRING) List<Long> userIds);
@KeyColumn("owner_id")
@ValueColumn("plugin_id")
@SqlQuery("SELECT p.owner_id owner_id, p.plugin_id plugin_id FROM project_stars JOIN projects p ON p.id = project_stars.project_id WHERE p.owner_id in (<userIds>)")
List<Map.Entry<Long, String>> getStarredPlugins(@BindList(onEmpty = EmptyHandling.NULL_STRING) List<Long> userIds);
@KeyColumn("user_id")
@RegisterBeanMapper(RolesTable.class)
@SqlQuery("SELECT ugr.user_id user_id, r.id, r.name, r.category, r.title, r.color, r.is_assignable, r.rank, r.permission::BIGINT FROM user_global_roles ugr JOIN roles r ON r.id = ugr.role_id WHERE user_id in (<userIds>)")
List<Map.Entry<Long, RolesTable>> getUsersGlobalRoles(@BindList(onEmpty = EmptyHandling.NULL_STRING) List<Long> userIds);
@KeyColumn("p_id")
@RegisterBeanMapper(ProjectChannelsTable.class)
@SqlQuery("SELECT project_id p_id, * FROM project_channels WHERE project_id IN (<projectIds>)")
List<Map.Entry<Long, ProjectChannelsTable>> getProjectsChannels(@BindList(onEmpty = EmptyHandling.NULL_STRING) List<Long> projectIds);
@KeyColumn("p_id")
@RegisterBeanMapper(ProjectVersionsTable.class)
@SqlQuery("SELECT p.id p_id, pv.* FROM project_versions pv JOIN projects p ON pv.project_id = p.id WHERE p.recommended_version_id = pv.id AND p.id IN (<projectIds>)")
Map<Long, ProjectVersionsTable> getProjectsRecommendedVersion(@BindList(onEmpty = EmptyHandling.NULL_STRING) List<Long> projectIds);
@KeyColumn("p_id")
@RegisterBeanMapper(ProjectChannelsTable.class)
@SqlQuery("SELECT p.id p_id, pc.* FROM project_channels pc JOIN project_versions pv ON pc.id = pv.channel_id JOIN projects p ON p.id = pc.project_id WHERE p.id IN (<projectIds>) AND p.recommended_version_id = pv.id")
Map<Long, ProjectChannelsTable> getProjectsRecommendedVersionChannel(@BindList(onEmpty = EmptyHandling.NULL_STRING) List<Long> projectIds);
@RegisterBeanMapper(value = UserProjectRolesTable.class, prefix = "upr")
@RegisterBeanMapper(UsersTable.class)
@SqlQuery("SELECT u.*, upr.id upr_id, upr.created_at upr_created_at, upr.user_id upr_user_id, upr.role_type upr_role_type, upr.project_id upr_project_id, upr.is_accepted upr_is_accepted " +
"FROM user_project_roles upr " +
"JOIN users u ON upr.user_id = u.id " +
"WHERE upr.is_accepted AND upr.project_id IN (<projectIds>)")
List<Map.Entry<UserProjectRolesTable, UsersTable>> getProjectsMembers(@BindList(onEmpty = EmptyHandling.NULL_STRING) List<Long> projectIds);
@KeyColumn("pv_id")
@RegisterBeanMapper(ProjectVersionTagsTable.class)
@SqlQuery("SELECT pv.id pv_id, pvt.* FROM project_version_tags pvt JOIN project_versions pv ON pv.id = pvt.version_id WHERE pv.visibility = 0 AND pv.id IN (<versionIds>)")
List<Map.Entry<Long, ProjectVersionTagsTable>> getVersionsTags(@BindList(onEmpty = EmptyHandling.NULL_STRING) List<Long> versionIds);
}

View File

@ -0,0 +1,100 @@
package me.minidigger.hangar.service.api;
import me.minidigger.hangar.db.dao.HangarDao;
import me.minidigger.hangar.db.dao.api.V1ApiDao;
import me.minidigger.hangar.db.model.ProjectChannelsTable;
import me.minidigger.hangar.db.model.ProjectVersionTagsTable;
import me.minidigger.hangar.db.model.ProjectVersionsTable;
import me.minidigger.hangar.db.model.ProjectsTable;
import me.minidigger.hangar.db.model.UserProjectRolesTable;
import me.minidigger.hangar.db.model.UsersTable;
import me.minidigger.hangar.model.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
@Service
public class V1ApiService {
private final HangarDao<V1ApiDao> v1ApiDao;
@Autowired
public V1ApiService(HangarDao<V1ApiDao> v1ApiDao) {
this.v1ApiDao = v1ApiDao;
}
public Map<Long, List<ProjectsTable>> getUsersProjects(List<Long> userIds) {
return v1ApiDao.get().getProjectsForUsers(userIds).stream().collect(Collectors.groupingBy(ProjectsTable::getOwnerId));
}
// TODO better way for this?
public Map<Long, List<String>> getStarredPlugins(List<Long> userIds) {
return v1ApiDao.get().getStarredPlugins(userIds).stream()
.collect(
Collectors.groupingBy(Entry::getKey)
).entrySet().stream()
.collect(
Collectors.toMap(
Entry::getKey,
longListEntry -> longListEntry.getValue().stream().map(Entry::getValue).collect(Collectors.toList()))
);
}
public Map<Long, List<Role>> getUsersGlobalRoles(List<Long> userIds) {
return v1ApiDao.get().getUsersGlobalRoles(userIds).stream()
.collect(
Collectors.groupingBy(Entry::getKey)
).entrySet().stream()
.collect(
Collectors.toMap(
Entry::getKey,
listEntry -> listEntry.getValue().stream().map(entry -> Role.fromId(entry.getValue().getId())).collect(Collectors.toList())
)
);
}
public Map<Long, List<ProjectChannelsTable>> getProjectsChannels(List<Long> projectIds) {
return v1ApiDao.get().getProjectsChannels(projectIds).stream()
.collect(
Collectors.groupingBy(Entry::getKey)
).entrySet().stream()
.collect(
Collectors.toMap(
Entry::getKey,
listEntry -> listEntry.getValue().stream().map(Entry::getValue).collect(Collectors.toList())
)
);
}
public Map<Long, ProjectVersionsTable> getProjectsRecommendedVersion(List<Long> projectIds) {
return v1ApiDao.get().getProjectsRecommendedVersion(projectIds);
}
public Map<Long, ProjectChannelsTable> getProjectsRecommendedVersionChannel(List<Long> projectIds) {
return v1ApiDao.get().getProjectsRecommendedVersionChannel(projectIds);
}
public Map<Long, List<Entry<UserProjectRolesTable, UsersTable>>> getProjectsMembers(List<Long> projectIds) {
return v1ApiDao.get().getProjectsMembers(projectIds).stream()
.collect(
Collectors.groupingBy(entry -> entry.getKey().getProjectId())
);
}
public Map<Long, List<ProjectVersionTagsTable>> getVersionsTags(List<Long> versionIds) {
return v1ApiDao.get().getVersionsTags(versionIds).stream()
.collect(
Collectors.groupingBy(Entry::getKey)
).entrySet().stream()
.collect(
Collectors.toMap(
Entry::getKey,
listEntry -> listEntry.getValue().stream().map(Entry::getValue).collect(Collectors.toList())
)
);
}
}