preparing storing of new contact
This commit is contained in:
@@ -3,6 +3,7 @@ package de.srsoftware.umbrella.contact;
|
|||||||
|
|
||||||
import static de.srsoftware.tools.jdbc.Condition.equal;
|
import static de.srsoftware.tools.jdbc.Condition.equal;
|
||||||
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
|
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
|
||||||
|
import static de.srsoftware.tools.jdbc.Query.insertInto;
|
||||||
import static de.srsoftware.tools.jdbc.Query.select;
|
import static de.srsoftware.tools.jdbc.Query.select;
|
||||||
import static de.srsoftware.umbrella.contact.Constants.*;
|
import static de.srsoftware.umbrella.contact.Constants.*;
|
||||||
import static de.srsoftware.umbrella.core.Constants.*;
|
import static de.srsoftware.umbrella.core.Constants.*;
|
||||||
@@ -92,7 +93,16 @@ public class SqliteDb extends BaseDb implements ContactDb{
|
|||||||
@Override
|
@Override
|
||||||
public Contact save(Contact contact) {
|
public Contact save(Contact contact) {
|
||||||
if (contact.id() == 0){ // new contact
|
if (contact.id() == 0){ // new contact
|
||||||
throw UmbrellaException.unprocessable("Storing of new contacts not implemented");
|
try {
|
||||||
|
var rs = insertInto(TABLE_CONTACTS,DATA).values(contact.vcard()).execute(db).getGeneratedKeys();
|
||||||
|
Long id = null;
|
||||||
|
if (rs.next()) id = rs.getLong(1);
|
||||||
|
rs.close();
|
||||||
|
if (id != null) return new Contact(id,contact.vcard());
|
||||||
|
throw databaseException("Failed to store new vcard");
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw databaseException("Failed to store new vcard",e);
|
||||||
|
}
|
||||||
} else try { // update
|
} else try { // update
|
||||||
Query.update(TABLE_CONTACTS).set(DATA).where(ID,equal(contact.id())).prepare(db).apply(contact.vcard()).execute();
|
Query.update(TABLE_CONTACTS).set(DATA).where(ID,equal(contact.id())).prepare(db).apply(contact.vcard()).execute();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
|
|||||||
@@ -9,7 +9,9 @@
|
|||||||
import ExtraField from './ExtraField.svelte';
|
import ExtraField from './ExtraField.svelte';
|
||||||
import FN from './FN.svelte';
|
import FN from './FN.svelte';
|
||||||
import Name from './Name.svelte';
|
import Name from './Name.svelte';
|
||||||
|
import Number from './Number.svelte';
|
||||||
import Org from './Org.svelte';
|
import Org from './Org.svelte';
|
||||||
|
import URL from './URL.svelte';
|
||||||
|
|
||||||
let { contact } = $props();
|
let { contact } = $props();
|
||||||
|
|
||||||
@@ -18,7 +20,9 @@
|
|||||||
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 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));
|
||||||
|
|
||||||
async function patch(from,to){
|
async function patch(from,to){
|
||||||
if (from == to) return;
|
if (from == to) return;
|
||||||
@@ -44,7 +48,11 @@
|
|||||||
|
|
||||||
<fieldset class="vcard">
|
<fieldset class="vcard">
|
||||||
<legend>
|
<legend>
|
||||||
|
{#if contact.id}
|
||||||
{t('contact_number',{number:contact.id})}
|
{t('contact_number',{number:contact.id})}
|
||||||
|
{:else}
|
||||||
|
{t('new_contact')}
|
||||||
|
{/if}
|
||||||
<button class="symbol" onclick={toggleCode}></button>
|
<button class="symbol" onclick={toggleCode}></button>
|
||||||
</legend>
|
</legend>
|
||||||
<table>
|
<table>
|
||||||
@@ -81,6 +89,13 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{#each numbers as code}
|
||||||
|
<Number {code} {patch} />
|
||||||
|
{/each}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
{#each emails as code}
|
{#each emails as code}
|
||||||
@@ -95,6 +110,13 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{#each urls as code}
|
||||||
|
<URL {code} {patch} />
|
||||||
|
{/each}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@@ -15,6 +15,27 @@
|
|||||||
yikes();
|
yikes();
|
||||||
var data = await res.json();
|
var data = await res.json();
|
||||||
contacts = Object.values(data).sort(byName);
|
contacts = Object.values(data).sort(byName);
|
||||||
|
contacts.unshift({
|
||||||
|
id: 0,
|
||||||
|
vcard: `BEGIN:VCARD
|
||||||
|
VERSION:3.0
|
||||||
|
PRODID:Umbrella Contact manager by SRSoftware
|
||||||
|
FN:${t('formatted_name')}
|
||||||
|
N:${t('family_name')};${t('given_name')};;;
|
||||||
|
ORG:${t('organization')}
|
||||||
|
EMAIL;TYPE=HOME:${t('email')}
|
||||||
|
EMAIL;TYPE=WORK:${t('email')}
|
||||||
|
ADR;TYPE=HOME:;;${t('street')};${t('locality')};${t('region')};${t('post_code')};${t('country')}
|
||||||
|
ADR;TYPE=WORK:;;${t('street')};${t('locality')};${t('region')};${t('post_code')};${t('country')}
|
||||||
|
TEL;TYPE=CELL;:${t('phone_cell')}
|
||||||
|
TEL;TYPE=HOME;:${t('phone_home')}
|
||||||
|
TEL;TYPE=WORK;:${t('phone_work')}
|
||||||
|
X-TAX-NUMBER:${t('tax_id')}
|
||||||
|
X-BANK-ACCOUNT:${t('bank_account')}\\nIBAN:XXXX\\nBIC:XXXX
|
||||||
|
X-COURT:${t('local_court')}
|
||||||
|
URL:https://example.com
|
||||||
|
END:VCARD`
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
error(res);
|
error(res);
|
||||||
}
|
}
|
||||||
|
|||||||
43
frontend/src/routes/contact/Number.svelte
Normal file
43
frontend/src/routes/contact/Number.svelte
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<script>
|
||||||
|
import LineEditor from '../../Components/LineEditor.svelte';
|
||||||
|
import { number } from '../../vcard.js';
|
||||||
|
|
||||||
|
let { code, patch = (from, to) => true } = $props();
|
||||||
|
|
||||||
|
let cell = $derived(code.toLowerCase().includes('type=cell'));
|
||||||
|
let home = $derived(code.toLowerCase().includes('type=home'));
|
||||||
|
let work = $derived(code.toLowerCase().includes('type=work'));
|
||||||
|
let value = $derived(number(code));
|
||||||
|
|
||||||
|
function onSet(newVal){
|
||||||
|
const newCode = code.replace(value,newVal);
|
||||||
|
return patch(code,newCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleCell(){
|
||||||
|
toggleType('CELL');
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleHome(){
|
||||||
|
toggleType('HOME');
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleType(key){
|
||||||
|
key = key.toUpperCase();
|
||||||
|
if (code.toUpperCase().includes(';TYPE='+key)) {
|
||||||
|
const regex = new RegExp(';TYPE='+key, "ig");
|
||||||
|
patch(code,code.replace(regex,''));
|
||||||
|
} else patch(code,code.replace('TEL','TEL;TYPE='+key));
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleWork(){
|
||||||
|
toggleType('WORK');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if value}
|
||||||
|
<span class="symbol {cell?'':'inactive'}" onclick={toggleCell} ></span>
|
||||||
|
<span class="symbol {home?'':'inactive'}" onclick={toggleHome}></span>
|
||||||
|
<span class="symbol {work?'':'inactive'}" onclick={toggleWork} ></span>
|
||||||
|
<LineEditor type="span" editable={true} {value} {onSet} /><br/>
|
||||||
|
{/if}
|
||||||
18
frontend/src/routes/contact/URL.svelte
Normal file
18
frontend/src/routes/contact/URL.svelte
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<script>
|
||||||
|
import LineEditor from '../../Components/LineEditor.svelte';
|
||||||
|
import { url } from '../../vcard.js';
|
||||||
|
import { t } from '../../translations.svelte';
|
||||||
|
|
||||||
|
let { code, patch = (from, to) => true } = $props();
|
||||||
|
|
||||||
|
let value = $derived(url(code));
|
||||||
|
|
||||||
|
function onSet(newVal){
|
||||||
|
const newCode = code.replace(value,newVal);
|
||||||
|
return patch(code,newCode);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if value}
|
||||||
|
<LineEditor type="span" editable={true} {value} {onSet} title={t('url')}/>
|
||||||
|
{/if}
|
||||||
@@ -37,11 +37,22 @@ export function fn(vcard){
|
|||||||
return match ? match[1].trim() : '';
|
return match ? match[1].trim() : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function number(vcard){
|
||||||
|
const match = vcard.match(/^TEL.*:(.+)$/m);
|
||||||
|
return match ? match[1].trim() : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export function org(vcard){
|
export function org(vcard){
|
||||||
const match = vcard.match(/^ORG:(.+)$/m);
|
const match = vcard.match(/^ORG:(.+)$/m);
|
||||||
return match ? match[1].trim() : '';
|
return match ? match[1].trim() : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function url(vcard){
|
||||||
|
const match = vcard.match(/^URL:(.+)$/m);
|
||||||
|
return match ? match[1].trim() : '';
|
||||||
|
}
|
||||||
|
|
||||||
export function name(vcard){
|
export function name(vcard){
|
||||||
const match = vcard.match(/^N:(.+)$/m);
|
const match = vcard.match(/^N:(.+)$/m);
|
||||||
let name = {
|
let name = {
|
||||||
|
|||||||
@@ -91,6 +91,7 @@
|
|||||||
|
|
||||||
"failed": "fehlgeschlagen",
|
"failed": "fehlgeschlagen",
|
||||||
"failed_login_attempts" : "Account nach {attempts} fehlgeschlagenen Logins gesperrt bis {release_time}",
|
"failed_login_attempts" : "Account nach {attempts} fehlgeschlagenen Logins gesperrt bis {release_time}",
|
||||||
|
"family_name": "Familenname",
|
||||||
"file": "Datei",
|
"file": "Datei",
|
||||||
"files": "Dateien",
|
"files": "Dateien",
|
||||||
"filter": "Filter",
|
"filter": "Filter",
|
||||||
@@ -100,6 +101,7 @@
|
|||||||
"formatted_name": "Anzeigename",
|
"formatted_name": "Anzeigename",
|
||||||
"fulltext": "Volltextsuche",
|
"fulltext": "Volltextsuche",
|
||||||
|
|
||||||
|
"given_name": "Vorname",
|
||||||
"go": "los!",
|
"go": "los!",
|
||||||
"go_to_url_to_reset_password": "Um ein neues Passwort zu erhalten, öffnen Sie bitte den folgenden Link: {url}",
|
"go_to_url_to_reset_password": "Um ein neues Passwort zu erhalten, öffnen Sie bitte den folgenden Link: {url}",
|
||||||
"gross_sum": "Brutto-Summe",
|
"gross_sum": "Brutto-Summe",
|
||||||
@@ -167,6 +169,7 @@
|
|||||||
"name": "Name",
|
"name": "Name",
|
||||||
"net_price": "Nettopreis",
|
"net_price": "Nettopreis",
|
||||||
"net_sum": "Netto-Summe",
|
"net_sum": "Netto-Summe",
|
||||||
|
"new_contact": "neuer Kontakt",
|
||||||
"new_password": "neues Passwort",
|
"new_password": "neues Passwort",
|
||||||
"new_document_from": "{number} / neues {type}s-Dokument von {sender}",
|
"new_document_from": "{number} / neues {type}s-Dokument von {sender}",
|
||||||
"no_company": "keine Firma",
|
"no_company": "keine Firma",
|
||||||
|
|||||||
Reference in New Issue
Block a user