Browse Source

implemented storing of new vcards, editing of names

module/contact
Stephan Richter 4 weeks ago
parent
commit
e5227c3e19
  1. 3
      contact/src/main/java/de/srsoftware/umbrella/contact/ContactDb.java
  2. 31
      contact/src/main/java/de/srsoftware/umbrella/contact/ContactModule.java
  3. 9
      contact/src/main/java/de/srsoftware/umbrella/contact/SqliteDb.java
  4. 13
      frontend/src/routes/contact/Card.svelte
  5. 22
      frontend/src/routes/contact/Name.svelte

3
contact/src/main/java/de/srsoftware/umbrella/contact/ContactDb.java

@ -3,6 +3,7 @@ package de.srsoftware.umbrella.contact;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import de.srsoftware.umbrella.core.model.Contact; import de.srsoftware.umbrella.core.model.Contact;
import de.srsoftware.umbrella.core.model.UmbrellaUser;
import java.util.Map; import java.util.Map;
@ -12,4 +13,6 @@ public interface ContactDb {
Contact load(long id, long userId); Contact load(long id, long userId);
Contact save(Contact contact); Contact save(Contact contact);
void setOwner(long userId, Contact contact);
} }

31
contact/src/main/java/de/srsoftware/umbrella/contact/ContactModule.java

@ -69,11 +69,24 @@ public class ContactModule extends BaseHandler implements ContactService {
} }
} }
private boolean patchContact(long id, UmbrellaUser user, HttpExchange ex) throws IOException { @Override
var contact = contactDb.load(id, user.id()).patch(json(ex)); public boolean doPost(Path path, HttpExchange ex) throws IOException {
return sendContent(ex,contactDb.save(contact).toMap()); addCors(ex);
try {
Optional<Token> token = SessionToken.from(ex).map(Token::of);
var user = userService().loadUser(token);
if (user.isEmpty()) return unauthorized(ex);
var head = path.pop();
if (head == null) {
return postNewContact(user.get(),ex);
}
return super.doPatch(path,ex);
} catch (UmbrellaException e) {
return send(ex,e);
}
} }
private boolean getContacts(UmbrellaUser user, HttpExchange ex) throws IOException { private boolean getContacts(UmbrellaUser user, HttpExchange ex) throws IOException {
return sendContent(ex,mapValues(listContactsOf(user))); return sendContent(ex,mapValues(listContactsOf(user)));
} }
@ -82,4 +95,16 @@ public class ContactModule extends BaseHandler implements ContactService {
public Map<Long,Contact> listContactsOf(UmbrellaUser user) throws UmbrellaException { public Map<Long,Contact> listContactsOf(UmbrellaUser user) throws UmbrellaException {
return contactDb.listContactsOf(user.id()); return contactDb.listContactsOf(user.id());
} }
private boolean patchContact(long id, UmbrellaUser user, HttpExchange ex) throws IOException {
var contact = contactDb.load(id, user.id()).patch(json(ex));
return sendContent(ex,contactDb.save(contact));
}
private boolean postNewContact(UmbrellaUser user, HttpExchange ex) throws IOException {
var contact = new Contact(0,body(ex));
contact = contactDb.save(contact);
contactDb.setOwner(user.id(),contact);
return sendContent(ex,contact);
}
} }

9
contact/src/main/java/de/srsoftware/umbrella/contact/SqliteDb.java

@ -110,4 +110,13 @@ public class SqliteDb extends BaseDb implements ContactDb{
} }
return contact; return contact;
} }
@Override
public void setOwner(long userId, Contact contact) {
try {
Query.replaceInto(TABLE_CONTACTS_USERS,USER_ID,CONTACT_ID,ASSIGNED).values(userId,contact.id(),false).execute(db).close();
} catch (SQLException e) {
throw databaseException("Failed to assign contact {0} to user {1]",contact.id(),userId);
}
}
} }

13
frontend/src/routes/contact/Card.svelte

@ -20,17 +20,20 @@
let emails = $derived(contact.vcard.match(/^EMAIL.*:.+$/gm)); let emails = $derived(contact.vcard.match(/^EMAIL.*:.+$/gm));
let extra_fields = $derived(contact.vcard.match(/^X-.*:.+/gm)); let extra_fields = $derived(contact.vcard.match(/^X-.*:.+/gm));
let fns = $derived(contact.vcard.match(/^FN.*:.+$/gm)); let fns = $derived(contact.vcard.match(/^FN.*:.+$/gm));
let names = $derived(contact.vcard.match(/^N.*:.+$/gm));
let numbers = $derived(contact.vcard.match(/^TEL.*:.+$/gm)); let numbers = $derived(contact.vcard.match(/^TEL.*:.+$/gm));
let orgs = $derived(contact.vcard.match(/^ORG.*:.+$/gm)); let orgs = $derived(contact.vcard.match(/^ORG.*:.+$/gm));
let urls = $derived(contact.vcard.match(/^URL.*:.+$/gm)); let urls = $derived(contact.vcard.match(/^URL.*:.+$/gm));
async function patch(from,to){ async function patch(from,to){
if (from == to) return; if (from == to) return;
const url = api(`contact/${contact.id}`); const newContact = contact.id == 0;
const url = api(newContact ? 'contact' : `contact/${contact.id}`);
const changeset = JSON.stringify({ from: from, to: to });
const res = await fetch(url,{ const res = await fetch(url,{
method:'PATCH', method: newContact ? 'POST' : 'PATCH',
credentials:'include', credentials:'include',
body:JSON.stringify({from:from,to:to}) body: newContact ? contact.vcard.replace(from,to) : changeset
}); });
if (res.ok){ if (res.ok){
yikes(); yikes();
@ -79,7 +82,9 @@
</tr> </tr>
<tr> <tr>
<td> <td>
<Name vcard={contact.vcard} /> {#each names as code}
<Name {code} {patch} />
{/each}
</td> </td>
</tr> </tr>
<tr> <tr>

22
frontend/src/routes/contact/Name.svelte

@ -1,25 +1,33 @@
<script> <script>
import LineEditor from '../../Components/LineEditor.svelte';
import { name } from '../../vcard.js'; import { name } from '../../vcard.js';
import { t } from '../../translations.svelte';
let { vcard } = $props(); let { code, patch = (from, to) => true } = $props();
let n = $derived(name(vcard)); let n = $derived(name(code));
function onSet(oldVal,newVal){
console.log(`onset(${oldVal} → ${newVal})`);
const newCode = code.replace(oldVal,newVal);
return patch(code,newCode);
}
</script> </script>
<div class="name"> <div class="name">
{#if n.prefix} {#if n.prefix}
<span class="prefix">{n.prefix}</span> <LineEditor type="span" editable={true} value={n.prefix} onSet={newVal => onSet(n.prefix,newVal)} title={t('name_prefix')} />
{/if} {/if}
{#if n.given} {#if n.given}
<span class="given">{n.given}</span> <LineEditor type="span" editable={true} value={n.given} onSet={newVal => onSet(n.given,newVal)} title={t('given_name')} />
{/if} {/if}
{#if n.additional} {#if n.additional}
<span class="additional">{n.additional}</span> <LineEditor type="span" editable={true} value={n.additional} onSet={newVal => onSet(n.additional,newVal)} title={t('additional_name')} />
{/if} {/if}
{#if n.family} {#if n.family}
<span class="family">{n.family}</span> <LineEditor type="span" editable={true} value={n.family} onSet={newVal => onSet(n.family,newVal)} title={t('family_name')} />
{/if} {/if}
{#if n.suffix} {#if n.suffix}
<span class="suffix">{n.suffix}</span> <LineEditor type="span" editable={true} value={n.suffix} onSet={newVal => onSet(n.suffix,newVal)} title={t('<name_suffix></name_suffix>')} />
{/if} {/if}
</div> </div>
Loading…
Cancel
Save