Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 38430feca0 | |||
| 73f74a0929 | |||
| 0a3f33c70d | |||
| e7c8039249 | |||
| cc0dd85814 | |||
| 33bff55811 | |||
| 182060134e | |||
| 64be02d863 | |||
| 70ea315fa7 | |||
| 889599dc40 | |||
| ac0b61dca0 | |||
| 07492d34de | |||
| 9e4158ad19 | |||
| b81d518a2b | |||
| e17fdbc619 | |||
| 433ea6ddd3 | |||
| 6249cdb7b9 |
@@ -16,7 +16,7 @@ public interface AccountDb {
|
|||||||
|
|
||||||
Collection<UmbrellaUser> getMembers(long accountId);
|
Collection<UmbrellaUser> getMembers(long accountId);
|
||||||
|
|
||||||
Optional<Transaction> lastTransaction(long accountId, String source, String dest, double amount);
|
Optional<Transaction> lastTransaction(long accountId, String source, String destination, Double amount);
|
||||||
|
|
||||||
Collection<Account> listAccounts(long userId);
|
Collection<Account> listAccounts(long userId);
|
||||||
|
|
||||||
|
|||||||
@@ -311,12 +311,11 @@ public class AccountingModule extends BaseHandler implements AccountingService {
|
|||||||
var source = src.get(src.has(Field.ID) ? Field.ID : Field.DISPLAY).toString();
|
var source = src.get(src.has(Field.ID) ? Field.ID : Field.DISPLAY).toString();
|
||||||
if (!json.has(Field.DESTINATION)) throw missingField(Field.DESTINATION);
|
if (!json.has(Field.DESTINATION)) throw missingField(Field.DESTINATION);
|
||||||
if (!(json.get(Field.DESTINATION) instanceof JSONObject dst)) throw invalidField(Field.SOURCE,JSON);
|
if (!(json.get(Field.DESTINATION) instanceof JSONObject dst)) throw invalidField(Field.SOURCE,JSON);
|
||||||
var dest = dst.get(dst.has(Field.ID) ? Field.ID : Field.DISPLAY).toString();
|
String destination = dst.has(Field.ID) ? dst.get(Field.ID).toString() : dst.has(Field.DISPLAY) ? dst.get(Field.DISPLAY).toString() : null;
|
||||||
if (!json.has(Field.AMOUNT)) throw missingField(Field.AMOUNT);
|
Double amount = null;
|
||||||
if (!(json.get(Field.AMOUNT) instanceof Number amt)) throw invalidField(Field.AMOUNT,Text.NUMBER);
|
if (json.has(Field.AMOUNT) && json.get(Field.AMOUNT) instanceof Number amt) amount = amt.doubleValue();
|
||||||
var amount = amt.doubleValue();
|
|
||||||
|
|
||||||
var transaction = accountDb.lastTransaction(accountId, source, dest, amount);
|
var transaction = accountDb.lastTransaction(accountId, source, destination, amount);
|
||||||
return transaction.isPresent() ? sendContent(ex,transaction.get()) : notFound(ex);
|
return transaction.isPresent() ? sendContent(ex,transaction.get()) : notFound(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -170,22 +170,42 @@ public class SqliteDb extends BaseDb implements AccountDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Transaction> lastTransaction(long accountId, String source, String dest, double amount) {
|
public Optional<Transaction> lastTransaction(long accountId, String source, String destination, Double amount) {
|
||||||
try {
|
try {
|
||||||
var rs = select(ALL).from(TABLE_TRANSACTIONS)
|
var query = select(ALL).from(TABLE_TRANSACTIONS).where(ACCOUNT,equal(accountId));
|
||||||
.where(ACCOUNT,equal(accountId)).where(SOURCE,equal(source)).where(DESTINATION,equal(dest)).where(AMOUNT,equal(amount))
|
if (source != null) query = query.where(SOURCE,equal(source));
|
||||||
.sort(ID+" DESC")
|
if (destination != null) query = query.where(DESTINATION,equal(destination));
|
||||||
.limit(1)
|
if (amount != null) query = query.where(AMOUNT,equal(amount));
|
||||||
.exec(db);
|
var rs = query.sort(ID+" DESC").limit(1).exec(db);
|
||||||
Transaction ta = null;
|
Transaction ta = null;
|
||||||
if (rs.next()) ta = Transaction.of(rs);
|
if (rs.next()) ta = Transaction.of(rs);
|
||||||
rs.close();
|
rs.close();
|
||||||
|
|
||||||
|
if (ta == null && amount != null) { // try to search by amount, ignore source and dest
|
||||||
|
rs = select(ALL).from(TABLE_TRANSACTIONS).where(ACCOUNT, equal(accountId)).where(AMOUNT, equal(amount))
|
||||||
|
.sort(ID + " DESC").limit(1).exec(db);
|
||||||
|
if (rs.next()) ta = Transaction.of(rs);
|
||||||
|
rs.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ta == null && source != null && destination != null) { // try to search by amount, ignore source and dest
|
||||||
|
rs = select(ALL).from(TABLE_TRANSACTIONS)
|
||||||
|
.where(SOURCE,equal(source))
|
||||||
|
.where(DESTINATION,equal(destination))
|
||||||
|
.where(ACCOUNT, equal(accountId))
|
||||||
|
.sort(ID + " DESC").limit(1).exec(db);
|
||||||
|
if (rs.next()) ta = Transaction.of(rs);
|
||||||
|
rs.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (ta != null){
|
if (ta != null){
|
||||||
var tags = ta.tags();
|
var tags = ta.tags();
|
||||||
rs = select(TAG).from(TABLE_TAGS_TRANSACTIONS).leftJoin(TAG_ID,TABLE_TAGS,ID).where(TRANSACTION_ID,equal(ta.id())).exec(db);
|
rs = select(TAG).from(TABLE_TAGS_TRANSACTIONS).leftJoin(TAG_ID,TABLE_TAGS,ID).where(TRANSACTION_ID,equal(ta.id())).exec(db);
|
||||||
while (rs.next()) tags.add(rs.getString(1));
|
while (rs.next()) tags.add(rs.getString(1));
|
||||||
rs.close();
|
rs.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullable(ta);
|
return nullable(ta);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw failedToSearchDb(t(Text.ACCOUNTING));
|
throw failedToSearchDb(t(Text.ACCOUNTING));
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import de.srsoftware.umbrella.bookmarks.BookmarkApi;
|
|||||||
import de.srsoftware.umbrella.company.CompanyModule;
|
import de.srsoftware.umbrella.company.CompanyModule;
|
||||||
import de.srsoftware.umbrella.contact.ContactModule;
|
import de.srsoftware.umbrella.contact.ContactModule;
|
||||||
import de.srsoftware.umbrella.core.SettingsService;
|
import de.srsoftware.umbrella.core.SettingsService;
|
||||||
import de.srsoftware.umbrella.core.Util;
|
|
||||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||||
import de.srsoftware.umbrella.documents.DocumentApi;
|
import de.srsoftware.umbrella.documents.DocumentApi;
|
||||||
import de.srsoftware.umbrella.files.FileModule;
|
import de.srsoftware.umbrella.files.FileModule;
|
||||||
@@ -34,7 +33,6 @@ import de.srsoftware.umbrella.translations.Translations;
|
|||||||
import de.srsoftware.umbrella.user.UserModule;
|
import de.srsoftware.umbrella.user.UserModule;
|
||||||
import de.srsoftware.umbrella.web.WebHandler;
|
import de.srsoftware.umbrella.web.WebHandler;
|
||||||
import de.srsoftware.umbrella.wiki.WikiModule;
|
import de.srsoftware.umbrella.wiki.WikiModule;
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import static java.lang.System.Logger.Level.*;
|
|||||||
import static java.lang.System.Logger.Level.WARNING;
|
import static java.lang.System.Logger.Level.WARNING;
|
||||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
|
||||||
import com.xrbpowered.jparsedown.JParsedown;
|
|
||||||
import de.srsoftware.tools.Mappable;
|
import de.srsoftware.tools.Mappable;
|
||||||
import de.srsoftware.tools.Query;
|
import de.srsoftware.tools.Query;
|
||||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||||
@@ -32,7 +31,6 @@ import java.time.LocalDateTime;
|
|||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
public class Util {
|
public class Util {
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
*.db-journal
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
"umbrella": {
|
||||||
|
"base_url": "http://127.0.0.1:5173",
|
||||||
|
"logging": {
|
||||||
|
"rootLevel": "INFO"
|
||||||
|
},
|
||||||
|
"http": {
|
||||||
|
"port": 8080
|
||||||
|
},
|
||||||
|
"threads": 16,
|
||||||
|
"modules": {
|
||||||
|
"accounting": {
|
||||||
|
"database": "demodata/accounting.db"
|
||||||
|
},
|
||||||
|
"bookmark": {
|
||||||
|
"database": "demodata/bookmark.db"
|
||||||
|
},
|
||||||
|
"company": {
|
||||||
|
"database": "demodata/company.db"
|
||||||
|
},
|
||||||
|
"contact": {
|
||||||
|
"database": "demodata/contacts.db"
|
||||||
|
},
|
||||||
|
"document": {
|
||||||
|
"database": "demodata/documents.db",
|
||||||
|
"templates": "demodata/templates"
|
||||||
|
},
|
||||||
|
"files": {
|
||||||
|
"database": "demodata/files.db",
|
||||||
|
"base_dir": "demodata/filestore"
|
||||||
|
},
|
||||||
|
"journal": {
|
||||||
|
"database": "demodata/journal.db"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"database": "demodata/message.db",
|
||||||
|
"smtp": {
|
||||||
|
"from": "umbrella@example.com",
|
||||||
|
"host": "none",
|
||||||
|
"pass": "none",
|
||||||
|
"port": 587,
|
||||||
|
"user": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notes": {
|
||||||
|
"database": "demodata/notes.db"
|
||||||
|
},
|
||||||
|
"poll": {
|
||||||
|
"database": "demodata/poll.db"
|
||||||
|
},
|
||||||
|
"project": {
|
||||||
|
"database": "demodata/projects.db"
|
||||||
|
},
|
||||||
|
"stock": {
|
||||||
|
"database": "demodata/stock.db"
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"database": "demodata/tags.db"
|
||||||
|
},
|
||||||
|
"task": {
|
||||||
|
"database": "demodata/tasks.db"
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"database": "demodata/times.db"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"database": "demodata/users.db"
|
||||||
|
},
|
||||||
|
"wiki": {
|
||||||
|
"database": "demodata/wiki.db"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -115,7 +115,7 @@
|
|||||||
|
|
||||||
function select(index){
|
function select(index){
|
||||||
candidate = candidates[index];
|
candidate = candidates[index];
|
||||||
disableDropdown();
|
<disableDropdown></disableDropdown>();
|
||||||
onSelect(candidate);
|
onSelect(candidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
import { error, yikes } from '../../warn.svelte';
|
import { error, yikes } from '../../warn.svelte';
|
||||||
import { t } from '../../translations.svelte';
|
import { t } from '../../translations.svelte';
|
||||||
|
|
||||||
import EntryForm from './add_entry.svelte';
|
import EntryForm from './add_entry_new.svelte';
|
||||||
import Transaction from './transaction.svelte';
|
import Transaction from './transaction.svelte';
|
||||||
|
|
||||||
let { id } = $props();
|
let { id } = $props();
|
||||||
@@ -163,5 +163,5 @@
|
|||||||
</table>
|
</table>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<EntryForm {account} {onSave} />
|
<EntryForm {account} {onSave} {users} />
|
||||||
{/if}
|
{/if}
|
||||||
@@ -0,0 +1,205 @@
|
|||||||
|
<script>
|
||||||
|
import { useTinyRouter } from 'svelte-tiny-router';
|
||||||
|
|
||||||
|
import { t } from '../../translations.svelte';
|
||||||
|
import { api, post } from '../../urls.svelte';
|
||||||
|
import { error, yikes } from '../../warn.svelte';
|
||||||
|
import { user } from '../../user.svelte';
|
||||||
|
import Autocomplete from '../../Components/Autocomplete.svelte';
|
||||||
|
import Tags from '../tags/TagList.svelte';
|
||||||
|
|
||||||
|
let defaultAccount = {
|
||||||
|
id : 0,
|
||||||
|
name : '',
|
||||||
|
currency : ''
|
||||||
|
};
|
||||||
|
let { account = defaultAccount, new_account = false, onSave = () => {}, users } = $props();
|
||||||
|
|
||||||
|
let entry = $state({
|
||||||
|
account,
|
||||||
|
date : new Date().toISOString().substring(0, 10),
|
||||||
|
source : {
|
||||||
|
display: user.name,
|
||||||
|
id: user.id
|
||||||
|
},
|
||||||
|
destination : {},
|
||||||
|
amount : 0.0,
|
||||||
|
purpose : {},
|
||||||
|
tags : []
|
||||||
|
});
|
||||||
|
let router = useTinyRouter();
|
||||||
|
|
||||||
|
async function dst_selected(destination){
|
||||||
|
destination = JSON.parse(JSON.stringify(destination));
|
||||||
|
let source = JSON.parse(JSON.stringify(entry.source));
|
||||||
|
const url = api(`accounting/${entry.account.id}/tags`)
|
||||||
|
const res = await post(url,{source,destination});
|
||||||
|
if (res.ok) {
|
||||||
|
yikes();
|
||||||
|
const json = await res.json();
|
||||||
|
await proposePurpose();
|
||||||
|
entry.tags = json;
|
||||||
|
} else error(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
function focusOnEnter(ev,id){
|
||||||
|
if (ev.key == 'Enter') {
|
||||||
|
proposePurpose();
|
||||||
|
document.getElementById(id).focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAccountTags(text){
|
||||||
|
if (!text) return [];
|
||||||
|
const url = api(`accounting/${entry.account.id}/tags`)
|
||||||
|
return await getProposals(text,url);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getDestinations(text){
|
||||||
|
const url = api('accounting/destinations');
|
||||||
|
return await getProposals(text,url);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getProposals(text,url){
|
||||||
|
const res = await post(url,text);
|
||||||
|
if (res.ok){
|
||||||
|
yikes();
|
||||||
|
const input = await res.json();
|
||||||
|
return Object.values(input).map(mapDisplay);
|
||||||
|
} else {
|
||||||
|
error(res);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function getPurposes(text) {
|
||||||
|
const url = api('accounting/purposes');
|
||||||
|
return await getProposals(text,url);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getSources(text){
|
||||||
|
const url = api('accounting/sources');
|
||||||
|
return await getProposals(text,url);
|
||||||
|
}
|
||||||
|
|
||||||
|
function gotoTags(purpose){
|
||||||
|
document.getElementById('new_tag_input');
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapDisplay(object){
|
||||||
|
if (object.display){
|
||||||
|
return object;
|
||||||
|
} else if (object.name) {
|
||||||
|
return {...object, display: object.name};
|
||||||
|
} else {
|
||||||
|
return { display : object }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function proposePurpose(){
|
||||||
|
console.log('proposePurpose()');
|
||||||
|
const amount = entry.amount;
|
||||||
|
const source = entry.source;
|
||||||
|
const destination = entry.destination;
|
||||||
|
const url = api(`accounting/${account.id}/purposes`);
|
||||||
|
const res = await post(url,{source,destination,amount});
|
||||||
|
if (res.ok) {
|
||||||
|
yikes();
|
||||||
|
var lastTransaction = await res.json();
|
||||||
|
console.log({lastTransaction,users:JSON.parse(JSON.stringify(users))});
|
||||||
|
entry.purpose = { display: lastTransaction.purpose};
|
||||||
|
entry.tags = lastTransaction.tags;
|
||||||
|
if (lastTransaction.source.value){
|
||||||
|
if (users[lastTransaction.source.value]){
|
||||||
|
let user = users[lastTransaction.source.value];
|
||||||
|
entry.source = { id : +lastTransaction.source.value, display : user.name };
|
||||||
|
} else entry.source = { display: lastTransaction.source.value };
|
||||||
|
}
|
||||||
|
if (lastTransaction.destination.value){
|
||||||
|
if (users[lastTransaction.destination.value]){
|
||||||
|
let user = users[lastTransaction.destination.value];
|
||||||
|
entry.destination = { id : +lastTransaction.destination.value, display : user.name };
|
||||||
|
} else entry.destination = { display: lastTransaction.destination.value };
|
||||||
|
}
|
||||||
|
} else error(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function save(){
|
||||||
|
let data = {
|
||||||
|
...entry,
|
||||||
|
purpose: entry.purpose.display
|
||||||
|
}
|
||||||
|
let url = api('accounting');
|
||||||
|
let res = await post(url, data);
|
||||||
|
if (res.ok) {
|
||||||
|
yikes();
|
||||||
|
if (new_account){
|
||||||
|
router.navigate('/accounting');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//entry.tags = [];
|
||||||
|
onSave();
|
||||||
|
document.getElementById('date-input').focus();
|
||||||
|
} else error(res);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
hr{
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
border: 0;
|
||||||
|
height: 1px;
|
||||||
|
align-self: center;
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<fieldset class="grid2 new_transaction">
|
||||||
|
{#if new_account}
|
||||||
|
<legend>{t('create_new_object',{object:t('account')})}</legend>
|
||||||
|
<span style="display:none"></span>
|
||||||
|
<span>{t('account name')}</span>
|
||||||
|
<span>
|
||||||
|
<input type="text" bind:value={entry.account.name} />
|
||||||
|
</span>
|
||||||
|
<span>{t('currency')}</span>
|
||||||
|
<span>
|
||||||
|
<input type="text" bind:value={entry.account.currency} />
|
||||||
|
</span>
|
||||||
|
<hr/>
|
||||||
|
<span style="grid-column-end: span 2">{t('first transaction')}</span>
|
||||||
|
{:else}
|
||||||
|
<legend>{t('add_object',{object:t('transaction')})}</legend>
|
||||||
|
<span style="display:none"></span>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<span>{t('date')}</span>
|
||||||
|
<span>
|
||||||
|
<input type="date" bind:value={entry.date} id="date-input" />
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span>{t('amount')}</span>
|
||||||
|
<span>
|
||||||
|
<input type="number" bind:value={entry.amount} onkeyup={e => focusOnEnter(e,'source-input')} /> {entry.account.currency}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span>{t('source')}</span>
|
||||||
|
<Autocomplete bind:candidate={entry.source} getCandidates={getSources} id="source-input" />
|
||||||
|
|
||||||
|
<span>{t('destination')}</span>
|
||||||
|
<Autocomplete bind:candidate={entry.destination} getCandidates={getDestinations} onSelect={dst_selected} />
|
||||||
|
|
||||||
|
|
||||||
|
<span>{t('purpose')}</span>
|
||||||
|
<Autocomplete bind:candidate={entry.purpose} getCandidates={getPurposes} onCommit={gotoTags} id="purpose_input" />
|
||||||
|
|
||||||
|
<span>{t('tags')}</span>
|
||||||
|
<Tags getCandidates={getAccountTags} module={null} bind:tags={entry.tags} onEmptyCommit={save} />
|
||||||
|
|
||||||
|
<span></span>
|
||||||
|
<span>
|
||||||
|
<button onclick={save}>{t('save')}</button>
|
||||||
|
</span>
|
||||||
|
</fieldset>
|
||||||
@@ -13,8 +13,6 @@ import de.srsoftware.umbrella.core.BaseDb;
|
|||||||
import de.srsoftware.umbrella.messagebus.events.Event;
|
import de.srsoftware.umbrella.messagebus.events.Event;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.time.ZoneOffset;
|
|
||||||
|
|
||||||
public class SqliteDb extends BaseDb implements JournalDb{
|
public class SqliteDb extends BaseDb implements JournalDb{
|
||||||
public SqliteDb(Connection connection) {
|
public SqliteDb(Connection connection) {
|
||||||
@@ -35,14 +33,13 @@ public class SqliteDb extends BaseDb implements JournalDb{
|
|||||||
var sql = """
|
var sql = """
|
||||||
CREATE TABLE IF NOT EXISTS {0} (
|
CREATE TABLE IF NOT EXISTS {0} (
|
||||||
{1} INTEGER PRIMARY KEY,
|
{1} INTEGER PRIMARY KEY,
|
||||||
{2} LONG NOT NULL,
|
{2} INTEGER,
|
||||||
{3} INTEGER,
|
{3} VARCHAR(255) NOT NULL,
|
||||||
{4} VARCHAR(255) NOT NULL,
|
{4} VARCHAR(16) NOT NULL,
|
||||||
{5} VARCHAR(16) NOT NULL,
|
{5} TEXT
|
||||||
{6} TEXT
|
|
||||||
);
|
);
|
||||||
""";
|
""";
|
||||||
sql = format(sql,TABLE_JOURNAL,ID,TIMESTAMP,USER_ID,MODULE,ACTION,DESCRIPTION);
|
sql = format(sql,TABLE_JOURNAL,ID,USER_ID,MODULE,ACTION,DESCRIPTION);
|
||||||
try {
|
try {
|
||||||
db.prepareStatement(sql).execute();
|
db.prepareStatement(sql).execute();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
@@ -53,9 +50,8 @@ public class SqliteDb extends BaseDb implements JournalDb{
|
|||||||
@Override
|
@Override
|
||||||
public void logEvent(Event<?> event) {
|
public void logEvent(Event<?> event) {
|
||||||
try {
|
try {
|
||||||
var timestamp = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);
|
insertInto(TABLE_JOURNAL,USER_ID,MODULE,ACTION,DESCRIPTION)
|
||||||
insertInto(TABLE_JOURNAL,TIMESTAMP,USER_ID,MODULE,ACTION,DESCRIPTION)
|
.values(event.initiator().id(), event.module(), event.eventType(), event.describe())
|
||||||
.values(timestamp,event.initiator().id(), event.module(), event.eventType(), event.describe())
|
|
||||||
.execute(db).close();
|
.execute(db).close();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw databaseException(ERROR_WRITE_EVENT,event.eventType(),event.initiator().name());
|
throw databaseException(ERROR_WRITE_EVENT,event.eventType(),event.initiator().name());
|
||||||
|
|||||||
@@ -14,11 +14,8 @@ import de.srsoftware.configuration.Configuration;
|
|||||||
import de.srsoftware.tools.Path;
|
import de.srsoftware.tools.Path;
|
||||||
import de.srsoftware.umbrella.core.BaseHandler;
|
import de.srsoftware.umbrella.core.BaseHandler;
|
||||||
import de.srsoftware.umbrella.core.ModuleRegistry;
|
import de.srsoftware.umbrella.core.ModuleRegistry;
|
||||||
import de.srsoftware.umbrella.core.Util;
|
|
||||||
import de.srsoftware.umbrella.core.api.MarkdownService;
|
import de.srsoftware.umbrella.core.api.MarkdownService;
|
||||||
import de.srsoftware.umbrella.core.constants.Field;
|
|
||||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|||||||
Reference in New Issue
Block a user