mirror of
https://github.com/HangarMC/Hangar.git
synced 2024-12-27 07:03:26 +08:00
work on api keys page (#56)
Co-authored-by: MiniDigger <admin@minidigger.me>
This commit is contained in:
parent
e56ec0ec27
commit
daef6b18f1
@ -1,12 +1,13 @@
|
||||
package me.minidigger.hangar.controller;
|
||||
|
||||
import me.minidigger.hangar.model.viewhelpers.UserData;
|
||||
import me.minidigger.hangar.service.ApiKeyService;
|
||||
import me.minidigger.hangar.service.PermissionService;
|
||||
import me.minidigger.hangar.db.customtypes.LoggedActionType;
|
||||
import me.minidigger.hangar.db.customtypes.LoggedActionType.UserContext;
|
||||
import me.minidigger.hangar.service.UserActionLogService;
|
||||
import me.minidigger.hangar.util.AlertUtil;
|
||||
import me.minidigger.hangar.util.AlertUtil.AlertType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -14,7 +15,6 @@ import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@ -27,6 +27,7 @@ import me.minidigger.hangar.db.model.UsersTable;
|
||||
import me.minidigger.hangar.service.AuthenticationService;
|
||||
import me.minidigger.hangar.service.UserService;
|
||||
import me.minidigger.hangar.util.RouteHelper;
|
||||
import org.springframework.web.servlet.view.RedirectView;
|
||||
|
||||
@Controller
|
||||
public class UsersController extends HangarController {
|
||||
@ -37,15 +38,19 @@ public class UsersController extends HangarController {
|
||||
private final UserService userService;
|
||||
private final UserActionLogService userActionLogService;
|
||||
private final RouteHelper routeHelper;
|
||||
private final ApiKeyService apiKeyService;
|
||||
private final PermissionService permissionService;
|
||||
|
||||
@Autowired
|
||||
public UsersController(HangarConfig hangarConfig, HangarDao<UserDao> userDao, AuthenticationService authenticationService, ApplicationController applicationController, UserService userService, UserActionLogService userActionLogService, RouteHelper routeHelper) {
|
||||
public UsersController(HangarConfig hangarConfig, HangarDao<UserDao> userDao, AuthenticationService authenticationService, ApplicationController applicationController, UserService userService, UserActionLogService userActionLogService, RouteHelper routeHelper, ApiKeyService apiKeyService, PermissionService permissionService) {
|
||||
this.hangarConfig = hangarConfig;
|
||||
this.userDao = userDao;
|
||||
this.authenticationService = authenticationService;
|
||||
this.userService = userService;
|
||||
this.userActionLogService = userActionLogService;
|
||||
this.routeHelper = routeHelper;
|
||||
this.apiKeyService = apiKeyService;
|
||||
this.permissionService = permissionService;
|
||||
}
|
||||
|
||||
@RequestMapping("/authors")
|
||||
@ -81,9 +86,9 @@ public class UsersController extends HangarController {
|
||||
}
|
||||
|
||||
@RequestMapping("/logout")
|
||||
public ModelAndView logout(HttpSession session) {
|
||||
public RedirectView logout(HttpSession session) {
|
||||
session.invalidate();
|
||||
return new ModelAndView("redirect:/"); // TODO redirect to sso
|
||||
return new RedirectView(routeHelper.getRouteUrl("showHome")); // TODO redirect to sso
|
||||
}
|
||||
|
||||
@Secured("ROLE_USER")
|
||||
@ -126,26 +131,30 @@ public class UsersController extends HangarController {
|
||||
|
||||
@RequestMapping("/{user}")
|
||||
public ModelAndView showProjects(@PathVariable String user) {
|
||||
UsersTable dbUser = userDao.get().getByName(user);
|
||||
if (dbUser == null) {
|
||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
ModelAndView mav = new ModelAndView("users/projects");
|
||||
mav.addObject("u", userService.getUserData(dbUser));
|
||||
mav.addObject("u", userService.getUserData(user));
|
||||
mav.addObject("o", null);
|
||||
return fillModel(mav);
|
||||
}
|
||||
|
||||
@Secured("ROLE_USER")
|
||||
@RequestMapping("/{user}/settings/apiKeys")
|
||||
public Object editApiKeys(@PathVariable Object user) {
|
||||
return null; // TODO implement editApiKeys request controller
|
||||
@GetMapping("/{user}/settings/apiKeys")
|
||||
public ModelAndView editApiKeys(@PathVariable String user) {
|
||||
ModelAndView mav = new ModelAndView("users/apiKeys");
|
||||
UserData userData = userService.getUserData(user);
|
||||
long userId = userData.getUser().getId();
|
||||
mav.addObject("u", userData);
|
||||
mav.addObject("keys", apiKeyService.getKeysForUser(userId));
|
||||
mav.addObject("perms", permissionService.getPossibleOrganizationPermissions(userId).add(permissionService.getPossibleProjectPermissions(userId)).add(userData.getUserPerm()).toNamed());
|
||||
return fillModel(mav); // TODO implement editApiKeys request controller
|
||||
}
|
||||
|
||||
@Secured("ROLE_USER")
|
||||
@RequestMapping("/{user}/settings/lock/{locked}")
|
||||
public Object setLocked(@PathVariable Object user, @PathVariable Object locked, @RequestParam Object sso, @RequestParam Object sig) {
|
||||
return null; // TODO implement setLocked request controller
|
||||
public RedirectView setLocked(@PathVariable String user, @PathVariable boolean locked, @RequestParam Object sso, @RequestParam Object sig) {
|
||||
// TODO auth
|
||||
userService.setLocked(user, locked);
|
||||
return new RedirectView(routeHelper.getRouteUrl("users.showProjects", user));
|
||||
}
|
||||
|
||||
@Secured("ROLE_USER")
|
||||
|
27
src/main/java/me/minidigger/hangar/db/dao/ApiKeyDao.java
Normal file
27
src/main/java/me/minidigger/hangar/db/dao/ApiKeyDao.java
Normal file
@ -0,0 +1,27 @@
|
||||
package me.minidigger.hangar.db.dao;
|
||||
|
||||
import me.minidigger.hangar.db.model.ApiKeysTable;
|
||||
import me.minidigger.hangar.model.Permission;
|
||||
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
|
||||
import org.jdbi.v3.sqlobject.customizer.BindBean;
|
||||
import org.jdbi.v3.sqlobject.customizer.Timestamped;
|
||||
import org.jdbi.v3.sqlobject.statement.GetGeneratedKeys;
|
||||
import org.jdbi.v3.sqlobject.statement.SqlQuery;
|
||||
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
@RegisterBeanMapper(ApiKeysTable.class)
|
||||
public interface ApiKeyDao {
|
||||
|
||||
@Timestamped
|
||||
@GetGeneratedKeys
|
||||
@SqlUpdate("INSERT INTO api_keys (created_at, name, owner_id, token_identifier, token, raw_key_permissions) VALUES (:now, :name, :ownerId, :tokenIdentifier, :token, :rawKeyPermissions)")
|
||||
ApiKeysTable insert(@BindBean ApiKeysTable apiKeysTable);
|
||||
|
||||
@RegisterBeanMapper(value = Permission.class, prefix = "perm")
|
||||
@SqlQuery("SELECT *, raw_key_permissions::BIGINT perm_value FROM api_keys WHERE owner_id = :ownerId")
|
||||
List<ApiKeysTable> getByOwner(long ownerId);
|
||||
}
|
@ -6,9 +6,15 @@ import org.jdbi.v3.sqlobject.statement.SqlQuery;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
@RegisterBeanMapper(value = Permission.class, prefix = "perm")
|
||||
public interface PermissionsDao {
|
||||
|
||||
@RegisterBeanMapper(value = Permission.class, prefix = "perm")
|
||||
@SqlQuery("SELECT gt.permission::bigint perm_value FROM global_trust gt JOIN users u on gt.user_id = u.id WHERE (u.id = :userId OR u.name = :userName)")
|
||||
@SqlQuery("SELECT gt.permission::BIGINT perm_value FROM global_trust gt JOIN users u on gt.user_id = u.id WHERE (u.id = :userId OR u.name = :userName)")
|
||||
Permission getGlobalPermission(Long userId, String userName);
|
||||
|
||||
@SqlQuery("SELECT coalesce(bit_or(r.permission), B'0'::BIT(64))::BIGINT perm_value FROM user_project_roles upr JOIN roles r ON upr.role_type = r.name WHERE upr.user_id = :userId")
|
||||
Permission getPossibleProjectPermissions(long userId);
|
||||
|
||||
@SqlQuery("SELECT coalesce(bit_or(r.permission), B'0'::BIT(64))::BIGINT perm_value FROM user_organization_roles uor JOIN roles r ON uor.role_type = r.name WHERE uor.user_id = :userId")
|
||||
Permission getPossibleOrganizationPermissions(long userId);
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ public interface UserGlobalRolesDao {
|
||||
void insert(@BindBean UserGlobalRolesTable entry);
|
||||
|
||||
@AllowUnusedBindings
|
||||
@SqlQuery("SELECT r.id, r.name, r.category, r.title, r.color, r.is_assignable, r.rank, r.permission " +
|
||||
@SqlQuery("SELECT 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 ugr.role_id = r.id " +
|
||||
"JOIN users u on ugr.user_id = u.id " +
|
||||
|
@ -1,6 +1,9 @@
|
||||
package me.minidigger.hangar.db.model;
|
||||
|
||||
|
||||
import me.minidigger.hangar.model.Permission;
|
||||
import org.jdbi.v3.core.mapper.Nested;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
public class ApiKeysTable {
|
||||
@ -11,7 +14,8 @@ public class ApiKeysTable {
|
||||
private long ownerId;
|
||||
private String tokenIdentifier;
|
||||
private String token;
|
||||
private long rawKeyPermissions;
|
||||
@Nested("perm")
|
||||
private Permission rawKeyPermissions;
|
||||
|
||||
|
||||
public long getId() {
|
||||
@ -68,11 +72,11 @@ public class ApiKeysTable {
|
||||
}
|
||||
|
||||
|
||||
public long getRawKeyPermissions() {
|
||||
public Permission getRawKeyPermissions() {
|
||||
return rawKeyPermissions;
|
||||
}
|
||||
|
||||
public void setRawKeyPermissions(long rawKeyPermissions) {
|
||||
public void setRawKeyPermissions(Permission rawKeyPermissions) {
|
||||
this.rawKeyPermissions = rawKeyPermissions;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,27 @@
|
||||
package me.minidigger.hangar.model.viewhelpers;
|
||||
|
||||
import me.minidigger.hangar.db.model.ApiKeysTable;
|
||||
import me.minidigger.hangar.model.NamedPermission;
|
||||
import me.minidigger.hangar.model.Permission;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class ApiKey {
|
||||
private ApiKeysTable key;
|
||||
|
||||
public ApiKey(ApiKeysTable key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public ApiKeysTable getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public boolean getIsSubKey(Permission perm) {
|
||||
return key.getRawKeyPermissions().has(perm);
|
||||
}
|
||||
|
||||
public Collection<NamedPermission> getNamedRawPermissions() {
|
||||
return key.getRawKeyPermissions().toNamed();
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package me.minidigger.hangar.service;
|
||||
|
||||
import me.minidigger.hangar.db.dao.ApiKeyDao;
|
||||
import me.minidigger.hangar.db.dao.HangarDao;
|
||||
import me.minidigger.hangar.db.model.ApiKeysTable;
|
||||
import me.minidigger.hangar.model.viewhelpers.ApiKey;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class ApiKeyService {
|
||||
|
||||
private final HangarDao<ApiKeyDao> apiKeyDao;
|
||||
|
||||
@Autowired
|
||||
public ApiKeyService(HangarDao<ApiKeyDao> apiKeyDao) {
|
||||
this.apiKeyDao = apiKeyDao;
|
||||
}
|
||||
|
||||
public List<ApiKey> getKeysForUser(long userId) {
|
||||
return apiKeyDao.get().getByOwner(userId).stream().map(ApiKey::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
@ -23,4 +23,12 @@ public class PermissionService {
|
||||
public Permission getGlobalPermission(String userName) {
|
||||
return permissionsDao.get().getGlobalPermission(null, userName);
|
||||
}
|
||||
|
||||
public Permission getPossibleProjectPermissions(long userId) {
|
||||
return permissionsDao.get().getPossibleProjectPermissions(userId);
|
||||
}
|
||||
|
||||
public Permission getPossibleOrganizationPermissions(long userId) {
|
||||
return permissionsDao.get().getPossibleOrganizationPermissions(userId);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import me.minidigger.hangar.model.viewhelpers.Organization;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
@ -28,6 +29,7 @@ import me.minidigger.hangar.model.viewhelpers.HeaderData;
|
||||
import me.minidigger.hangar.model.viewhelpers.Staff;
|
||||
import me.minidigger.hangar.model.viewhelpers.UserData;
|
||||
import me.minidigger.hangar.security.HangarAuthentication;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
@Service
|
||||
public class UserService {
|
||||
@ -125,7 +127,20 @@ public class UserService {
|
||||
}
|
||||
}
|
||||
|
||||
public void setLocked(String userName, boolean locked) {
|
||||
UsersTable user = userDao.get().getByName(userName);
|
||||
user.setIsLocked(locked);
|
||||
userDao.get().update(user);
|
||||
}
|
||||
|
||||
public UserData getUserData(String userName) {
|
||||
return getUserData(userDao.get().getByName(userName));
|
||||
}
|
||||
|
||||
public UserData getUserData(UsersTable user) {
|
||||
if (user == null) {
|
||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
// TODO getUserData
|
||||
boolean isOrga = false;
|
||||
int projectCount = projectDao.get().getProjectCountByUserId(user.getId());
|
||||
|
@ -1,16 +1,11 @@
|
||||
<#import "/spring.ftl" as spring />
|
||||
<#import "*/utils/hangar.ftlh" as hangar />
|
||||
<#import "*/users/view.ftlh" as user />
|
||||
|
||||
<#--@import controllers.sugar.Requests.OreRequest
|
||||
@import models.viewhelper.{OrganizationData, ScopedOrganizationData, UserData}
|
||||
@import ore.OreConfig
|
||||
@import ore.models.api.ApiKey
|
||||
@import ore.permission.NamedPermission
|
||||
@import views.html.helper.CSPNonce-->
|
||||
<#import "*/users/view.ftlh" as userView />
|
||||
|
||||
<#--@(u: UserData, o: Option[(OrganizationData, ScopedOrganizationData)], keys: Seq[ApiKey], perms: Seq[NamedPermission])(implicit messages: Messages, flash: Flash, request: OreRequest[_], config: OreConfig, assetsFinder: AssetsFinder)-->
|
||||
|
||||
<#-- @ftlvariable name="u" type="me.minidigger.hangar.model.viewhelpers.UserData" -->
|
||||
<#-- @ftlvariable name="keys" type="java.util.List<ApiKey>" -->
|
||||
<#-- @ftlvariable name="perms" type="java.util.Collection<NamedPermission>" -->
|
||||
<#assign scriptsVar>
|
||||
<script type="text/javascript" src="<@hangar.url "javascripts/apiKeysManagement.js" />"></script>
|
||||
<script <#--@CSPNonce.attr-->>
|
||||
@ -22,7 +17,8 @@
|
||||
</script>
|
||||
</#assign>
|
||||
|
||||
<@user.view u=u o=o additionalScripts=scriptsVar>
|
||||
<#assign NamedPermission=@helper["me.minidigger.hangar.model.NamedPermission"] />
|
||||
<@userView.view u=u o=o additionalScripts=scriptsVar>
|
||||
<div id="keyAlert" class="alert alert-danger" role="alert" style="display: none;"></div>
|
||||
|
||||
<div class="row">
|
||||
@ -30,24 +26,18 @@
|
||||
<h2><@spring.message "user.apiKeys.createNew" /></h2>
|
||||
<div id="api-create-key-form">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<#list perms.take(NamedPermission.values.length / 2) as perm>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" id="perm.${perm.entryName}"> ${perm.entryName}
|
||||
</label>
|
||||
</div>
|
||||
</#list>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<#list perms.drop(NamedPermission.values.length / 2) as perm>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" id="perm.${perm.entryName}"> ${perm.entryName}
|
||||
</label>
|
||||
</div>
|
||||
</#list>
|
||||
</div>
|
||||
<#list perms?chunk( (perms?size/2)?int ) as chunk>
|
||||
<div class="col-md-6">
|
||||
<#list chunk as perm>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" id="perm.${perm.name()}"> ${perm.name()}
|
||||
</label>
|
||||
</div>
|
||||
</#list>
|
||||
</div>
|
||||
</#list>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
@ -71,12 +61,13 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="api-key-rows">
|
||||
<#-- @ftlvariable name="key" type="me.minidigger.hangar.model.viewhelpers.ApiKey" -->
|
||||
<#list keys as key>
|
||||
<tr class="api-key-row">
|
||||
<th class="api-key-name">${key.name}</th>
|
||||
<th class="api-key-name">${key.key.name}</th>
|
||||
<th></th>
|
||||
<th>${key.tokenIdentifier}</th>
|
||||
<th>@key.namedRawPermissions.map(_.entryName).mkString(", ")</th>
|
||||
<th>${key.key.tokenIdentifier}</th>
|
||||
<th>${key.namedRawPermissions?map(np -> np.name())?join(", ")}</th>
|
||||
<th><button class="btn btn-danger api-key-row-delete-button"><@spring.message "user.apiKeys.keyDeleteButton" /></button></th>
|
||||
</tr>
|
||||
</#list>
|
||||
@ -84,4 +75,4 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</@user.view>
|
||||
</@userView.view>
|
||||
|
Loading…
Reference in New Issue
Block a user