working on Autocomplete field for member addition to projects
This commit is contained in:
@@ -16,5 +16,4 @@ public interface ProjectService {
|
||||
loadMembers(List.of(project));
|
||||
return project;
|
||||
}
|
||||
Map<Long, Map<String,Object>> mapProjects(Map<Long, Project> projects);
|
||||
}
|
||||
|
||||
47
frontend/src/Components/Autocomplete.svelte
Normal file
47
frontend/src/Components/Autocomplete.svelte
Normal file
@@ -0,0 +1,47 @@
|
||||
<script>
|
||||
import { t } from '../translations.svelte.js'
|
||||
import { tick } from "svelte";
|
||||
|
||||
let { getOptionsFor = text => [], onSelect = text => [] } = $props();
|
||||
|
||||
let text = $state('')
|
||||
let options = $state([]);
|
||||
|
||||
async function onkeyup(evt){
|
||||
var select = evt.target;
|
||||
var key = evt.key;
|
||||
var ignore = ['Escape','Tab','ArrowUp','ArrowLeft','ArrowRight']
|
||||
if (ignore.includes(key)) return;
|
||||
if (key == 'ArrowDown'){
|
||||
if (select.selectedIndex == 0) select.selectedIndex=1;
|
||||
return;
|
||||
}
|
||||
if (key == 'Enter'){
|
||||
text = select.value;
|
||||
onSelect(text);
|
||||
options=[];
|
||||
return;
|
||||
}
|
||||
if (key == 'Backspace'){
|
||||
text = text.substring(0,text.length-1)
|
||||
} else if (key.length<2){
|
||||
text += evt.key
|
||||
}
|
||||
options = await getOptionsFor(text);
|
||||
await tick();
|
||||
for (let o of select.getElementsByTagName('option')) o.selected = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
select{
|
||||
min-width: 200px;
|
||||
}
|
||||
</style>
|
||||
<select size={options.length<2?2:options.length+1} {onkeyup} autofocus width="40">
|
||||
<option>{text}</option>
|
||||
{#each options as option,i}
|
||||
<option>{option}</option>
|
||||
{/each}
|
||||
</select>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { t } from '../translations.svelte.js';
|
||||
import Autocomplete from './Autocomplete.svelte';
|
||||
import PermissionSelector from './PermissionSelector.svelte';
|
||||
let { members, updatePermission = (uid,perm) => console.log({user:uid,perm:perm}) } = $props();
|
||||
let error = $state(null);
|
||||
@@ -18,6 +19,32 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function getOptionsFor(text){
|
||||
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/search`;
|
||||
var resp = await fetch(url,{
|
||||
credentials: 'include',
|
||||
method: 'POST',
|
||||
body: text
|
||||
});
|
||||
if (resp.ok){
|
||||
var json = await resp.json();
|
||||
if (Array.isArray(json)) return json;
|
||||
if (typeof json == 'object'){
|
||||
let names = Object.values(json).map(user => user.name);
|
||||
if (names.length > 10) names.length = 10;
|
||||
return names;
|
||||
}
|
||||
console.warn('not an array:',json);
|
||||
return [];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function onSelect(name){
|
||||
console.log({selected_user:name})
|
||||
}
|
||||
|
||||
onMount(loadPermissions);
|
||||
|
||||
</script>
|
||||
@@ -41,7 +68,9 @@
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>{t('add_member')}</td>
|
||||
<td><input type="text" /></td>
|
||||
<td>
|
||||
<Autocomplete {getOptionsFor} {onSelect} />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -4,6 +4,7 @@ package de.srsoftware.umbrella.project;
|
||||
import static de.srsoftware.umbrella.core.ConnectionProvider.connect;
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
import static de.srsoftware.umbrella.core.Paths.LIST;
|
||||
import static de.srsoftware.umbrella.core.Util.mapValues;
|
||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*;
|
||||
import static de.srsoftware.umbrella.core.model.Permission.EDIT;
|
||||
import static de.srsoftware.umbrella.core.model.Permission.OWNER;
|
||||
@@ -14,6 +15,7 @@ import static java.net.HttpURLConnection.HTTP_OK;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import de.srsoftware.configuration.Configuration;
|
||||
import de.srsoftware.tools.Mappable;
|
||||
import de.srsoftware.tools.Path;
|
||||
import de.srsoftware.tools.SessionToken;
|
||||
import de.srsoftware.umbrella.core.BaseHandler;
|
||||
@@ -130,7 +132,7 @@ public class ProjectModule extends BaseHandler implements ProjectService {
|
||||
var company = companies.get(companyId);
|
||||
if (!companies.membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name());
|
||||
var projects = listCompanyProjects(companyId,false);
|
||||
return sendContent(ex,mapProjects(projects));
|
||||
return sendContent(ex,mapValues(projects));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -142,7 +144,7 @@ public class ProjectModule extends BaseHandler implements ProjectService {
|
||||
|
||||
private boolean listUserProjects(HttpExchange ex, UmbrellaUser user, boolean showClosed) throws IOException, UmbrellaException {
|
||||
var projects = listUserProjects(user.id(),showClosed);
|
||||
return sendContent(ex,mapProjects(projects));
|
||||
return sendContent(ex,mapValues(projects));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -159,12 +161,6 @@ public class ProjectModule extends BaseHandler implements ProjectService {
|
||||
return projectList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, Map<String, Object>> mapProjects(Map<Long, Project> projects) {
|
||||
var mapped = new HashMap<Long,Map<String,Object>>();
|
||||
for (var entry : projects.entrySet()) mapped.put(entry.getKey(),entry.getValue().toMap());
|
||||
return mapped;
|
||||
}
|
||||
|
||||
private void patchMembers(Project project, JSONObject json) {
|
||||
var members = project.members();
|
||||
|
||||
@@ -7,12 +7,11 @@ import static de.srsoftware.tools.Strings.uuid;
|
||||
import static de.srsoftware.umbrella.core.ConnectionProvider.connect;
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
import static de.srsoftware.umbrella.core.Constants.CODE;
|
||||
import static de.srsoftware.umbrella.core.Paths.LIST;
|
||||
import static de.srsoftware.umbrella.core.Paths.LOGOUT;
|
||||
import static de.srsoftware.umbrella.core.Constants.TOKEN;
|
||||
import static de.srsoftware.umbrella.core.Paths.*;
|
||||
import static de.srsoftware.umbrella.core.ResponseCode.*;
|
||||
import static de.srsoftware.umbrella.core.ResponseCode.HTTP_SERVER_ERROR;
|
||||
import static de.srsoftware.umbrella.core.Util.open;
|
||||
import static de.srsoftware.umbrella.core.Util.request;
|
||||
import static de.srsoftware.umbrella.core.Util.*;
|
||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*;
|
||||
import static de.srsoftware.umbrella.user.Constants.*;
|
||||
import static de.srsoftware.umbrella.user.Paths.*;
|
||||
@@ -257,6 +256,7 @@ public class UserModule extends BaseHandler implements UserService {
|
||||
case OIDC -> postOIDC(ex, path);
|
||||
case IMPERSONATE -> impersonate(ex, targetId);
|
||||
case LOGIN -> postLogin(ex);
|
||||
case SEARCH -> postSearch(ex);
|
||||
case RESET_PW -> postResetPassword(ex);
|
||||
case null, default -> super.doPost(path,ex);
|
||||
};
|
||||
@@ -449,6 +449,17 @@ public class UserModule extends BaseHandler implements UserService {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean patchService(HttpExchange ex, String serviceName, UmbrellaUser requestingUser) throws IOException, UmbrellaException {
|
||||
if (!(requestingUser instanceof DbUser user && user.permissions().contains(MANAGE_LOGIN_SERVICES))) throw forbidden("You are not allowed to manage that service!");
|
||||
var json = json(ex);
|
||||
if (!json.has(NAME) || !(json.get(NAME) instanceof String name) || name.isBlank()) throw missingFieldException(NAME);
|
||||
if (!json.has(URL) || !(json.get(URL) instanceof String url) || url.isBlank()) throw missingFieldException(URL);
|
||||
if (!json.has(CLIENT_ID) || !(json.get(CLIENT_ID) instanceof String clientId) || clientId.isBlank()) throw missingFieldException(CLIENT_ID);
|
||||
if (!json.has(CLIENT_SECRET) || !(json.get(CLIENT_SECRET) instanceof String secret) || secret.isBlank()) throw missingFieldException(CLIENT_SECRET);
|
||||
var service = logins.save(new LoginService(name,url,clientId,secret, DEFAULT_FIELD));
|
||||
return sendContent(ex,service.toMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PostBox postBox() {
|
||||
return messages;
|
||||
@@ -496,17 +507,6 @@ public class UserModule extends BaseHandler implements UserService {
|
||||
return ok(ex);
|
||||
}
|
||||
|
||||
private boolean patchService(HttpExchange ex, String serviceName, UmbrellaUser requestingUser) throws IOException, UmbrellaException {
|
||||
if (!(requestingUser instanceof DbUser user && user.permissions().contains(MANAGE_LOGIN_SERVICES))) throw forbidden("You are not allowed to manage that service!");
|
||||
var json = json(ex);
|
||||
if (!json.has(NAME) || !(json.get(NAME) instanceof String name) || name.isBlank()) throw missingFieldException(NAME);
|
||||
if (!json.has(URL) || !(json.get(URL) instanceof String url) || url.isBlank()) throw missingFieldException(URL);
|
||||
if (!json.has(CLIENT_ID) || !(json.get(CLIENT_ID) instanceof String clientId) || clientId.isBlank()) throw missingFieldException(CLIENT_ID);
|
||||
if (!json.has(CLIENT_SECRET) || !(json.get(CLIENT_SECRET) instanceof String secret) || secret.isBlank()) throw missingFieldException(CLIENT_SECRET);
|
||||
var service = logins.save(new LoginService(name,url,clientId,secret, DEFAULT_FIELD));
|
||||
return sendContent(ex,service.toMap());
|
||||
}
|
||||
|
||||
private boolean postLogin(HttpExchange ex) throws IOException {
|
||||
var json = json(ex);
|
||||
if (!(json.has(USERNAME) && json.get(USERNAME) instanceof String username)) return sendContent(ex, HTTP_UNPROCESSABLE,"Username missing");
|
||||
@@ -522,7 +522,12 @@ public class UserModule extends BaseHandler implements UserService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean postSearch(HttpExchange ex) throws IOException {
|
||||
var requestingUser = loadUser(ex);
|
||||
if (!(requestingUser.isPresent() && requestingUser.get() instanceof DbUser dbUser)) return unauthorized(ex);
|
||||
var key = body(ex);
|
||||
return sendContent(ex,mapValues(users.search(key)));
|
||||
}
|
||||
|
||||
static int score(String password){
|
||||
if (password == null) return 0;
|
||||
|
||||
@@ -17,6 +17,8 @@ public interface UserDb {
|
||||
|
||||
Boolean dropSession(Token token) throws UmbrellaException;
|
||||
|
||||
Session extend(Session session) throws UmbrellaException;
|
||||
|
||||
/**
|
||||
* Get a session for the provided user.
|
||||
* @param user
|
||||
@@ -24,8 +26,6 @@ public interface UserDb {
|
||||
*/
|
||||
Session getSession(UmbrellaUser user) throws UmbrellaException;
|
||||
|
||||
Session extend(Session session) throws UmbrellaException;
|
||||
|
||||
Map<Long, UmbrellaUser> list(Integer start, Integer limit, Collection<Long> ids) throws UmbrellaException;
|
||||
|
||||
Session load(Token token) throws UmbrellaException;
|
||||
@@ -39,4 +39,6 @@ public interface UserDb {
|
||||
UmbrellaUser load(String key, Password password) throws UmbrellaException;
|
||||
|
||||
UmbrellaUser save(DbUser user) throws UmbrellaException;
|
||||
|
||||
Map<Long,DbUser> search(String key);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import static de.srsoftware.tools.jdbc.Condition.*;
|
||||
import static de.srsoftware.tools.jdbc.Query.*;
|
||||
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
import static de.srsoftware.umbrella.core.ResponseCode.HTTP_SERVER_ERROR;
|
||||
import static de.srsoftware.umbrella.user.Constants.*;
|
||||
import static de.srsoftware.umbrella.user.model.DbUser.ADMIN_PERMISSIONS;
|
||||
import static java.lang.System.Logger.Level.*;
|
||||
@@ -499,6 +500,22 @@ CREATE TABLE IF NOT EXISTS {0} (
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, DbUser> search(String key) {
|
||||
try {
|
||||
var rs = select(ALL).from(TABLE_USERS).where(LOGIN,like("%"+key+"%")).exec(db);
|
||||
var users = new HashMap<Long,DbUser>();
|
||||
while (rs.next()){
|
||||
var user = toUser(rs);
|
||||
users.put(user.id(),user);
|
||||
}
|
||||
rs.close();
|
||||
return users;
|
||||
} catch (SQLException e){
|
||||
throw new UmbrellaException(HTTP_SERVER_ERROR,"Failed to search for user by key = {0}",key);
|
||||
}
|
||||
}
|
||||
|
||||
public Instant then(){
|
||||
return LocalDateTime.now().plus(DEFAULT_SESSION_DURATION).toInstant(ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user