Merge branch 'master' into dev

This commit is contained in:
lesion 2023-11-05 22:23:14 +01:00
commit 19eab92d39
No known key found for this signature in database
GPG key ID: 352918250B012177
86 changed files with 5538 additions and 3842 deletions

2
.gitmodules vendored
View file

@ -1,3 +1,3 @@
[submodule "gancio_plugins/gancio-plugin-telegram-bridge"] [submodule "gancio_plugins/gancio-plugin-telegram-bridge"]
path = gancio_plugins/gancio-plugin-telegram-bridge path = gancio_plugins/gancio-plugin-telegram-bridge
url = https://framagit.org/bcn.convocala/gancio-plugin-telegram-bridge.git url = https://framagit.org/bcn.convocala/gancio-plugin-telegram-bridge

View file

@ -1,4 +1,56 @@
All notable changes to this project will be documented in this file. # Changelog
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [1.6.19](https://framagit.org/les/gancio/compare/v1.6.18...v1.6.19) (2023-11-04)
### Bug Fixes
* issue displaying recurrent event string ([a94ccda](https://framagit.org/les/gancio/commit/a94ccda049f7571a9caa90507141a0aac30331a9))
### 1.6.18 - 3 Nov '23
- [feat] allow to specify password while create new user via CLI to [support yunohost](https://github.com/YunoHost-Apps/gancio_ynh/pull/2#discussion_r1364285417)
- [feat] check if I'm reachable to myself to help in [#298](https://framagit.org/les/gancio/-/issues/298)
- [feat] improve recover and user_confirm error messages
- [feat] improve export and allow to export `collections` in rss/ics/widget
- [fix] fix postgres image version in docker-compose [#303](https://framagit.org/les/gancio/-/issues/303)
- [fix] Improve json-ld representation of events [#33](https://framagit.org/les/gancio/-/merge_requests/33)
- [fix] Add description field to admin's new user form, closes [#307](https://framagit.org/les/gancio/-/issues/307)
- [fix] use tls SSLv3 to send email, fix [#192](https://framagit.org/les/gancio/-/issues/192)
- [fix] notify user when accepted, fix [#308](https://framagit.org/les/gancio/-/issues/308)
- [fix] forgot password on active user only
- [fix] make search case insensitive, fix [#301](https://framagit.org/les/gancio/-/issues/301)
### 1.6.17 - 4 Oct '23
- [fix] typo
### 1.6.16 - 4 Oct '23
- [feat] add Czech locale
- [fix] improve datetime validation
### 1.6.15 - 3 Oct '23
- [feat] clone event
- [feat] am/pm / 24hr support, fix [#294](https://framagit.org/les/gancio/-/issues/294) [#264](https://framagit.org/les/gancio/-/issues/264)
- [feat] update telegram plugin bridge to v1.0.3, [#299](https://framagit.org/les/gancio/-/issues/299)
- [feat] include Brazilian Portuguese (pt-br) and Portugual Portuguese (pt-pt) [#292](https://framagit.org/les/gancio/-/issues/292)
- [fix] MariaDB JSON fields manual fix
- [fix] improve some corner case with SMTP From field [#297](https://framagit.org/les/gancio/-/issues/297)
- [fix] CLI has to fail when configuration not present [#284](https://framagit.org/les/gancio/-/issues/284)
- [minor] remove html2text dep from client
- [minor] RSS item's title format is now YYYY-MM-DD, [#300](https://framagit.org/les/gancio/-/issues/300)
### 1.6.14 - 30 June '23
- improve CLI accounts operations ([documentation](https://gancio.org/usage/cli))
- allow plugins to expose API ([documentation](http://gancio.org/dev/plugins))
- allow plugins to access DB ([documentation](http://gancio.org/dev/plugins))
- show map on the places page, #276 #30
- add node v18 support, #278
- fix media update, #285
- fix nodejs v14 compatibility in export
- fix invalid event microdata, #277
- fix recurrent event, #280
- update deps and locales
### 1.6.13 - 16 may '23 ### 1.6.13 - 16 may '23
- fix feed, ics, json exports - fix feed, ics, json exports

View file

@ -25,10 +25,10 @@ function ye(t) {
function u(t, e) { function u(t, e) {
t.appendChild(e); t.appendChild(e);
} }
function p(t, e, i) { function k(t, e, i) {
t.insertBefore(e, i || null); t.insertBefore(e, i || null);
} }
function k(t) { function x(t) {
t.parentNode.removeChild(t); t.parentNode.removeChild(t);
} }
function be(t, e) { function be(t, e) {
@ -38,14 +38,14 @@ function be(t, e) {
function m(t) { function m(t) {
return document.createElement(t); return document.createElement(t);
} }
function $(t) { function z(t) {
return document.createTextNode(t); return document.createTextNode(t);
} }
function M() { function C() {
return $(" "); return z(" ");
} }
function pe() { function pe() {
return $(""); return z("");
} }
function a(t, e, i) { function a(t, e, i) {
i == null ? t.removeAttribute(e) : t.getAttribute(e) !== i && t.setAttribute(e, i); i == null ? t.removeAttribute(e) : t.getAttribute(e) !== i && t.setAttribute(e, i);
@ -69,25 +69,25 @@ let O;
function I(t) { function I(t) {
O = t; O = t;
} }
function $e() { function Ee() {
if (!O) if (!O)
throw new Error("Function called outside component initialization"); throw new Error("Function called outside component initialization");
return O; return O;
} }
function ke(t) { function ke(t) {
$e().$$.on_mount.push(t); Ee().$$.on_mount.push(t);
} }
const R = [], Z = [], P = [], ee = [], Ee = Promise.resolve(); const R = [], Z = [], P = [], ee = [], $e = Promise.resolve();
let K = !1; let K = !1;
function je() { function je() {
K || (K = !0, Ee.then(x)); K || (K = !0, $e.then(y));
} }
function Q(t) { function Q(t) {
P.push(t); P.push(t);
} }
const J = /* @__PURE__ */ new Set(); const J = /* @__PURE__ */ new Set();
let D = 0; let D = 0;
function x() { function y() {
const t = O; const t = O;
do { do {
for (; D < R.length; ) { for (; D < R.length; ) {
@ -120,8 +120,8 @@ function Ce(t, e) {
function Ae(t, e, i, l) { function Ae(t, e, i, l) {
const { fragment: n, on_mount: r, on_destroy: o, after_update: f } = t.$$; const { fragment: n, on_mount: r, on_destroy: o, after_update: f } = t.$$;
n && n.m(e, i), l || Q(() => { n && n.m(e, i), l || Q(() => {
const c = r.map(W).filter(ge); const s = r.map(W).filter(ge);
o ? o.push(...c) : U(c), t.$$.on_mount = []; o ? o.push(...s) : U(s), t.$$.on_mount = [];
}), f.forEach(Q); }), f.forEach(Q);
} }
function Me(t, e) { function Me(t, e) {
@ -132,9 +132,9 @@ function Ne(t, e) {
t.$$.dirty[0] === -1 && (R.push(t), je(), t.$$.dirty.fill(0)), t.$$.dirty[e / 31 | 0] |= 1 << e % 31; t.$$.dirty[0] === -1 && (R.push(t), je(), t.$$.dirty.fill(0)), t.$$.dirty[e / 31 | 0] |= 1 << e % 31;
} }
function we(t, e, i, l, n, r, o, f = [-1]) { function we(t, e, i, l, n, r, o, f = [-1]) {
const c = O; const s = O;
I(t); I(t);
const s = t.$$ = { const c = t.$$ = {
fragment: null, fragment: null,
ctx: null, ctx: null,
props: r, props: r,
@ -146,26 +146,26 @@ function we(t, e, i, l, n, r, o, f = [-1]) {
on_disconnect: [], on_disconnect: [],
before_update: [], before_update: [],
after_update: [], after_update: [],
context: new Map(e.context || (c ? c.$$.context : [])), context: new Map(e.context || (s ? s.$$.context : [])),
callbacks: Y(), callbacks: Y(),
dirty: f, dirty: f,
skip_bound: !1, skip_bound: !1,
root: e.target || c.$$.root root: e.target || s.$$.root
}; };
o && o(s.root); o && o(c.root);
let w = !1; let w = !1;
if (s.ctx = i ? i(t, e.props || {}, (g, _, ...A) => { if (c.ctx = i ? i(t, e.props || {}, (g, _, ...A) => {
const y = A.length ? A[0] : _; const E = A.length ? A[0] : _;
return s.ctx && n(s.ctx[g], s.ctx[g] = y) && (!s.skip_bound && s.bound[g] && s.bound[g](y), w && Ne(t, g)), _; return c.ctx && n(c.ctx[g], c.ctx[g] = E) && (!c.skip_bound && c.bound[g] && c.bound[g](E), w && Ne(t, g)), _;
}) : [], s.update(), w = !0, U(s.before_update), s.fragment = l ? l(s.ctx) : !1, e.target) { }) : [], c.update(), w = !0, U(c.before_update), c.fragment = l ? l(c.ctx) : !1, e.target) {
if (e.hydrate) { if (e.hydrate) {
const g = xe(e.target); const g = xe(e.target);
s.fragment && s.fragment.l(g), g.forEach(k); c.fragment && c.fragment.l(g), g.forEach(x);
} else } else
s.fragment && s.fragment.c(); c.fragment && c.fragment.c();
e.intro && Ce(t.$$.fragment), Ae(t, e.target, e.anchor, e.customElement), x(); e.intro && Ce(t.$$.fragment), Ae(t, e.target, e.anchor, e.customElement), y();
} }
I(c); I(s);
} }
let X; let X;
typeof HTMLElement == "function" && (X = class extends HTMLElement { typeof HTMLElement == "function" && (X = class extends HTMLElement {
@ -213,11 +213,11 @@ function V(t) {
} }
function te(t, e, i) { function te(t, e, i) {
const l = t.slice(); const l = t.slice();
return l[12] = e[i], l; return l[13] = e[i], l;
} }
function ie(t, e, i) { function ie(t, e, i) {
const l = t.slice(); const l = t.slice();
return l[15] = e[i], l; return l[16] = e[i], l;
} }
function le(t) { function le(t) {
let e; let e;
@ -226,13 +226,13 @@ function le(t) {
e = m("link"), a(e, "rel", "stylesheet"), a(e, "href", t[4]); e = m("link"), a(e, "rel", "stylesheet"), a(e, "href", t[4]);
}, },
m(i, l) { m(i, l) {
p(i, e, l); k(i, e, l);
}, },
p(i, l) { p(i, l) {
l & 16 && a(e, "href", i[4]); l & 16 && a(e, "href", i[4]);
}, },
d(i) { d(i) {
i && k(e); i && x(e);
} }
}; };
} }
@ -242,32 +242,32 @@ function ne(t) {
r[o] = fe(te(t, n, o)); r[o] = fe(te(t, n, o));
return { return {
c() { c() {
e = m("div"), l && l.c(), i = M(); e = m("div"), l && l.c(), i = C();
for (let o = 0; o < r.length; o += 1) for (let o = 0; o < r.length; o += 1)
r[o].c(); r[o].c();
a(e, "id", "gancioEvents"), L(e, "dark", t[2] === "dark"), L(e, "light", t[2] === "light"), L(e, "sidebar", t[3] === "true"), L(e, "nosidebar", t[3] !== "true"); a(e, "id", "gancioEvents"), L(e, "dark", t[2] === "dark"), L(e, "light", t[2] === "light"), L(e, "sidebar", t[3] === "true"), L(e, "nosidebar", t[3] !== "true");
}, },
m(o, f) { m(o, f) {
p(o, e, f), l && l.m(e, null), u(e, i); k(o, e, f), l && l.m(e, null), u(e, i);
for (let c = 0; c < r.length; c += 1) for (let s = 0; s < r.length; s += 1)
r[c].m(e, null); r[s].m(e, null);
}, },
p(o, f) { p(o, f) {
if (o[1] && o[3] === "true" ? l ? l.p(o, f) : (l = re(o), l.c(), l.m(e, i)) : l && (l.d(1), l = null), f & 41) { if (o[1] && o[3] === "true" ? l ? l.p(o, f) : (l = re(o), l.c(), l.m(e, i)) : l && (l.d(1), l = null), f & 41) {
n = o[5]; n = o[5];
let c; let s;
for (c = 0; c < n.length; c += 1) { for (s = 0; s < n.length; s += 1) {
const s = te(o, n, c); const c = te(o, n, s);
r[c] ? r[c].p(s, f) : (r[c] = fe(s), r[c].c(), r[c].m(e, null)); r[s] ? r[s].p(c, f) : (r[s] = fe(c), r[s].c(), r[s].m(e, null));
} }
for (; c < r.length; c += 1) for (; s < r.length; s += 1)
r[c].d(1); r[s].d(1);
r.length = n.length; r.length = n.length;
} }
f & 4 && L(e, "dark", o[2] === "dark"), f & 4 && L(e, "light", o[2] === "light"), f & 8 && L(e, "sidebar", o[3] === "true"), f & 8 && L(e, "nosidebar", o[3] !== "true"); f & 4 && L(e, "dark", o[2] === "dark"), f & 4 && L(e, "light", o[2] === "light"), f & 8 && L(e, "sidebar", o[3] === "true"), f & 8 && L(e, "nosidebar", o[3] !== "true");
}, },
d(o) { d(o) {
o && k(e), l && l.d(), be(r, o); o && x(e), l && l.d(), be(r, o);
} }
}; };
} }
@ -275,23 +275,23 @@ function re(t) {
let e, i, l, n, r, o, f; let e, i, l, n, r, o, f;
return { return {
c() { c() {
e = m("a"), i = m("div"), l = m("div"), n = $(t[1]), r = M(), o = m("img"), a(l, "class", "title"), a(o, "id", "logo"), a(o, "alt", "logo"), H(o.src, f = t[0] + "/logo.png") || a(o, "src", f), a(i, "class", "content"), a(e, "href", t[0]), a(e, "target", "_blank"), a(e, "id", "header"); e = m("a"), i = m("div"), l = m("div"), n = z(t[1]), r = C(), o = m("img"), a(l, "class", "title"), a(o, "id", "logo"), a(o, "alt", "logo"), H(o.src, f = t[0] + "/logo.png") || a(o, "src", f), a(i, "class", "content"), a(e, "href", t[0]), a(e, "target", "_blank"), a(e, "id", "header");
}, },
m(c, s) { m(s, c) {
p(c, e, s), u(e, i), u(i, l), u(l, n), u(i, r), u(i, o); k(s, e, c), u(e, i), u(i, l), u(l, n), u(i, r), u(i, o);
}, },
p(c, s) { p(s, c) {
s & 2 && T(n, c[1]), s & 1 && !H(o.src, f = c[0] + "/logo.png") && a(o, "src", f), s & 1 && a(e, "href", c[0]); c & 2 && T(n, s[1]), c & 1 && !H(o.src, f = s[0] + "/logo.png") && a(o, "src", f), c & 1 && a(e, "href", s[0]);
}, },
d(c) { d(s) {
c && k(e); s && x(e);
} }
}; };
} }
function oe(t) { function oe(t) {
let e; let e;
function i(r, o) { function i(r, o) {
return r[12].media.length ? Le : Te; return r[13].media.length ? Le : Te;
} }
let l = i(t), n = l(t); let l = i(t), n = l(t);
return { return {
@ -299,13 +299,13 @@ function oe(t) {
e = m("div"), n.c(), a(e, "class", "img"); e = m("div"), n.c(), a(e, "class", "img");
}, },
m(r, o) { m(r, o) {
p(r, e, o), n.m(e, null); k(r, e, o), n.m(e, null);
}, },
p(r, o) { p(r, o) {
l === (l = i(r)) && n ? n.p(r, o) : (n.d(1), n = l(r), n && (n.c(), n.m(e, null))); l === (l = i(r)) && n ? n.p(r, o) : (n.d(1), n = l(r), n && (n.c(), n.m(e, null)));
}, },
d(r) { d(r) {
r && k(e), n.d(); r && x(e), n.d();
} }
}; };
} }
@ -313,16 +313,16 @@ function Te(t) {
let e, i, l; let e, i, l;
return { return {
c() { c() {
e = m("img"), a(e, "style", "aspect-ratio=1.7778;"), a(e, "alt", i = t[12].title), H(e.src, l = t[0] + "/fallbackimage.png") || a(e, "src", l), a(e, "loading", "lazy"); e = m("img"), a(e, "style", "aspect-ratio=1.7778;"), a(e, "alt", i = t[13].title), H(e.src, l = t[0] + "/fallbackimage.png") || a(e, "src", l), a(e, "loading", "lazy");
}, },
m(n, r) { m(n, r) {
p(n, e, r); k(n, e, r);
}, },
p(n, r) { p(n, r) {
r & 32 && i !== (i = n[12].title) && a(e, "alt", i), r & 1 && !H(e.src, l = n[0] + "/fallbackimage.png") && a(e, "src", l); r & 32 && i !== (i = n[13].title) && a(e, "alt", i), r & 1 && !H(e.src, l = n[0] + "/fallbackimage.png") && a(e, "src", l);
}, },
d(n) { d(n) {
n && k(e); n && x(e);
} }
}; };
} }
@ -330,38 +330,38 @@ function Le(t) {
let e, i, l, n; let e, i, l, n;
return { return {
c() { c() {
e = m("img"), a(e, "style", i = "object-position: " + ue(t[12]) + "; aspect-ratio=1.7778;"), a(e, "alt", l = t[12].media[0].name), H(e.src, n = t[0] + "/media/thumb/" + t[12].media[0].url) || a(e, "src", n), a(e, "loading", "lazy"); e = m("img"), a(e, "style", i = "object-position: " + ue(t[13]) + "; aspect-ratio=1.7778;"), a(e, "alt", l = t[13].media[0].name), H(e.src, n = t[0] + "/media/thumb/" + t[13].media[0].url) || a(e, "src", n), a(e, "loading", "lazy");
}, },
m(r, o) { m(r, o) {
p(r, e, o); k(r, e, o);
}, },
p(r, o) { p(r, o) {
o & 32 && i !== (i = "object-position: " + ue(r[12]) + "; aspect-ratio=1.7778;") && a(e, "style", i), o & 32 && l !== (l = r[12].media[0].name) && a(e, "alt", l), o & 33 && !H(e.src, n = r[0] + "/media/thumb/" + r[12].media[0].url) && a(e, "src", n); o & 32 && i !== (i = "object-position: " + ue(r[13]) + "; aspect-ratio=1.7778;") && a(e, "style", i), o & 32 && l !== (l = r[13].media[0].name) && a(e, "alt", l), o & 33 && !H(e.src, n = r[0] + "/media/thumb/" + r[13].media[0].url) && a(e, "src", n);
}, },
d(r) { d(r) {
r && k(e); r && x(e);
} }
}; };
} }
function ae(t) { function ae(t) {
let e, i = t[12].place.address + "", l; let e, i = t[13].place.address + "", l;
return { return {
c() { c() {
e = m("span"), l = $(i), a(e, "class", "subtitle"); e = m("span"), l = z(i), a(e, "class", "subtitle");
}, },
m(n, r) { m(n, r) {
p(n, e, r), u(e, l); k(n, e, r), u(e, l);
}, },
p(n, r) { p(n, r) {
r & 32 && i !== (i = n[12].place.address + "") && T(l, i); r & 32 && i !== (i = n[13].place.address + "") && T(l, i);
}, },
d(n) { d(n) {
n && k(e); n && x(e);
} }
}; };
} }
function se(t) { function se(t) {
let e, i = t[12].tags, l = []; let e, i = t[13].tags, l = [];
for (let n = 0; n < i.length; n += 1) for (let n = 0; n < i.length; n += 1)
l[n] = ce(ie(t, i, n)); l[n] = ce(ie(t, i, n));
return { return {
@ -372,13 +372,13 @@ function se(t) {
a(e, "class", "tags"); a(e, "class", "tags");
}, },
m(n, r) { m(n, r) {
p(n, e, r); k(n, e, r);
for (let o = 0; o < l.length; o += 1) for (let o = 0; o < l.length; o += 1)
l[o].m(e, null); l[o].m(e, null);
}, },
p(n, r) { p(n, r) {
if (r & 32) { if (r & 32) {
i = n[12].tags; i = n[13].tags;
let o; let o;
for (o = 0; o < i.length; o += 1) { for (o = 0; o < i.length; o += 1) {
const f = ie(n, i, o); const f = ie(n, i, o);
@ -390,42 +390,41 @@ function se(t) {
} }
}, },
d(n) { d(n) {
n && k(e), be(l, n); n && x(e), be(l, n);
} }
}; };
} }
function ce(t) { function ce(t) {
let e, i, l = t[15] + "", n; let e, i, l = t[16] + "", n;
return { return {
c() { c() {
e = m("span"), i = $("#"), n = $(l), a(e, "class", "tag"); e = m("span"), i = z("#"), n = z(l), a(e, "class", "tag");
}, },
m(r, o) { m(r, o) {
p(r, e, o), u(e, i), u(e, n); k(r, e, o), u(e, i), u(e, n);
}, },
p(r, o) { p(r, o) {
o & 32 && l !== (l = r[15] + "") && T(n, l); o & 32 && l !== (l = r[16] + "") && T(n, l);
}, },
d(r) { d(r) {
r && k(e); r && x(e);
} }
}; };
} }
function fe(t) { function fe(t) {
let e, i, l, n, r = V(t[12]) + "", o, f, c, s = t[12].title + "", w, g, _, A, y = t[12].place.name + "", d, z, h, v, C, q, E = t[3] !== "true" && oe(t), j = t[12].place.name !== "online" && ae(t), S = t[12].tags.length && se(t); let e, i, l, n, r = V(t[13]) + "", o, f, s, c = t[13].title + "", w, g, _, A, E = t[13].place.name + "", M, d, h, p, v, q, $ = t[3] !== "true" && oe(t), j = t[13].place.name !== "online" && ae(t), S = t[13].tags.length && se(t);
return { return {
c() { c() {
e = m("a"), E && E.c(), i = M(), l = m("div"), n = m("div"), o = $(r), f = M(), c = m("div"), w = $(s), g = M(), _ = m("span"), A = $('@"'), d = $(y), z = $(`" e = m("a"), $ && $.c(), i = C(), l = m("div"), n = m("div"), o = z(r), f = C(), s = m("div"), w = z(c), g = C(), _ = m("span"), A = z("@"), M = z(E), d = C(), j && j.c(), h = C(), S && S.c(), p = C(), a(n, "class", "subtitle"), a(s, "class", "title"), a(_, "class", "place"), a(l, "class", "content"), a(e, "href", v = t[0] + "/event/" + (t[13].slug || t[13].id)), a(e, "class", "event"), a(e, "title", q = t[13].title), a(e, "target", "_blank");
`), j && j.c(), h = M(), S && S.c(), v = M(), a(n, "class", "subtitle"), a(c, "class", "title"), a(_, "class", "place"), a(l, "class", "content"), a(e, "href", C = t[0] + "/event/" + (t[12].slug || t[12].id)), a(e, "class", "event"), a(e, "title", q = t[12].title), a(e, "target", "_blank");
}, },
m(b, N) { m(b, N) {
p(b, e, N), E && E.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, c), u(c, w), u(l, g), u(l, _), u(_, A), u(_, d), u(_, z), j && j.m(_, null), u(l, h), S && S.m(l, null), u(e, v); k(b, e, N), $ && $.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, s), u(s, w), u(l, g), u(l, _), u(_, A), u(_, M), u(_, d), j && j.m(_, null), u(l, h), S && S.m(l, null), u(e, p);
}, },
p(b, N) { p(b, N) {
b[3] !== "true" ? E ? E.p(b, N) : (E = oe(b), E.c(), E.m(e, i)) : E && (E.d(1), E = null), N & 32 && r !== (r = V(b[12]) + "") && T(o, r), N & 32 && s !== (s = b[12].title + "") && T(w, s), N & 32 && y !== (y = b[12].place.name + "") && T(d, y), b[12].place.name !== "online" ? j ? j.p(b, N) : (j = ae(b), j.c(), j.m(_, null)) : j && (j.d(1), j = null), b[12].tags.length ? S ? S.p(b, N) : (S = se(b), S.c(), S.m(l, null)) : S && (S.d(1), S = null), N & 33 && C !== (C = b[0] + "/event/" + (b[12].slug || b[12].id)) && a(e, "href", C), N & 32 && q !== (q = b[12].title) && a(e, "title", q); b[3] !== "true" ? $ ? $.p(b, N) : ($ = oe(b), $.c(), $.m(e, i)) : $ && ($.d(1), $ = null), N & 32 && r !== (r = V(b[13]) + "") && T(o, r), N & 32 && c !== (c = b[13].title + "") && T(w, c), N & 32 && E !== (E = b[13].place.name + "") && T(M, E), b[13].place.name !== "online" ? j ? j.p(b, N) : (j = ae(b), j.c(), j.m(_, null)) : j && (j.d(1), j = null), b[13].tags.length ? S ? S.p(b, N) : (S = se(b), S.c(), S.m(l, null)) : S && (S.d(1), S = null), N & 33 && v !== (v = b[0] + "/event/" + (b[13].slug || b[13].id)) && a(e, "href", v), N & 32 && q !== (q = b[13].title) && a(e, "title", q);
}, },
d(b) { d(b) {
b && k(e), E && E.d(), j && j.d(), S && S.d(); b && x(e), $ && $.d(), j && j.d(), S && S.d();
} }
}; };
} }
@ -433,10 +432,10 @@ function Ge(t) {
let e, i, l = t[4] && le(t), n = t[5].length && ne(t); let e, i, l = t[4] && le(t), n = t[5].length && ne(t);
return { return {
c() { c() {
l && l.c(), e = M(), n && n.c(), i = pe(), this.c = G; l && l.c(), e = C(), n && n.c(), i = pe(), this.c = G;
}, },
m(r, o) { m(r, o) {
l && l.m(r, o), p(r, e, o), n && n.m(r, o), p(r, i, o); l && l.m(r, o), k(r, e, o), n && n.m(r, o), k(r, i, o);
}, },
p(r, [o]) { p(r, [o]) {
r[4] ? l ? l.p(r, o) : (l = le(r), l.c(), l.m(e.parentNode, e)) : l && (l.d(1), l = null), r[5].length ? n ? n.p(r, o) : (n = ne(r), n.c(), n.m(i.parentNode, i)) : n && (n.d(1), n = null); r[4] ? l ? l.p(r, o) : (l = le(r), l.c(), l.m(e.parentNode, e)) : l && (l.d(1), l = null), r[5].length ? n ? n.p(r, o) : (n = ne(r), n.c(), n.m(i.parentNode, i)) : n && (n.d(1), n = null);
@ -444,7 +443,7 @@ function Ge(t) {
i: G, i: G,
o: G, o: G,
d(r) { d(r) {
l && l.d(r), r && k(e), n && n.d(r), r && k(i); l && l.d(r), r && x(e), n && n.d(r), r && x(i);
} }
}; };
} }
@ -456,34 +455,37 @@ function ue(t) {
return "center center"; return "center center";
} }
function He(t, e, i) { function He(t, e, i) {
let { baseurl: l = "" } = e, { title: n = "" } = e, { maxlength: r = !1 } = e, { tags: o = "" } = e, { places: f = "" } = e, { theme: c = "light" } = e, { show_recurrent: s = !1 } = e, { sidebar: w = "true" } = e, { external_style: g = "" } = e, _ = !1, A = []; let { baseurl: l = "" } = e, { title: n = "" } = e, { maxlength: r = !1 } = e, { collection: o = "" } = e, { tags: f = "" } = e, { places: s = "" } = e, { theme: c = "light" } = e, { show_recurrent: w = !1 } = e, { sidebar: g = "true" } = e, { external_style: _ = "" } = e, A = !1, E = [];
function y(d) { function M(d) {
if (!_) if (!A)
return; return;
const z = []; const h = [];
r && z.push(`max=${r}`), o && z.push(`tags=${o}`), f && z.push(`places=${f}`), z.push(`show_recurrent=${s ? "true" : "false"}`), fetch(`${l}/api/events?${z.join("&")}`).then((h) => h.json()).then((h) => { r && h.push(`max=${r}`);
i(5, A = h); let p = "/api/events";
}).catch((h) => { o ? p = `/api/collections/${o}` : (f && h.push(`tags=${f}`), s && h.push(`places=${s}`)), h.push(`show_recurrent=${w ? "true" : "false"}`), fetch(`${l}${p}?${h.join("&")}`).then((v) => v.json()).then((v) => {
console.error("Error loading Gancio API -> ", h); i(5, E = v.events || v);
}).catch((v) => {
console.error("Error loading Gancio API -> ", v);
}); });
} }
return ke(() => { return ke(() => {
_ = !0, y(); A = !0, M();
}), t.$$set = (d) => { }), t.$$set = (d) => {
"baseurl" in d && i(0, l = d.baseurl), "title" in d && i(1, n = d.title), "maxlength" in d && i(6, r = d.maxlength), "tags" in d && i(7, o = d.tags), "places" in d && i(8, f = d.places), "theme" in d && i(2, c = d.theme), "show_recurrent" in d && i(9, s = d.show_recurrent), "sidebar" in d && i(3, w = d.sidebar), "external_style" in d && i(4, g = d.external_style); "baseurl" in d && i(0, l = d.baseurl), "title" in d && i(1, n = d.title), "maxlength" in d && i(6, r = d.maxlength), "collection" in d && i(7, o = d.collection), "tags" in d && i(8, f = d.tags), "places" in d && i(9, s = d.places), "theme" in d && i(2, c = d.theme), "show_recurrent" in d && i(10, w = d.show_recurrent), "sidebar" in d && i(3, g = d.sidebar), "external_style" in d && i(4, _ = d.external_style);
}, t.$$.update = () => { }, t.$$.update = () => {
t.$$.dirty & 975 && y(); t.$$.dirty & 1999 && M();
}, [ }, [
l, l,
n, n,
c, c,
w,
g, g,
A, _,
E,
r, r,
o, o,
f, f,
s s,
w
]; ];
} }
class Re extends X { class Re extends X {
@ -508,21 +510,23 @@ class Re extends X {
baseurl: 0, baseurl: 0,
title: 1, title: 1,
maxlength: 6, maxlength: 6,
tags: 7, collection: 7,
places: 8, tags: 8,
places: 9,
theme: 2, theme: 2,
show_recurrent: 9, show_recurrent: 10,
sidebar: 3, sidebar: 3,
external_style: 4 external_style: 4
}, },
null null
), e && (e.target && p(e.target, this, e.anchor), e.props && (this.$set(e.props), x())); ), e && (e.target && k(e.target, this, e.anchor), e.props && (this.$set(e.props), y()));
} }
static get observedAttributes() { static get observedAttributes() {
return [ return [
"baseurl", "baseurl",
"title", "title",
"maxlength", "maxlength",
"collection",
"tags", "tags",
"places", "places",
"theme", "theme",
@ -535,72 +539,78 @@ class Re extends X {
return this.$$.ctx[0]; return this.$$.ctx[0];
} }
set baseurl(e) { set baseurl(e) {
this.$$set({ baseurl: e }), x(); this.$$set({ baseurl: e }), y();
} }
get title() { get title() {
return this.$$.ctx[1]; return this.$$.ctx[1];
} }
set title(e) { set title(e) {
this.$$set({ title: e }), x(); this.$$set({ title: e }), y();
} }
get maxlength() { get maxlength() {
return this.$$.ctx[6]; return this.$$.ctx[6];
} }
set maxlength(e) { set maxlength(e) {
this.$$set({ maxlength: e }), x(); this.$$set({ maxlength: e }), y();
} }
get tags() { get collection() {
return this.$$.ctx[7]; return this.$$.ctx[7];
} }
set tags(e) { set collection(e) {
this.$$set({ tags: e }), x(); this.$$set({ collection: e }), y();
} }
get places() { get tags() {
return this.$$.ctx[8]; return this.$$.ctx[8];
} }
set tags(e) {
this.$$set({ tags: e }), y();
}
get places() {
return this.$$.ctx[9];
}
set places(e) { set places(e) {
this.$$set({ places: e }), x(); this.$$set({ places: e }), y();
} }
get theme() { get theme() {
return this.$$.ctx[2]; return this.$$.ctx[2];
} }
set theme(e) { set theme(e) {
this.$$set({ theme: e }), x(); this.$$set({ theme: e }), y();
} }
get show_recurrent() { get show_recurrent() {
return this.$$.ctx[9]; return this.$$.ctx[10];
} }
set show_recurrent(e) { set show_recurrent(e) {
this.$$set({ show_recurrent: e }), x(); this.$$set({ show_recurrent: e }), y();
} }
get sidebar() { get sidebar() {
return this.$$.ctx[3]; return this.$$.ctx[3];
} }
set sidebar(e) { set sidebar(e) {
this.$$set({ sidebar: e }), x(); this.$$set({ sidebar: e }), y();
} }
get external_style() { get external_style() {
return this.$$.ctx[4]; return this.$$.ctx[4];
} }
set external_style(e) { set external_style(e) {
this.$$set({ external_style: e }), x(); this.$$set({ external_style: e }), y();
} }
} }
customElements.define("gancio-events", Re); customElements.define("gancio-events", Re);
function de(t) { function de(t) {
let e, i, l, n, r = t[1].title + "", o, f, c, s = V(t[1]) + "", w, g, _, A, y = t[1].place.name + "", d, z, h = t[1].media.length && he(t); let e, i, l, n, r = t[1].title + "", o, f, s, c = V(t[1]) + "", w, g, _, A, E = t[1].place.name + "", M, d, h = t[1].media.length && he(t);
return { return {
c() { c() {
e = m("a"), h && h.c(), i = M(), l = m("div"), n = m("strong"), o = $(r), f = M(), c = m("div"), w = $(s), g = M(), _ = m("div"), A = $("@"), d = $(y), a(_, "class", "place"), a(l, "class", "container"), a(e, "href", z = t[0] + "/event/" + (t[1].slug || t[1].id)), a(e, "class", "card"), a(e, "target", "_blank"); e = m("a"), h && h.c(), i = C(), l = m("div"), n = m("strong"), o = z(r), f = C(), s = m("div"), w = z(c), g = C(), _ = m("div"), A = z("@"), M = z(E), a(_, "class", "place"), a(l, "class", "container"), a(e, "href", d = t[0] + "/event/" + (t[1].slug || t[1].id)), a(e, "class", "card"), a(e, "target", "_blank");
}, },
m(v, C) { m(p, v) {
p(v, e, C), h && h.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, c), u(c, w), u(l, g), u(l, _), u(_, A), u(_, d); k(p, e, v), h && h.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, s), u(s, w), u(l, g), u(l, _), u(_, A), u(_, M);
}, },
p(v, C) { p(p, v) {
v[1].media.length ? h ? h.p(v, C) : (h = he(v), h.c(), h.m(e, i)) : h && (h.d(1), h = null), C & 2 && r !== (r = v[1].title + "") && T(o, r), C & 2 && s !== (s = V(v[1]) + "") && T(w, s), C & 2 && y !== (y = v[1].place.name + "") && T(d, y), C & 3 && z !== (z = v[0] + "/event/" + (v[1].slug || v[1].id)) && a(e, "href", z); p[1].media.length ? h ? h.p(p, v) : (h = he(p), h.c(), h.m(e, i)) : h && (h.d(1), h = null), v & 2 && r !== (r = p[1].title + "") && T(o, r), v & 2 && c !== (c = V(p[1]) + "") && T(w, c), v & 2 && E !== (E = p[1].place.name + "") && T(M, E), v & 3 && d !== (d = p[0] + "/event/" + (p[1].slug || p[1].id)) && a(e, "href", d);
}, },
d(v) { d(p) {
v && k(e), h && h.d(); p && x(e), h && h.d();
} }
}; };
} }
@ -611,13 +621,13 @@ function he(t) {
e = m("img"), H(e.src, i = t[2](t[1])) || a(e, "src", i), a(e, "alt", l = t[1].media[0].name), a(e, "style", n = "object-position: " + me(t[1]) + "; aspect-ratio=1.7778;"); e = m("img"), H(e.src, i = t[2](t[1])) || a(e, "src", i), a(e, "alt", l = t[1].media[0].name), a(e, "style", n = "object-position: " + me(t[1]) + "; aspect-ratio=1.7778;");
}, },
m(r, o) { m(r, o) {
p(r, e, o); k(r, e, o);
}, },
p(r, o) { p(r, o) {
o & 2 && !H(e.src, i = r[2](r[1])) && a(e, "src", i), o & 2 && l !== (l = r[1].media[0].name) && a(e, "alt", l), o & 2 && n !== (n = "object-position: " + me(r[1]) + "; aspect-ratio=1.7778;") && a(e, "style", n); o & 2 && !H(e.src, i = r[2](r[1])) && a(e, "src", i), o & 2 && l !== (l = r[1].media[0].name) && a(e, "alt", l), o & 2 && n !== (n = "object-position: " + me(r[1]) + "; aspect-ratio=1.7778;") && a(e, "style", n);
}, },
d(r) { d(r) {
r && k(e); r && x(e);
} }
}; };
} }
@ -628,7 +638,7 @@ function Ie(t) {
i && i.c(), e = pe(), this.c = G; i && i.c(), e = pe(), this.c = G;
}, },
m(l, n) { m(l, n) {
i && i.m(l, n), p(l, e, n); i && i.m(l, n), k(l, e, n);
}, },
p(l, [n]) { p(l, [n]) {
l[1] ? i ? i.p(l, n) : (i = de(l), i.c(), i.m(e.parentNode, e)) : i && (i.d(1), i = null); l[1] ? i ? i.p(l, n) : (i = de(l), i.c(), i.m(e.parentNode, e)) : i && (i.d(1), i = null);
@ -636,7 +646,7 @@ function Ie(t) {
i: G, i: G,
o: G, o: G,
d(l) { d(l) {
i && i.d(l), l && k(e); i && i.d(l), l && x(e);
} }
}; };
} }
@ -649,20 +659,20 @@ function me(t) {
} }
function Oe(t, e, i) { function Oe(t, e, i) {
let { baseurl: l = "https://demo.gancio.org" } = e, { id: n } = e, r = !1, o; let { baseurl: l = "https://demo.gancio.org" } = e, { id: n } = e, r = !1, o;
function f(s, w) { function f(c, w) {
r && fetch(`${w}/api/event/detail/${s}`).then((g) => g.json()).then((g) => i(1, o = g)); r && fetch(`${w}/api/event/detail/${c}`).then((g) => g.json()).then((g) => i(1, o = g));
} }
ke(() => { ke(() => {
r = !0, f(n, l); r = !0, f(n, l);
}); });
function c(s) { function s(c) {
return `${l}/media/thumb/${s.media[0].url}`; return `${l}/media/thumb/${c.media[0].url}`;
} }
return t.$$set = (s) => { return t.$$set = (c) => {
"baseurl" in s && i(0, l = s.baseurl), "id" in s && i(3, n = s.id); "baseurl" in c && i(0, l = c.baseurl), "id" in c && i(3, n = c.id);
}, t.$$.update = () => { }, t.$$.update = () => {
t.$$.dirty & 9 && f(n, l); t.$$.dirty & 9 && f(n, l);
}, [l, o, c, n]; }, [l, o, s, n];
} }
class Ue extends X { class Ue extends X {
constructor(e) { constructor(e) {
@ -679,7 +689,7 @@ class Ue extends X {
_e, _e,
{ baseurl: 0, id: 3 }, { baseurl: 0, id: 3 },
null null
), e && (e.target && p(e.target, this, e.anchor), e.props && (this.$set(e.props), x())); ), e && (e.target && k(e.target, this, e.anchor), e.props && (this.$set(e.props), y()));
} }
static get observedAttributes() { static get observedAttributes() {
return ["baseurl", "id"]; return ["baseurl", "id"];
@ -688,13 +698,13 @@ class Ue extends X {
return this.$$.ctx[0]; return this.$$.ctx[0];
} }
set baseurl(e) { set baseurl(e) {
this.$$set({ baseurl: e }), x(); this.$$set({ baseurl: e }), y();
} }
get id() { get id() {
return this.$$.ctx[3]; return this.$$.ctx[3];
} }
set id(e) { set id(e) {
this.$$set({ id: e }), x(); this.$$set({ id: e }), y();
} }
} }
customElements.define("gancio-event", Ue); customElements.define("gancio-event", Ue);

View file

@ -1,6 +1,7 @@
html, body { html, body {
scrollbar-width: thin; scrollbar-width: thin;
overflow: auto !important; overflow-y: auto !important;
overflow-x: hidden;
scrollbar-color: #FF4511 #111; scrollbar-color: #FF4511 #111;
font-family: sans-serif; font-family: sans-serif;
} }

View file

@ -47,7 +47,7 @@ v-col(cols=12)
:clear-icon='mdiClose' :clear-icon='mdiClose'
@click:clear='() => change("fromHour")' @click:clear='() => change("fromHour")'
:label="$t('event.from')" :label="$t('event.from')"
:value="value.fromHour" :value="$time.formatHour(value.fromHour)"
:disabled='!value.from' :disabled='!value.from'
readonly readonly
:prepend-icon="mdiClockTimeFourOutline" :prepend-icon="mdiClockTimeFourOutline"
@ -59,7 +59,7 @@ v-col(cols=12)
:value="value.fromHour" :value="value.fromHour"
:allowedMinutes='allowedMinutes' :allowedMinutes='allowedMinutes'
full-width full-width
format='24hr' :format='$time.timeFormat()'
@click:minute='menuFromHour = false' @click:minute='menuFromHour = false'
@input='hr => change("fromHour", hr)') @input='hr => change("fromHour", hr)')
@ -79,7 +79,7 @@ v-col(cols=12)
:clear-icon='mdiClose' :clear-icon='mdiClose'
@click:clear='() => change("dueHour")' @click:clear='() => change("dueHour")'
:label="$t('event.due')" :label="$t('event.due')"
:value="value.dueHour" :value="$time.formatHour(value.dueHour)"
:disabled='!value.fromHour' :disabled='!value.fromHour'
readonly readonly
:prepend-icon="mdiClockTimeEightOutline" :prepend-icon="mdiClockTimeEightOutline"
@ -90,7 +90,7 @@ v-col(cols=12)
:value="value.dueHour" :value="value.dueHour"
full-width full-width
:allowedMinutes='allowedMinutes' :allowedMinutes='allowedMinutes'
format='24hr' :format='$time.timeFormat()'
@click:minute='menuDueHour = false' @click:minute='menuDueHour = false'
@input='hr => change("dueHour", hr)') @input='hr => change("dueHour", hr)')

View file

@ -16,7 +16,7 @@
<template v-slot:activator="{ on, attrs }"> <template v-slot:activator="{ on, attrs }">
<v-btn icon large v-bind='attrs' v-on='on' aria-label='Language' v-text="$i18n.locale" /> <v-btn icon large v-bind='attrs' v-on='on' aria-label='Language' v-text="$i18n.locale" />
</template> </template>
<v-list> <v-list dense>
<v-list-item v-for='locale in $i18n.locales' @click.prevent.stop="$i18n.setLocale(locale.code)" :key='locale.code'> <v-list-item v-for='locale in $i18n.locales' @click.prevent.stop="$i18n.setLocale(locale.code)" :key='locale.code'>
<v-list-item-content> <v-list-item-content>
<v-list-item-title v-text='locale.name' /> <v-list-item-title v-text='locale.name' />

View file

@ -1,6 +1,6 @@
<template lang="pug"> <template lang="pug">
v-row v-row
v-col(cols=12) v-col(sm=3 cols=12)
v-switch( v-switch(
v-if='settings.allow_recurrent_event' v-if='settings.allow_recurrent_event'
v-model='show_recurrent' v-model='show_recurrent'
@ -8,12 +8,12 @@ v-row
inset color='primary' inset color='primary'
hide-details hide-details
:label="$t('event.show_recurrent')") :label="$t('event.show_recurrent')")
v-col.mb-4(cols=12) v-col(sm="5" cols=12)
v-autocomplete.p-0( v-autocomplete.p-0(
v-model='meta' :disabled='!!collection'
:label='$t("common.search")' v-model="filters"
:filter='filter' outlined
cache-items :label='$t("common.filter")'
hide-details hide-details
color='primary' color='primary'
hide-selected hide-selected
@ -35,35 +35,65 @@ v-row
@click:close='remove(item)' @click:close='remove(item)'
:close-icon='mdiCloseCircle') :close-icon='mdiCloseCircle')
v-avatar(left) v-avatar(left)
v-icon(small v-text="item.type === 'place' ? mdiMapMarker : mdiTag") v-icon(small v-text="item.type === 'place' ? mdiMapMarker : item.type === 'tag' ? mdiTag : mdiCollage")
span {{ item.label }} span {{ item.label }}
template(v-slot:item='{ item }') template(v-slot:item='{ item }')
v-list-item-avatar v-list-item-avatar
v-icon(v-text="item.type === 'place' ? mdiMapMarker : mdiTag") v-icon(v-text="item.type === 'place' ? mdiMapMarker : item.type === 'tag' ? mdiTag : mdiCollage")
v-list-item-content v-list-item-content
v-list-item-title(v-text='item.label') v-list-item-title(v-text='item.label')
v-list-item-subtitle(v-if='item.type ==="place"' v-text='item.address') v-list-item-subtitle(v-if='item.type ==="place"' v-text='item.label !== "online" && item.address')
v-col(sm=4 cols=12)
v-autocomplete.p-0(
:disabled='!!filters.length'
v-model="collection"
outlined
:label='$t("common.collections")'
hide-details
color='primary'
hide-selected
:menu-props="{ maxWidth: '400' }"
:items='collections'
@change='change'
hide-no-data
clearable
:clear-icon='mdiCloseCircle'
item-text='name')
template(v-slot:itsdfems='{ item }')
v-list-item-avatar
v-icon(v-text="item.type === 'place' ? mdiMapMarker : item.type === 'tag' ? mdiTag : mdiCollage")
v-list-item-content
v-list-item-title(v-text='item.label')
v-list-item-subtitle(v-if='item.type ==="place"' v-text='item.label !== "online" && item.address')
</template> </template>
<script> <script>
import { mapState } from 'vuex' import { mapState } from 'vuex'
import { mdiMapMarker, mdiTag, mdiCloseCircle } from '@mdi/js' import { mdiMapMarker, mdiTag, mdiCloseCircle, mdiCollage } from '@mdi/js'
import debounce from 'lodash/debounce' import debounce from 'lodash/debounce'
export default { export default {
name: 'Search', name: 'Search',
props: { props: {
filters: { type: Object, default: () => ({ }) } value: { type: Object, default: () => ({ }) }
}, },
data () { data () {
return { return {
mdiTag, mdiMapMarker, mdiCloseCircle, mdiTag, mdiMapMarker, mdiCloseCircle, mdiCollage,
meta: [],
items: [], items: [],
show_recurrent: this.filters.show_recurrent || false filters: [],
collection: null,
collections: [],
show_recurrent: this.value.show_recurrent || false
} }
}, },
computed: mapState(['settings']), async fetch () {
this.collections = await this.$axios.$get('/collections')
},
computed: {
...mapState(['settings']),
},
methods: { methods: {
filter (item, queryText, itemText) { filter (item, queryText, itemText) {
return itemText.toLocaleLowerCase().indexOf(queryText.toLocaleLowerCase()) > -1 || return itemText.toLocaleLowerCase().indexOf(queryText.toLocaleLowerCase()) > -1 ||
@ -71,18 +101,31 @@ export default {
}, },
search: debounce(async function(search) { search: debounce(async function(search) {
this.items = await this.$axios.$get(`/event/meta?search=${search.target.value}`) this.items = await this.$axios.$get(`/event/meta?search=${search.target.value}`)
console.error('items ', this.items.length)
}, 100), }, 100),
remove (item) { remove (item) {
this.meta = this.meta.filter(m => m.type !== item.type || m.type === 'place' ? m.id !== item.id : m.label !== item.label) // const filters = {
// tags: this.filters.filter(t => t.type === 'tag' && t.label !== item.label).map(t => t.label),
// places: this.filters.filter(p => p.type === 'place' && p.id !== item.id).map(p => p.id),
// show_recurrent: this.show_recurrent
// }
this.filters = this.filters.filter(m => m.type !== item.type || m.type === 'place' ? m.id !== item.id : m.label !== item.label)
// this.$emit('input', filters)
this.change() this.change()
}, },
change () { change () {
const filters = { if (this.collection) {
tags: this.meta.filter(t => t.type === 'tag').map(t => t.label), this.filters = []
places: this.meta.filter(p => p.type === 'place').map(p => p.id), this.$emit('input', { collection: this.collection, places: [], tags: [], show_recurrent: this.show_recurrent })
show_recurrent: this.show_recurrent } else {
const filters = {
tags: this.filters.filter(t => t.type === 'tag').map(t => t.label),
places: this.filters.filter(p => p.type === 'place').map(p => p.id),
show_recurrent: this.show_recurrent
}
this.$emit('input', filters)
} }
this.$emit('update', filters)
} }
} }
} }

View file

@ -79,7 +79,6 @@ v-container
<script> <script>
import { mapActions, mapState } from 'vuex' import { mapActions, mapState } from 'vuex'
import get from 'lodash/get' import get from 'lodash/get'
import axios from 'axios'
import { mdiDeleteForever, mdiPlus, mdiChevronLeft, mdiChevronRight, mdiChevronDown } from '@mdi/js' import { mdiDeleteForever, mdiPlus, mdiChevronLeft, mdiChevronRight, mdiChevronDown } from '@mdi/js'
export default { export default {
@ -140,21 +139,15 @@ export default {
this.instance_url = `https://${this.instance_url}` this.instance_url = `https://${this.instance_url}`
} }
this.instance_url = this.instance_url.replace(/\/$/, '') this.instance_url = this.instance_url.replace(/\/$/, '')
const instance = await this.$axios.$get(`${this.instance_url}/.well-known/nodeinfo/2.1`)
// const instance = await axios.get(`${this.instance_url}/.well-known/nodeinfo/2.1`) this.setSetting({
// // this.setSetting({ key: 'trusted_instances',
// // key: 'trusted_instances', value: this.settings.trusted_instances.concat({
// // value: this.settings.trusted_instances.concat({ url: this.instance_url,
// const instance = { name: get(instance, 'metadata.nodeName', ''),
// url: this.instance_url, label: get(instance, 'metadata.nodeLabel', '')
// name: get(instance, 'data.metadata.nodeName', ''), })
// label: get(instance, 'data.metadata.nodeLabel', ''), })
// actor: get(instance, 'data.medatada.nodeActor', ''),
// timezone: get(instance, 'data.metadata.nodeTimezone', '')
// }
const ret = await this.$axios.$post('/instances/add_friendly', { instance_url: this.instance_url })
console.error(ret)
this.$refs.form.reset() this.$refs.form.reset()
this.dialogAddInstance = false this.dialogAddInstance = false
} catch (e) { } catch (e) {

View file

@ -18,7 +18,7 @@ v-container
:rules="[setting.required ? $validators.required(setting.description) : false]") :rules="[setting.required ? $validators.required(setting.description) : false]")
v-text-field(v-if='setting.type === "NUMBER"' v-model='selectedPlugin.settingsValue[name]' type='number' :label='setting.description') v-text-field(v-if='setting.type === "NUMBER"' v-model='selectedPlugin.settingsValue[name]' type='number' :label='setting.description')
v-switch(v-if='setting.type === "CHECK"' v-model='selectedPlugin.settingsValue[name]' :label='setting.description') v-switch(v-if='setting.type === "CHECK"' v-model='selectedPlugin.settingsValue[name]' :label='setting.description' inset)
v-select(v-if='setting.type === "LIST"' v-model='selectedPlugin.settingsValue[name]' :items='setting.items' :label='setting.description') v-select(v-if='setting.type === "LIST"' v-model='selectedPlugin.settingsValue[name]' :items='setting.items' :label='setting.description')
v-switch(:label="$t('common.enable')" inset color='primary' v-model='selectedPlugin.settingsValue["enable"]') v-switch(:label="$t('common.enable')" inset color='primary' v-model='selectedPlugin.settingsValue["enable"]')
v-card-actions v-card-actions

View file

@ -73,7 +73,7 @@ export default {
computed: mapState(['settings']), computed: mapState(['settings']),
watch: { watch: {
'smtp.secure' (value) { 'smtp.secure' (value) {
this.smtp.port = value ? 465 : 25 this.smtp.port = value ? 465 : 587
} }
}, },
methods: { methods: {

View file

@ -19,6 +19,7 @@ v-container
v-text-field(v-model='new_user.email' v-text-field(v-model='new_user.email'
:label="$t('common.email')" :label="$t('common.email')"
:rules="$validators.email") :rules="$validators.email")
v-text-field(v-model='new_user.description' :label="$t('common.description')")
v-switch(v-model='new_user.is_admin' :label="$t('common.admin')" inset) v-switch(v-model='new_user.is_admin' :label="$t('common.admin')" inset)
v-alert(type='info' :closable='false' :icon='mdiInformation') {{$t('admin.user_add_help')}} v-alert(type='info' :closable='false' :icon='mdiInformation') {{$t('admin.user_add_help')}}
v-card-actions v-card-actions

View file

@ -20,6 +20,13 @@ span
v-list-item-content v-list-item-content
v-list-item-title(v-text="$t('common.edit')") v-list-item-title(v-text="$t('common.edit')")
//- Clone
v-list-item(v-if='!event.parentId' :to='`/add/${event.id}?clone=true`')
v-list-item-icon
v-icon(v-text='mdiScanner')
v-list-item-content
v-list-item-title(v-text="$t('common.clone')")
//- Remove //- Remove
v-list-item(v-if='!event.parentId' @click='remove(false)') v-list-item(v-if='!event.parentId' @click='remove(false)')
v-list-item-icon v-list-item-icon
@ -53,26 +60,13 @@ span
v-list-item-content v-list-item-content
v-list-item-title(v-text="$t('common.remove')") v-list-item-title(v-text="$t('common.remove')")
//- v-btn(text color='primary' v-if='event.is_visible' @click='toggle(false)') {{$t(`common.${event.parentId?'skip':'hide'}`)}}
//- v-btn(text color='success' v-else @click='toggle(false)') <v-icon color='yellow' v-text='mdiAlert'></v-icon> {{$t('common.confirm')}}
//- v-btn(text color='primary' @click='$router.push(`/add/${event.id}`)') {{$t('common.edit')}}
//- v-btn(text color='primary' v-if='!event.parentId' @click='remove(false)') {{$t('common.remove')}}
//- template(v-if='event.parentId')
//- v-divider
//- span.mr-1 <v-icon v-text='mdiRepeat'></v-icon> {{$t('event.edit_recurrent')}}
//- v-btn(text color='primary' v-if='event.parent.is_visible' @click='toggle(true)') {{$t('common.pause')}}
//- v-btn(text color='primary' v-else @click='toggle(true)') {{$t('common.start')}}
//- v-btn(text color='primary' @click='$router.push(`/add/${event.parentId}`)') {{$t('common.edit')}}
//- v-btn(text color='primary' @click='remove(true)') {{$t('common.remove')}}
</template> </template>
<script> <script>
import { mdiChevronUp, mdiRepeat, mdiDelete, mdiCalendarEdit, mdiEyeOff, mdiEye, mdiPause, mdiPlay, mdiDeleteForever } from '@mdi/js' import { mdiChevronUp, mdiRepeat, mdiDelete, mdiCalendarEdit, mdiEyeOff, mdiEye, mdiPause, mdiPlay, mdiDeleteForever, mdiScanner } from '@mdi/js'
export default { export default {
name: 'EventAdmin', name: 'EventAdmin',
data () { data () {
return { mdiChevronUp, mdiRepeat, mdiDelete, mdiCalendarEdit, mdiEyeOff, mdiEye, mdiPause, mdiPlay, mdiDeleteForever } return { mdiChevronUp, mdiRepeat, mdiDelete, mdiCalendarEdit, mdiEyeOff, mdiEye, mdiPause, mdiPlay, mdiDeleteForever, mdiScanner }
}, },
props: { props: {
event: { event: {

View file

@ -25,10 +25,10 @@ function ye(t) {
function u(t, e) { function u(t, e) {
t.appendChild(e); t.appendChild(e);
} }
function p(t, e, i) { function k(t, e, i) {
t.insertBefore(e, i || null); t.insertBefore(e, i || null);
} }
function k(t) { function x(t) {
t.parentNode.removeChild(t); t.parentNode.removeChild(t);
} }
function be(t, e) { function be(t, e) {
@ -38,14 +38,14 @@ function be(t, e) {
function m(t) { function m(t) {
return document.createElement(t); return document.createElement(t);
} }
function $(t) { function z(t) {
return document.createTextNode(t); return document.createTextNode(t);
} }
function M() { function C() {
return $(" "); return z(" ");
} }
function pe() { function pe() {
return $(""); return z("");
} }
function a(t, e, i) { function a(t, e, i) {
i == null ? t.removeAttribute(e) : t.getAttribute(e) !== i && t.setAttribute(e, i); i == null ? t.removeAttribute(e) : t.getAttribute(e) !== i && t.setAttribute(e, i);
@ -69,25 +69,25 @@ let O;
function I(t) { function I(t) {
O = t; O = t;
} }
function $e() { function Ee() {
if (!O) if (!O)
throw new Error("Function called outside component initialization"); throw new Error("Function called outside component initialization");
return O; return O;
} }
function ke(t) { function ke(t) {
$e().$$.on_mount.push(t); Ee().$$.on_mount.push(t);
} }
const R = [], Z = [], P = [], ee = [], Ee = Promise.resolve(); const R = [], Z = [], P = [], ee = [], $e = Promise.resolve();
let K = !1; let K = !1;
function je() { function je() {
K || (K = !0, Ee.then(x)); K || (K = !0, $e.then(y));
} }
function Q(t) { function Q(t) {
P.push(t); P.push(t);
} }
const J = /* @__PURE__ */ new Set(); const J = /* @__PURE__ */ new Set();
let D = 0; let D = 0;
function x() { function y() {
const t = O; const t = O;
do { do {
for (; D < R.length; ) { for (; D < R.length; ) {
@ -120,8 +120,8 @@ function Ce(t, e) {
function Ae(t, e, i, l) { function Ae(t, e, i, l) {
const { fragment: n, on_mount: r, on_destroy: o, after_update: f } = t.$$; const { fragment: n, on_mount: r, on_destroy: o, after_update: f } = t.$$;
n && n.m(e, i), l || Q(() => { n && n.m(e, i), l || Q(() => {
const c = r.map(W).filter(ge); const s = r.map(W).filter(ge);
o ? o.push(...c) : U(c), t.$$.on_mount = []; o ? o.push(...s) : U(s), t.$$.on_mount = [];
}), f.forEach(Q); }), f.forEach(Q);
} }
function Me(t, e) { function Me(t, e) {
@ -132,9 +132,9 @@ function Ne(t, e) {
t.$$.dirty[0] === -1 && (R.push(t), je(), t.$$.dirty.fill(0)), t.$$.dirty[e / 31 | 0] |= 1 << e % 31; t.$$.dirty[0] === -1 && (R.push(t), je(), t.$$.dirty.fill(0)), t.$$.dirty[e / 31 | 0] |= 1 << e % 31;
} }
function we(t, e, i, l, n, r, o, f = [-1]) { function we(t, e, i, l, n, r, o, f = [-1]) {
const c = O; const s = O;
I(t); I(t);
const s = t.$$ = { const c = t.$$ = {
fragment: null, fragment: null,
ctx: null, ctx: null,
props: r, props: r,
@ -146,26 +146,26 @@ function we(t, e, i, l, n, r, o, f = [-1]) {
on_disconnect: [], on_disconnect: [],
before_update: [], before_update: [],
after_update: [], after_update: [],
context: new Map(e.context || (c ? c.$$.context : [])), context: new Map(e.context || (s ? s.$$.context : [])),
callbacks: Y(), callbacks: Y(),
dirty: f, dirty: f,
skip_bound: !1, skip_bound: !1,
root: e.target || c.$$.root root: e.target || s.$$.root
}; };
o && o(s.root); o && o(c.root);
let w = !1; let w = !1;
if (s.ctx = i ? i(t, e.props || {}, (g, _, ...A) => { if (c.ctx = i ? i(t, e.props || {}, (g, _, ...A) => {
const y = A.length ? A[0] : _; const E = A.length ? A[0] : _;
return s.ctx && n(s.ctx[g], s.ctx[g] = y) && (!s.skip_bound && s.bound[g] && s.bound[g](y), w && Ne(t, g)), _; return c.ctx && n(c.ctx[g], c.ctx[g] = E) && (!c.skip_bound && c.bound[g] && c.bound[g](E), w && Ne(t, g)), _;
}) : [], s.update(), w = !0, U(s.before_update), s.fragment = l ? l(s.ctx) : !1, e.target) { }) : [], c.update(), w = !0, U(c.before_update), c.fragment = l ? l(c.ctx) : !1, e.target) {
if (e.hydrate) { if (e.hydrate) {
const g = xe(e.target); const g = xe(e.target);
s.fragment && s.fragment.l(g), g.forEach(k); c.fragment && c.fragment.l(g), g.forEach(x);
} else } else
s.fragment && s.fragment.c(); c.fragment && c.fragment.c();
e.intro && Ce(t.$$.fragment), Ae(t, e.target, e.anchor, e.customElement), x(); e.intro && Ce(t.$$.fragment), Ae(t, e.target, e.anchor, e.customElement), y();
} }
I(c); I(s);
} }
let X; let X;
typeof HTMLElement == "function" && (X = class extends HTMLElement { typeof HTMLElement == "function" && (X = class extends HTMLElement {
@ -213,11 +213,11 @@ function V(t) {
} }
function te(t, e, i) { function te(t, e, i) {
const l = t.slice(); const l = t.slice();
return l[12] = e[i], l; return l[13] = e[i], l;
} }
function ie(t, e, i) { function ie(t, e, i) {
const l = t.slice(); const l = t.slice();
return l[15] = e[i], l; return l[16] = e[i], l;
} }
function le(t) { function le(t) {
let e; let e;
@ -226,13 +226,13 @@ function le(t) {
e = m("link"), a(e, "rel", "stylesheet"), a(e, "href", t[4]); e = m("link"), a(e, "rel", "stylesheet"), a(e, "href", t[4]);
}, },
m(i, l) { m(i, l) {
p(i, e, l); k(i, e, l);
}, },
p(i, l) { p(i, l) {
l & 16 && a(e, "href", i[4]); l & 16 && a(e, "href", i[4]);
}, },
d(i) { d(i) {
i && k(e); i && x(e);
} }
}; };
} }
@ -242,32 +242,32 @@ function ne(t) {
r[o] = fe(te(t, n, o)); r[o] = fe(te(t, n, o));
return { return {
c() { c() {
e = m("div"), l && l.c(), i = M(); e = m("div"), l && l.c(), i = C();
for (let o = 0; o < r.length; o += 1) for (let o = 0; o < r.length; o += 1)
r[o].c(); r[o].c();
a(e, "id", "gancioEvents"), L(e, "dark", t[2] === "dark"), L(e, "light", t[2] === "light"), L(e, "sidebar", t[3] === "true"), L(e, "nosidebar", t[3] !== "true"); a(e, "id", "gancioEvents"), L(e, "dark", t[2] === "dark"), L(e, "light", t[2] === "light"), L(e, "sidebar", t[3] === "true"), L(e, "nosidebar", t[3] !== "true");
}, },
m(o, f) { m(o, f) {
p(o, e, f), l && l.m(e, null), u(e, i); k(o, e, f), l && l.m(e, null), u(e, i);
for (let c = 0; c < r.length; c += 1) for (let s = 0; s < r.length; s += 1)
r[c].m(e, null); r[s].m(e, null);
}, },
p(o, f) { p(o, f) {
if (o[1] && o[3] === "true" ? l ? l.p(o, f) : (l = re(o), l.c(), l.m(e, i)) : l && (l.d(1), l = null), f & 41) { if (o[1] && o[3] === "true" ? l ? l.p(o, f) : (l = re(o), l.c(), l.m(e, i)) : l && (l.d(1), l = null), f & 41) {
n = o[5]; n = o[5];
let c; let s;
for (c = 0; c < n.length; c += 1) { for (s = 0; s < n.length; s += 1) {
const s = te(o, n, c); const c = te(o, n, s);
r[c] ? r[c].p(s, f) : (r[c] = fe(s), r[c].c(), r[c].m(e, null)); r[s] ? r[s].p(c, f) : (r[s] = fe(c), r[s].c(), r[s].m(e, null));
} }
for (; c < r.length; c += 1) for (; s < r.length; s += 1)
r[c].d(1); r[s].d(1);
r.length = n.length; r.length = n.length;
} }
f & 4 && L(e, "dark", o[2] === "dark"), f & 4 && L(e, "light", o[2] === "light"), f & 8 && L(e, "sidebar", o[3] === "true"), f & 8 && L(e, "nosidebar", o[3] !== "true"); f & 4 && L(e, "dark", o[2] === "dark"), f & 4 && L(e, "light", o[2] === "light"), f & 8 && L(e, "sidebar", o[3] === "true"), f & 8 && L(e, "nosidebar", o[3] !== "true");
}, },
d(o) { d(o) {
o && k(e), l && l.d(), be(r, o); o && x(e), l && l.d(), be(r, o);
} }
}; };
} }
@ -275,23 +275,23 @@ function re(t) {
let e, i, l, n, r, o, f; let e, i, l, n, r, o, f;
return { return {
c() { c() {
e = m("a"), i = m("div"), l = m("div"), n = $(t[1]), r = M(), o = m("img"), a(l, "class", "title"), a(o, "id", "logo"), a(o, "alt", "logo"), H(o.src, f = t[0] + "/logo.png") || a(o, "src", f), a(i, "class", "content"), a(e, "href", t[0]), a(e, "target", "_blank"), a(e, "id", "header"); e = m("a"), i = m("div"), l = m("div"), n = z(t[1]), r = C(), o = m("img"), a(l, "class", "title"), a(o, "id", "logo"), a(o, "alt", "logo"), H(o.src, f = t[0] + "/logo.png") || a(o, "src", f), a(i, "class", "content"), a(e, "href", t[0]), a(e, "target", "_blank"), a(e, "id", "header");
}, },
m(c, s) { m(s, c) {
p(c, e, s), u(e, i), u(i, l), u(l, n), u(i, r), u(i, o); k(s, e, c), u(e, i), u(i, l), u(l, n), u(i, r), u(i, o);
}, },
p(c, s) { p(s, c) {
s & 2 && T(n, c[1]), s & 1 && !H(o.src, f = c[0] + "/logo.png") && a(o, "src", f), s & 1 && a(e, "href", c[0]); c & 2 && T(n, s[1]), c & 1 && !H(o.src, f = s[0] + "/logo.png") && a(o, "src", f), c & 1 && a(e, "href", s[0]);
}, },
d(c) { d(s) {
c && k(e); s && x(e);
} }
}; };
} }
function oe(t) { function oe(t) {
let e; let e;
function i(r, o) { function i(r, o) {
return r[12].media.length ? Le : Te; return r[13].media.length ? Le : Te;
} }
let l = i(t), n = l(t); let l = i(t), n = l(t);
return { return {
@ -299,13 +299,13 @@ function oe(t) {
e = m("div"), n.c(), a(e, "class", "img"); e = m("div"), n.c(), a(e, "class", "img");
}, },
m(r, o) { m(r, o) {
p(r, e, o), n.m(e, null); k(r, e, o), n.m(e, null);
}, },
p(r, o) { p(r, o) {
l === (l = i(r)) && n ? n.p(r, o) : (n.d(1), n = l(r), n && (n.c(), n.m(e, null))); l === (l = i(r)) && n ? n.p(r, o) : (n.d(1), n = l(r), n && (n.c(), n.m(e, null)));
}, },
d(r) { d(r) {
r && k(e), n.d(); r && x(e), n.d();
} }
}; };
} }
@ -313,16 +313,16 @@ function Te(t) {
let e, i, l; let e, i, l;
return { return {
c() { c() {
e = m("img"), a(e, "style", "aspect-ratio=1.7778;"), a(e, "alt", i = t[12].title), H(e.src, l = t[0] + "/fallbackimage.png") || a(e, "src", l), a(e, "loading", "lazy"); e = m("img"), a(e, "style", "aspect-ratio=1.7778;"), a(e, "alt", i = t[13].title), H(e.src, l = t[0] + "/fallbackimage.png") || a(e, "src", l), a(e, "loading", "lazy");
}, },
m(n, r) { m(n, r) {
p(n, e, r); k(n, e, r);
}, },
p(n, r) { p(n, r) {
r & 32 && i !== (i = n[12].title) && a(e, "alt", i), r & 1 && !H(e.src, l = n[0] + "/fallbackimage.png") && a(e, "src", l); r & 32 && i !== (i = n[13].title) && a(e, "alt", i), r & 1 && !H(e.src, l = n[0] + "/fallbackimage.png") && a(e, "src", l);
}, },
d(n) { d(n) {
n && k(e); n && x(e);
} }
}; };
} }
@ -330,38 +330,38 @@ function Le(t) {
let e, i, l, n; let e, i, l, n;
return { return {
c() { c() {
e = m("img"), a(e, "style", i = "object-position: " + ue(t[12]) + "; aspect-ratio=1.7778;"), a(e, "alt", l = t[12].media[0].name), H(e.src, n = t[0] + "/media/thumb/" + t[12].media[0].url) || a(e, "src", n), a(e, "loading", "lazy"); e = m("img"), a(e, "style", i = "object-position: " + ue(t[13]) + "; aspect-ratio=1.7778;"), a(e, "alt", l = t[13].media[0].name), H(e.src, n = t[0] + "/media/thumb/" + t[13].media[0].url) || a(e, "src", n), a(e, "loading", "lazy");
}, },
m(r, o) { m(r, o) {
p(r, e, o); k(r, e, o);
}, },
p(r, o) { p(r, o) {
o & 32 && i !== (i = "object-position: " + ue(r[12]) + "; aspect-ratio=1.7778;") && a(e, "style", i), o & 32 && l !== (l = r[12].media[0].name) && a(e, "alt", l), o & 33 && !H(e.src, n = r[0] + "/media/thumb/" + r[12].media[0].url) && a(e, "src", n); o & 32 && i !== (i = "object-position: " + ue(r[13]) + "; aspect-ratio=1.7778;") && a(e, "style", i), o & 32 && l !== (l = r[13].media[0].name) && a(e, "alt", l), o & 33 && !H(e.src, n = r[0] + "/media/thumb/" + r[13].media[0].url) && a(e, "src", n);
}, },
d(r) { d(r) {
r && k(e); r && x(e);
} }
}; };
} }
function ae(t) { function ae(t) {
let e, i = t[12].place.address + "", l; let e, i = t[13].place.address + "", l;
return { return {
c() { c() {
e = m("span"), l = $(i), a(e, "class", "subtitle"); e = m("span"), l = z(i), a(e, "class", "subtitle");
}, },
m(n, r) { m(n, r) {
p(n, e, r), u(e, l); k(n, e, r), u(e, l);
}, },
p(n, r) { p(n, r) {
r & 32 && i !== (i = n[12].place.address + "") && T(l, i); r & 32 && i !== (i = n[13].place.address + "") && T(l, i);
}, },
d(n) { d(n) {
n && k(e); n && x(e);
} }
}; };
} }
function se(t) { function se(t) {
let e, i = t[12].tags, l = []; let e, i = t[13].tags, l = [];
for (let n = 0; n < i.length; n += 1) for (let n = 0; n < i.length; n += 1)
l[n] = ce(ie(t, i, n)); l[n] = ce(ie(t, i, n));
return { return {
@ -372,13 +372,13 @@ function se(t) {
a(e, "class", "tags"); a(e, "class", "tags");
}, },
m(n, r) { m(n, r) {
p(n, e, r); k(n, e, r);
for (let o = 0; o < l.length; o += 1) for (let o = 0; o < l.length; o += 1)
l[o].m(e, null); l[o].m(e, null);
}, },
p(n, r) { p(n, r) {
if (r & 32) { if (r & 32) {
i = n[12].tags; i = n[13].tags;
let o; let o;
for (o = 0; o < i.length; o += 1) { for (o = 0; o < i.length; o += 1) {
const f = ie(n, i, o); const f = ie(n, i, o);
@ -390,42 +390,41 @@ function se(t) {
} }
}, },
d(n) { d(n) {
n && k(e), be(l, n); n && x(e), be(l, n);
} }
}; };
} }
function ce(t) { function ce(t) {
let e, i, l = t[15] + "", n; let e, i, l = t[16] + "", n;
return { return {
c() { c() {
e = m("span"), i = $("#"), n = $(l), a(e, "class", "tag"); e = m("span"), i = z("#"), n = z(l), a(e, "class", "tag");
}, },
m(r, o) { m(r, o) {
p(r, e, o), u(e, i), u(e, n); k(r, e, o), u(e, i), u(e, n);
}, },
p(r, o) { p(r, o) {
o & 32 && l !== (l = r[15] + "") && T(n, l); o & 32 && l !== (l = r[16] + "") && T(n, l);
}, },
d(r) { d(r) {
r && k(e); r && x(e);
} }
}; };
} }
function fe(t) { function fe(t) {
let e, i, l, n, r = V(t[12]) + "", o, f, c, s = t[12].title + "", w, g, _, A, y = t[12].place.name + "", d, z, h, v, C, q, E = t[3] !== "true" && oe(t), j = t[12].place.name !== "online" && ae(t), S = t[12].tags.length && se(t); let e, i, l, n, r = V(t[13]) + "", o, f, s, c = t[13].title + "", w, g, _, A, E = t[13].place.name + "", M, d, h, p, v, q, $ = t[3] !== "true" && oe(t), j = t[13].place.name !== "online" && ae(t), S = t[13].tags.length && se(t);
return { return {
c() { c() {
e = m("a"), E && E.c(), i = M(), l = m("div"), n = m("div"), o = $(r), f = M(), c = m("div"), w = $(s), g = M(), _ = m("span"), A = $('@"'), d = $(y), z = $(`" e = m("a"), $ && $.c(), i = C(), l = m("div"), n = m("div"), o = z(r), f = C(), s = m("div"), w = z(c), g = C(), _ = m("span"), A = z("@"), M = z(E), d = C(), j && j.c(), h = C(), S && S.c(), p = C(), a(n, "class", "subtitle"), a(s, "class", "title"), a(_, "class", "place"), a(l, "class", "content"), a(e, "href", v = t[0] + "/event/" + (t[13].slug || t[13].id)), a(e, "class", "event"), a(e, "title", q = t[13].title), a(e, "target", "_blank");
`), j && j.c(), h = M(), S && S.c(), v = M(), a(n, "class", "subtitle"), a(c, "class", "title"), a(_, "class", "place"), a(l, "class", "content"), a(e, "href", C = t[0] + "/event/" + (t[12].slug || t[12].id)), a(e, "class", "event"), a(e, "title", q = t[12].title), a(e, "target", "_blank");
}, },
m(b, N) { m(b, N) {
p(b, e, N), E && E.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, c), u(c, w), u(l, g), u(l, _), u(_, A), u(_, d), u(_, z), j && j.m(_, null), u(l, h), S && S.m(l, null), u(e, v); k(b, e, N), $ && $.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, s), u(s, w), u(l, g), u(l, _), u(_, A), u(_, M), u(_, d), j && j.m(_, null), u(l, h), S && S.m(l, null), u(e, p);
}, },
p(b, N) { p(b, N) {
b[3] !== "true" ? E ? E.p(b, N) : (E = oe(b), E.c(), E.m(e, i)) : E && (E.d(1), E = null), N & 32 && r !== (r = V(b[12]) + "") && T(o, r), N & 32 && s !== (s = b[12].title + "") && T(w, s), N & 32 && y !== (y = b[12].place.name + "") && T(d, y), b[12].place.name !== "online" ? j ? j.p(b, N) : (j = ae(b), j.c(), j.m(_, null)) : j && (j.d(1), j = null), b[12].tags.length ? S ? S.p(b, N) : (S = se(b), S.c(), S.m(l, null)) : S && (S.d(1), S = null), N & 33 && C !== (C = b[0] + "/event/" + (b[12].slug || b[12].id)) && a(e, "href", C), N & 32 && q !== (q = b[12].title) && a(e, "title", q); b[3] !== "true" ? $ ? $.p(b, N) : ($ = oe(b), $.c(), $.m(e, i)) : $ && ($.d(1), $ = null), N & 32 && r !== (r = V(b[13]) + "") && T(o, r), N & 32 && c !== (c = b[13].title + "") && T(w, c), N & 32 && E !== (E = b[13].place.name + "") && T(M, E), b[13].place.name !== "online" ? j ? j.p(b, N) : (j = ae(b), j.c(), j.m(_, null)) : j && (j.d(1), j = null), b[13].tags.length ? S ? S.p(b, N) : (S = se(b), S.c(), S.m(l, null)) : S && (S.d(1), S = null), N & 33 && v !== (v = b[0] + "/event/" + (b[13].slug || b[13].id)) && a(e, "href", v), N & 32 && q !== (q = b[13].title) && a(e, "title", q);
}, },
d(b) { d(b) {
b && k(e), E && E.d(), j && j.d(), S && S.d(); b && x(e), $ && $.d(), j && j.d(), S && S.d();
} }
}; };
} }
@ -433,10 +432,10 @@ function Ge(t) {
let e, i, l = t[4] && le(t), n = t[5].length && ne(t); let e, i, l = t[4] && le(t), n = t[5].length && ne(t);
return { return {
c() { c() {
l && l.c(), e = M(), n && n.c(), i = pe(), this.c = G; l && l.c(), e = C(), n && n.c(), i = pe(), this.c = G;
}, },
m(r, o) { m(r, o) {
l && l.m(r, o), p(r, e, o), n && n.m(r, o), p(r, i, o); l && l.m(r, o), k(r, e, o), n && n.m(r, o), k(r, i, o);
}, },
p(r, [o]) { p(r, [o]) {
r[4] ? l ? l.p(r, o) : (l = le(r), l.c(), l.m(e.parentNode, e)) : l && (l.d(1), l = null), r[5].length ? n ? n.p(r, o) : (n = ne(r), n.c(), n.m(i.parentNode, i)) : n && (n.d(1), n = null); r[4] ? l ? l.p(r, o) : (l = le(r), l.c(), l.m(e.parentNode, e)) : l && (l.d(1), l = null), r[5].length ? n ? n.p(r, o) : (n = ne(r), n.c(), n.m(i.parentNode, i)) : n && (n.d(1), n = null);
@ -444,7 +443,7 @@ function Ge(t) {
i: G, i: G,
o: G, o: G,
d(r) { d(r) {
l && l.d(r), r && k(e), n && n.d(r), r && k(i); l && l.d(r), r && x(e), n && n.d(r), r && x(i);
} }
}; };
} }
@ -456,34 +455,37 @@ function ue(t) {
return "center center"; return "center center";
} }
function He(t, e, i) { function He(t, e, i) {
let { baseurl: l = "" } = e, { title: n = "" } = e, { maxlength: r = !1 } = e, { tags: o = "" } = e, { places: f = "" } = e, { theme: c = "light" } = e, { show_recurrent: s = !1 } = e, { sidebar: w = "true" } = e, { external_style: g = "" } = e, _ = !1, A = []; let { baseurl: l = "" } = e, { title: n = "" } = e, { maxlength: r = !1 } = e, { collection: o = "" } = e, { tags: f = "" } = e, { places: s = "" } = e, { theme: c = "light" } = e, { show_recurrent: w = !1 } = e, { sidebar: g = "true" } = e, { external_style: _ = "" } = e, A = !1, E = [];
function y(d) { function M(d) {
if (!_) if (!A)
return; return;
const z = []; const h = [];
r && z.push(`max=${r}`), o && z.push(`tags=${o}`), f && z.push(`places=${f}`), z.push(`show_recurrent=${s ? "true" : "false"}`), fetch(`${l}/api/events?${z.join("&")}`).then((h) => h.json()).then((h) => { r && h.push(`max=${r}`);
i(5, A = h); let p = "/api/events";
}).catch((h) => { o ? p = `/api/collections/${o}` : (f && h.push(`tags=${f}`), s && h.push(`places=${s}`)), h.push(`show_recurrent=${w ? "true" : "false"}`), fetch(`${l}${p}?${h.join("&")}`).then((v) => v.json()).then((v) => {
console.error("Error loading Gancio API -> ", h); i(5, E = v.events || v);
}).catch((v) => {
console.error("Error loading Gancio API -> ", v);
}); });
} }
return ke(() => { return ke(() => {
_ = !0, y(); A = !0, M();
}), t.$$set = (d) => { }), t.$$set = (d) => {
"baseurl" in d && i(0, l = d.baseurl), "title" in d && i(1, n = d.title), "maxlength" in d && i(6, r = d.maxlength), "tags" in d && i(7, o = d.tags), "places" in d && i(8, f = d.places), "theme" in d && i(2, c = d.theme), "show_recurrent" in d && i(9, s = d.show_recurrent), "sidebar" in d && i(3, w = d.sidebar), "external_style" in d && i(4, g = d.external_style); "baseurl" in d && i(0, l = d.baseurl), "title" in d && i(1, n = d.title), "maxlength" in d && i(6, r = d.maxlength), "collection" in d && i(7, o = d.collection), "tags" in d && i(8, f = d.tags), "places" in d && i(9, s = d.places), "theme" in d && i(2, c = d.theme), "show_recurrent" in d && i(10, w = d.show_recurrent), "sidebar" in d && i(3, g = d.sidebar), "external_style" in d && i(4, _ = d.external_style);
}, t.$$.update = () => { }, t.$$.update = () => {
t.$$.dirty & 975 && y(); t.$$.dirty & 1999 && M();
}, [ }, [
l, l,
n, n,
c, c,
w,
g, g,
A, _,
E,
r, r,
o, o,
f, f,
s s,
w
]; ];
} }
class Re extends X { class Re extends X {
@ -508,21 +510,23 @@ class Re extends X {
baseurl: 0, baseurl: 0,
title: 1, title: 1,
maxlength: 6, maxlength: 6,
tags: 7, collection: 7,
places: 8, tags: 8,
places: 9,
theme: 2, theme: 2,
show_recurrent: 9, show_recurrent: 10,
sidebar: 3, sidebar: 3,
external_style: 4 external_style: 4
}, },
null null
), e && (e.target && p(e.target, this, e.anchor), e.props && (this.$set(e.props), x())); ), e && (e.target && k(e.target, this, e.anchor), e.props && (this.$set(e.props), y()));
} }
static get observedAttributes() { static get observedAttributes() {
return [ return [
"baseurl", "baseurl",
"title", "title",
"maxlength", "maxlength",
"collection",
"tags", "tags",
"places", "places",
"theme", "theme",
@ -535,72 +539,78 @@ class Re extends X {
return this.$$.ctx[0]; return this.$$.ctx[0];
} }
set baseurl(e) { set baseurl(e) {
this.$$set({ baseurl: e }), x(); this.$$set({ baseurl: e }), y();
} }
get title() { get title() {
return this.$$.ctx[1]; return this.$$.ctx[1];
} }
set title(e) { set title(e) {
this.$$set({ title: e }), x(); this.$$set({ title: e }), y();
} }
get maxlength() { get maxlength() {
return this.$$.ctx[6]; return this.$$.ctx[6];
} }
set maxlength(e) { set maxlength(e) {
this.$$set({ maxlength: e }), x(); this.$$set({ maxlength: e }), y();
} }
get tags() { get collection() {
return this.$$.ctx[7]; return this.$$.ctx[7];
} }
set tags(e) { set collection(e) {
this.$$set({ tags: e }), x(); this.$$set({ collection: e }), y();
} }
get places() { get tags() {
return this.$$.ctx[8]; return this.$$.ctx[8];
} }
set tags(e) {
this.$$set({ tags: e }), y();
}
get places() {
return this.$$.ctx[9];
}
set places(e) { set places(e) {
this.$$set({ places: e }), x(); this.$$set({ places: e }), y();
} }
get theme() { get theme() {
return this.$$.ctx[2]; return this.$$.ctx[2];
} }
set theme(e) { set theme(e) {
this.$$set({ theme: e }), x(); this.$$set({ theme: e }), y();
} }
get show_recurrent() { get show_recurrent() {
return this.$$.ctx[9]; return this.$$.ctx[10];
} }
set show_recurrent(e) { set show_recurrent(e) {
this.$$set({ show_recurrent: e }), x(); this.$$set({ show_recurrent: e }), y();
} }
get sidebar() { get sidebar() {
return this.$$.ctx[3]; return this.$$.ctx[3];
} }
set sidebar(e) { set sidebar(e) {
this.$$set({ sidebar: e }), x(); this.$$set({ sidebar: e }), y();
} }
get external_style() { get external_style() {
return this.$$.ctx[4]; return this.$$.ctx[4];
} }
set external_style(e) { set external_style(e) {
this.$$set({ external_style: e }), x(); this.$$set({ external_style: e }), y();
} }
} }
customElements.define("gancio-events", Re); customElements.define("gancio-events", Re);
function de(t) { function de(t) {
let e, i, l, n, r = t[1].title + "", o, f, c, s = V(t[1]) + "", w, g, _, A, y = t[1].place.name + "", d, z, h = t[1].media.length && he(t); let e, i, l, n, r = t[1].title + "", o, f, s, c = V(t[1]) + "", w, g, _, A, E = t[1].place.name + "", M, d, h = t[1].media.length && he(t);
return { return {
c() { c() {
e = m("a"), h && h.c(), i = M(), l = m("div"), n = m("strong"), o = $(r), f = M(), c = m("div"), w = $(s), g = M(), _ = m("div"), A = $("@"), d = $(y), a(_, "class", "place"), a(l, "class", "container"), a(e, "href", z = t[0] + "/event/" + (t[1].slug || t[1].id)), a(e, "class", "card"), a(e, "target", "_blank"); e = m("a"), h && h.c(), i = C(), l = m("div"), n = m("strong"), o = z(r), f = C(), s = m("div"), w = z(c), g = C(), _ = m("div"), A = z("@"), M = z(E), a(_, "class", "place"), a(l, "class", "container"), a(e, "href", d = t[0] + "/event/" + (t[1].slug || t[1].id)), a(e, "class", "card"), a(e, "target", "_blank");
}, },
m(v, C) { m(p, v) {
p(v, e, C), h && h.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, c), u(c, w), u(l, g), u(l, _), u(_, A), u(_, d); k(p, e, v), h && h.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, s), u(s, w), u(l, g), u(l, _), u(_, A), u(_, M);
}, },
p(v, C) { p(p, v) {
v[1].media.length ? h ? h.p(v, C) : (h = he(v), h.c(), h.m(e, i)) : h && (h.d(1), h = null), C & 2 && r !== (r = v[1].title + "") && T(o, r), C & 2 && s !== (s = V(v[1]) + "") && T(w, s), C & 2 && y !== (y = v[1].place.name + "") && T(d, y), C & 3 && z !== (z = v[0] + "/event/" + (v[1].slug || v[1].id)) && a(e, "href", z); p[1].media.length ? h ? h.p(p, v) : (h = he(p), h.c(), h.m(e, i)) : h && (h.d(1), h = null), v & 2 && r !== (r = p[1].title + "") && T(o, r), v & 2 && c !== (c = V(p[1]) + "") && T(w, c), v & 2 && E !== (E = p[1].place.name + "") && T(M, E), v & 3 && d !== (d = p[0] + "/event/" + (p[1].slug || p[1].id)) && a(e, "href", d);
}, },
d(v) { d(p) {
v && k(e), h && h.d(); p && x(e), h && h.d();
} }
}; };
} }
@ -611,13 +621,13 @@ function he(t) {
e = m("img"), H(e.src, i = t[2](t[1])) || a(e, "src", i), a(e, "alt", l = t[1].media[0].name), a(e, "style", n = "object-position: " + me(t[1]) + "; aspect-ratio=1.7778;"); e = m("img"), H(e.src, i = t[2](t[1])) || a(e, "src", i), a(e, "alt", l = t[1].media[0].name), a(e, "style", n = "object-position: " + me(t[1]) + "; aspect-ratio=1.7778;");
}, },
m(r, o) { m(r, o) {
p(r, e, o); k(r, e, o);
}, },
p(r, o) { p(r, o) {
o & 2 && !H(e.src, i = r[2](r[1])) && a(e, "src", i), o & 2 && l !== (l = r[1].media[0].name) && a(e, "alt", l), o & 2 && n !== (n = "object-position: " + me(r[1]) + "; aspect-ratio=1.7778;") && a(e, "style", n); o & 2 && !H(e.src, i = r[2](r[1])) && a(e, "src", i), o & 2 && l !== (l = r[1].media[0].name) && a(e, "alt", l), o & 2 && n !== (n = "object-position: " + me(r[1]) + "; aspect-ratio=1.7778;") && a(e, "style", n);
}, },
d(r) { d(r) {
r && k(e); r && x(e);
} }
}; };
} }
@ -628,7 +638,7 @@ function Ie(t) {
i && i.c(), e = pe(), this.c = G; i && i.c(), e = pe(), this.c = G;
}, },
m(l, n) { m(l, n) {
i && i.m(l, n), p(l, e, n); i && i.m(l, n), k(l, e, n);
}, },
p(l, [n]) { p(l, [n]) {
l[1] ? i ? i.p(l, n) : (i = de(l), i.c(), i.m(e.parentNode, e)) : i && (i.d(1), i = null); l[1] ? i ? i.p(l, n) : (i = de(l), i.c(), i.m(e.parentNode, e)) : i && (i.d(1), i = null);
@ -636,7 +646,7 @@ function Ie(t) {
i: G, i: G,
o: G, o: G,
d(l) { d(l) {
i && i.d(l), l && k(e); i && i.d(l), l && x(e);
} }
}; };
} }
@ -649,20 +659,20 @@ function me(t) {
} }
function Oe(t, e, i) { function Oe(t, e, i) {
let { baseurl: l = "https://demo.gancio.org" } = e, { id: n } = e, r = !1, o; let { baseurl: l = "https://demo.gancio.org" } = e, { id: n } = e, r = !1, o;
function f(s, w) { function f(c, w) {
r && fetch(`${w}/api/event/detail/${s}`).then((g) => g.json()).then((g) => i(1, o = g)); r && fetch(`${w}/api/event/detail/${c}`).then((g) => g.json()).then((g) => i(1, o = g));
} }
ke(() => { ke(() => {
r = !0, f(n, l); r = !0, f(n, l);
}); });
function c(s) { function s(c) {
return `${l}/media/thumb/${s.media[0].url}`; return `${l}/media/thumb/${c.media[0].url}`;
} }
return t.$$set = (s) => { return t.$$set = (c) => {
"baseurl" in s && i(0, l = s.baseurl), "id" in s && i(3, n = s.id); "baseurl" in c && i(0, l = c.baseurl), "id" in c && i(3, n = c.id);
}, t.$$.update = () => { }, t.$$.update = () => {
t.$$.dirty & 9 && f(n, l); t.$$.dirty & 9 && f(n, l);
}, [l, o, c, n]; }, [l, o, s, n];
} }
class Ue extends X { class Ue extends X {
constructor(e) { constructor(e) {
@ -679,7 +689,7 @@ class Ue extends X {
_e, _e,
{ baseurl: 0, id: 3 }, { baseurl: 0, id: 3 },
null null
), e && (e.target && p(e.target, this, e.anchor), e.props && (this.$set(e.props), x())); ), e && (e.target && k(e.target, this, e.anchor), e.props && (this.$set(e.props), y()));
} }
static get observedAttributes() { static get observedAttributes() {
return ["baseurl", "id"]; return ["baseurl", "id"];
@ -688,13 +698,13 @@ class Ue extends X {
return this.$$.ctx[0]; return this.$$.ctx[0];
} }
set baseurl(e) { set baseurl(e) {
this.$$set({ baseurl: e }), x(); this.$$set({ baseurl: e }), y();
} }
get id() { get id() {
return this.$$.ctx[3]; return this.$$.ctx[3];
} }
set id(e) { set id(e) {
this.$$set({ id: e }), x(); this.$$set({ id: e }), y();
} }
} }
customElements.define("gancio-event", Ue); customElements.define("gancio-event", Ue);

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View file

@ -5,9 +5,59 @@ permalink: /changelog
nav_order: 10 nav_order: 10
--- ---
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
### [1.6.19](https://framagit.org/les/gancio/compare/v1.6.18...v1.6.19) (2023-11-04)
### Bug Fixes
* issue displaying recurrent event string ([a94ccda](https://framagit.org/les/gancio/commit/a94ccda049f7571a9caa90507141a0aac30331a9))
### 1.6.18 - 3 Nov '23
- [feat] allow to specify password while create new user via CLI to [support yunohost](https://github.com/YunoHost-Apps/gancio_ynh/pull/2#discussion_r1364285417)
- [feat] check if I'm reachable to myself to help in [#298](https://framagit.org/les/gancio/-/issues/298)
- [feat] improve recover and user_confirm error messages
- [feat] improve export and allow to export `collections` in rss/ics/widget
- [fix] fix postgres image version in docker-compose [#303](https://framagit.org/les/gancio/-/issues/303)
- [fix] Improve json-ld representation of events [#33](https://framagit.org/les/gancio/-/merge_requests/33)
- [fix] Add description field to admin's new user form, closes [#307](https://framagit.org/les/gancio/-/issues/307)
- [fix] use tls SSLv3 to send email, fix [#192](https://framagit.org/les/gancio/-/issues/192)
- [fix] notify user when accepted, fix [#308](https://framagit.org/les/gancio/-/issues/308)
- [fix] forgot password on active user only
- [fix] make search case insensitive, fix [#301](https://framagit.org/les/gancio/-/issues/301)
### 1.6.17 - 4 Oct '23
- [fix] typo
### 1.6.16 - 4 Oct '23
- [feat] add Czech locale
- [fix] improve datetime validation
### 1.6.15 - 3 Oct '23
- [feat] clone event
- [feat] am/pm / 24hr support, fix [#294](https://framagit.org/les/gancio/-/issues/294) [#264](https://framagit.org/les/gancio/-/issues/264)
- [feat] update telegram plugin bridge to v1.0.3, [#299](https://framagit.org/les/gancio/-/issues/299)
- [feat] include Brazilian Portuguese (pt-br) and Portugual Portuguese (pt-pt) [#292](https://framagit.org/les/gancio/-/issues/292)
- [fix] MariaDB JSON fields manual fix
- [fix] improve some corner case with SMTP From field [#297](https://framagit.org/les/gancio/-/issues/297)
- [fix] CLI has to fail when configuration not present [#284](https://framagit.org/les/gancio/-/issues/284)
- [minor] remove html2text dep from client
- [minor] RSS item's title format is now YYYY-MM-DD, [#300](https://framagit.org/les/gancio/-/issues/300)
### 1.6.14 - 30 June '23
- improve CLI accounts operations ([documentation](https://gancio.org/usage/cli))
- allow plugins to expose API ([documentation](http://gancio.org/dev/plugins))
- allow plugins to access DB ([documentation](http://gancio.org/dev/plugins))
- show map on the places page, [#276]((https://framagit.org/les/gancio/-/issues/276)) #30
- add node v18 support, [#278]((https://framagit.org/les/gancio/-/issues/278))
- fix media update, [#285]((https://framagit.org/les/gancio/-/issues/285))
- fix nodejs v14 compatibility in export
- fix invalid event microdata, [#277]((https://framagit.org/les/gancio/-/issues/277))
- fix recurrent event, [#280]((https://framagit.org/les/gancio/-/issues/280))
- update deps and locales
### 1.6.13 - 16 may '23 ### 1.6.13 - 16 may '23
- fix feed, ics, json exports - fix feed, ics, json exports

View file

@ -52,6 +52,9 @@ POST
| description | `string` | event's description (html accepted and sanitized) | | description | `string` | event's description (html accepted and sanitized) |
| place_name | `string` | the name of the place | | place_name | `string` | the name of the place |
| place_address | `string` | the address of the place | | place_address | `string` | the address of the place |
| place_latitude | `float` | the latitude of the place |
| place_longitude | `float` | the longitude of the place |
| online_locations | `array` | List of online locations |
| start_datetime | `integer` | start timestamp | | start_datetime | `integer` | start timestamp |
| multidate | `integer` | is a multidate event? | | multidate | `integer` | is a multidate event? |
| tags | `array` | List of tags | | tags | `array` | List of tags |

View file

@ -16,16 +16,110 @@ Since **v.1.2.2** you can write your own plugin that react to event related acti
> >
> [**<u>Please share your plugins or your needs</u>**](/contacts) > [**<u>Please share your plugins or your needs</u>**](/contacts)
Plugins should be inside `./plugins` directory, this is an example:
## Example
Here is a complete example of plugins feature: [https://framagit.org/les/gancio/-/blob/master/plugins/gancioPluginExample.js](https://framagit.org/les/gancio/-/blob/master/plugins/gancioPluginExample.js) .
## Basic plugin syntax
A plugin is essentially an `index.js` file inside its own path in `./plugins`, e.g. `./plugins/my-example-plugin/index.js`
```javascript
module.exports = {
}
```
Plugins should be inside `./plugins` directory but you can specify another location using [`plugins_path`](https://gancio.org/install/config#plugins-path) configuration.
## Plugin details
A plugins **MUST** expose a `configuration` key where to specify its details:
```js ```js
const plugin = { module.exports = {
gancio: null, configuration: {
load (gancio) { name: 'Example',
console.error('Plugin GancioPluginExample loaded!') author: 'lesion',
plugin.gancio = gancio url: 'https://framagit.org/les/gancio/plugins/gancioPluginExample.js',
}, description: 'Example plugin',
settings: {
my_plugin_string_setting: {
type: 'TEXT',
description: 'My plugin string setting',
required: true,
hint: 'My plugin setting support <strong>html too</strong>'
},
enable_this_feature_in_my_plugin: {
type: 'CHECK',
description: 'My plugin best feature',
required: true,
hint: 'This feature is super dupe, enable it!'
},
min_post: {
type: 'NUMBER',
description: 'it supports number too'
},
my_default_language: {
description: 'My default language',
type: 'LIST',
items: ['it', 'en', 'fr']
}
}
}
}
```
[![/assets/plugins/settings.png](/assets/plugins/settings.png)](/assets/plugins/settings.png){: data-fancybox="group" data-caption="Home"}
## Load a plugin
When a plugin is enabled by an administrator, Gancio will call the `load` method if specified:
```js
load ({ settings: gancio_settings, db, helpers, log}, settings) {
// access to your plugin local settings
console.info('Your local settings are in ', settings)
console.info(`For example, you can access to your default language setting by using ${settings.my_default_language}`)
// access to gancio settings
console.info(`Gancio settings are in ${gancio_settings}, e.g. ${gancio.settings.baseurl}`)
// log something
log.warn('This is a log entry from my example plugin')
// use the DB (since 1.6.14)
console.info(db.models.findAll())
console.info(db.query('CREATE TABLE IF NOT EXISTS myPluginTable'))
}
```
## Expose an API <span class='label label-yellow'>since 1.6.4</span>
Plugins could have public HTTP endpoints by exposing an express Router in routeAPI object.
```js
const express = require('express')
const routeAPI = express.Router()
routeAPI.get('/test', (req, res) => {
res.json('WOW!')
})
```
This endpoint will be exposed at <your_instance>/api/plugin/<your_plugin_name>/test
## Access to DB <span class='label label-yellow'>since 1.6.4</span>
TODO
## Helpers <span class='label label-red'>DOCUMENTATION NEEDED</span>
- randomString
- sanitizeHTML
- queryParamToBool
## React to events
```js
onEventCreate (event) { onEventCreate (event) {
const eventLink = `${plugin.gancio.settings.baseurl}/event/${event.slug}` const eventLink = `${plugin.gancio.settings.baseurl}/event/${event.slug}`
if (!event.is_visible) { if (!event.is_visible) {
@ -42,10 +136,6 @@ const plugin = {
onEventDelete (event) { onEventDelete (event) {
console.error(`Event "${event.title}" deleted`) console.error(`Event "${event.title}" deleted`)
} }
}
module.exports = plugin
``` ```

View file

@ -2,7 +2,7 @@ version: '3'
services: services:
db: db:
image: postgres image: postgres:15
container_name: postgres container_name: postgres
volumes: volumes:
- ./postgres:/var/lib/postgresql/data - ./postgres:/var/lib/postgresql/data

View file

@ -10,7 +10,7 @@ permalink: /
A shared agenda for local communities. A shared agenda for local communities.
{: .fs-6 } {: .fs-6 }
Last release **[1.6.13 - 16 May 2023](/changelog#1613---16-may-23)** Last release **[1.6.19 - 4 November 2023](/changelog#1619-2023-11-04)**
[Install]({% link install/install.md %}){: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 } [Install]({% link install/install.md %}){: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 }
[Demo](https://demo.gancio.org){: .btn .btn-green .fs-5 .mb-4 .mb-md-0 .mr-2 } [Demo](https://demo.gancio.org){: .btn .btn-green .fs-5 .mb-4 .mb-md-0 .mr-2 }

View file

@ -53,7 +53,7 @@ put something like this in `/opt/gancio/user_locale/en.json` to override the reg
english: english:
```json ```json
{ {
"registrer": { "register": {
"description": "My new registration page description" "description": "My new registration page description"
} }
} }

View file

@ -55,5 +55,5 @@ You'll need to [setup nginx as a proxy]({% link install/nginx.md %}) then you ca
```bash ```bash
cd /opt/gancio # or where your installation is cd /opt/gancio # or where your installation is
docker-compose pull && docker-compose restart docker-compose pull && docker-compose up -d
``` ```

View file

@ -15,7 +15,7 @@ nav_order: 7
--- ---
## Testing ## Testing
For testing purposes you could skip the nominatim installation and use one of this geocoding providers that run a server for free: For testing purposes you could skip the nominatim installation and use one of these geocoding providers that run a server for free:
- [https://photon.komoot.io/](https://photon.komoot.io/) [Terms of service](https://photon.komoot.io/) - [https://photon.komoot.io/](https://photon.komoot.io/) [Terms of service](https://photon.komoot.io/)
- [https://nominatim.openstreetmap.org/](https://nominatim.openstreetmap.org/) [Terms of service](https://operations.osmfoundation.org/policies/nominatim/) - [https://nominatim.openstreetmap.org/](https://nominatim.openstreetmap.org/) [Terms of service](https://operations.osmfoundation.org/policies/nominatim/)
@ -28,25 +28,25 @@ From [https://nominatim.org/release-docs/latest/admin/Installation/](https://nom
"A minimum of 2GB of RAM is required or installation will fail. For a full planet import 128GB of RAM or more are strongly recommended. Do not report out of memory problems if you have less than 64GB RAM." "A minimum of 2GB of RAM is required or installation will fail. For a full planet import 128GB of RAM or more are strongly recommended. Do not report out of memory problems if you have less than 64GB RAM."
### Planet mirrors ### Planet mirrors
There is a list of planet mirror at [https://wiki.openstreetmap.org/wiki/Planet.osm#Planet.osm_mirrors](https://wiki.openstreetmap.org/wiki/Planet.osm#Planet.osm_mirrors) There is a list of planet mirrors at [https://wiki.openstreetmap.org/wiki/Planet.osm#Planet.osm_mirrors](https://wiki.openstreetmap.org/wiki/Planet.osm#Planet.osm_mirrors)
There you can also find `Country and area extracts`, divided by `Worldwide extract sources` and `Regional extract sources` There you can also find `Country and area extracts`, divided by `Worldwide extract sources` and `Regional extract sources`
### Download an extract ### Download an extract
For Nominatim to work, you will needs to import files in [PBF Format](https://wiki.openstreetmap.org/wiki/PBF_Format) in the PostGis database. Those files have extension `*.osm.pbf`. For Nominatim to work, you need to import files in [PBF Format](https://wiki.openstreetmap.org/wiki/PBF_Format) in the PostGis database. Those files have extension `*.osm.pbf`.
Some of these mirrors provide also incremental updates via [OsmChange](https://wiki.openstreetmap.org/wiki/OsmChange), for example: Some of these mirrors provide also incremental updates via [OsmChange](https://wiki.openstreetmap.org/wiki/OsmChange), for example:
- Provides updates but with a lower detail - These provide updates but with a lower detail
[https://download.geofabrik.de/europe/italy/nord-ovest-updates/nord-ovest-latest.osm.pbf](http://download.geofabrik.de/europe/italy/nord-ovest-latest.osm.pbf) [https://download.geofabrik.de/europe/italy/nord-ovest-updates/nord-ovest-latest.osm.pbf](http://download.geofabrik.de/europe/italy/nord-ovest-latest.osm.pbf)
[https://download.geofabrik.de/europe/italy/nord-ovest-updates/](https://download.geofabrik.de/europe/italy/nord-ovest-updates/) [https://download.geofabrik.de/europe/italy/nord-ovest-updates/](https://download.geofabrik.de/europe/italy/nord-ovest-updates/)
- Does not provide updates but as higher level of detail - This doesn't provide updates but has an higher level of detail
[https://osmit-estratti-test.wmcloud.org/dati/poly/province/pbf/015_Milano_poly.osm.pbf](https://osmit-estratti-test.wmcloud.org/dati/poly/province/pbf/015_Milano_poly.osm.pbf) [https://osmit-estratti-test.wmcloud.org/dati/poly/province/pbf/015_Milano_poly.osm.pbf](https://osmit-estratti-test.wmcloud.org/dati/poly/province/pbf/015_Milano_poly.osm.pbf)
Needs to host multiple areas? Checkout [Osmium](https://osmcode.org/osmium-tool/manual.html), to merge multiple PBF files into one. Do you need to host multiple areas? Checkout [Osmium](https://osmcode.org/osmium-tool/manual.html), to merge multiple PBF files into one.
--- ---
## Install on Debian ## Install on Debian
There is a [detailed documentaion](https://nominatim.org/release-docs/latest/appendix/Install-on-Ubuntu-22/) for installing nominatim on `Ubuntu 22` that should be valid also to install on `Debian`. There is a [detailed documentation](https://nominatim.org/release-docs/latest/appendix/Install-on-Ubuntu-22/) for installing nominatim on `Ubuntu 22` that should be valid also to install on `Debian`.
### Setup ### Setup
[https://nominatim.org/release-docs/latest/appendix/Install-on-Ubuntu-22/#installing-the-required-software](https://nominatim.org/release-docs/latest/appendix/Install-on-Ubuntu-22/#installing-the-required-software) [https://nominatim.org/release-docs/latest/appendix/Install-on-Ubuntu-22/#installing-the-required-software](https://nominatim.org/release-docs/latest/appendix/Install-on-Ubuntu-22/#installing-the-required-software)
@ -54,14 +54,14 @@ There is a [detailed documentaion](https://nominatim.org/release-docs/latest/app
### Building and Configuration ### Building and Configuration
Get the source code from Github and change into the source directory Get the source code from Github and change into the source directory
``` ```bash
cd $USERHOME cd $USERHOME
wget https://nominatim.org/release/Nominatim-4.2.0.tar.bz2 wget https://nominatim.org/release/Nominatim-4.2.0.tar.bz2
tar xf Nominatim-4.2.0.tar.bz2 tar xf Nominatim-4.2.0.tar.bz2
``` ```
The code must be built in a separate directory. Create this directory, then configure and build Nominatim in there: The code must be built in a separate directory. Create this directory, then configure and build Nominatim in there:
``` ```bash
mkdir $USERHOME/build mkdir $USERHOME/build
cd $USERHOME/build cd $USERHOME/build
cmake $USERHOME/Nominatim-4.2.0 cmake $USERHOME/Nominatim-4.2.0
@ -91,13 +91,12 @@ From [https://github.com/mediagis/nominatim-docker](https://github.com/mediagis/
- Clone the project from sources - Clone the project from sources
```bash ```bash
git clone git@github.com:mediagis/nominatim-docker.git git clone git@github.com:mediagis/nominatim-docker.git
# cd nominatim-docker/<version>
cd nominatim-docker/4.2/contrib # released Nov 29, 2022 cd nominatim-docker/4.2/contrib # released Nov 29, 2022
docker-compose pull docker-compose pull
``` ```
- Or, use the template at `docs/docker/nominatim` - Or, use the template at `docs/docker/nominatim`
``` ```bash
cd /opt/gancio/docs/docker/nominatim cd /opt/gancio/docs/docker/nominatim
docker-compose pull docker-compose pull
``` ```
@ -111,15 +110,13 @@ wget https://download.geofabrik.de/europe/italy/nord-ovest-latest.osm.pbf \
``` ```
### Configure the environment file ### Configure the environment file
``` ```bash
cd docs/docker/nominatim/ cd docs/docker/nominatim/
cp .env.example .env cp .env.example .env
``` ```
Create a random password for nominatim a add it to .env file Create a random password for nominatim and add it to .env file
```bash ```bash
NOMINATIM_PASSWORD=random_password; NOMINATIM_PASSWORD=$(echo random_password | openssl passwd --stdin);
NOMINATIM_PASSWORD=$(echo $NOMINATIM_PASSWORD | openssl passwd --stdin);
echo $NOMINATIM_PASSWORD;
sed -i -e 's/\(NOMINATIM_PASSWORD=\)\(.*\)/\1'$NOMINATIM_PASSWORD'/g' .env sed -i -e 's/\(NOMINATIM_PASSWORD=\)\(.*\)/\1'$NOMINATIM_PASSWORD'/g' .env
``` ```

60
docs/usage/cli.md Normal file
View file

@ -0,0 +1,60 @@
---
layout: default
title: CLI
permalink: /usage/cli
nav_order: 2
parent: Usage
has_toc: true
---
# CLI - Command Line Interface
{: .no_toc }
1. TOC
{:toc}
## Using CLI
Gancio is distributed with an embedded CLI.
To use the CLI you need to specify the `config.json` configuration file via `--config <your_config.json>` flag; by default the CLI will look for one in the current directory, so if your current directory is /opt/gancio (having followed the [installation instructions](/install/debian)) there is no need to specify it.
### Using CLI with Docker installation
To use the CLI in a docker installation you can execute a shell inside the container with:
`docker exec --workdir /home/node/data -it gancio sh` and following the normal CLI usage or running commands with:
`docker exec --workdir /home/node/data gancio gancio <your command>`
(the first "gancio" is the container name)
## Users <span class='label label-yellow'>since 1.6.14</span>
All users related sub-commands starts with `gancio users`.
Note that most of this actions could be done from administration panel (Admin > Users).
### List all users
To list all users use
`gancio users list`
### Create a new user
`gancio users create <username|email>` [password]
To create an user with administrator privileges use the `--admin` flag, e.g. `gancio users create admin@example.com --admin`
### Remove a user
`gancio users remove <username|email>`
### Reset password
`gancio users reset-password <username|email>`
### Change administrator privileges
To add administrator privileges to an user:
`gancio users set-admin <username|email>`
To remove administrator privileges from an user:
`gancio users unset-admin <username|email>`

View file

@ -10,13 +10,12 @@ has_toc: true
# Plugins # Plugins
{: .no_toc } {: .no_toc }
This page is a guide to install plugins, if you want to develop one instead look [here](/dev/plugins) This page is a guide to install plugins, if you want to develop one instead look [here](/dev/plugins).
__Please note that some plugins are officially supported and distributed along with the release__
1. TOC 1. TOC
{:toc} {:toc}
## Install ## Install
To install a plugin you have to: To install a plugin you have to:
@ -49,7 +48,7 @@ __with docker__
docker-compose restart docker-compose restart
``` ```
# List of plugins # List of embedded plugins
## __Telegram__ ## __Telegram__
@ -57,6 +56,5 @@ This plugin republishes events to Telegram channels or groups.
The goal is to spread the info of our networks to the capitalist cyberspace, and pull otherwise isolated people to our radical and free part of the internet. The goal is to spread the info of our networks to the capitalist cyberspace, and pull otherwise isolated people to our radical and free part of the internet.
- **Website**: [https://framagit.org/bcn.convocala/gancio-plugin-telegram-bridge](https://framagit.org/bcn.convocala/gancio-plugin-telegram-bridge) - **Website**: [https://framagit.org/bcn.convocala/gancio-plugin-telegram-bridge](https://framagit.org/bcn.convocala/gancio-plugin-telegram-bridge)
- **Download**: [gancio-plugin-telegram-bridge-v0.2.0.zip](https://framagit.org/les/gancio-plugin-telegram-bridge/-/archive/v0.2.0/gancio-plugin-telegram-bridge-v0.2.0.zip) - **Release**: https://framagit.org/bcn.convocala/gancio-plugin-telegram-bridge/-/commit/af0eed7b42242ba484d9828157f1be0355bba69b
- **Release**: v0.2.0 / 10 Dec '22

@ -1 +1 @@
Subproject commit 971ea23b6a0d4f120387fa47673424c4a6cea21c Subproject commit 6536eb079f31f60597fb20e6f0f0a5eefe02364f

View file

@ -26,7 +26,7 @@
"places": "Llocs", "places": "Llocs",
"settings": "Configuració", "settings": "Configuració",
"actions": "Accions", "actions": "Accions",
"deactivate": "Deshabilita", "deactivate": "Desactiva",
"remove_admin": "Treu els permisos d'admin", "remove_admin": "Treu els permisos d'admin",
"activate": "Activa", "activate": "Activa",
"save": "Desa", "save": "Desa",
@ -106,7 +106,8 @@
"search_coordinates": "Cerca les coordenades", "search_coordinates": "Cerca les coordenades",
"online": "En línia", "online": "En línia",
"test": "Prova", "test": "Prova",
"show_preview": "Previsualitza" "show_preview": "Previsualitza",
"clone": "Clonar"
}, },
"login": { "login": {
"description": "Amb la sessió iniciada pots afegir activitats noves.", "description": "Amb la sessió iniciada pots afegir activitats noves.",

363
locales/cs.json Normal file
View file

@ -0,0 +1,363 @@
{
"admin": {
"announcement_remove_ok": "Oznámení odebráno",
"description_description": "Zobrazuje se v hlavičce stránky vedle názvu",
"config_plugin": "Nastavení doplňků",
"delete_announcement_confirm": "Určitě chceš odebrat toto oznámení?",
"header_image": "Úvodní obrázek",
"instance_locale_description": "Preferovaný jazyk stránek. Někdy je nutné zobrazit zprávy ve stejném jazyce pro všechny (například při zveřejňování událostí skrz ActivityPub nebo v některých e-mailech). V takových případech bude použit vybraný jazyk.",
"delete_footer_link_confirm": "Opravduc chceš odebrat tento odkaz?",
"edit_place": "Upravit místo",
"user_add_help": "Novému uživateli přijde e-mail s potvrzením a odkazem pro vyvoření hesla",
"instance_block_confirm": "Určitě chceš zablokovat instanci {instance}?",
"delete_user_confirm": "Určitě chceš odstranit tohoto uživatele?",
"hide_boost_bookmark_help": "Skryje malé ikony které zobrazují počet boostů a záložek z Fediverse",
"smtp_use_sendmail": "Použít sendmail",
"block_user": "Zablokovat uživatele",
"instance_timezone_description": "Gancio je navrženo aby pracovalo s událostmi z jednoho místa, třeba města. Všechny události v tomto místě budou zobrazování v nastavené časové zóně.",
"geocoding_test_error": "Geokódovací služba není dostupná {service_name}",
"announcement_description": "V této sekci můžeš přidat oznámení které zůstane na domovksé stránce",
"geocoding_provider_type_help": "Defaultní software je Nominatim",
"smtp_test_success": "Testovací email byl odeslán na {admin_email}, prosím zkontroluj svou schránku",
"blocked": "Zablokováno",
"hide_thumbs": "Skrýt náhledy",
"block": "Blokovat",
"domain": "Doména",
"tilelayer_test_button": "Otestovat mapové podklady",
"collections_description": "Sbírky seskupují události podle tagů a míst. Budou se zobrazovat na hlavní stránce",
"edit_tag": "Upravit tag",
"smtp_port": "SMTP Port",
"new_announcement": "Nové oznámení",
"show_resource": "Zobrazit reakci",
"enable_resources": "Povolit reakce",
"title_description": "Používá se v hlavičce stránky, v předmětech e-mailů a v exportech RSS a ICS.",
"allow_recurrent_event": "Povolit pravidelné události",
"add_link": "Přidat odkaz",
"instance_locale": "Defaultní jazyk",
"edit_tag_help": "Můžeš upravit tag tím že ho nahradíš novým nebo existujícím. {n} propojených událostí bude také upraveno.",
"trusted_instances_help": "Seznam spřátelených instancí zobrazených v záhlaví",
"widget": "Widget",
"allow_online_event_hint": "Požadovat URL ",
"known_users": "Známí uživatelé",
"enable_trusted_instances": "Zapnout přátelské instance",
"user_create_ok": "Uživatel vytvořen",
"default_images": "Defaultní obrázky",
"admin_email": "E-mail admina",
"resources": "Reakce",
"smtp_secure": "SMTP zabezpečení (TLS nebo STARTTLS)",
"allow_multidate_event": "Povolit vícedenní události",
"tilelayer_provider": "Poskytovtel mapových podkladů",
"remove_admin": "Odebrat admina",
"instance_place_help": "Zobrazí se na ostatních instancích",
"federation": "Federace / ActivityPub",
"unblock": "Odblokovat",
"footer_links": "Odkazy v patičce",
"instance_name": "Jméno instance",
"delete_trusted_instance_confirm": "Opravdu chceš odebrat tuto položku ze seznamu sprátelených instancí?",
"recurrent_event_visible": "Zobrazit defaultně pravidelné události",
"smtp_description": "<ul><li>Administrátor by měl obdržet e-mail, když je přidána anonymní událost (pokud je to povolené).</li><li>Administrátor by měl obdržet e-mail s žádostí o registraci (pokud jsou povoleny).</li><li>Uživatel by měl obdržet e-mail s žádostí o registraci.</li><li>Uživatel by měl obdržet e-mail s potvrzením registrace.</li><li>Uživatel by měl obdržet potvrzovací e-mail, když ho administrátor přidá přímo.</li><li>Uživatelé by měli obdržet e-mail pro obnovení hesla, když ho zapomněli</li></ul>",
"fallback_image": "Záložní obrázek",
"disable_user_confirm": "Určitě chceš deaktivovat tohoto uživatele?",
"delete_resource_confirm": "Určitě chceš smazat tuto reakci?",
"enable_federation_help": "Bude možné sledovat tuto instanci z Fediverse",
"user_blocked": "Uživatel {user} zablokován",
"smtp_test_button": "Odeslat testovací email",
"event_remove_ok": "Událost odstraněna",
"trusted_instances_label_default": "Spřátelené instance",
"filter_instances": "Filtrovt instance",
"trusted_instances_label": "Štítek zobrazený u spřátelených instancí",
"hide_calendar": "Skrýt kalendář",
"allow_online_event": "Povolit online události",
"allow_geolocation": "Povolit přidávání souřadnic k událostem",
"colors": "Barvy",
"favicon": "Logo",
"geocoding_countrycodes_help": "Umožňuje filtrovat vyhledávání podle PSČ",
"geocoding_provider_help": "Defaultní poskytovatel je Nominatim",
"geocoding_provider": "Poskytovatel geokódování",
"default_images_help": "Musíš <a href='/admin?tab=theme'>obnovit</a> stránku pro zobrazení změn.",
"tilelayer_test_error": "Mapové podklady od {service_name} nejsou dostupné",
"geolocation": "Geolokace",
"event_confirm_description": "Zde můžeš schválit události přidané anonymně",
"tilelayer_test_success": "Mapové podklady od {service_name} jsou funkční",
"geocoding_test_button": "Vyzkoušet geokódování",
"created_at": "Vytvořeno",
"trusted_instances_label_help": "Defaultní štítek je \"Spřátelené instance\"",
"allow_anon_event": "Povolit vytváření anonymních událostí (ty musí být později potvrzeny)?",
"hide_resource": "Skrýt reakci",
"smtp_hostname": "SMTP Hostname",
"select_instance_timezone": "Časové pásmo",
"edit_collection": "Upravit sbírku",
"user_remove_ok": "Uživatel odebrán",
"tilelayer_provider_attribution": "Poděkování",
"user_block_confirm": "Určitě chceš zablokovat uživatele {user}?",
"delete_user": "Odebrat",
"admin_email_help": "Tato adresa bude použitá jako odesílatel e-mailů. Je to také adresa na kterou jsou odesílány zprávy pro admina",
"is_dark": "Tmavý motiv",
"delete_tag_confirm": "Určitě chceš smazat tag \"{tag}\"? Tag bude odstraněn z {0} událostí.",
"allow_registration_description": "Povolit registrace?",
"geolocation_description": "<b>1. Definujte poskytovatele služby geokódování</b>.<br>V současné době jsou z těch uvedených na <a href=\"https://wiki.openstreetmap.org/wiki/Nominatim#Alternatives_.2F_Third-party_providers\">wiki webu OpenStreetMap </a>, podporovány <a href=\"https://github.com/osm-search/Nominatim\">Nominatim</a> a <a href=\"https://github.com/komoot /photon\">Photon</a>.<br>Můžete použít jednu ze souvisejících oficiálních ukázek zkopírováním odkazu v poli 'Geocoding provider':<ul><li>https://nominatim.openstreetmap.org/search (<a href=\"https://operations.osmfoundation.org/policies/nominatim/\">Smluvní podmínky</a>)</li><li>https://photon.komoot.io/api/ (<a href=\"https://photon.komoot.io/\">Smluvní podmínky</a>)</li></ul><br><b>2. Nastavte poskytovatele mapových podkladů.</b><br>Jejich seznam naleznete zde: <a href=\"https://leaflet-extras.github.io/leaflet-providers/preview/\">https: //leaflet-extras.github.io/leaflet-providers/preview/</a>",
"enable_admin_user_confirm": "Určitě chceš dát admin práva {user}?",
"instance_name_help": "Účet pro sledování skrz ActivityPub",
"new_collection": "Nová sbírka",
"geocoding_provider_type": "Software pro geokódování",
"enable_resources_help": "Povolit přidávání reakcí k událostem z Fediverse",
"delete_collection_confirm": "Určitě chceš odstranit sbírku <u>{collection}</u>?",
"add_instance": "Přidat instanci",
"tilelayer_provider_help": "Defaultní posytovatel je OpenStreetMap",
"disable_admin_user_confirm": "Určitě chceš {user} odebrat práva admina?",
"show_smtp_setup": "Nastavení E-mailů",
"geocoding_test_success": "Geokódovací služba {service_name} je funkční",
"hide_boost_bookmark": "Skrýt boosty/záložky",
"filter_users": "Filtrovat uživatele",
"place_description": "Pokud máš adresu místa špatně zadanou, můžeš ji změnit.<br/>Adresa se změní i u všech současných i minulých událostí v tomto místě.",
"instance_place": "Přibližná lokalita této instance",
"add_trusted_instance": "Přidat spřátelenou instanci",
"geocoding_countrycodes": "PSČ",
"delete_resource": "Smazat reakci",
"enable_federation": "Povolit federování",
"wrong_domain_warning": "Adresa v config.json <b>({baseurl})</b> je jiná než ta na kterou se připojuješ <b>({url})</b>"
},
"common": {
"related": "Příbuzné",
"password_updated": "Heslo změněno.",
"follow": "Sledovat",
"hide": "Skrýt",
"embed_help": "Po vložení tohoto kódu do tvého webu bude událost zobrazena takto",
"recover_password": "Obnovit heslo",
"preview": "Náhled",
"media": "Média",
"start": "Spustit",
"email": "E-mail",
"tag": "Štítek",
"events": "Události",
"announcements": "Oznámení",
"edit": "Upravit",
"calendar": "Kalendář",
"plugins": "Doplňky",
"save": "Uložit",
"edit_event": "Upravit událost",
"remove_admin": "Odebrat admina",
"feed": "RSS Zdroj",
"add": "Přidat",
"export": "Export",
"authorize": "Autorizovat",
"feed_url_copied": "Otevři zkopírovaný odkaz ve své RSS čtečce",
"copy_link": "Kopírovat odkaz",
"activate": "Zapnout",
"address": "Adresa",
"user": "Uživatel",
"deactivate": "Vypnout",
"share": "Sdílet",
"add_to_calendar": "Přidat do kalendáře",
"embed": "Vložit na web",
"logout": "Odhlásit se",
"name": "Jméno",
"set_password": "Nastavit heslo",
"new_user": "Nový uživatel",
"moderation": "Moderace",
"latitude": "Latitude",
"ok": "Ok",
"description": "Popis",
"logout_ok": "Odhlášený",
"label": "Označení",
"show_map": "Zobrazit mapu",
"max_events": "N. maximum událostí",
"admin": "Admin",
"info": "Info",
"users": "Uživatelé",
"event": "Událost",
"instances": "Instance",
"admin_actions": "Administrátorské nástroje",
"password": "Heslo",
"me": "Ty",
"enable": "Povolit",
"copied": "Zkopírováno",
"tags": "Štítky",
"delete": "Odstranit",
"cancel": "Zrušit",
"resources": "Zdroje",
"recurring_event_actions": "Akce pravidelných událostí",
"login": "Login",
"about": "About",
"title": "Nadpis",
"search_coordinates": "Vyhledat souřadnice",
"filter": "Filtr",
"federation": "Federace",
"url": "URL",
"follow_me_title": "Sleduj novinky z Fediverse",
"copy": "Kopírovat",
"help_translate": "Pomoc s překladem",
"skip": "Přeskočit",
"places": "Místa",
"pause": "Pozastavit",
"embed_title": "Vložit tuto událost na web",
"collections": "Sbírky",
"displayname": "Zobrazované jméno",
"settings": "Nastavení",
"theme": "Téma",
"actions": "Akce",
"send": "Odeslat",
"import": "Import",
"confirm": "Potvrdit",
"send_via_mail": "Odeslat e-mail",
"home": "Domů",
"reset": "Reset",
"longitude": "Longitude",
"disable": "Zakázat",
"fediverse": "Fediverse",
"add_event": "Přidat událost",
"n_resources": "žádný zdroj|zdroj|{n} zdrojů",
"online": "On-line",
"new_password": "Nové heslo",
"when": "Kdy",
"register": "Registrovat se",
"content": "Obsah",
"activate_user": "Potvrzeno",
"place": "Lokace",
"search": "Vyhledat",
"show_preview": "Zobrazit náhled",
"next": "Další",
"where": "Kde",
"remove": "Odstranit",
"associate": "Propojit",
"what": "Co",
"test": "Test",
"close": "Zavřít"
},
"export": {
"email_description": "Můžeš dostávat události které tě zajímají na e-mail.",
"feed_description": "Chceš-li sledovat nové události z počítače nebo smartphonu bez nutnosti pravidelně chodit na tento web, použij RSS. </p>\n\n<p> S RSS můžeš použávat speciální aplikaci pro příjem novinek z webů, které tě zajímají. Je to dobrý způsob, jak rychle sledovat mnoho stránek, bez nutnosti vytvářet si na nich účet </p>\n\n<li> Pokud máš Android, doporučujeme <a href=\"https://f-droid.org/cs/packages/net.frju.flym/\">Flym</a> nebo Feeder </li>\n<li> Pro iPhone / iPad můžeš použít <a href=\"https://itunes.apple.com/ua/app/feeds4u/id1038456442442?mt=8\"> Feed4U </a> </li> </li>\n<li> Pro stolní / notebook doporučujeme Feedbro, dá se nainstalovat do <a href=\"https://addons.mozilla.org/cs-GB/firefox/addon/feedbroreader/\"> Firefoxu </a> nebo <a href=\"https://chrome.google.com/webstore/detail/feedbro/mefgmmbdailogpfhfblcnnjfmnmdfa\"> Chrome </a>. </li>\n<br/>\nPřidej si tento odkaz do své RSS čtečky a zůstaň v obraze.",
"intro": "Na rozdíl od asociálních platforem které dělají vše proto aby si udrželi uživatele a jejich data, my věříme že informace musí být svobodné, stejně jako lidí. Proto můžete získávat aktuality o událostech i bez nutnosti chodit na tuto stránku.",
"list_description": "Pokud máte vlastní webovou stránku a chcete sdílet seznam událostí, použijte tento kód",
"ical_description": "Počítače a telefony jsou obvykle vybaveny aplikací kalendáře která umožňuje připojení vzdáleného kalendáře.",
"insert_your_address": "Vlož svoji e-mailovou adresu"
},
"event": {
"added_anon": "Událost přidána, ještě ale musí být schválena.",
"image_too_big": "Obrázek nesmí být větší než 4MB",
"where_advanced_options": "Místo - Pokročilé možnosti",
"import_description": "Můžete importovat události z jiných platforem pomocí standartních formátů (ics a h-event)",
"online_locations_fallback_urls": "Záložní odkazy",
"address_description": "Jaká je adresa?",
"anon": "Anonym",
"interact_with_me_at": "Interaguj se mnou ve Fediverse na",
"choose_focal_point": "Vyber střed náhledu",
"follow_me_description": "Jeden ze způsobů, jak zůstat v obraze o událostech zveřejněných zde na {title},\nje sledovat účet <u>{account}</u> ve fediverse, například přes Mastodon, a odtamtud případně reagovat na události.<br/><br/>\nPokud jsi nikdy neslyšel*a o Mastodonu a fediverse, doporučujeme přečíst si <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'>tento článek</a> .<br/><br/>Níže zadejte svou instanci (např. mastodon.social)",
"import_ICS": "Importovat z ICS",
"interact_with_me": "Sledovat",
"show_recurrent": "pravidelné události",
"confirmed": "Událost potvrzena",
"show_multidate": "vícedenní události",
"normal_description": "Vybrat den.",
"from": "Od",
"updated": "Událost aktualizována",
"show_past": "také předchozí události",
"download_flyer": "Stáhnout leták",
"ics": "ICS",
"not_found": "Událost nenalezena",
"added": "Událost přidána",
"recurrent_2m_days": "Vždy {days} každý druhý měsíc",
"multidate_description": "Jde o festival? Vyber kdy začíná a končí",
"where_advanced_options_description": "Zde můžete nastavit další parametry místa",
"online_locations": "Online místa",
"online_locations_help": "Například adresa videokonferenční místosti, nebo záložní adresa (maximálně 3)",
"edit_recurrent": "Upravit pravidelnou událost:",
"recurrent_2w_days": "Každý druhý: {days}",
"each_2w": "Každý druhý týden",
"media_description": "Můžeš přidat leták (volitelně)",
"due": "do",
"address_geocoded_disclaimer": "Pokud ve výsledcích geokódování nemůžete najít <strong>adresu ulice</strong> nebo <strong>číslo domu</strong>, které hledáte, můžete je ručně vložit do pole 'Adresa', aniž byste ztratili souřadnice. Nezapomeňte také, že projekt <a target=\"_blank\" href=\"https://www.openstreetmap.org/\">OpenStreetMap</a> je otevřen úpravám. Pokud máte Android, doporučujeme aplikaci <a target=\"_blank\" href=\"https://f-droid.org/en/packages/de.westnordost.streetcomplete/\">StreetComplete</a> ",
"alt_text_description": "Popis pro lidi s poruchami zraku",
"recurrent_1m_ordinal": "Každý {n} {days} of the month",
"normal": "Normální",
"recurrent_2m_ordinal": "Každý {n} {days} každý druhý měsíc",
"anon_description": "Můžeš přidat událost bez registrace i přihlášení, budeš ale muset počkat než si ji někdo přečte,\na posoudí její schválení. Pak už nebude možné ji upravova.<br/><br/>\nMůžeš se ale taky <a href='/login'>přihlásit</a> či <a href='/register'>zaregistrovat</a>. Jinak můžeš pokračovat a my se pokusíme odpovědět co nejdřív. ",
"recurrent_1w_days": "Každý {days}",
"recurrent_1m_days": "Vždy {days} v měsící",
"each_week": "Každý týden",
"what_description": "Nadpis",
"only_future": "pouze budoucí události",
"multidate": "Více dní",
"description_description": "Popis",
"recurrent": "Pravidelné",
"remove_recurrent_confirmation": "Přejete si odstranit tuto pravidelnou událost?\nMinulé události budou zachovány, nebudou ale vytvořeny žádné budoucí.",
"where_description": "Kde se událost nachází? Pokud místo ještě neexistuje, můžeš ho vytvořit.",
"address_description_osm": "Vyhledat souřadnice podle adresy (díky <a href='http://osm.org/copyright'>OpenStreetMap</a>)",
"same_day": "ve stejný den",
"recurrent_description": "Vybrat frekvenci a dny",
"import_URL": "Importovat z URL",
"remove_media_confirmation": "Chceš opravdu odstranit obrázek?",
"each_month": "Každý měsíc",
"remove_confirmation": "Určitě chceš odstranit tuto událost?",
"tag_description": "Tag",
"saved": "Událost uložena"
},
"validators": {
"latitude": "Vlož platnou zeměpisnou šířku (-90 < šířka < 90)",
"email": "Vlož platný e-mail",
"longitude": "Vlož platnou zeměpisnou délku (-180 < délka < 180)",
"required": "{fieldName} je nutné vyplnit"
},
"login": {
"insert_email": "Vlož svou e-mailovou adresu",
"not_registered": "Nemáš registraci?",
"description": "Po přihlášení můžeš přidávat nové události.",
"ok": "Přihlášení úspěšné",
"forgot_password": "Zapomenuté heslo?",
"check_email": "Zkontroluj svůj e-mail a spam.",
"error": "Přihlášení se nezdařilo. Zkontroluj údaje."
},
"ordinal": {
"-1": "poslední",
"5": "pátý",
"1": "první",
"2": "druhý",
"3": "třetí",
"4": "čtvrtý"
},
"error": {
"email_taken": "Tento email je již používán.",
"nick_taken": "Tato přezdívka je již používána."
},
"settings": {
"password_updated": "Heslo změněno.",
"remove_account": "Kliknutím na tlačítko bude tvůj účet odstraněn. Vytvořené události budou zachovány.",
"update_confirm": "Chceš uložit změny?",
"danger_section": "Nebezpečná sekce",
"change_password": "Změnit heslo",
"remove_account_confirm": "Tímto permanentně smažeš svůj účet"
},
"confirm": {
"valid": "Tvůj účet je potvrzený, nyní se můžeš <a href=\"/login\">přihlásit</a>",
"title": "Ověření uživatele",
"not_valid": "Něco se pokazilo."
},
"oauth": {
"scopes": {
"event:write": "Přidat a upravovat události"
},
"authorization_request": "Aplikace <code>{app}</code> žádá o následující oprávnění na <code>{instance_name}</code>:",
"redirected_to": "Po potvrzení dojde k přesměrování na <code>{url}</code>"
},
"recover": {
"not_valid_code": "Něco se pokazilo."
},
"setup": {
"start": "Začít",
"completed_description": "<p>Nyní se můžeš přihlásit jako tento uživatel:<br/><br/>Uživatel: <b>{email}</b><br/>Heslo: <b>{password}<b/></p>",
"copy_password_dialog": "Ano, opravdu je pořeba okopírovat si heslo!",
"https_warning": "Přístupuješ na web skrz HTTP, nezapomeň změnit baseurl v config.json pokud budeš nastavovat HTTPS!",
"completed": "Nastavení dokončeno"
},
"register": {
"error": "Chyba: ",
"description": "Sociální hnutí by se měla organizovat a samofinancovat.<br/>\n<br/>Než budeš moci zveřejňovat události, <strong> musí být tvůj účet schválen</strong>, měj na paměti, že <strong>za tímto webem najdeš skutečné lidi</strong>, takže nám prosím napiš dva řádky, abyste věděli, jaké události budeš chtít zveřejňovat.",
"complete": "Registrace byla potvrzena.",
"first_user": "Admin vytvořen"
},
"auth": {
"fail": "Přihlášení se nezdařilo. Máš určitě správné heslo?",
"not_confirmed": "Zatím nepotvrzeno…"
},
"about": "\n <p><a href='https://gancio.org'>Gancio</a> je sdílená nástěnka pro místní komunity.</p>\n "
}

View file

@ -65,7 +65,7 @@
"add_event": "Veranstaltung hinzufügen", "add_event": "Veranstaltung hinzufügen",
"import": "Importieren", "import": "Importieren",
"reset": "Zurücksetzen", "reset": "Zurücksetzen",
"tags": "Markierung", "tags": "Stichworte",
"place": "Ort", "place": "Ort",
"url": "URL", "url": "URL",
"announcements": "Ankündigungen", "announcements": "Ankündigungen",
@ -99,8 +99,14 @@
"plugins": "Plugins", "plugins": "Plugins",
"help_translate": "Hilf beim Übersetzen mit", "help_translate": "Hilf beim Übersetzen mit",
"content": "Inhalt", "content": "Inhalt",
"admin_actions": "Aktionen der Administrierenden", "admin_actions": "Admin-Aktionen",
"recurring_event_actions": "Einstellungen für regelmäßige Veranstaltungen" "recurring_event_actions": "Einstellungen für regelmäßige Veranstaltungen",
"clone": "Klon",
"tag": "Stichwort",
"search_coordinates": "Suche Koordinaten",
"online": "On-line",
"show_preview": "Vorschau anzeigen",
"test": "Test"
}, },
"admin": { "admin": {
"delete_footer_link_confirm": "Möchtest du diesen Link löschen?", "delete_footer_link_confirm": "Möchtest du diesen Link löschen?",
@ -111,7 +117,7 @@
"new_announcement": "Neue Ankündigung", "new_announcement": "Neue Ankündigung",
"edit_place": "Ort bearbeiten", "edit_place": "Ort bearbeiten",
"enable_resources": "Ressourcen freischalten", "enable_resources": "Ressourcen freischalten",
"hide_boost_bookmark_help": "Versteckt die kleinen Icons, die die Anzahl der eingehenden Boosts und Lesezeichen aus dem Fediverse anzeigen", "hide_boost_bookmark_help": "Blendet die kleinen Bilder aus, die die Anzahl der eingehenden Boosts und Lesezeichen aus dem Fediverse anzeigen",
"user_add_help": "Es wird eine E-Mail an die neue nutzende Person mit einem Hinweis auf die Bestätigung der Registrierung und die Wahl eines Passworts gesendet", "user_add_help": "Es wird eine E-Mail an die neue nutzende Person mit einem Hinweis auf die Bestätigung der Registrierung und die Wahl eines Passworts gesendet",
"block_user": "nutzende Person sperren", "block_user": "nutzende Person sperren",
"filter_instances": "Instanzen filtern", "filter_instances": "Instanzen filtern",
@ -132,7 +138,7 @@
"wrong_domain_warning": "Die \"baseurl\" die in config.json konfiguriert ist <b>({baseurl})</b> unterscheidet sich von derjenigen <b>({url})</b> die du besuchst", "wrong_domain_warning": "Die \"baseurl\" die in config.json konfiguriert ist <b>({baseurl})</b> unterscheidet sich von derjenigen <b>({url})</b> die du besuchst",
"instance_place_help": "Diese Textzeile wird im Menü der anderen befreundeten Instanzen angezeigt", "instance_place_help": "Diese Textzeile wird im Menü der anderen befreundeten Instanzen angezeigt",
"place_description": "Falls ein Ort falsch ist oder sich die Adresse ändert, kannst du ihn ändern.<br/>Bitte beachte, dass alle Veranstaltungen, die mit diesem Ort verbunden sind, die Adresse ändern (auch zurückliegende).", "place_description": "Falls ein Ort falsch ist oder sich die Adresse ändert, kannst du ihn ändern.<br/>Bitte beachte, dass alle Veranstaltungen, die mit diesem Ort verbunden sind, die Adresse ändern (auch zurückliegende).",
"enable_admin_user_confirm": "Bist du dir sicher, dass du der nutzenden Person {user} Admin-Rechte gewährst?", "enable_admin_user_confirm": "Bist du dir sicher, dass du {user} Admin-Rechte zuordnen möchtest?",
"trusted_instances_help": "Befreundete Instanzen werden in der Navigationsleiste oben auf der Seite angezeigt", "trusted_instances_help": "Befreundete Instanzen werden in der Navigationsleiste oben auf der Seite angezeigt",
"trusted_instances_label": "Navigationsbezeichnung zu Friend-Instanzen", "trusted_instances_label": "Navigationsbezeichnung zu Friend-Instanzen",
"trusted_instances_label_default": "Freundliche Instanzen", "trusted_instances_label_default": "Freundliche Instanzen",
@ -188,9 +194,9 @@
"config_plugin": "Plugin Konfiguration", "config_plugin": "Plugin Konfiguration",
"hide_thumbs": "Vorschaubilder ausblenden", "hide_thumbs": "Vorschaubilder ausblenden",
"hide_calendar": "Kalender verstecken", "hide_calendar": "Kalender verstecken",
"admin_email_help": "Die Adresse, die wir als Absender für den Versand von E-Mails verwenden. Sie ist auch die Adresse, an die deine E-Mails an die Administrator:innen geschickt werden.", "admin_email_help": "Die Adresse, die wir als Absender für den Versand von E-Mails verwenden. Sie ist auch die Adresse, an die deine Admin-E-Mails geschickt werden",
"blocked": "Geblockt", "blocked": "Geblockt",
"domain": "Domain", "domain": "Internetadresse",
"known_users": "Bekannte Nutzer:innen", "known_users": "Bekannte Nutzer:innen",
"created_at": "Erstellt am", "created_at": "Erstellt am",
"geocoding_provider_type": "Software für Georeferenzierung", "geocoding_provider_type": "Software für Georeferenzierung",
@ -201,18 +207,22 @@
"geocoding_countrycodes_help": "Ermöglicht die Einrichtung eines Filters für die Suche auf der Grundlage von Ländercodes", "geocoding_countrycodes_help": "Ermöglicht die Einrichtung eines Filters für die Suche auf der Grundlage von Ländercodes",
"geocoding_test_button": "Geokodierung testen", "geocoding_test_button": "Geokodierung testen",
"geocoding_test_success": "Der Geokodierdienst unter {service_name} funktioniert", "geocoding_test_success": "Der Geokodierdienst unter {service_name} funktioniert",
"geocoding_test_error": "Der Dienst ist unter der angegebenen Adresse nicht zu erreichen: {service_name}", "geocoding_test_error": "Der Geokodierungs-Dienst ist unter der angegebenen Adresse nicht erreichbar: {service_name}",
"tilelayer_provider": "Kachel-LayerAnbieter", "tilelayer_provider": "Kachel-LayerAnbieter",
"tilelayer_provider_help": "Der Standard-Anbieter ist OpenStreetMap", "tilelayer_provider_help": "Der Standard-Anbieter ist OpenStreetMap",
"tilelayer_provider_attribution": "Namensnennung", "tilelayer_provider_attribution": "Namensnennung",
"tilelayer_test_button": "Kachel-Layer testen", "tilelayer_test_button": "Kachel-Layer testen",
"tilelayer_test_success": "Der Kachel-Layer-Dienst unter {service_name} funktioniert", "tilelayer_test_success": "Der Kachel-Layer-Dienst unter {service_name} funktioniert",
"tilelayer_test_error": "Der Dienst ist unter der angegebenen Adresse nicht zu erreichen: {service_name}", "tilelayer_test_error": "Der Tilelayer-Dienst {service_name} ist nicht erreichbar",
"geolocation": "Geolokation", "geolocation": "Geolokation",
"allow_multidate_event": "Lasse mehrtägige Veranstaltungen zu", "allow_multidate_event": "Lasse mehrtägige Veranstaltungen zu",
"admin_email": "E-Mail von der administrierenden Person", "admin_email": "E-Mail von der administrierenden Person",
"geolocation_description": "<b>1. Bestimme einen Anbieter für einen Geokodierdienst</b>.<br>Derzeit gibt es unter den im <a href=\"https://wiki.openstreetmap.org/wiki/Nominatim#Alternatives_.2F_Third-party_providers\">Wiki von OpenStreetMap</a>, Anbietern Unterstützung für die Software <a href=\"https://github.com/osm-search/Nominatim\">Nominatim</a> und <a href=\"https://github.com/komoot/photon\">Photon</a>.<br>Du kannst eine der entsprechenden offiziellen Demos verwenden, indem du den Link in das Feld \"Geocoding provider\" kopierst:<ul><li>https://nominatim.openstreetmap.org/search (<a href=\"https://operations.osmfoundation.org/policies/nominatim/\">Terms of Service</a>)</li><li>https://photon.komoot.io/api/ (<a href=\"https://photon.komoot.io/\">Terms of Service</a>)</li></ul><br><b>2. Definiere einen Anbieter für Kartenebenen.</b><br>Eine Liste von ihnen findest du hier: <a href=\"https://leaflet-extras.github.io/leaflet-providers/preview/\">https://leaflet-extras.github.io/leaflet-providers/preview/</a>", "geolocation_description": "<b>1. Bestimme einen Anbieter für einen Geokodierdienst</b>.<br>Derzeit gibt es unter den im <a href=\"https://wiki.openstreetmap.org/wiki/Nominatim#Alternatives_.2F_Third-party_providers\">Wiki von OpenStreetMap</a>, Anbietern Unterstützung für die Software <a href=\"https://github.com/osm-search/Nominatim\">Nominatim</a> und <a href=\"https://github.com/komoot/photon\">Photon</a>.<br>Du kannst eine der entsprechenden offiziellen Demos verwenden, indem du den Link in das Feld \"Geocoding provider\" kopierst:<ul><li>https://nominatim.openstreetmap.org/search (<a href=\"https://operations.osmfoundation.org/policies/nominatim/\">Terms of Service</a>)</li><li>https://photon.komoot.io/api/ (<a href=\"https://photon.komoot.io/\">Terms of Service</a>)</li></ul><br><b>2. Definiere einen Anbieter für Kartenebenen.</b><br>Eine Liste von ihnen findest du hier: <a href=\"https://leaflet-extras.github.io/leaflet-providers/preview/\">https://leaflet-extras.github.io/leaflet-providers/preview/</a>",
"default_images_help": "Du musst <a href='/admin?tab=theme'>die Seite neu laden</a>, um die Änderungen sehen zu können." "default_images_help": "Du musst <a href='/admin?tab=theme'>die Seite neu laden</a>, um die Änderungen sehen zu können.",
"edit_tag": "Stichwort bearbeiten",
"allow_online_event_hint": "Nach Internetadressen fragen ",
"allow_online_event": "Erlaube Online-Veranstaltungen",
"colors": "Farben"
}, },
"settings": { "settings": {
"update_confirm": "Willst du deine Änderung speichern?", "update_confirm": "Willst du deine Änderung speichern?",
@ -237,7 +247,9 @@
}, },
"validators": { "validators": {
"required": "{fieldName} ist erforderlich", "required": "{fieldName} ist erforderlich",
"email": "Füge eine gültige E-Mail ein" "email": "Füge eine gültige E-Mail ein",
"latitude": "Gib einen gültigen Breitengrad ein (-90 < Breitengrad < 90)",
"longitude": "Gib einen gültigen Längengrad ein (-180 < Längengrad < 180)"
}, },
"ordinal": { "ordinal": {
"-1": "letzte", "-1": "letzte",
@ -255,7 +267,7 @@
"authorization_request": "Die Anwendung <code>{app}</code> verlangt die Berechtigung die folgenden Aktionen auf <code>{instance_name}</code> ausüben zu können:" "authorization_request": "Die Anwendung <code>{app}</code> verlangt die Berechtigung die folgenden Aktionen auf <code>{instance_name}</code> ausüben zu können:"
}, },
"event": { "event": {
"tag_description": "Markierung", "tag_description": "Stichwort",
"description_description": "Beschreibung", "description_description": "Beschreibung",
"what_description": "Titel", "what_description": "Titel",
"same_day": "am selben Tag", "same_day": "am selben Tag",
@ -274,14 +286,14 @@
"each_2w": "Jede zweite Woche", "each_2w": "Jede zweite Woche",
"ics": "ICS", "ics": "ICS",
"remove_recurrent_confirmation": "Bist du dir sicher, dass du diese wiederkehrende Veranstaltung entfernen möchtest?\nFrühere Veranstaltungen werden beibehalten, aber es werden keine zukünftigen Veranstaltungen mehr hinzugefügt.", "remove_recurrent_confirmation": "Bist du dir sicher, dass du diese wiederkehrende Veranstaltung entfernen möchtest?\nFrühere Veranstaltungen werden beibehalten, aber es werden keine zukünftigen Veranstaltungen mehr hinzugefügt.",
"anon_description": "Du kannst eine Veranstaltung hinzufügen, ohne dich zu registrieren oder anzumelden,\nmusst dann aber warten, bis jemand es liest und bestätigt, dass es eine zulässige Veranstaltung ist.\nEs ist nicht möglich, den Eintrag zu verändern.<br/><br/>\nDu kannst dich stattdessen <a href='/login'>anmelden</a> oder <a href='/register'>registrieren</a>. In diesem Fall solltest du so schnell wie möglich eine Antwort erhalten. ", "anon_description": "Es ist möglich, eine Veranstaltung hinzufügen, ohne vorherige Registrierung oder Anmeldung. Die Veranstaltung wartet, bis sie von einer Person bestätigt wird.\nEs ist nicht möglich, den Eintrag nachträglich zu verändern.<br/><br/>\nDu kannst dich stattdessen <a href='/login'>anmelden</a> oder <a href='/register'>registrieren</a>. Falls nicht, fahre fort. Wir schalten Deine Veranstaltung frei, sobald es uns möglich ist. ",
"where_description": "Wo ist die Veranstaltung? Wenn der Ort noch nicht beschrieben wurde, kannst du ihn selbst eintragen.", "where_description": "Wo ist die Veranstaltung? Wenn der Ort noch nicht beschrieben wurde, kannst du ihn selbst eintragen.",
"coordinates_search": "Suche nach Koordinaten", "coordinates_search": "Suche nach Koordinaten",
"coordinates_search_description": "Sie können den Ort anhand des Namens suchen oder das Koordinatenpaar einfügen.", "coordinates_search_description": "Sie können den Ort anhand des Namens suchen oder das Koordinatenpaar einfügen.",
"follow_me_description": "Eine Möglichkeit, über die hier auf {title} veröffentlichten Veranstaltungen auf dem Laufenden zu bleiben, besteht darin, dem Account <u>{account}</u> aus dem Fediverse zu folgen, zum Beispiel über Mastodon, und von dort aus eventuell Ressourcen für eine Veranstaltung hinzuzufügen.<br/><br/>\nWenn Du noch nie von Mastodon und dem Fediverse gehört hast, empfehlen wir dir, diesen Artikel <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'> zu lesen</a>.<br/><br/>Gib unten deine Instanz ein (z.B. mastodon.social)", "follow_me_description": "Eine Möglichkeit, über die hier auf {title} veröffentlichten Veranstaltungen auf dem Laufenden zu bleiben,\nbesteht darin, dem Account <u>{account}</u> aus dem Fediverse zu folgen, zum Beispiel über Mastodon, und von dort aus eventuell Ressourcen für eine Veranstaltung hinzuzufügen.<br/><br/>\nWenn Du noch nie von Mastodon und dem Fediverse gehört hast, empfehlen wir dir, diesen Artikel <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'> zu lesen</a>.<br/><br/>Gib unten deine Instanz ein (z.B. mastodon.social)",
"media_description": "Du kannst (optional) einen Flyer hinzufügen", "media_description": "Du kannst (optional) einen Flyer hinzufügen",
"edit_recurrent": "Bearbeite eine sich wiederholende Veranstaltung :", "edit_recurrent": "Bearbeite eine sich wiederholende Veranstaltung :",
"show_recurrent": "wiederkehrende Termine", "show_recurrent": "wiederkehrende Veranstaltungen",
"show_past": "auch ältere Veranstaltungen", "show_past": "auch ältere Veranstaltungen",
"only_future": "nur zukünftige Veranstaltungen", "only_future": "nur zukünftige Veranstaltungen",
"recurrent_description": "Wähle die Häufigkeit und Tage aus", "recurrent_description": "Wähle die Häufigkeit und Tage aus",
@ -292,10 +304,10 @@
"recurrent_1w_days": "Jeden {days}", "recurrent_1w_days": "Jeden {days}",
"recurrent_2w_days": "Jeden zweiten {days} eine", "recurrent_2w_days": "Jeden zweiten {days} eine",
"recurrent_1m_days": "Der {days} in jedem Monat", "recurrent_1m_days": "Der {days} in jedem Monat",
"recurrent_2m_days": "Der {days} jeden zweiten Monat", "recurrent_2m_days": "{days}, jeden zweiten Monat",
"recurrent_1m_ordinal": "Jeden {n} {days} im Monat", "recurrent_1m_ordinal": "Alle {n} {days}, im Monat",
"each_week": "Jede Woche", "each_week": "Jede Woche",
"recurrent_2m_ordinal": "Der {n} {days} jeden zweiten Monat", "recurrent_2m_ordinal": "Alle {n} {days}, jeden zweiten Monat",
"each_month": "Jeden Monat", "each_month": "Jeden Monat",
"due": "bis", "due": "bis",
"from": "von", "from": "von",
@ -307,7 +319,13 @@
"alt_text_description": "Beschreibung für Menschen mit Sehbehinderungen", "alt_text_description": "Beschreibung für Menschen mit Sehbehinderungen",
"choose_focal_point": "Auswahl des Schwerpunkts", "choose_focal_point": "Auswahl des Schwerpunkts",
"address_description": "Was ist die Adresse?", "address_description": "Was ist die Adresse?",
"address_description_osm": "Wo ist die Adresse? (<a href='http://osm.org/copyright'>OpenStreetMap</a> contributors)" "address_description_osm": "Koordinaten ermitteln, indem du nach einer Adresse suchst. (<a href='http://osm.org/copyright'>OpenStreetMap</a>-Mitwirkende)",
"where_advanced_options": "Ort Erweiterte Angaben",
"online_locations_fallback_urls": "Alternativadressen",
"show_multidate": "Veranstaltungen mit mehreren Terminen",
"where_advanced_options_description": "Gib hier zusätzliche Angaben zum Ort an",
"online_locations": "Orte online",
"online_locations_help": "Etwa eine Internetadresse eines Videokonferenzraums und eine Alternativadresse (maximal 3)"
}, },
"register": { "register": {
"first_user": "Admin erstellt", "first_user": "Admin erstellt",
@ -320,7 +338,7 @@
"ical_description": "Computer und Smartphones sind üblicherweise mit einer Kalenderanwendung ausgestattet, mit der ein Fernkalender importiert werden kann.", "ical_description": "Computer und Smartphones sind üblicherweise mit einer Kalenderanwendung ausgestattet, mit der ein Fernkalender importiert werden kann.",
"insert_your_address": "Gib deine E-Mail-Adresse ein", "insert_your_address": "Gib deine E-Mail-Adresse ein",
"email_description": "Du kannst interessante Veranstaltungen per E-Mail erhalten.", "email_description": "Du kannst interessante Veranstaltungen per E-Mail erhalten.",
"feed_description": "Um Updates auf deinem Computer oder Smartphone zu erhalten, ohne regelmäßig diese Seite zu öffnen, kannst du RSS-Feeds benutzen. </p>\n\n<p> Mit RSS-Feeds nutzt du eine spezielle App, um Updates von den Seiten, die dich interessieren, zu erhalten. Damit kannst du rasch vielen Seiten folgen, ohne einen\nAccount erstellen zu müssen und ohne sonstige Komplikationen. </p>\n\n<li> Für Android-Geräte empfehlen wir <a href=\"https://f-droid.org/en/packages/net.frju.flym/\">Flym</a> oder Feeder </li>\n<li> Auf iPhones / iPads kannst du <a href=\"https://itunes.apple.com/ua/app/feeds4u/id1038456442?mt=8\"> Feed4U </a> nutzen</li>\n<li> Auf Desktop-PCs oder Laptops empfehlen wir Feedbro, den du in <a href=\"https://addons.mozilla.org/en-GB/firefox/addon/feedbroreader/\"> Firefox </a> oder <a \nref=\"https://chrome.google.com/webstore/detail/feedbro/mefgmmbdailogpfhfblcnnjfmnpnmdfa\"> Chrome </a> installieren kannst. </li>\n<br/>\nIndem du diesen Link deinem RSS-Feed-Reader hinzufügst, wirst du auf dem Laufenden gehalten.", "feed_description": "Um Aktualisierungen auf deinem Computer oder Smartphone zu erhalten, ohne regelmäßig diese Seite zu öffnen, kannst du RSS-Feeds benutzen. </p>\n\n<p> Mit RSS-Feeds nutzt du eine spezielle App, um Aktualisierungen von den Seiten, die dich interessieren, zu erhalten. Damit kannst du viele Seiten überblicken, ohne ein Benutzerkonto erstellen zu müssen oder sonstige Komplikationen. </p>\n\n\n<li> Für Android-Geräte empfehlen wir <a href=\"https://f-droid.org/en/packages/net.frju.flym/\">Flym</a> oder Feeder </li>\n<li> Auf iPhones / iPads kannst du <a href=\"https://itunes.apple.com/ua/app/feeds4u/id1038456442?mt=8\"> Feed4U </a> nutzen</li>\n<li> Auf Desktop-PCs oder Laptops empfehlen wir Feedbro, den du in <a href=\"https://addons.mozilla.org/en-GB/firefox/addon/feedbroreader/\"> Firefox </a> oder <a \nref=\"https://chrome.google.com/webstore/detail/feedbro/mefgmmbdailogpfhfblcnnjfmnpnmdfa\"> Chrome </a> installieren kannst. </li>\n<br/>\nFügst du diesen Link dem RSS-Feed-Reader hinzu, wird dieser dich auf dem Laufenden halten.",
"intro": "Anders als unsoziale Netzwerke, die alles unternehmen, um nutzende Personen und deren Daten bei sich zu (be)halten, glauben wir, dass Informationen und Menschen gleichermaßen frei sein müssen. Deshalb kannst du dich über Veranstaltungen aktuell informieren, ohne zwangsläufig über diese Seite zu gehen." "intro": "Anders als unsoziale Netzwerke, die alles unternehmen, um nutzende Personen und deren Daten bei sich zu (be)halten, glauben wir, dass Informationen und Menschen gleichermaßen frei sein müssen. Deshalb kannst du dich über Veranstaltungen aktuell informieren, ohne zwangsläufig über diese Seite zu gehen."
}, },
"recover": { "recover": {
@ -329,7 +347,7 @@
"login": { "login": {
"ok": "Angemeldet", "ok": "Angemeldet",
"insert_email": "Gib deine E-Mail-Adresse ein", "insert_email": "Gib deine E-Mail-Adresse ein",
"error": "Anmeldung nicht möglich. Bitte überprüfe deine Informationen zur Anmeldung.", "error": "Anmeldung nicht möglich. Bitte überprüfe die Anmelde-Informationen.",
"forgot_password": "Passwort vergessen?", "forgot_password": "Passwort vergessen?",
"not_registered": "Nicht registriert?", "not_registered": "Nicht registriert?",
"check_email": "Überprüfe deinen E-Mail-Posteingang und Spam.", "check_email": "Überprüfe deinen E-Mail-Posteingang und Spam.",

29
locales/email/cs.json Normal file
View file

@ -0,0 +1,29 @@
{
"register": {
"content": "Přijali jsme žádost o registraci, potvrdíme ji co nejdříve.",
"subject": "Žádost o registraci byla přijata"
},
"user_confirm": {
"content": "Ahoj, tvůj účet na <a href='{{config.baseurl}}'>{{config.title}}</a> byl vytvořený. <a href='{{config.baseurl}}/user_confirm/{{user.recover_code}}'>Potvrď ho a nastav si heslo.</a>.",
"subject": "Nyní můžeš začít zveřejňovat události"
},
"event_confirm": {
"content": "Tuto událost můžeš potvrdit na <a href='{{url}}'>této stránce </a>"
},
"admin_register": {
"subject": "Nová registrace",
"content": "{{user.email}} požádal o registraci na {{config.title}}: <br/><pre>{{user.description}}</pre><br/> Potvrď ji <a href='{{config.baseurl}}/admin'>zde</a>."
},
"confirm": {
"subject": "Teď můžete začít zveřejňovat události",
"content": "Ahoj, tvůj účet na <a href='{{config.baseurl}}'>{{config.title}}</a> byl schválený. Napiš nám na {{config.admin_email}} pokud potřebuješ další informace."
},
"recover": {
"subject": "Obnova hesla",
"content": "Ahoj, požádali jste o změnu hesla na {{config.title}}. <a href='{{config.baseurl}}/recover/{{user.recover_code}}'>Klikni zde</a> pro potvrzení."
},
"test": {
"content": "Toto je testovací email, nastavení je funkční.",
"subject": "Nastavení SMTP je funkční"
}
}

View file

@ -24,6 +24,6 @@
}, },
"test": { "test": {
"content": "Dieses ist eine Test-E-Mail. Wenn du das hier lesen kannst, dann funktioniert deine Konfiguration richtig.", "content": "Dieses ist eine Test-E-Mail. Wenn du das hier lesen kannst, dann funktioniert deine Konfiguration richtig.",
"subject": "Deine SMTP Konfiguration funktioniert" "subject": "Deine SMTP-Konfiguration funktioniert"
} }
} }

29
locales/email/pt-BR.json Normal file
View file

@ -0,0 +1,29 @@
{
"register": {
"subject": "Pedido de registo recebido",
"content": "Recebemos o pedido de registo. Vamos confirmar assim que possível."
},
"confirm": {
"content": "Olá, sua conta em <a href='{{config.baseurl}}'>{{config.title}}</a> foi confirmada. Escreva para {{config.admin_email}} para obter qualquer informação.",
"subject": "Você pode agora começar a publicar eventos"
},
"event_confirm": {
"content": "Pode confirmar este evento <a href='{{url}}'>nesta página</a>"
},
"test": {
"subject": "A sua configuração SMTP funciona",
"content": "Este é um e-mail de teste, se estiver a ler isto, a sua configuração funciona."
},
"user_confirm": {
"subject": "Você pode agora começar a publicar eventos",
"content": "Olá, a sua conta em <a href='{{config.baseurl}}'>{{config.title}}</a> foi criada. <a href='{{config.baseurl}}/user_confirm/{{user.recover_code}}'>Confirme e escolha uma palavra-passe.</a>."
},
"admin_register": {
"subject": "Novo registo",
"content": "{{user.email}} pediu o registo em {{config.title}}: <br/><pre>{{user.description}}</pre><br/> Confirme <a href='{{config.baseurl}}/admin'>aqui</a>."
},
"recover": {
"subject": "Recuperação da palavra-passe",
"content": "Olá, solicitou a recuperação da sua palavra-passe em {{config.title}}. <a href='{{config.baseurl}}/recover/{{user.recover_code}}'>Clique aqui</a> para confirmar."
}
}

1
locales/email/pt-PT.json Normal file
View file

@ -0,0 +1 @@
{}

View file

@ -8,22 +8,22 @@
"subject": "Você pode agora começar a publicar eventos" "subject": "Você pode agora começar a publicar eventos"
}, },
"event_confirm": { "event_confirm": {
"content": "Você pode confirmar este evento <a href='{{url}}'>nesta página</a>" "content": "Pode confirmar este evento <a href='{{url}}'>nesta página</a>"
}, },
"test": { "test": {
"subject": "Sua configuração SMTP está funcionando", "subject": "A sua configuração SMTP funciona",
"content": "Este é um e-mail de teste, se estiver lendo isto, sua configuração está funcionando." "content": "Este é um e-mail de teste, se estiver a ler isto, a sua configuração funciona."
}, },
"user_confirm": { "user_confirm": {
"subject": "Você pode agora começar a publicar eventos", "subject": "Você pode agora começar a publicar eventos",
"content": "Olá, sua conta em <a href='{{config.baseurl}}'>{{config.title}}</a> foi criada. <a href='{{config.baseurl}}/user_confirm/{{user.recover_code}}'>Confirme e escolha uma senha.</a>." "content": "Olá, a sua conta em <a href='{{config.baseurl}}'>{{config.title}}</a> foi criada. <a href='{{config.baseurl}}/user_confirm/{{user.recover_code}}'>Confirme e escolha uma palavra-passe.</a>."
}, },
"admin_register": { "admin_register": {
"subject": "Novo registro", "subject": "Novo registo",
"content": "{{user.email}} pediu o registro em {{config.title}}: <br/><pre>{{user.description}}</pre><br/> Confirme <a href='{{config.baseurl}}/admin'>aqui</a>." "content": "{{user.email}} pediu o registo em {{config.title}}: <br/><pre>{{user.description}}</pre><br/> Confirme <a href='{{config.baseurl}}/admin'>aqui</a>."
}, },
"recover": { "recover": {
"subject": "Recuperação de senha", "subject": "Recuperação da palavra-passe",
"content": "Olá, você solicitou a recuperação de sua senha em {{config.title}}. <a href='{{config.baseurl}}/recover/{{user.recover_code}}'>Clique aqui</a> para confirmar." "content": "Olá, solicitou a recuperação da sua palavra-passe em {{config.title}}. <a href='{{config.baseurl}}/recover/{{user.recover_code}}'>Clique aqui</a> para confirmar."
} }
} }

View file

@ -1,364 +1,366 @@
{ {
"common": { "common": {
"add_event": "Add event", "add_event": "Add event",
"next": "Next", "next": "Next",
"export": "Export", "export": "Export",
"send": "Send", "send": "Send",
"where": "Where", "where": "Where",
"address": "Address", "address": "Address",
"when": "When", "when": "When",
"what": "What", "what": "What",
"media": "Media", "media": "Media",
"login": "Login", "login": "Login",
"email": "E-mail", "email": "E-mail",
"password": "Password", "password": "Password",
"register": "Register", "register": "Register",
"description": "Description", "description": "Description",
"remove": "Remove", "remove": "Remove",
"hide": "Hide", "hide": "Hide",
"search": "Search", "search": "Search",
"edit": "Edit", "edit": "Edit",
"info": "Info", "info": "Info",
"confirm": "Confirm", "confirm": "Confirm",
"admin": "Admin", "admin": "Admin",
"users": "Users", "users": "Users",
"events": "Events", "events": "Events",
"places": "Places", "places": "Places",
"settings": "Options", "settings": "Options",
"actions": "Actions", "actions": "Actions",
"deactivate": "Turn off", "deactivate": "Turn off",
"remove_admin": "Remove admin", "remove_admin": "Remove admin",
"activate": "Activate", "activate": "Activate",
"save": "Save", "save": "Save",
"preview": "Preview", "preview": "Preview",
"logout": "Log out", "logout": "Log out",
"share": "Share", "share": "Share",
"name": "Name", "name": "Name",
"associate": "Associate", "associate": "Associate",
"edit_event": "Edit event", "edit_event": "Edit event",
"related": "Related", "related": "Related",
"add": "Add", "add": "Add",
"logout_ok": "Logged out", "logout_ok": "Logged out",
"copy": "Copy", "copy": "Copy",
"recover_password": "Recover password", "recover_password": "Recover password",
"new_password": "New password", "new_password": "New password",
"new_user": "New user", "new_user": "New user",
"ok": "Ok", "ok": "Ok",
"cancel": "Cancel", "cancel": "Cancel",
"enable": "Enable", "enable": "Enable",
"disable": "Disable", "disable": "Disable",
"me": "You", "me": "You",
"password_updated": "Password changed.", "password_updated": "Password changed.",
"resources": "Resources", "resources": "Resources",
"n_resources": "no resource|a resource|{n} resources", "n_resources": "no resource|a resource|{n} resources",
"activate_user": "Confirmed", "activate_user": "Confirmed",
"displayname": "Display name", "displayname": "Display name",
"federation": "Federation", "federation": "Federation",
"set_password": "Set password", "set_password": "Set password",
"copy_link": "Copy link", "copy_link": "Copy link",
"send_via_mail": "Send e-mail", "send_via_mail": "Send e-mail",
"add_to_calendar": "Add to calendar", "add_to_calendar": "Add to calendar",
"instances": "Instances", "instances": "Instances",
"copied": "Copied", "copied": "Copied",
"embed": "Embed", "embed": "Embed",
"embed_title": "Embed this event on your website", "embed_title": "Embed this event on your website",
"embed_help": "Copying the following code into your website and the event will be shown like here", "embed_help": "Copying the following code into your website and the event will be shown like here",
"feed": "RSS Feed", "feed": "RSS Feed",
"feed_url_copied": "Open the copied feed URL in your RSS feed reader", "feed_url_copied": "Open the copied feed URL in your RSS feed reader",
"follow_me_title": "Follow updates from fediverse", "follow_me_title": "Follow updates from fediverse",
"follow": "Follow", "follow": "Follow",
"moderation": "Moderation", "moderation": "Moderation",
"user": "User", "user": "User",
"authorize": "Authorize", "authorize": "Authorize",
"title": "Title", "title": "Title",
"filter": "Filter", "filter": "Filter",
"event": "Event", "event": "Event",
"pause": "Pause", "pause": "Pause",
"start": "Start", "start": "Start",
"fediverse": "Fediverse", "fediverse": "Fediverse",
"skip": "Skip", "skip": "Skip",
"delete": "Remove", "delete": "Remove",
"announcements": "Announcements", "announcements": "Announcements",
"url": "URL", "url": "URL",
"place": "Place", "place": "Place",
"tags": "Tags", "tags": "Tags",
"tag": "Tag", "tag": "Tag",
"theme": "Theme", "theme": "Theme",
"reset": "Reset", "reset": "Reset",
"import": "Import", "import": "Import",
"max_events": "N. max events", "max_events": "N. max events",
"label": "Label", "label": "Label",
"collections": "Collections", "collections": "Collections",
"close": "Close", "close": "Close",
"plugins": "Plugins", "plugins": "Plugins",
"help_translate": "Help Translate", "help_translate": "Help Translate",
"show_map": "Show map", "show_map": "Show map",
"calendar": "Calendar", "calendar": "Calendar",
"home": "Home", "home": "Home",
"about": "About", "about": "About",
"content": "Content", "content": "Content",
"admin_actions": "Admin actions", "admin_actions": "Admin actions",
"recurring_event_actions": "Recurring event actions", "recurring_event_actions": "Recurring event actions",
"latitude": "Latitude", "latitude": "Latitude",
"longitude": "Longitude", "longitude": "Longitude",
"search_coordinates": "Search coordinates", "search_coordinates": "Search coordinates",
"online": "On-line", "online": "On-line",
"test": "Test", "test": "Test",
"show_preview": "Show preview" "show_preview": "Show preview",
}, "clone": "Clone"
"login": { },
"description": "By logging in you can publish new events.", "login": {
"check_email": "Check your e-mail inbox and spam.", "description": "By logging in you can publish new events.",
"not_registered": "Not registered?", "check_email": "Check your e-mail inbox and spam.",
"forgot_password": "Forgot your password?", "not_registered": "Not registered?",
"error": "Could not log in. Check your login info.", "forgot_password": "Forgot your password?",
"insert_email": "Enter your e-mail address", "error": "Could not log in. Check your login info.",
"ok": "Logged in" "insert_email": "Enter your e-mail address",
}, "ok": "Logged in"
"recover": { },
"not_valid_code": "Something went wrong." "recover": {
}, "not_valid_code": "Something went wrong."
"export": { },
"intro": "Unlike the unsocial platforms that do everything to keep users and data about them, we believe that information, like people, must be free. For this you can stay updated on the events you want, without necessarily going through this site.", "export": {
"email_description": "You can get events that interest sent via e-mail.", "intro": "Unlike the unsocial platforms that do everything to keep users and data about them, we believe that information, like people, must be free. For this you can stay updated on the events you want, without necessarily going through this site.",
"insert_your_address": "Enter your e-mail address", "email_description": "You can get events that interest sent via e-mail.",
"feed_description": "To follow updates from a computer or smartphone without the need to periodically open this site, use RSS feeds. </p>\n\n<p> With RSS feeds you use a special app to receive updates from sites that interest you. It's a good way to follow many sites quickly, without the need to create an account or other complications. </p>\n\n<li> If you have Android, we recommend <a href=\"https://f-droid.org/en/packages/net.frju.flym/\">Flym</a> or Feeder </li>\n<li> For iPhone / iPad you can use <a href=\"https://itunes.apple.com/ua/app/feeds4u/id1038456442?mt=8\"> Feed4U </a> </li>\n<li> For desktop / laptop we recommend Feedbro, to be installed on <a href=\"https://addons.mozilla.org/en-GB/firefox/addon/feedbroreader/\"> Firefox </a> or <a href=\"https://chrome.google.com/webstore/detail/feedbro/mefgmmbdailogpfhfblcnnjfmnpnmdfa\"> Chrome </a>. </li>\n<br/>\nAdding this link to your RSS feed reader will keep you up to date.", "insert_your_address": "Enter your e-mail address",
"ical_description": "Computers and smartphones are commonly equipped with a calendar app capable of importing a remote calendar.", "feed_description": "To follow updates from a computer or smartphone without the need to periodically open this site, use RSS feeds. </p>\n\n<p> With RSS feeds you use a special app to receive updates from sites that interest you. It's a good way to follow many sites quickly, without the need to create an account or other complications. </p>\n\n<li> If you have Android, we recommend <a href=\"https://f-droid.org/en/packages/net.frju.flym/\">Flym</a> or Feeder </li>\n<li> For iPhone / iPad you can use <a href=\"https://itunes.apple.com/ua/app/feeds4u/id1038456442?mt=8\"> Feed4U </a> </li>\n<li> For desktop / laptop we recommend Feedbro, to be installed on <a href=\"https://addons.mozilla.org/en-GB/firefox/addon/feedbroreader/\"> Firefox </a> or <a href=\"https://chrome.google.com/webstore/detail/feedbro/mefgmmbdailogpfhfblcnnjfmnpnmdfa\"> Chrome </a>. </li>\n<br/>\nAdding this link to your RSS feed reader will keep you up to date.",
"list_description": "If you have a website and want to show a list of events, use the following code" "ical_description": "Computers and smartphones are commonly equipped with a calendar app capable of importing a remote calendar.",
}, "list_description": "If you have a website and want to show a list of events, use the following code",
"register": { "filter_description": "You can filter your export here by tags and place or by a preset collection"
"description": "Social movements should organize and self-finance.<br/>\n<br/>Before you can publish, <strong> the account must be approved</strong>, consider that <strong> behind this site you will find real people</strong>, so write two lines to let us know what events you would like to publish.", },
"error": "Error: ", "register": {
"complete": "Registration has to be confirmed.", "description": "Social movements should organize and self-finance.<br/>\n<br/>Before you can publish, <strong> the account must be approved</strong>, consider that <strong> behind this site you will find real people</strong>, so write two lines to let us know what events you would like to publish.",
"first_user": "Administrator created" "error": "Error: ",
}, "complete": "Registration has to be confirmed.",
"event": { "first_user": "Administrator created"
"anon": "Anon", },
"anon_description": "You can add an event without registering or logging in, but will have to wait for someone to read it,\nconfirming that it is a suitable event. It will not be possible to modify it.<br/><br/>\nYou can instead <a href='/login'>log in</a> or <a href='/register'>register</a>. Otherwise go ahead and get an answer as soon as possible. ", "event": {
"same_day": "on same day", "anon": "Anon",
"what_description": "Title", "anon_description": "You can add an event without registering or logging in, but will have to wait for someone to read it,\nconfirming that it is a suitable event. It will not be possible to modify it.<br/><br/>\nYou can instead <a href='/login'>log in</a> or <a href='/register'>register</a>. Otherwise go ahead and get an answer as soon as possible. ",
"description_description": "Description", "same_day": "on same day",
"tag_description": "Tag", "what_description": "Title",
"media_description": "You can add a flyer (optional)", "description_description": "Description",
"added": "Event added", "tag_description": "Tag",
"saved": "Event saved", "media_description": "You can add a flyer (optional)",
"added_anon": "Event added, but has yet to be confirmed.", "added": "Event added",
"updated": "Event updated", "saved": "Event saved",
"where_description": "Where's the event? If not present you can create it.", "added_anon": "Event added, but has yet to be confirmed.",
"address_description": "What is the address?", "updated": "Event updated",
"address_description_osm": "Search coordinates by typing the address. (<a href='http://osm.org/copyright'>OpenStreetMap</a> contributors)", "where_description": "Where's the event? If not present you can create it.",
"confirmed": "Event confirmed", "address_description": "What is the address?",
"not_found": "Could not find event", "address_description_osm": "Search coordinates by typing the address. (<a href='http://osm.org/copyright'>OpenStreetMap</a> contributors)",
"remove_confirmation": "Are you sure you want to remove this event?", "confirmed": "Event confirmed",
"recurrent": "Recurring", "not_found": "Could not find event",
"edit_recurrent": "Edit recurring event:", "remove_confirmation": "Are you sure you want to remove this event?",
"show_recurrent": "recurring events", "recurrent": "Recurring",
"show_multidate": "multidate events", "edit_recurrent": "Edit recurring event:",
"show_past": "also prior events", "show_recurrent": "recurring events",
"only_future": "only upcoming events", "show_multidate": "multidate events",
"recurrent_description": "Choose frequency and select days", "show_past": "also prior events",
"multidate_description": "Is it a festival? Choose when it starts and ends", "only_future": "only upcoming events",
"multidate": "More days", "recurrent_description": "Choose frequency and select days",
"normal": "Normal", "multidate_description": "Is it a festival? Choose when it starts and ends",
"normal_description": "Choose the day.", "multidate": "More days",
"recurrent_1w_days": "Each {days}", "normal": "Normal",
"recurrent_2w_days": "A {days} every other", "normal_description": "Choose the day.",
"recurrent_1m_days": "The {days} of each month", "recurrent_1w_days": "Each {days}",
"recurrent_2m_days": "The {days} a month every other", "recurrent_2w_days": "A {days} every other",
"recurrent_1m_ordinal": "Each {n} {days} of the month", "recurrent_1m_days": "The {days} of each month",
"recurrent_2m_ordinal": "Each {n} {days} a month every other", "recurrent_2m_days": "The {days} a month every other",
"each_week": "Each week", "recurrent_1m_ordinal": "Each {n} {days} of the month",
"each_2w": "Every other weeks", "recurrent_2m_ordinal": "Each {n} {days} a month every other",
"each_month": "Each month", "each_week": "Each week",
"due": "until", "each_2w": "Every other weeks",
"from": "From", "each_month": "Each month",
"image_too_big": "The image can't be bigger than 4MB", "due": "until",
"interact_with_me_at": "Interact with me on fediverse at", "from": "From",
"follow_me_description": "One of the ways to stay up to date on events published here on {title},\nis following the account <u>{account}</u> from the fediverse, for example via Mastodon, and possibly add resources to an event from there.<br/><br/>\nIf you have never heard of Mastodon and the fediverse we recommend reading <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'>this article</a>.<br/><br/>Enter your instance below (e.g. mastodon.social)", "image_too_big": "The image can't be bigger than 4MB",
"interact_with_me": "Follow me", "interact_with_me_at": "Interact with me on fediverse at",
"remove_recurrent_confirmation": "Are you sure you want to remove this recurring event?\nPast events will be maintained, but no further events will be created.", "follow_me_description": "One of the ways to stay up to date on events published here on {title},\nis following the account <u>{account}</u> from the fediverse, for example via Mastodon, and possibly add resources to an event from there.<br/><br/>\nIf you have never heard of Mastodon and the fediverse we recommend reading <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'>this article</a>.<br/><br/>Enter your instance below (e.g. mastodon.social)",
"import_URL": "Import from URL", "interact_with_me": "Follow me",
"import_ICS": "Import from ICS", "remove_recurrent_confirmation": "Are you sure you want to remove this recurring event?\nPast events will be maintained, but no further events will be created.",
"ics": "ICS", "import_URL": "Import from URL",
"import_description": "You can import events from other platforms and other instances through standard formats (ics and h-event)", "import_ICS": "Import from ICS",
"alt_text_description": "Description for people with visual impairments", "ics": "ICS",
"choose_focal_point": "Choose the focal point", "import_description": "You can import events from other platforms and other instances through standard formats (ics and h-event)",
"remove_media_confirmation": "Do you confirm the image removal?", "alt_text_description": "Description for people with visual impairments",
"download_flyer": "Download flyer", "choose_focal_point": "Choose the focal point",
"where_advanced_options": "Place - Advanced options", "remove_media_confirmation": "Do you confirm the image removal?",
"where_advanced_options_description": "Define here additional place properties", "download_flyer": "Download flyer",
"online_locations": "Online locations", "where_advanced_options": "Place - Advanced options",
"online_locations_help": "For instance an url to a videconference room and a fallback url (max. 3)", "where_advanced_options_description": "Define here additional place properties",
"online_locations_fallback_urls": "Fallback links", "online_locations": "Online locations",
"address_geocoded_disclaimer": "If you cannot find the <strong>street address</strong> or the <strong>housenumber</strong> you are looking for in the geocoding results, you can manually insert them in the 'Address' field without loose the coordinates. Consider also that the <a target=\"_blank\" href=\"https://www.openstreetmap.org/\">OpenStreetMap</a> project is open to contributions. If you have Android, we recommend <a target=\"_blank\" href=\"https://f-droid.org/en/packages/de.westnordost.streetcomplete/\">StreetComplete</a> " "online_locations_help": "For instance an url to a videconference room and a fallback url (max. 3)",
}, "online_locations_fallback_urls": "Fallback links",
"admin": { "address_geocoded_disclaimer": "If you cannot find the <strong>street address</strong> or the <strong>housenumber</strong> you are looking for in the geocoding results, you can manually insert them in the 'Address' field without loose the coordinates. Consider also that the <a target=\"_blank\" href=\"https://www.openstreetmap.org/\">OpenStreetMap</a> project is open to contributions. If you have Android, we recommend <a target=\"_blank\" href=\"https://f-droid.org/en/packages/de.westnordost.streetcomplete/\">StreetComplete</a> "
"place_description": "If you have gotten the place or address wrong, you can change it.<br/>All current and past events associated with this place will change address.", },
"event_confirm_description": "You can confirm events entered by anonymous users here", "admin": {
"delete_user": "Remove", "place_description": "If you have gotten the place or address wrong, you can change it.<br/>All current and past events associated with this place will change address.",
"remove_admin": "Remove admin", "event_confirm_description": "You can confirm events entered by anonymous users here",
"disable_user_confirm": "Are you sure you want to disable {user}?", "delete_user": "Remove",
"delete_user_confirm": "Are you sure you want to remove {user}?", "remove_admin": "Remove admin",
"disable_admin_user_confirm": "Are you sure to remove admin permissions from {user}?", "disable_user_confirm": "Are you sure you want to disable {user}?",
"enable_admin_user_confirm": "Are you sure to add admin permissions to {user}?", "delete_user_confirm": "Are you sure you want to remove {user}?",
"user_remove_ok": "User removed", "disable_admin_user_confirm": "Are you sure to remove admin permissions from {user}?",
"user_create_ok": "User created", "enable_admin_user_confirm": "Are you sure to add admin permissions to {user}?",
"event_remove_ok": "Event removed", "user_remove_ok": "User removed",
"allow_registration_description": "Allow open registrations?", "user_create_ok": "User created",
"allow_anon_event": "Allow anonymous events (has to be confirmed)?", "event_remove_ok": "Event removed",
"allow_multidate_event": "Allow multi-day events", "allow_registration_description": "Allow open registrations?",
"allow_recurrent_event": "Allow recurring events", "allow_anon_event": "Allow anonymous events (has to be confirmed)?",
"allow_online_event": "Allow online events", "allow_multidate_event": "Allow multi-day events",
"allow_online_event_hint": "Ask for urls ", "allow_recurrent_event": "Allow recurring events",
"allow_geolocation": "Allow events geolocation", "allow_online_event": "Allow online events",
"recurrent_event_visible": "Show recurring events by default", "allow_online_event_hint": "Ask for urls ",
"federation": "Federation / ActivityPub", "allow_geolocation": "Allow events geolocation",
"enable_federation": "Turn on federation", "recurrent_event_visible": "Show recurring events by default",
"enable_federation_help": "It will be possible to follow this instance from the fediverse", "federation": "Federation / ActivityPub",
"add_instance": "Add instance", "enable_federation": "Turn on federation",
"select_instance_timezone": "Time zone", "enable_federation_help": "It will be possible to follow this instance from the fediverse",
"enable_resources": "Turn on resources", "add_instance": "Add instance",
"enable_resources_help": "Allows adding resources to the event from the fediverse", "select_instance_timezone": "Time zone",
"hide_boost_bookmark": "Hides boost/bookmarks", "enable_resources": "Turn on resources",
"hide_boost_bookmark_help": "Hides the small icons showing the number of boosts and bookmarks coming from the fediverse", "enable_resources_help": "Allows adding resources to the event from the fediverse",
"block": "Block", "hide_boost_bookmark": "Hides boost/bookmarks",
"unblock": "Unblock", "hide_boost_bookmark_help": "Hides the small icons showing the number of boosts and bookmarks coming from the fediverse",
"user_add_help": "An e-mail with instructions on confirming the subscription and choosing a password will be sent to the new user", "block": "Block",
"instance_name": "Instance name", "unblock": "Unblock",
"show_resource": "Show resource", "user_add_help": "An e-mail with instructions on confirming the subscription and choosing a password will be sent to the new user",
"hide_resource": "Hide resource", "instance_name": "Instance name",
"delete_resource": "Delete resource", "show_resource": "Show resource",
"delete_resource_confirm": "Are you sure you want to delete this resource?", "hide_resource": "Hide resource",
"delete_tag_confirm": "Are you sure you want to remove the tag \"{tag}\"? The tag will be removed from {n} events.", "delete_resource": "Delete resource",
"block_user": "Block user", "delete_resource_confirm": "Are you sure you want to delete this resource?",
"filter_instances": "Filter instances", "delete_tag_confirm": "Are you sure you want to remove the tag \"{tag}\"? The tag will be removed from {n} events.",
"filter_users": "Filter users", "block_user": "Block user",
"resources": "Resources", "filter_instances": "Filter instances",
"user_blocked": "User {user} blocked", "filter_users": "Filter users",
"favicon": "Logo", "resources": "Resources",
"user_block_confirm": "Are you sure you want to block user {user}?", "user_blocked": "User {user} blocked",
"instance_block_confirm": "Are you sure you want block instance {instance}?", "favicon": "Logo",
"delete_announcement_confirm": "Are you sure you want to remove the announcement?", "user_block_confirm": "Are you sure you want to block user {user}?",
"announcement_remove_ok": "Announce removed", "instance_block_confirm": "Are you sure you want block instance {instance}?",
"announcement_description": "In this section you can insert announcements to remain on the homepage", "delete_announcement_confirm": "Are you sure you want to remove the announcement?",
"instance_locale": "Default language", "announcement_remove_ok": "Announce removed",
"instance_timezone_description": "Gancio is designed to collect the events of a specific place, such as a city. All events in this place will be shown in the time zone chosen for it.", "announcement_description": "In this section you can insert announcements to remain on the homepage",
"instance_locale_description": "Preferred user language for pages. Sometimes messages must be shown in the same language for everyone (for example when publishing via ActivityPub or when sending some e-mails). In these cases the language selected above will be used.", "instance_locale": "Default language",
"title_description": "It is used in the title of the page, in the subject of the e-mail to export RSS and ICS feeds.", "instance_timezone_description": "Gancio is designed to collect the events of a specific place, such as a city. All events in this place will be shown in the time zone chosen for it.",
"description_description": "Appears in the header next to the title", "instance_locale_description": "Preferred user language for pages. Sometimes messages must be shown in the same language for everyone (for example when publishing via ActivityPub or when sending some e-mails). In these cases the language selected above will be used.",
"instance_place": "Indicative place of this instance", "title_description": "It is used in the title of the page, in the subject of the e-mail to export RSS and ICS feeds.",
"instance_name_help": "ActivityPub's account to follow", "description_description": "Appears in the header next to the title",
"enable_trusted_instances": "Turn on friendly instances", "instance_place": "Indicative place of this instance",
"trusted_instances_help": "The list of friendly instances will be shown in the header", "instance_name_help": "ActivityPub's account to follow",
"trusted_instances_label": "Navigation label to friendly instances", "enable_trusted_instances": "Turn on friendly instances",
"trusted_instances_label_default": "Friendly instances", "trusted_instances_help": "The list of friendly instances will be shown in the header",
"trusted_instances_label_help": "The default label is 'Friendly instances'", "trusted_instances_label": "Navigation label to friendly instances",
"add_trusted_instance": "Add a friendly instance", "trusted_instances_label_default": "Friendly instances",
"instance_place_help": "The label to show in instances of others", "trusted_instances_label_help": "The default label is 'Friendly instances'",
"delete_trusted_instance_confirm": "Do you really want to delete this item from the friend instance menu?", "add_trusted_instance": "Add a friendly instance",
"is_dark": "Dark theme", "instance_place_help": "The label to show in instances of others",
"add_link": "Add link", "delete_trusted_instance_confirm": "Do you really want to delete this item from the friend instance menu?",
"footer_links": "Footer links", "is_dark": "Dark theme",
"delete_footer_link_confirm": "Sure to remove this link?", "add_link": "Add link",
"edit_place": "Edit place", "footer_links": "Footer links",
"edit_tag": "Edit tag", "delete_footer_link_confirm": "Sure to remove this link?",
"edit_tag_help": "You can change the tag by replacing it with a new one or merging it with an existing one. The {n} associated events will also be changed.", "edit_place": "Edit place",
"new_announcement": "New announcement", "edit_tag": "Edit tag",
"show_smtp_setup": "Email settings", "edit_tag_help": "You can change the tag by replacing it with a new one or merging it with an existing one. The {n} associated events will also be changed.",
"smtp_hostname": "SMTP Hostname", "new_announcement": "New announcement",
"smtp_port": "SMTP Port", "show_smtp_setup": "Email settings",
"smtp_secure": "SMTP Secure (TLS or STARTTLS)", "smtp_hostname": "SMTP Hostname",
"smtp_description": "<ul><li>Admin should receive an email when anon event is added (if enabled).</li><li>Admin should receive email of registration request (if enabled).</li><li>User should receive an email of registration request.</li><li>User should receive email of confirmed registration.</li><li>User should receive a confirmation email when subscribed directly by admin.</li><li>Users should receive email to restore password when they forgot it</li></ul>", "smtp_port": "SMTP Port",
"smtp_test_success": "A test email is sent to {admin_email}, please check your inbox", "smtp_secure": "SMTP Secure (TLS or STARTTLS)",
"smtp_test_button": "Send a test email", "smtp_description": "<ul><li>Admin should receive an email when anon event is added (if enabled).</li><li>Admin should receive email of registration request (if enabled).</li><li>User should receive an email of registration request.</li><li>User should receive email of confirmed registration.</li><li>User should receive a confirmation email when subscribed directly by admin.</li><li>Users should receive email to restore password when they forgot it</li></ul>",
"smtp_use_sendmail": "Use sendmail", "smtp_test_success": "A test email is sent to {admin_email}, please check your inbox",
"admin_email": "Admin e-mail", "smtp_test_button": "Send a test email",
"admin_email_help": "The address we use as the sender to send emails. This is also the address to which admin emails are sent", "smtp_use_sendmail": "Use sendmail",
"widget": "Widget", "admin_email": "Admin e-mail",
"wrong_domain_warning": "The baseurl configured in config.json <b>({baseurl})</b> differs from the one you're visiting <b>({url})</b>", "admin_email_help": "The address we use as the sender to send emails. This is also the address to which admin emails are sent",
"new_collection": "New collection", "widget": "Widget",
"collections_description": "Collections are groupings of events by tags and places. They will be displayed on the home page", "wrong_domain_warning": "The baseurl configured in config.json <b>({baseurl})</b> differs from the one you're visiting <b>({url})</b>",
"edit_collection": "Edit Collection", "new_collection": "New collection",
"delete_collection_confirm": "Are you sure you want to remove the collection <u>{collection}</u>?", "collections_description": "Collections are groupings of events by tags and places. They will be displayed on the home page",
"config_plugin": "Plugin configuration", "edit_collection": "Edit Collection",
"plugins_description": "Plugins are small pieces of code that provide additional features to the main application. They are usually written by developers external to the project that take advantage of the <a href=\"https://gancio.org/dev/plugins\">plugin system</a> to, mostly, but not limited to send events to other platforms and channels.", "delete_collection_confirm": "Are you sure you want to remove the collection <u>{collection}</u>?",
"fallback_image": "Fallback image", "config_plugin": "Plugin configuration",
"header_image": "Header image", "plugins_description": "Plugins are small pieces of code that provide additional features to the main application. They are usually written by developers external to the project that take advantage of the <a href=\"https://gancio.org/dev/plugins\">plugin system</a> to, mostly, but not limited to send events to other platforms and channels.",
"hide_thumbs": "Hide thumbs", "fallback_image": "Fallback image",
"hide_calendar": "Hide calendar", "header_image": "Header image",
"default_images": "Default images", "hide_thumbs": "Hide thumbs",
"default_images_help": "You have to <a href='/admin?tab=theme'>refresh</a> the page to see the changes.", "hide_calendar": "Hide calendar",
"blocked": "Blocked", "default_images": "Default images",
"domain": "Domain", "default_images_help": "You have to <a href='/admin?tab=theme'>refresh</a> the page to see the changes.",
"known_users": "Known users", "blocked": "Blocked",
"created_at": "Created at", "domain": "Domain",
"geolocation_description": "<b>1. Define a provider for geocoding service</b>.<br>Currently, among those listed in the <a href=\"https://wiki.openstreetmap.org/wiki/Nominatim#Alternatives_.2F_Third-party_providers\">wiki of OpenStreetMap</a>, there is support for software <a href=\"https://github.com/osm-search/Nominatim\">Nominatim</a> and <a href=\"https://github.com/komoot/photon\">Photon</a>.<br>You can use one of the related official demos by copying the link in the 'Geocoding provider' field:<ul><li>https://nominatim.openstreetmap.org/search (<a href=\"https://operations.osmfoundation.org/policies/nominatim/\">Terms of Service</a>)</li><li>https://photon.komoot.io/api/ (<a href=\"https://photon.komoot.io/\">Terms of Service</a>)</li></ul><br><b>2. Define a provider for map layers.</b><br>You can find a list of them here: <a href=\"https://leaflet-extras.github.io/leaflet-providers/preview/\">https://leaflet-extras.github.io/leaflet-providers/preview/</a>", "known_users": "Known users",
"geocoding_provider_type": "Geocoding software", "created_at": "Created at",
"geocoding_provider_type_help": "The default software is Nominatim", "geolocation_description": "<b>1. Define a provider for geocoding service</b>.<br>Currently, among those listed in the <a href=\"https://wiki.openstreetmap.org/wiki/Nominatim#Alternatives_.2F_Third-party_providers\">wiki of OpenStreetMap</a>, there is support for software <a href=\"https://github.com/osm-search/Nominatim\">Nominatim</a> and <a href=\"https://github.com/komoot/photon\">Photon</a>.<br>You can use one of the related official demos by copying the link in the 'Geocoding provider' field:<ul><li>https://nominatim.openstreetmap.org/search (<a href=\"https://operations.osmfoundation.org/policies/nominatim/\">Terms of Service</a>)</li><li>https://photon.komoot.io/api/ (<a href=\"https://photon.komoot.io/\">Terms of Service</a>)</li></ul><br><b>2. Define a provider for map layers.</b><br>You can find a list of them here: <a href=\"https://leaflet-extras.github.io/leaflet-providers/preview/\">https://leaflet-extras.github.io/leaflet-providers/preview/</a>",
"geocoding_provider": "Geocoding provider", "geocoding_provider_type": "Geocoding software",
"geocoding_provider_help": "The default provider is Nominatim", "geocoding_provider_type_help": "The default software is Nominatim",
"geocoding_countrycodes": "Country codes", "geocoding_provider": "Geocoding provider",
"geocoding_countrycodes_help": "Allows you to set a filter to searches based on area codes", "geocoding_provider_help": "The default provider is Nominatim",
"geocoding_test_button": "Test geocoding", "geocoding_countrycodes": "Country codes",
"geocoding_test_success": "The geocoding service at {service_name} is working", "geocoding_countrycodes_help": "Allows you to set a filter to searches based on area codes",
"geocoding_test_error": "The geocoding service is not reachable at {service_name}", "geocoding_test_button": "Test geocoding",
"tilelayer_provider": "Tilelayer provider", "geocoding_test_success": "The geocoding service at {service_name} is working",
"tilelayer_provider_help": "The default provider is OpenStreetMap", "geocoding_test_error": "The geocoding service is not reachable at {service_name}",
"tilelayer_provider_attribution": "Attribution", "tilelayer_provider": "Tilelayer provider",
"tilelayer_test_button": "Test tilelayer", "tilelayer_provider_help": "The default provider is OpenStreetMap",
"tilelayer_test_success": "The tilelayer service at {service_name} is working", "tilelayer_provider_attribution": "Attribution",
"tilelayer_test_error": "The tilelayer service is not reachable at {service_name}", "tilelayer_test_button": "Test tilelayer",
"geolocation": "Geolocation", "tilelayer_test_success": "The tilelayer service at {service_name} is working",
"colors": "Colors" "tilelayer_test_error": "The tilelayer service is not reachable at {service_name}",
}, "geolocation": "Geolocation",
"auth": { "colors": "Colors"
"not_confirmed": "Not confirmed yet…", },
"fail": "Could not log in. Are you sure the password is correct?" "auth": {
}, "not_confirmed": "Not confirmed yet…",
"settings": { "fail": "Could not log in. Are you sure the password is correct?"
"update_confirm": "Do you want to save your modification?", },
"change_password": "Change your password", "settings": {
"password_updated": "Password changed.", "update_confirm": "Do you want to save your modification?",
"danger_section": "Dangerous section", "change_password": "Change your password",
"remove_account": "By pressing the following button your user account will be deleted. Events you published won't be.", "password_updated": "Password changed.",
"remove_account_confirm": "You are about to permanently delete your account" "danger_section": "Dangerous section",
}, "remove_account": "By pressing the following button your user account will be deleted. Events you published won't be.",
"error": { "remove_account_confirm": "You are about to permanently delete your account"
"nick_taken": "This nickname is already in use.", },
"email_taken": "This e-mail is already in use." "error": {
}, "nick_taken": "This nickname is already in use.",
"confirm": { "email_taken": "This e-mail is already in use."
"title": "User confirmation", },
"not_valid": "Something went wrong.", "confirm": {
"valid": "Your account is confirmed, you can now <a href=\"/login\">log in</a>" "title": "User confirmation",
}, "not_valid": "Something went wrong.",
"ordinal": { "valid": "Your account is confirmed, you can now <a href=\"/login\">log in</a>"
"1": "first", },
"2": "second", "ordinal": {
"3": "third", "1": "first",
"4": "fourth", "2": "second",
"5": "fifth", "3": "third",
"-1": "last" "4": "fourth",
}, "5": "fifth",
"validators": { "-1": "last"
"required": "{fieldName} is required", },
"email": "Insert a valid email", "validators": {
"latitude": "Insert a valid latitude (-90 < latitude < 90)", "required": "{fieldName} is required",
"longitude": "Insert a valid latitude (-180 < latitude < 180)" "email": "Insert a valid email",
}, "latitude": "Insert a valid latitude (-90 < latitude < 90)",
"about": "\n <p><a href='https://gancio.org'>Gancio</a> is a shared agenda for local communities.</p>\n ", "longitude": "Insert a valid longitude (-180 < longitude < 180)"
"oauth": { },
"authorization_request": "The application <code>{app}</code> asks for the following authorization on <code>{instance_name}</code>:", "about": "\n <p><a href='https://gancio.org'>Gancio</a> is a shared agenda for local communities.</p>\n ",
"redirected_to": "After confirmation you will be redirected to <code>{url}</code>", "oauth": {
"scopes": { "authorization_request": "The application <code>{app}</code> asks for the following authorization on <code>{instance_name}</code>:",
"event:write": "Add and edit your events" "redirected_to": "After confirmation you will be redirected to <code>{url}</code>",
} "scopes": {
}, "event:write": "Add and edit your events"
"setup": {
"completed": "Setup completed",
"completed_description": "<p>You can now login with the following user:<br/><br/>User: <b>{email}</b><br/>Password: <b>{password}<b/></p>",
"copy_password_dialog": "Yes, you have to copy the password!",
"start": "Start",
"https_warning": "You're visiting from HTTP, remember to change baseurl in config.json if you switch to HTTPS!"
} }
},
"setup": {
"completed": "Setup completed",
"completed_description": "<p>You can now login with the following user:<br/><br/>User: <b>{email}</b><br/>Password: <b>{password}<b/></p>",
"copy_password_dialog": "Yes, you have to copy the password!",
"start": "Start",
"https_warning": "You're visiting from HTTP, remember to change baseurl in config.json if you switch to HTTPS!"
}
} }

View file

@ -106,7 +106,8 @@
"search_coordinates": "Buscar las coordenadas", "search_coordinates": "Buscar las coordenadas",
"online": "En línea", "online": "En línea",
"test": "Prueba", "test": "Prueba",
"show_preview": "Mostrar una vista previa" "show_preview": "Mostrar una vista previa",
"clone": "Clon"
}, },
"login": { "login": {
"description": "Entrando podrás publicar nuevos eventos.", "description": "Entrando podrás publicar nuevos eventos.",
@ -356,7 +357,7 @@
"validators": { "validators": {
"email": "Introduce un correo electrónico valido", "email": "Introduce un correo electrónico valido",
"required": "{fieldName} es requerido", "required": "{fieldName} es requerido",
"longitude": "Introduce una latitud válida (-180 < latitud < 180)", "longitude": "Introduce una longitud válida (-180 < longitud < 180)",
"latitude": "Introduce una latitud válida (-90 < latitud < 90)" "latitude": "Introduce una latitud válida (-90 < latitud < 90)"
}, },
"setup": { "setup": {

View file

@ -1,7 +1,7 @@
{ {
"common": { "common": {
"add_event": "Sortu ekitaldia", "add_event": "Sortu ekitaldia",
"next": "Jarraitu", "next": "Hurrengoa",
"export": "Esportatu", "export": "Esportatu",
"send": "Bidali", "send": "Bidali",
"where": "Non", "where": "Non",
@ -81,7 +81,7 @@
"announcements": "Iragarpenak", "announcements": "Iragarpenak",
"url": "URLa", "url": "URLa",
"place": "Lekua", "place": "Lekua",
"label": "Izena", "label": "Etiketa",
"max_events": "Gehienezko ekitaldi kopurua", "max_events": "Gehienezko ekitaldi kopurua",
"import": "Inportatu", "import": "Inportatu",
"reset": "Berrezarri", "reset": "Berrezarri",
@ -99,7 +99,14 @@
"recurring_event_actions": "Ekitaldi errepikarien eragiketak", "recurring_event_actions": "Ekitaldi errepikarien eragiketak",
"content": "Edukia", "content": "Edukia",
"admin_actions": "Administratzaile eragiketak", "admin_actions": "Administratzaile eragiketak",
"tag": "Etiketa" "tag": "Etiketa",
"latitude": "Latitudea",
"longitude": "Longitudea",
"search_coordinates": "Bilbatu koordenatuak",
"online": "Online",
"test": "Proba",
"show_preview": "Erakutsi aurrebista",
"clone": "Klonatu"
}, },
"login": { "login": {
"description": "Saioa hasten baduzu ekitaldi berriak sortu ahal izango dituzu.", "description": "Saioa hasten baduzu ekitaldi berriak sortu ahal izango dituzu.",
@ -181,7 +188,10 @@
"address_description_osm": "Bilatu koordenatuak helbidea idatziz. (<a href='http://osm.org/copyright'>OpenStreetMap</a> kolaboratzaileak)", "address_description_osm": "Bilatu koordenatuak helbidea idatziz. (<a href='http://osm.org/copyright'>OpenStreetMap</a> kolaboratzaileak)",
"show_multidate": "data anitzeko ekitaldiak", "show_multidate": "data anitzeko ekitaldiak",
"where_advanced_options": "Lekua - Aukera aurreratuak", "where_advanced_options": "Lekua - Aukera aurreratuak",
"where_advanced_options_description": "Zehaztu hemen lekuaren ezaugarri gehigarriak" "where_advanced_options_description": "Zehaztu hemen lekuaren ezaugarri gehigarriak",
"online_locations_help": "Esaterako bideokonferentzia baten URLa eta URL alternatiboa (gehienez 3)",
"online_locations": "Online kokapenak",
"online_locations_fallback_urls": "Esteka alternatiboak"
}, },
"admin": { "admin": {
"place_description": "Lekua edo helbidea oker badago, alda dezakezu.<br/>Leku honekin lotutako iraganeko eta etorkizuneko ekitaldien helbidea aldatuko da.", "place_description": "Lekua edo helbidea oker badago, alda dezakezu.<br/>Leku honekin lotutako iraganeko eta etorkizuneko ekitaldien helbidea aldatuko da.",
@ -297,7 +307,10 @@
"geocoding_test_success": "Geokodeketa zerbitzua {service_name}-(e)n martxan dago", "geocoding_test_success": "Geokodeketa zerbitzua {service_name}-(e)n martxan dago",
"tilelayer_test_success": "Lauza-geruzen zerbitzua {service_name}(e)n martxan dago", "tilelayer_test_success": "Lauza-geruzen zerbitzua {service_name}(e)n martxan dago",
"colors": "Koloreak", "colors": "Koloreak",
"edit_tag": "Editatu etiketa" "edit_tag": "Editatu etiketa",
"allow_online_event_hint": "URLak eskatu ",
"allow_online_event": "Online ekitaldiak ahalbidetu",
"delete_tag_confirm": "Ziur al zaude \"{tag}\" etiketa ezabatu nahi duzula? Etiketa {n} ekitalditik ezabatuko da."
}, },
"auth": { "auth": {
"not_confirmed": "Oraindik baieztatu gabe dago…", "not_confirmed": "Oraindik baieztatu gabe dago…",
@ -338,7 +351,9 @@
}, },
"validators": { "validators": {
"email": "Sartu baliozko eposta bat", "email": "Sartu baliozko eposta bat",
"required": "{fieldName} beharrezkoa da" "required": "{fieldName} beharrezkoa da",
"latitude": "Sartu baliozko latitude bat (-90 < latitudea < 90)",
"longitude": "Sartu baliozko longitudea bat (-180 < longitudea < 180)"
}, },
"setup": { "setup": {
"start": "Hasi", "start": "Hasi",

View file

@ -102,12 +102,17 @@
"tag": "Tag", "tag": "Tag",
"admin_actions": "Admin actions", "admin_actions": "Admin actions",
"recurring_event_actions": "Evènement Récurrent action", "recurring_event_actions": "Evènement Récurrent action",
"content": "Contenu" "content": "Contenu",
"online": "En ligne",
"search_coordinates": "Rechercher les coordonnées",
"test": "Tester",
"show_preview": "Afficher l'aperçu",
"clone": "Cloner"
}, },
"event": { "event": {
"follow_me_description": "Une des manières de rester informé sur les évènements publiés ici sur {title}\nest de suivre le compte <u>{account}</u> sur le fediverse, par exemple via Mastodon, et pourquoi pas d'ajouter des ressources à un évènement à partir de là.<br/><br/>\nSi vous n'avez jamais entendu parler de Mastodon and du fediverse, nous vous recommandons de lire <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'>cet article (en anglais)</a>.<br/><br/>Saisissez votre nom d'instance ci-dessous (par ex. mastodon.social)", "follow_me_description": "Une des manières de rester informé sur les évènements publiés ici sur {title}\nest de suivre le compte <u>{account}</u> sur le fediverse, par exemple via Mastodon, et pourquoi pas d'ajouter des ressources à un évènement à partir de là.<br/><br/>\nSi vous n'avez jamais entendu parler de Mastodon and du fediverse, nous vous recommandons de lire <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'>cet article (en anglais)</a>.<br/><br/>Saisissez votre nom d'instance ci-dessous (par ex. mastodon.social)",
"interact_with_me_at": "Interagissez avec moi sur le fediverse à", "interact_with_me_at": "Interagissez avec moi sur le fediverse à",
"recurrent_1m_ordinal": "Le {n} {days} de chaque mois", "recurrent_1m_ordinal": "Chaque {n} {days} du mois",
"import_ICS": "Importer à partir d'un fichier ICS", "import_ICS": "Importer à partir d'un fichier ICS",
"import_URL": "Importer à partir d'une URL", "import_URL": "Importer à partir d'une URL",
"remove_recurrent_confirmation": "Êtes-vous sûr·e de vouloir supprimer cet évènement récurrent ?\nLes évènements passés seront conservés, mais aucun évènement futur de sera créé.", "remove_recurrent_confirmation": "Êtes-vous sûr·e de vouloir supprimer cet évènement récurrent ?\nLes évènements passés seront conservés, mais aucun évènement futur de sera créé.",
@ -145,7 +150,7 @@
"anon": "Anonyme", "anon": "Anonyme",
"ics": "ICS", "ics": "ICS",
"each_2w": "Une semaine sur deux", "each_2w": "Une semaine sur deux",
"recurrent_2m_ordinal": "Les {n} {days} du mois un mois sur deux", "recurrent_2m_ordinal": "Chaque {n} {days} par mois un mois sur deux",
"recurrent_2m_days": "Le {days} un mois sur deux", "recurrent_2m_days": "Le {days} un mois sur deux",
"recurrent_2w_days": "Un {days} sur deux", "recurrent_2w_days": "Un {days} sur deux",
"edit_recurrent": "Modifier lévènement récurrent :", "edit_recurrent": "Modifier lévènement récurrent :",
@ -157,8 +162,14 @@
"download_flyer": "Télécharger le flyer", "download_flyer": "Télécharger le flyer",
"show_multidate": "évènements sur plusieurs jours", "show_multidate": "évènements sur plusieurs jours",
"choose_focal_point": "Choisir le centre d'intérêt", "choose_focal_point": "Choisir le centre d'intérêt",
"address_description_osm": "Quelle est l'adresse? (<a href='http://osm.org/copyright'>OpenStreetMap</a> contributeurs)", "address_description_osm": "Chercher des coordonnées en tapant l'adresse. (<a href='http://osm.org/copyright'>OpenStreetMap</a> contributeurs)",
"address_description": "Quelle adresse ?" "address_description": "Quelle adresse ?",
"where_advanced_options": "Lieu - Option avancées",
"online_locations_fallback_urls": "Liens alternatifs",
"where_advanced_options_description": "Définir ici les propriétés additionnelles du lieu",
"online_locations": "Localisations en ligne",
"online_locations_help": "Par exemple l'URL d'un salon de visioconférence et une URL alternative (max. 3)",
"address_geocoded_disclaimer": "Si vous ne pouvez pas trouver l'<strong>adresse</strong> our le <strong>numéro</strong> que vous cherchez dans les résultats de géocodage, vous pouvez les insérer manuellement dans le champ 'Adresse' sans coordonnées précises. Par ailleurs considérez que le projet <a target=\"_blank\" href=\"https://www.openstreetmap.org/\">OpenStreetMap</a> est ouvert aux contributions pour corriger cela. Si vous avez un téléphone Android, nous recommendons <a target=\"_blank\" href=\"https://f-droid.org/en/packages/de.westnordost.streetcomplete/\">StreetComplete</a> "
}, },
"register": { "register": {
"description": "Les mouvements sociaux doivent s'organiser et s'autofinancer.<br/>\n<br/>Avant de pouvoir publier, <strong> le compte doit être approuvé</strong>, considérez que <strong> derrière ce site vous trouverez de vraies personnes</strong>, à qui vous pouvez écrire en deux lignes pour exprimer les évènements que vous souhaiteriez publier.", "description": "Les mouvements sociaux doivent s'organiser et s'autofinancer.<br/>\n<br/>Avant de pouvoir publier, <strong> le compte doit être approuvé</strong>, considérez que <strong> derrière ce site vous trouverez de vraies personnes</strong>, à qui vous pouvez écrire en deux lignes pour exprimer les évènements que vous souhaiteriez publier.",
@ -265,7 +276,7 @@
"config_plugin": "Configuration du plugin", "config_plugin": "Configuration du plugin",
"colors": "Couleurs", "colors": "Couleurs",
"allow_multidate_event": "Autoriser les évènements sur plusieurs jours", "allow_multidate_event": "Autoriser les évènements sur plusieurs jours",
"delete_tag_confirm": "Etes vous certain.e de vouloir supprimer le tag \"{tag}\"? Le tag sera supprimé de {n} évènements.", "delete_tag_confirm": "Êtes vous certain.e de vouloir supprimer le tag \"{tag}\"? Le tag sera supprimé de {n} évènements.",
"hide_thumbs": "Cacher les vignettes", "hide_thumbs": "Cacher les vignettes",
"hide_calendar": "Cacher le calendrier", "hide_calendar": "Cacher le calendrier",
"default_images": "Images par défaut", "default_images": "Images par défaut",
@ -288,9 +299,13 @@
"geolocation": "Géolocalisation", "geolocation": "Géolocalisation",
"edit_tag_help": "Vous pouvez changer le tag en le remplaçant par un nouveau ou bien fusionner celui-ci avec l'existant. Les {n} évènements associés seront modifiés.", "edit_tag_help": "Vous pouvez changer le tag en le remplaçant par un nouveau ou bien fusionner celui-ci avec l'existant. Les {n} évènements associés seront modifiés.",
"edit_tag": "Modifier le tag", "edit_tag": "Modifier le tag",
"delete_collection_confirm": "Etes vous certain.e de vouloir supprimer la collection <u>{collection}</u>?", "delete_collection_confirm": "Êtes vous certain⋅e de vouloir supprimer la collection <u>{collection}</u>?",
"admin_email_help": "L'adresse que nous utilisons comme expéditeur pour envoyer des courriels. Il s'agit également de l'adresse à laquelle les mails admin sont envoyés.", "admin_email_help": "L'adresse que nous utilisons comme expéditeur pour envoyer des courriels. Il s'agit également de l'adresse à laquelle les mails admin sont envoyés.",
"geolocation_description": "<b>1. Définir un fournisseur de service de géolocalisation</b>.<br>Actuellement, parmi ceux listés dans le <a href=\"https://wiki.openstreetmap.org/wiki/Nominatim#Alternatives_.2F_Third-party_providers\">wiki d'OpenStreetMap</a>, il y a un service de support pour logiciel <a href=\"https://github.com/osm-search/Nominatim\">Nominatim</a> et <a href=\"https://github.com/komoot/photon\">Photon</a>.<br>Vous pouvez utiliser l'une des démos officielles en copiant le lien dans le champs ' Geocoding provider' :<ul><li>https://nominatim.openstreetmap.org/search (<a href=\"https://operations.osmfoundation.org/policies/nominatim/\">Terms of Service</a>)</li><li>https://photon.komoot.io/api/ (<a href=\"https://photon.komoot.io/\">Terms of Service</a>)</li></ul><br><b>2. Definir un fournisseur de fonds de carte.</b><br>Vous pouvez en trouvez une liste ici: <a href=\"https://leaflet-extras.github.io/leaflet-providers/preview/\">https://leaflet-extras.github.io/leaflet-providers/preview/</a>" "geolocation_description": "<b>1. Définir un fournisseur de service de géolocalisation</b>.<br>Actuellement, parmi ceux listés dans le <a href=\"https://wiki.openstreetmap.org/wiki/Nominatim#Alternatives_.2F_Third-party_providers\">wiki d'OpenStreetMap</a>, il y a un service de support pour logiciel <a href=\"https://github.com/osm-search/Nominatim\">Nominatim</a> et <a href=\"https://github.com/komoot/photon\">Photon</a>.<br>Vous pouvez utiliser l'une des démos officielles en copiant le lien dans le champs ' Fournisseurs de géocodage' :<ul><li>https://nominatim.openstreetmap.org/search (<a href=\"https://operations.osmfoundation.org/policies/nominatim/\">Conditions d'utilisations</a>)</li><li>https://photon.komoot.io/api/ (<a href=\"https://photon.komoot.io/\">Conditions d'utilisations</a>)</li></ul><br><b>2. Définir un fournisseur de fonds de carte.</b><br>Vous pouvez en trouvez une liste ici: <a href=\"https://leaflet-extras.github.io/leaflet-providers/preview/\">https://leaflet-extras.github.io/leaflet-providers/preview/</a>",
"header_image": "Image d'en-tête",
"allow_online_event_hint": "Demander des liens ",
"fallback_image": "Image de rechange",
"allow_online_event": "Permettre les évènements en ligne"
}, },
"oauth": { "oauth": {
"scopes": { "scopes": {
@ -302,15 +317,17 @@
"about": "\n <p><a href='https://gancio.org'>Gancio</a> est un agenda partagé pour les communautés locales.</p>\n ", "about": "\n <p><a href='https://gancio.org'>Gancio</a> est un agenda partagé pour les communautés locales.</p>\n ",
"validators": { "validators": {
"email": "Saisissez une adresse courriel valide", "email": "Saisissez une adresse courriel valide",
"required": "{fieldName} est requis" "required": "{fieldName} est requis",
"latitude": "Insérer une latitude valide (entre -90 et 90)",
"longitude": "Insérer une longitude valide (entre -180 et 180)"
}, },
"ordinal": { "ordinal": {
"-1": "dernier", "1": "premier",
"5": "cinquième",
"4": "quatrième",
"3": "troisième",
"2": "deuxième", "2": "deuxième",
"1": "premier" "3": "troisième",
"4": "quatrième",
"5": "cinquième",
"-1": "dernier"
}, },
"confirm": { "confirm": {
"valid": "Votre compte a bien été confirmé, vous pouvez désormais <a href=\"/login\">vous connecter</a>", "valid": "Votre compte a bien été confirmé, vous pouvez désormais <a href=\"/login\">vous connecter</a>",

View file

@ -28,7 +28,7 @@
"feed_url_copied": "Abrir o URL da fonte copiado no teu lector de RSS", "feed_url_copied": "Abrir o URL da fonte copiado no teu lector de RSS",
"event": "Evento", "event": "Evento",
"pause": "Pausa", "pause": "Pausa",
"start": "Inicio", "start": "Comezar",
"fediverse": "Fediverso", "fediverse": "Fediverso",
"announcements": "Anuncios", "announcements": "Anuncios",
"reset": "Restablecer", "reset": "Restablecer",
@ -102,11 +102,12 @@
"content": "Contido", "content": "Contido",
"admin_actions": "Accións de Admin", "admin_actions": "Accións de Admin",
"recurring_event_actions": "Accións de eventos recurrentes", "recurring_event_actions": "Accións de eventos recurrentes",
"tag": "Etiqueta", "tag": "Etiquetar",
"search_coordinates": "Buscar coordenadas", "search_coordinates": "Buscar coordenadas",
"online": "En liña", "online": "En liña",
"show_preview": "Mostrar vista previa", "show_preview": "Mostrar vista previa",
"test": "Proba" "test": "Proba",
"clone": "Clonar"
}, },
"recover": { "recover": {
"not_valid_code": "Algo fallou." "not_valid_code": "Algo fallou."
@ -170,7 +171,7 @@
"image_too_big": "A imaxe non pode superar os 4MB", "image_too_big": "A imaxe non pode superar os 4MB",
"recurrent_1m_days": "O {days} de cada mes", "recurrent_1m_days": "O {days} de cada mes",
"each_2w": "Cada dúas semanas", "each_2w": "Cada dúas semanas",
"follow_me_description": "Un dos xeitos de recibir actualizacións dos eventos que se publican aquí en {title},\né seguindo a conta <u>{account}</u> no fediverso, por exemplo a través de Mastodon, e posiblemente tamén engadir recursos para un evento desde alí.<br/><br/>\nSe nunco escoitaches falar de Mastodon e o fediverso recomendámosche ler <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'>este artigo</a>.<br/><br/>Escribe aquí a túa instancia (ex. mastodon.social)", "follow_me_description": "Un dos xeitos de recibir actualizacións dos eventos que se publican aquí en {title},\né seguindo a conta <u>{account}</u> no fediverso, por exemplo a través de Mastodon, e posiblemente tamén engadir recursos para un evento desde alí.<br/><br/>\nSe non escoitaches falar de Mastodon e o fediverso recomendámosche ler <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'>este artigo</a>.<br/><br/>Escribe aquí a túa instancia (ex. mastodon.social)",
"ics": "ICS", "ics": "ICS",
"import_description": "Podes importar eventos desde outras plataformas e outras instancias usando formatos estándar (ics e h-event)", "import_description": "Podes importar eventos desde outras plataformas e outras instancias usando formatos estándar (ics e h-event)",
"alt_text_description": "Descrición para persoas con problemas de visión", "alt_text_description": "Descrición para persoas con problemas de visión",
@ -241,11 +242,11 @@
"instance_locale": "Idioma por defecto", "instance_locale": "Idioma por defecto",
"delete_announcement_confirm": "Tes a certeza de querer eliminar o anuncio?", "delete_announcement_confirm": "Tes a certeza de querer eliminar o anuncio?",
"instance_locale_description": "Idioma preferido para as páxinas. A veces as mensaxes teñen que mostrarse no mesmo idioma para tódalas persoas (por exemplo cando publicas vía ActivityPub ou cando envías os emails). Nestos casos usarase o idioma elexido aquí arriba.", "instance_locale_description": "Idioma preferido para as páxinas. A veces as mensaxes teñen que mostrarse no mesmo idioma para tódalas persoas (por exemplo cando publicas vía ActivityPub ou cando envías os emails). Nestos casos usarase o idioma elexido aquí arriba.",
"enable_trusted_instances": "Activar instancias amigas", "enable_trusted_instances": "Activar instancias amigables",
"trusted_instances_help": "A lista das instancias amigas será mostrada na cabeceira", "trusted_instances_help": "A lista das instancias recomendadas será mostrada na cabeceira",
"trusted_instances_label": "Etiqueta de navegação para instâncias de amigos", "trusted_instances_label": "Etiqueta de navegación para instancias recomendadas",
"trusted_instances_label_default": "Casos amigáveis", "trusted_instances_label_default": "Instancias amigables",
"trusted_instances_label_help": "A etiqueta padrão é 'Instâncias amigáveis'", "trusted_instances_label_help": "A etiqueta por defecto é 'Instáncias amigables'",
"delete_trusted_instance_confirm": "Tes a certeza de querer eliminar este elemento do menú de instancias amigas?", "delete_trusted_instance_confirm": "Tes a certeza de querer eliminar este elemento do menú de instancias amigas?",
"instance_place_help": "A etiqueta a mostrar nas instancias de outras", "instance_place_help": "A etiqueta a mostrar nas instancias de outras",
"add_link": "Engadir ligazón", "add_link": "Engadir ligazón",
@ -316,7 +317,7 @@
"settings": { "settings": {
"change_password": "Cambia o contrasinal", "change_password": "Cambia o contrasinal",
"danger_section": "Sección perigosa", "danger_section": "Sección perigosa",
"remove_account": "Ao premer o seguinte botón vas eliminar túa conta de usuaria. Os eventos que publicaches permanecerán.", "remove_account": "Ao premer o seguinte botón vas eliminar túa conta. Os eventos que publicaches permanecerán.",
"password_updated": "Contrasinal cambiado.", "password_updated": "Contrasinal cambiado.",
"remove_account_confirm": "Vas eliminar permanentemente a túa conta", "remove_account_confirm": "Vas eliminar permanentemente a túa conta",
"update_confirm": "Queres gardar as modificacións?" "update_confirm": "Queres gardar as modificacións?"
@ -332,11 +333,11 @@
}, },
"ordinal": { "ordinal": {
"1": "primeiro", "1": "primeiro",
"2": "segundo",
"3": "terceiro", "3": "terceiro",
"4": "cuarto", "4": "cuarto",
"5": "quinto", "5": "quinto",
"-1": "último", "-1": "último"
"2": "segundo"
}, },
"validators": { "validators": {
"required": "{fieldName} é requerido", "required": "{fieldName} é requerido",

View file

@ -1,5 +1,6 @@
module.exports = { module.exports = {
ca: 'Català', ca: 'Català',
cs: 'Czech',
de: 'Deutsch', de: 'Deutsch',
en: 'English', en: 'English',
es: 'Español', es: 'Español',
@ -11,6 +12,7 @@ module.exports = {
nl: 'Dutch', nl: 'Dutch',
pl: 'Polski', pl: 'Polski',
pt: 'Português', pt: 'Português',
'pt-BR': 'Português (Brasilian)',
ru: 'Русский', ru: 'Русский',
sk: 'Slovak', sk: 'Slovak',
zh: '中国' zh: '中国'

View file

@ -105,7 +105,7 @@
"search_coordinates": "Cerca coordinate", "search_coordinates": "Cerca coordinate",
"online": "Online", "online": "Online",
"show_preview": "Mostra anteprima", "show_preview": "Mostra anteprima",
"test": "Prova" "clone": "Clona"
}, },
"login": { "login": {
"description": "Entrando puoi pubblicare nuovi eventi.", "description": "Entrando puoi pubblicare nuovi eventi.",
@ -343,7 +343,7 @@
"required": "Campo {fieldName} necessario", "required": "Campo {fieldName} necessario",
"email": "Inserisci un'e-mail valida", "email": "Inserisci un'e-mail valida",
"latitude": "Inserisci una latitudine valida (-90 < latitudine < 90)", "latitude": "Inserisci una latitudine valida (-90 < latitudine < 90)",
"longitude": "Inserisci una latitudine valida (-180 < latitude < 180)" "longitude": "Inserisci una longitudine valida (-180 < longitudine < 180)"
}, },
"about": "\n <p> <a href='https://gancio.org'> Gancio </a> è un'agenda condivisa per le comunità locali. </p>\n ", "about": "\n <p> <a href='https://gancio.org'> Gancio </a> è un'agenda condivisa per le comunità locali. </p>\n ",
"oauth": { "oauth": {

View file

@ -11,4 +11,4 @@ export default async (context, locale) => {
} }
return localeMessages return localeMessages
} }

View file

@ -242,7 +242,8 @@
"show_map": "Vis kart", "show_map": "Vis kart",
"latitude": "breddegrad", "latitude": "breddegrad",
"longitude": "Lengdegrad", "longitude": "Lengdegrad",
"getting_there": "Slik kommer du deg dit" "getting_there": "Slik kommer du deg dit",
"clone": "Klone"
}, },
"about": "\n <p><a href='https://gancio.org'>Gancio</a> er en delt agenda for lokale gemenskaper.</p>\n ", "about": "\n <p><a href='https://gancio.org'>Gancio</a> er en delt agenda for lokale gemenskaper.</p>\n ",
"validators": { "validators": {
@ -250,12 +251,12 @@
"required": "{fieldName} kreves" "required": "{fieldName} kreves"
}, },
"ordinal": { "ordinal": {
"-1": "siste", "1": "første",
"5": "femte",
"4": "fjerde",
"3": "tredje",
"2": "andre", "2": "andre",
"1": "første" "3": "tredje",
"4": "fjerde",
"5": "femte",
"-1": "siste"
}, },
"export": { "export": {
"list_description": "Hvis du har en nettside og ønsker å vise en liste over hendelser, bruk følgende kode", "list_description": "Hvis du har en nettside og ønsker å vise en liste over hendelser, bruk følgende kode",

View file

@ -104,12 +104,12 @@
"tilelayer_test_button": "Tilelayer testen" "tilelayer_test_button": "Tilelayer testen"
}, },
"ordinal": { "ordinal": {
"4": "vierde",
"1": "eerste", "1": "eerste",
"3": "derde",
"-1": "laatste",
"2": "tweede", "2": "tweede",
"5": "vijfde" "3": "derde",
"4": "vierde",
"5": "vijfde",
"-1": "laatste"
}, },
"common": { "common": {
"plugins": "Plugins", "plugins": "Plugins",
@ -210,7 +210,8 @@
"reset": "Resetten", "reset": "Resetten",
"import": "Importeren", "import": "Importeren",
"label": "Label", "label": "Label",
"collections": "Collecties" "collections": "Collecties",
"clone": "Kloon"
}, },
"login": { "login": {
"not_registered": "Niet geregistreerd?", "not_registered": "Niet geregistreerd?",

View file

@ -64,7 +64,8 @@
"embed": "Osadź", "embed": "Osadź",
"embed_help": "Skopiuj poniższy kod na swoją stronę internetową, a wydarzenie będzie wyglądało tak jak tutaj", "embed_help": "Skopiuj poniższy kod na swoją stronę internetową, a wydarzenie będzie wyglądało tak jak tutaj",
"feed": "Kanał RSS", "feed": "Kanał RSS",
"feed_url_copied": "Otwórz skopiowany link w swoim czytniku RSS" "feed_url_copied": "Otwórz skopiowany link w swoim czytniku RSS",
"clone": "Klon"
}, },
"settings": { "settings": {
"change_password": "Zmień swoje hasło", "change_password": "Zmień swoje hasło",
@ -75,11 +76,11 @@
}, },
"ordinal": { "ordinal": {
"1": "pierwszy", "1": "pierwszy",
"5": "piąty",
"-1": "ostatni",
"2": "drugi", "2": "drugi",
"3": "trzeci", "3": "trzeci",
"4": "czwarty" "4": "czwarty",
"5": "piąty",
"-1": "ostatni"
}, },
"confirm": { "confirm": {
"not_valid": "Coś poszło nie tak.", "not_valid": "Coś poszło nie tak.",

356
locales/pt-BR.json Normal file
View file

@ -0,0 +1,356 @@
{
"common": {
"add_event": "Adicionar evento",
"description": "Descrição",
"send": "Enviar",
"address": "Endereço",
"next": "Próximo",
"when": "Quando",
"where": "Onde",
"login": "Login",
"export": "Exportar",
"email": "E-mail",
"what": "O que",
"media": "Media",
"password": "Senha",
"register": "Registrar",
"remove": "Remover",
"confirm": "Confirmar",
"events": "Eventos",
"settings": "Opções",
"actions": "Ações",
"edit": "Editar",
"admin": "Admin",
"places": "Lugares",
"hide": "Ocultar",
"search": "Buscar",
"info": "Info",
"users": "Usuárias",
"share": "Compartilhar",
"name": "Nome",
"associate": "Associar",
"logout": "Sair",
"remove_admin": "Remover admin",
"activate": "Ativar",
"save": "Salvar",
"preview": "Visualizar",
"edit_event": "Editar evento",
"add": "Adicionar",
"copy": "Copiar",
"ok": "Ok",
"cancel": "Cancelar",
"me": "Você",
"password_updated": "Senha alterada.",
"resources": "Recursos",
"activate_user": "Confirmado",
"copy_link": "Copiar link",
"send_via_mail": "Enviar e-mail",
"add_to_calendar": "Adicionar ao calendário",
"copied": "Copiado",
"recover_password": "Recuperar senha",
"new_password": "Nova senha",
"new_user": "Nova usuária",
"deactivate": "Desligar",
"related": "Relacionado",
"enable": "Habilitar",
"disable": "Desabilitar",
"federation": "Federação",
"set_password": "Definir senha",
"instances": "Instâncias",
"follow": "Seguir",
"moderation": "Moderação",
"user": "Usuária",
"authorize": "Autorizar",
"title": "Título",
"filter": "Filtro",
"event": "Evento",
"pause": "Pausar",
"start": "Início",
"feed": "Feed RSS",
"skip": "Pular",
"delete": "Remover",
"fediverse": "Fediverso",
"announcements": "Anúncios",
"place": "Local",
"url": "URL",
"logout_ok": "Deslogado",
"n_resources": "nenhum recurso|um recurso|{n} recursos",
"embed": "Incorporar",
"embed_title": "Incorpore este evento em sua página",
"embed_help": "Copie o seguinte código em sua página e o evento será exibido desta maneira",
"displayname": "Nome de exibição",
"feed_url_copied": "Abra a URL copiada do feed em seu leitor de RSS",
"follow_me_title": "Siga as atualizações pelo Fediverso",
"tags": "Tags",
"theme": "Tema",
"reset": "Reiniciar",
"import": "Importar",
"collections": "Coleções",
"max_events": "N. máximo de eventos",
"label": "Etiqueta",
"close": "Fechar",
"plugins": "Plugins",
"help_translate": "Ajude a traduzir",
"show_map": "Exibir mapa",
"calendar": "Calendário",
"home": "Início",
"about": "Sobre",
"content": "Conteúdo",
"admin_actions": "Ações de admin",
"recurring_event_actions": "Ações para eventos recorrentes",
"tag": "Tag",
"latitude": "Latitude",
"longitude": "Longitude",
"search_coordinates": "Procurar coordenadas",
"online": "On-line",
"test": "Teste",
"show_preview": "Mostrar pré-visualização",
"clone": "Clone"
},
"admin": {
"user_block_confirm": "Têm a certeza que quer bloquear o utilizador {user}?",
"filter_instances": "Filtrar domínios",
"user_add_help": "Um e-mail com instruções para confirmar a inscrição e escolher uma senha será enviada ao novo usuário",
"show_resource": "Mostrar recurso",
"block_user": "Bloquear utilizador",
"filter_users": "Filtrar utilizadores",
"hide_resource": "Ocultar recurso",
"delete_resource": "Remover recurso",
"delete_resource_confirm": "Têm a certeza que quer remover este recurso?",
"show_smtp_setup": "Configurações de e-mail",
"resources": "Recursos",
"delete_announcement_confirm": "Têm a certeza que quer remover o anúncio?",
"smtp_hostname": "Hostname do SMTP",
"collections_description": "Coleções são agrupamentos de eventos por marcadores e locais. Eles serão exibidos na página principal",
"new_collection": "Nova coleção",
"disable_admin_user_confirm": "Têm a certeza que quer remover permissões de administração de {user}?",
"enable_admin_user_confirm": "Têm a certeza que quer adicionar permissões de administrador para {user}?",
"event_remove_ok": "Evento removido",
"smtp_description": "<ul><li>Administrador deve receber um e-mail quando um evento anónimo for adicionado (se habilitado).</li><li>Administrador deve receber um e-mail de requisição de registo (se habilitado).</li><li>Utilizador deve receber um e-mail de solicitação de registro.</li><li>Utilizador deve receber um e-mail de confirmação de registo.</li><li>Utilizador deve receber um e-mail de confirmação quando registado diretamente por um administrador.</li><li>Utilizadores devem receber um e-mail para recuperar a senha quando eles esquecerem ela</li></ul>",
"allow_registration_description": "Permitir registo aberto de utilizadores?",
"block": "Bloquear",
"unblock": "Desbloquear",
"instance_name": "Nome da instância",
"favicon": "Logo",
"instance_block_confirm": "Têm a certeza que quer bloquear o domínio {instance}?",
"enable_federation": "Habilitar federação",
"enable_federation_help": "Será possível seguir está instância a partir do Fediverso",
"add_instance": "Adicionar instância",
"hide_boost_bookmark_help": "Ocultar os pequenos ícones mostrando o número de impulsos e favoritos vindos do Fediverso",
"announcement_remove_ok": "Anúncio removido",
"instance_timezone_description": "Gancio é desenvolvido para coletar os eventos de um local específico, como uma cidade. Todos os eventos nesse local serão exibidos no fuso-horário escolhido para ele.",
"instance_locale_description": "Idioma de preferência para as páginas. Algumas vezes as mensagens precisam ser exibidas em um mesmo idioma para todos (por exemplo, quando publicando através do ActivityPub ou quando enviar alguns e-mails). Nestes casos o idioma seleciona abaixo será o utilizado.",
"title_description": "É utilizado no título da página, no assunto do e-mail para exportar feeds RSS e ICS.",
"instance_name_help": "Conta ActivityPub para seguir",
"enable_trusted_instances": "Habilitar domínios amigáveis",
"trusted_instances_help": "A lista de domínios amigáveis será exibido no cabeçalho",
"trusted_instances_label": "Etiqueta de navegação para domínios amigos",
"trusted_instances_label_default": "Domínios amigos",
"trusted_instances_label_help": "A etiqueta padrão é 'Domínios amigos'",
"add_trusted_instance": "Adicione um domínio amigável",
"footer_links": "Links de rodapé",
"delete_footer_link_confirm": "Têm a certeza que quer remover este link?",
"edit_place": "Editar local",
"smtp_port": "Porta do SMTP",
"smtp_secure": "SMTP Seguro (TLS ou STARTTLS)",
"smtp_use_sendmail": "Utilizar sendmail",
"instance_place_help": "A etiqueta para exibir em outros domínios",
"delete_trusted_instance_confirm": "Quer realmente remover este item do menu de domínios amigos?",
"sender_email": "E-mail do remetente",
"widget": "Widget",
"wrong_domain_warning": "O baseurl configurado no config.json <b>({baseurl})</b> é diferente do que está a usar para visitar <b>({url})</b>",
"edit_collection": "Editar Coleção",
"enable_resources_help": "Permitir adicionar recursos para o evento a partir do Fediverso",
"hide_boost_bookmark": "Ocultar impulsos/favoritos",
"select_instance_timezone": "Fuso horário",
"instance_locale": "Idioma padrão",
"enable_resources": "Habilitar recursos",
"delete_user": "Remover",
"remove_admin": "Remover administrador",
"place_description": "Se colocou o local ou o endereço errado, pode alterá-lo.<br/>Todos os eventos atuais e passados associados com este local terão o endereço alterado.",
"event_confirm_description": "Pode confirmar eventos criados por utilizadores anónimos aqui",
"disable_user_confirm": "Têm a certeza que quer desativar {user}?",
"delete_user_confirm": "Têm a certeza que quer remover {user}?",
"user_remove_ok": "Usuário removido",
"user_create_ok": "Usuário criado",
"allow_anon_event": "Permitir eventos anônimos (precisam ser confirmados)?",
"allow_recurrent_event": "Permitir eventos recorrentes",
"recurrent_event_visible": "Exibir eventos recorrentes por padrão",
"user_blocked": "Utilizador {user} bloqueado",
"announcement_description": "Nesta secção pode inserir anúncios que serão exibidos na página principal",
"description_description": "Exibido no cabeçalho próximo ao título",
"instance_place": "Local indicativo deste domínio",
"is_dark": "Tema escuro",
"add_link": "Adicionar link",
"new_announcement": "Novo anúncio",
"federation": "Federação / ActivityPub",
"smtp_test_success": "Um e-mail de teste foi enviado para {admin_email}, por favor verifique sua caixa de entrada",
"smtp_test_button": "Enviar e-mail de teste",
"allow_geolocation": "Permitir geolocalização de eventos",
"config_plugin": "Configuração da extensão",
"fallback_image": "Imagem alternativa",
"header_image": "Imagem de cabeçalho",
"hide_thumbs": "Ocultar miniaturas",
"default_images_help": "Precisa de <a href='/admin?tab=theme'>recarregar</a> a página para ver as mudanças.",
"domain": "Domínio",
"default_images": "Imagens padrão",
"known_users": "Utilizadores conhecidos",
"created_at": "Criado em",
"hide_calendar": "Ocultar calendário",
"blocked": "Bloqueado",
"admin_email": "E-mail do admin",
"tilelayer_provider_attribution": "Atribuição",
"geolocation": "Geolocalização",
"edit_tag": "Editar etiqueta",
"allow_online_event": "Permitir eventos online",
"allow_online_event_hint": "Pedir por links ",
"admin_email_help": "O e-mail que utilizaremos como remetente para enviar mensagens. Este é também o endereço para o qual são enviadas as mensagens da administração",
"allow_multidate_event": "Permitir eventos com múltiplas datas",
"delete_tag_confirm": "Tem certeza que quer remover a etiqueta \"{tag}\"? A etiqueta será removida de {n} eventos.",
"delete_collection_confirm": "Têm a certeza que quer remover a coleção <u>{collection}</u>?",
"colors": "Cores",
"geocoding_provider_help": "O provedor padrão é o Nominatim",
"geocoding_provider_type_help": "O software padrão é o Nominatim",
"geocoding_countrycodes": "Código de países",
"geocoding_provider_type": "Software de geocodificação",
"geocoding_provider": "Provedor de geocodificação",
"tilelayer_provider_help": "O provedor padrão é o OpenStreetMap",
"edit_tag_help": "Você pode alterar o marcador ao substituí-lo por um novo ou mesclando-o com um já existente. Os {n} eventos associados também serão alterados."
},
"event": {
"follow_me_description": "Uma das maneiras de se manter atualizado com os eventos publicados aqui em {title},\né seguir a conta <u>{account}</u> no Fediverso, por exemplo, via Mastodon, e possivelmente adicionar recursos para um evento a partir de lá.<br/><br/>\nSe nunca ouviu falar sobre Mastodon ou no Fediverso nós recomendamos ler <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'>este artigo</a>.<br/><br/>Entre com o seu domínio abaixo (e.g. mastodon.social)",
"saved": "Evento salvo",
"recurrent": "Recorrente",
"ics": "ICS",
"recurrent_1m_days": "Dia {days} de cada mês",
"interact_with_me": "Siga-me",
"media_description": "Pode adicionar um cartaz (opcional)",
"same_day": "no mesmo dia",
"added": "Evento adicionado",
"what_description": "Título",
"description_description": "Descrição",
"tag_description": "Marcador",
"show_recurrent": "eventos recorrentes",
"anon": "Anônimo",
"anon_description": "Pode adicionar um evento sem se registar ou autenticar, mas precisa de esperar para alguém o ler,\ne confirmar que é um evento adequado. Não será possível modificá-lo depois disso.<br/><br/>\nPodem por vez <a href='/login'>autenticar-se</a> ou <a href='/register'>registar-se</a>. De qualquer modo, vá em frente e poderá obter uma resposta o mais rápido possível. ",
"added_anon": "Evento adicionado, mas ainda precisa ser confirmado.",
"updated": "Evento atualizado",
"where_description": "Onde está o evento? Se não está presente, então pode criá-lo.",
"confirmed": "Evento confirmado",
"not_found": "Não foi possível encontrar o evento",
"remove_confirmation": "Têm a certeza que quer remover este evento?",
"edit_recurrent": "Editar evento recorrente:",
"only_future": "apenas eventos futuros",
"recurrent_description": "Escolha a frequência e selecione os dias",
"multidate_description": "É um festival? Escolha quando ele começa e quando termina",
"multidate": "Mais dias",
"normal": "Normal",
"show_past": "também eventos anteriores",
"normal_description": "Escolha o dia.",
"recurrent_1w_days": "A cada {days}",
"each_week": "Toda semana",
"each_2w": "A cada duas semanas",
"each_month": "Todo mês",
"recurrent_2w_days": "{days} a cada dois",
"recurrent_2m_days": "Dia {days} a cada dois meses",
"recurrent_1m_ordinal": "A cada {n} {days} dias do mês",
"recurrent_2m_ordinal": "{n} {days} a cada dois meses",
"due": "até",
"from": "De",
"image_too_big": "A imagem não pode ser maior que 4MB",
"interact_with_me_at": "Interaja comigo no Fediverso atráves de",
"remove_recurrent_confirmation": "Têm a certeza que quer remover este evento recorrente?\nEventos passados serão mantidos, mas nenhum evento seguinte será criado.",
"import_URL": "Importar a partir de URL",
"import_ICS": "Importar a partir de ICS",
"import_description": "Pode importar eventos de outras plataformas e de outros domínios via formatos padrão (ICS e H-Event)",
"alt_text_description": "Descrição para pessoas com deficiências visuais",
"choose_focal_point": "Escolha o ponto focal",
"remove_media_confirmation": "Confirma a remoção da imagem?",
"download_flyer": "Baixar flyer",
"address_description": "Qual é o endereço?",
"address_description_osm": "Procure as coordenadas escrevendo o endereço. (contribuidores do <a href='http://osm.org/copyright'>OpenStreetMap</a>)",
"show_multidate": "Eventos com múltiplas datas",
"where_advanced_options": "Lugar — Opções avançadas",
"where_advanced_options_description": "Defina aqui propriedades do local adicionais",
"online_locations": "Localizações online",
"address_geocoded_disclaimer": "Se não conseguir encontrar o <strong>endereço da rua</strong> ou a <strong>porta da casa</strong> que procura nos resultados da geocodificação, pode inseri-los manualmente no campo “Endereço” sem perder as coordenadas. Considere também que o projeto <a target=\"_blank\" href=\"https://www.openstreetmap.org/\">OpenStreetMap</a> está aberto a contribuições. Se tiver Android, recomendamos o <a target=\"_blank\" href=\"https://f-droid.org/en/packages/de.westnordost.streetcomplete/\">StreetComplete</a>. ",
"online_locations_help": "Por exemplo, um link para uma sala de video-conferência e um link para outros recursos (máx. 3)",
"online_locations_fallback_urls": "Links de retorno"
},
"confirm": {
"not_valid": "Algo deu errado.",
"title": "Confirmação de usuário",
"valid": "A sua conta está confirmada, pode agora <a href=\"/login\">autenticar-se</a>"
},
"export": {
"intro": "Diferente de plataformas não sociais que fazem tudo para manter os utilizadores e os dados sobre eles, nós acreditamos que a informação, como pessoas, deve ser livre. Para isso deve atualizar-se sobre os eventos do seu interesse, sem necessariamente entrar nesta página.",
"insert_your_address": "Informe seu endereço de e-mail",
"feed_description": "Para seguir as atualizações de um computador ou telemóvel sem que precise de aceder a esta página periodicamente, utilize um leitor de feeds RSS. </p>\n\n<p> Com feeds RSS pode utilizar uma aplicação especial para receber atualizações de páginas que sejam do teu interesse. É uma boa maneira de seguir muitas páginas rapidamente, sem a necessidade de criar contas de utilizadores ou outras complicações. </p>\n\n<li> Se possui um Android, recomendamos <a href=\"https://f-droid.org/en/packages/net.frju.flym/\">Flym</a> ou Feeder </li>\n<li> Para iPhone / iPad pode utilizar <a href=\"https://itunes.apple.com/ua/app/feeds4u/id1038456442?mt=8\"> Feed4U </a> </li>\n<li> Para computador fixo/ portátil nós recomendamos Feedbro, que pode ser instalado no <a href=\"https://addons.mozilla.org/en-GB/firefox/addon/feedbroreader/\"> Firefox </a> ou <a href=\"https://chrome.google.com/webstore/detail/feedbro/mefgmmbdailogpfhfblcnnjfmnpnmdfa\"> Chrome </a>. </li>\n<br/>\nAdicionado este link ao seu leitor de RSS irá mantê-lo atualizado.",
"ical_description": "Computadores e smartphones normalmente possuem aplicações de calendário capazes de importar um calendário remoto.",
"list_description": "Se têm uma página e quer exibir uma lista de eventos, use o seguinte código",
"email_description": "Podes obter eventos que sejam do teu interesse via e-mail."
},
"oauth": {
"authorization_request": "A aplicação <code>{app}</code> solicita autorização em <code>{instance_name}</code>:",
"scopes": {
"event:write": "Adicionar e editar os seus eventos"
},
"redirected_to": "Depois da confirmação, será redirecionado para <code>{url}</code>"
},
"ordinal": {
"1": "primeiro",
"2": "segundo",
"3": "terceiro",
"4": "quarto",
"5": "quinto",
"-1": "último"
},
"settings": {
"remove_account": "Ao pressionar este botão a sua conta de utilizador será apagada. Eventos que publicou serão mantidos.",
"remove_account_confirm": "Está prestes a apagar a sua conta de utilizador permanentemente",
"update_confirm": "Quer salvar as suas alterações?",
"change_password": "Alterar sua senha",
"password_updated": "Senha alterada.",
"danger_section": "Seção perigosa"
},
"error": {
"email_taken": "Este e-mail já está em uso.",
"nick_taken": "Este nome de usuário já está em uso."
},
"setup": {
"https_warning": "Está a aceder por HTTP, lembre-se de alterar o valor de baseurl em config.json se mudar para HTTPS!",
"completed": "Configuração completa",
"start": "Iniciar",
"completed_description": "<p>Pode agora autenticar-se com o seguinte utilizador:<br/><br/>Utilizador: <b>{email}</b><br/>Palavra-passe: <b>{password}<b/></p>",
"copy_password_dialog": "Sim, precisa copiar a palavra-passe!"
},
"validators": {
"email": "Insira um e-mail válido",
"required": "{fieldName} é obrigatório",
"longitude": "Insira uma longitude válida (-180 < longitude < 180)",
"latitude": "Insira uma latitude válida (90 < latitude < 90)"
},
"about": "\n <p><a href='https://gancio.org'>Gancio</a> é uma agenda compartilhada para comunidades locais.</p>\n ",
"login": {
"not_registered": "Não registrado?",
"forgot_password": "Esqueceu sua senha?",
"insert_email": "Informe seu endereço de e-mail",
"ok": "Autenticado",
"description": "Ao autenticar-se poderá publicar novos eventos.",
"check_email": "Verifique sua caixa de entrada e de spam.",
"error": "Autenticação não realizada. Verifique suas informações de autenticação."
},
"recover": {
"not_valid_code": "Algo não funcionou corretamente."
},
"register": {
"error": "Erro: ",
"complete": "Registro precisa ser confirmado.",
"first_user": "Administrador criado",
"description": "Movimentos sociais devem se organizar e autofinanciar-se.<br/>\n<br/>Antes de poder publicar, <strong> a conta precisa ser aprovada por um administrador</strong>, considere que <strong> atrás deste site vai encontrar pessoas reais</strong>, então escreva duas linhas para nos informar que eventos teria interesse em publicar."
},
"auth": {
"fail": "Autenticação não efetuada. Têm a certeza que a sua palavra-passe está correta?",
"not_confirmed": "Não confirmado ainda…"
}
}

View file

@ -25,8 +25,8 @@
"hide": "Ocultar", "hide": "Ocultar",
"search": "Buscar", "search": "Buscar",
"info": "Info", "info": "Info",
"users": "Usuários", "users": "Utilizadores",
"share": "Compartilhar", "share": "Partilhar",
"name": "Nome", "name": "Nome",
"associate": "Associar", "associate": "Associar",
"logout": "Sair", "logout": "Sair",
@ -39,7 +39,7 @@
"copy": "Copiar", "copy": "Copiar",
"ok": "Ok", "ok": "Ok",
"cancel": "Cancelar", "cancel": "Cancelar",
"me": "Você", "me": "Tu",
"password_updated": "Senha alterada.", "password_updated": "Senha alterada.",
"resources": "Recursos", "resources": "Recursos",
"activate_user": "Confirmado", "activate_user": "Confirmado",
@ -97,60 +97,68 @@
"about": "Sobre", "about": "Sobre",
"content": "Conteúdo", "content": "Conteúdo",
"admin_actions": "Ações de admin", "admin_actions": "Ações de admin",
"recurring_event_actions": "Ações de eventos recorrentes" "recurring_event_actions": "Ações de eventos recorrentes",
"tag": "Etiqueta",
"latitude": "Latitude",
"longitude": "Longitude",
"search_coordinates": "Procurar coordenadas",
"online": "On-line",
"test": "Teste",
"show_preview": "Mostrar pré-visualização",
"clone": "Clone"
}, },
"admin": { "admin": {
"user_block_confirm": "Você está certo que quer bloquear o usuário {user}?", "user_block_confirm": "Têm a certeza que quer bloquear o utilizador {user}?",
"filter_instances": "Filtrar instâncias", "filter_instances": "Filtrar domínios",
"user_add_help": "Um e-mail com instruções para confirmar a inscrição e escolher uma senha será enviada ao novo usuário", "user_add_help": "Um e-mail com instruções para confirmar a inscrição e escolher uma senha será enviada ao novo usuário",
"show_resource": "Mostrar recurso", "show_resource": "Mostrar recurso",
"block_user": "Bloquear usuário", "block_user": "Bloquear utilizador",
"filter_users": "Filtrar usuários", "filter_users": "Filtrar utilizadores",
"hide_resource": "Ocultar recurso", "hide_resource": "Ocultar recurso",
"delete_resource": "Remover recurso", "delete_resource": "Remover recurso",
"delete_resource_confirm": "Você está certo que quer remover este recurso?", "delete_resource_confirm": "Têm a certeza que quer remover este recurso?",
"show_smtp_setup": "Configurações de e-mail", "show_smtp_setup": "Configurações de e-mail",
"resources": "Recursos", "resources": "Recursos",
"delete_announcement_confirm": "Você está certo que quer remover o anúncio?", "delete_announcement_confirm": "Têm a certeza que quer remover o anúncio?",
"smtp_hostname": "Hostname SMTP", "smtp_hostname": "Hostname do SMTP",
"collections_description": "Coleções são agrupamentos de eventos por marcadores e locais. Eles serão exibidos na página principal", "collections_description": "Coleções são agrupamentos de eventos por marcadores e locais. Eles serão exibidos na página principal",
"new_collection": "Nova coleção", "new_collection": "Nova coleção",
"disable_admin_user_confirm": "Você está certo que quer remover permissões de administração de {user}?", "disable_admin_user_confirm": "Têm a certeza que quer remover permissões de administração de {user}?",
"enable_admin_user_confirm": "Você está certo que quer adicionar permissões de administrador para {user}?", "enable_admin_user_confirm": "Têm a certeza que quer adicionar permissões de administrador para {user}?",
"event_remove_ok": "Evento removido", "event_remove_ok": "Evento removido",
"smtp_description": "<ul><li>Administrador deve receber um e-mail quando um evento anônimo for adicionado (se habilitado).</li><li>Administrador deve receber um e-mail de requisição de registro (se habilitado).</li><li>Usuário deve receber um e-mail de solicitação de registro.</li><li>Usuário deve receber um e-mail de confirmação de registro.</li><li>Usuário deve recever um e-mail de confirmação quando registrado diretamente por um administrador.</li><li>Usuários devem receber um e-mail para recuperar a senha quando eles esquecerem ela</li></ul>", "smtp_description": "<ul><li>Administrador deve receber um e-mail quando um evento anónimo for adicionado (se habilitado).</li><li>Administrador deve receber um e-mail de requisição de registo (se habilitado).</li><li>Utilizador deve receber um e-mail de solicitação de registro.</li><li>Utilizador deve receber um e-mail de confirmação de registo.</li><li>Utilizador deve receber um e-mail de confirmação quando registado diretamente por um administrador.</li><li>Utilizadores devem receber um e-mail para recuperar a senha quando eles esquecerem ela</li></ul>",
"allow_registration_description": "Permitir registro aberto de usuários?", "allow_registration_description": "Permitir registo aberto de utilizadores?",
"block": "Bloquear", "block": "Bloquear",
"unblock": "Desbloquear", "unblock": "Desbloquear",
"instance_name": "Nome da instância", "instance_name": "Nome da instância",
"favicon": "Logo", "favicon": "Logo",
"instance_block_confirm": "Você está certo que quer bloquear a instância {instance}?", "instance_block_confirm": "Têm a certeza que quer bloquear o domínio {instance}?",
"enable_federation": "Habilitar federação", "enable_federation": "Habilitar federação",
"enable_federation_help": "Será possível seguir está instância a partir do Fediverso", "enable_federation_help": "Será possível seguir está instância a partir do Fediverso",
"add_instance": "Adicionar instância", "add_instance": "Adicionar instância",
"hide_boost_bookmark_help": "Ocultar os pequenos ícones mostrando o número de impulsos e favoritos vindos do Fediverso", "hide_boost_bookmark_help": "Ocultar os pequenos ícones mostrando o número de impulsos e favoritos vindos do Fediverso",
"announcement_remove_ok": "Anúncio removido", "announcement_remove_ok": "Anúncio removido",
"instance_timezone_description": "Gancio é desenvolvido para coletar os eventos de um local específico, como uma cidade. Todos os eventos nesse local serão exibidos no fuso-horário escolhido para ele.", "instance_timezone_description": "Gancio é desenvolvido para coletar os eventos de um local específico, como uma cidade. Todos os eventos nesse local serão exibidos no fuso-horário escolhido para ele.",
"instance_locale_description": "Idioma de preferência para as páginas. Algumas vezes as mensagens precisam ser exibidas em um mesmo idioma para todos (por exemplo quando publicando através do ActivityPub ou quando enviar alguns e-mails). Nestes casos o idioma seleciona abaixo será o utilizado.", "instance_locale_description": "Idioma de preferência para as páginas. Algumas vezes as mensagens precisam ser exibidas em um mesmo idioma para todos (por exemplo, quando publicando através do ActivityPub ou quando enviar alguns e-mails). Nestes casos o idioma seleciona abaixo será o utilizado.",
"title_description": "É utilizado no título da página, no assunto do e-mail para exportar feeds RSS e ICS.", "title_description": "É utilizado no título da página, no assunto do e-mail para exportar feeds RSS e ICS.",
"instance_name_help": "Conta ActivityPub para seguir", "instance_name_help": "Conta ActivityPub para seguir",
"enable_trusted_instances": "Habilitar instâncias amigáveis", "enable_trusted_instances": "Habilitar domínios amigáveis",
"trusted_instances_help": "A lista de instâncias amigáveis que serão exibidas no cabeçalho", "trusted_instances_help": "A lista de domínios amigáveis será exibido no cabeçalho",
"trusted_instances_label": "Etiqueta de navegação para instâncias amigas", "trusted_instances_label": "Etiqueta de navegação para domínios amigos",
"trusted_instances_label_default": "Instâncias amigas", "trusted_instances_label_default": "Domínios amigos",
"trusted_instances_label_help": "A etiqueta padrão é 'Instâncias amigas'", "trusted_instances_label_help": "A etiqueta padrão é 'Domínios amigos'",
"add_trusted_instance": "Adicione uma instância amigável", "add_trusted_instance": "Adicione um domínio amigável",
"footer_links": "Links de rodapé", "footer_links": "Links de rodapé",
"delete_footer_link_confirm": "Está certo que quer remover este link?", "delete_footer_link_confirm": "Têm a certeza que quer remover este link?",
"edit_place": "Editar local", "edit_place": "Editar local",
"smtp_port": "Porta SMTP", "smtp_port": "Porta do SMTP",
"smtp_secure": "SMTP Seguro (TLS ou STARTTLS)", "smtp_secure": "SMTP Seguro (TLS ou STARTTLS)",
"smtp_use_sendmail": "Utilizar sendmail", "smtp_use_sendmail": "Utilizar sendmail",
"instance_place_help": "A etiqueta para exibir em outras instâncias", "instance_place_help": "A etiqueta para exibir em outros domínios",
"delete_trusted_instance_confirm": "Você quer realmente remover este item do menu de instâncias amigas?", "delete_trusted_instance_confirm": "Quer realmente remover este item do menu de domínios amigos?",
"sender_email": "E-mail do remetente", "sender_email": "E-mail do remetente",
"widget": "Widget", "widget": "Widget",
"wrong_domain_warning": "A baseurl configurado em config.json <b>({baseurl})</b> é diferente da que você está visitando <b>({url})</b>", "wrong_domain_warning": "O baseurl configurado no config.json <b>({baseurl})</b> é diferente do que está a usar para visitar <b>({url})</b>",
"edit_collection": "Editar Coleção", "edit_collection": "Editar Coleção",
"enable_resources_help": "Permitir adicionar recursos para o evento a partir do Fediverso", "enable_resources_help": "Permitir adicionar recursos para o evento a partir do Fediverso",
"hide_boost_bookmark": "Ocultar impulsos/favoritos", "hide_boost_bookmark": "Ocultar impulsos/favoritos",
@ -159,19 +167,19 @@
"enable_resources": "Habilitar recursos", "enable_resources": "Habilitar recursos",
"delete_user": "Remover", "delete_user": "Remover",
"remove_admin": "Remover administrador", "remove_admin": "Remover administrador",
"place_description": "Se você colocou o local ou o endereço errado, você pode alterá-lo.<br/>Todos os eventos atuais e passados associados com esse local terão o endereço alterado.", "place_description": "Se colocou o local ou o endereço errado, pode alterá-lo.<br/>Todos os eventos atuais e passados associados com este local terão o endereço alterado.",
"event_confirm_description": "Você pode confirmar eventos criados por usuários anônimos aqui", "event_confirm_description": "Pode confirmar eventos criados por utilizadores anónimos aqui",
"disable_user_confirm": "Você está certo que quer desabilitar {user}?", "disable_user_confirm": "Têm a certeza que quer desativar {user}?",
"delete_user_confirm": "Você está certo que quer remover {user}?", "delete_user_confirm": "Têm a certeza que quer remover {user}?",
"user_remove_ok": "Usuário removido", "user_remove_ok": "Usuário removido",
"user_create_ok": "Usuário criado", "user_create_ok": "Usuário criado",
"allow_anon_event": "Permitir eventos anônimos (precisam ser confirmados)?", "allow_anon_event": "Permitir eventos anônimos (precisam ser confirmados)?",
"allow_recurrent_event": "Permitir eventos recorrentes", "allow_recurrent_event": "Permitir eventos recorrentes",
"recurrent_event_visible": "Exibir eventos recorrentes por padrão", "recurrent_event_visible": "Exibir eventos recorrentes por padrão",
"user_blocked": "Usuário {user} bloqueado", "user_blocked": "Utilizador {user} bloqueado",
"announcement_description": "Nesta seção você pode inserir anúncios que serão exibidos na página principal", "announcement_description": "Nesta secção pode inserir anúncios que serão exibidos na página principal",
"description_description": "Exibido no cabeçalho próximo ao título", "description_description": "Exibido no cabeçalho próximo ao título",
"instance_place": "Local indicativo desta instância", "instance_place": "Local indicativo deste domínio",
"is_dark": "Tema escuro", "is_dark": "Tema escuro",
"add_link": "Adicionar link", "add_link": "Adicionar link",
"new_announcement": "Novo anúncio", "new_announcement": "Novo anúncio",
@ -179,29 +187,44 @@
"smtp_test_success": "Um e-mail de teste foi enviado para {admin_email}, por favor verifique sua caixa de entrada", "smtp_test_success": "Um e-mail de teste foi enviado para {admin_email}, por favor verifique sua caixa de entrada",
"smtp_test_button": "Enviar e-mail de teste", "smtp_test_button": "Enviar e-mail de teste",
"allow_geolocation": "Permitir geolocalização de eventos", "allow_geolocation": "Permitir geolocalização de eventos",
"config_plugin": "Configuração de plugin", "config_plugin": "Configuração da extensão",
"fallback_image": "Imagem alternativa", "fallback_image": "Imagem alternativa",
"header_image": "Imagem de cabeçalho", "header_image": "Imagem de cabeçalho",
"hide_thumbs": "Ocultar miniaturas", "hide_thumbs": "Ocultar miniaturas",
"default_images_help": "Você precisa <a href='/admin?tab=theme'>recarregar</a> a página para ver as mudanças.", "default_images_help": "Precisa de <a href='/admin?tab=theme'>recarregar</a> a página para ver as mudanças.",
"domain": "Domínio", "domain": "Domínio",
"default_images": "Imagens padrão", "default_images": "Imagens padrão",
"known_users": "Usuários conhecidos", "known_users": "Utilizadores conhecidos",
"created_at": "Criado em", "created_at": "Criado em",
"hide_calendar": "Ocultar calendário", "hide_calendar": "Ocultar calendário",
"blocked": "Bloqueado", "blocked": "Bloqueado",
"admin_email": "E-mail do admin", "admin_email": "E-mail do admin",
"tilelayer_provider_attribution": "Atribuição", "tilelayer_provider_attribution": "Atribuição",
"geolocation": "Geolocalização" "geolocation": "Geolocalização",
"edit_tag": "Editar etiqueta",
"allow_online_event": "Permitir eventos online",
"allow_online_event_hint": "Pedir por links ",
"admin_email_help": "O e-mail que utilizaremos como remetente para enviar mensagens. Este é também o endereço para o qual são enviadas as mensagens da administração",
"allow_multidate_event": "Permitir eventos com múltiplas datas",
"delete_tag_confirm": "Tem certeza que quer remover a etiqueta \"{tag}\"? A etiqueta será removida de {n} eventos.",
"delete_collection_confirm": "Têm a certeza que quer remover a coleção <u>{collection}</u>?",
"colors": "Cores",
"geocoding_provider_help": "O provedor padrão é o Nominatim",
"geocoding_provider_type_help": "O software padrão é o Nominatim",
"geocoding_countrycodes": "Código de países",
"geocoding_provider_type": "Software de geocodificação",
"geocoding_provider": "Provedor de geocodificação",
"tilelayer_provider_help": "O provedor padrão é o OpenStreetMap",
"edit_tag_help": "Você pode alterar o marcador ao substituí-lo por um novo ou mesclando-o com um já existente. Os {n} eventos associados também serão alterados."
}, },
"event": { "event": {
"follow_me_description": "Uma das maneiras de se manter atualizado com os eventos publicados aqui em {title},\né seguir a conta <u>{account}</u> no Fediverso, por exemplo via Mastodon, e possivelmente adicionar recursos para um evento a partir de lá.<br/><br/>\nSe você nunca ouviu falar sobre Mastodon ou do Fediverso nós recomendamos ler <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'>este artigo</a>.<br/><br/>Entre com sua instância abaixo (e.g. mastodon.social)", "follow_me_description": "Uma das maneiras de se manter atualizado com os eventos publicados aqui em {title},\né seguir a conta <u>{account}</u> no Fediverso, por exemplo, via Mastodon, e possivelmente adicionar recursos para um evento a partir de lá.<br/><br/>\nSe nunca ouviu falar sobre Mastodon ou no Fediverso nós recomendamos ler <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'>este artigo</a>.<br/><br/>Entre com o seu domínio abaixo (e.g. mastodon.social)",
"saved": "Evento salvo", "saved": "Evento salvo",
"recurrent": "Recorrente", "recurrent": "Recorrente",
"ics": "ICS", "ics": "ICS",
"recurrent_1m_days": "Dia {days} de cada mês", "recurrent_1m_days": "Dia {days} de cada mês",
"interact_with_me": "Siga-me", "interact_with_me": "Siga-me",
"media_description": "Você pode adicionar um flyer (opcional)", "media_description": "Pode adicionar um cartaz (opcional)",
"same_day": "no mesmo dia", "same_day": "no mesmo dia",
"added": "Evento adicionado", "added": "Evento adicionado",
"what_description": "Título", "what_description": "Título",
@ -209,13 +232,13 @@
"tag_description": "Marcador", "tag_description": "Marcador",
"show_recurrent": "eventos recorrentes", "show_recurrent": "eventos recorrentes",
"anon": "Anônimo", "anon": "Anônimo",
"anon_description": "Você pode adicionar um evento sem se registrar ou autenticar-se, mas você precisa esperar alguém para ler,\nconfirmar que é um evento adequado. Não será possível modifiá-lo.<br/><br/>\nVocê pode ao invés <a href='/login'>autenticar-se</a> ou <a href='/register'>registrar-se</a>. De qualquer modo, vá em frente e consiga uma resposta o mais rápido possível. ", "anon_description": "Pode adicionar um evento sem se registar ou autenticar, mas precisa de esperar para alguém o ler,\ne confirmar que é um evento adequado. Não será possível modificá-lo depois disso.<br/><br/>\nPodem por vez <a href='/login'>autenticar-se</a> ou <a href='/register'>registar-se</a>. De qualquer modo, vá em frente e poderá obter uma resposta o mais rápido possível. ",
"added_anon": "Evento adicionado, mas ainda precisa ser confirmado.", "added_anon": "Evento adicionado, mas ainda precisa ser confirmado.",
"updated": "Evento atualizado", "updated": "Evento atualizado",
"where_description": "Onde está o evento? Se não está visível você pode criá-lo.", "where_description": "Onde está o evento? Se não está presente, então pode criá-lo.",
"confirmed": "Evento confirmado", "confirmed": "Evento confirmado",
"not_found": "Não foi possível encontrar o evento", "not_found": "Não foi possível encontrar o evento",
"remove_confirmation": "Você está certo que quer remover este evento?", "remove_confirmation": "Têm a certeza que quer remover este evento?",
"edit_recurrent": "Editar evento recorrente:", "edit_recurrent": "Editar evento recorrente:",
"only_future": "apenas eventos futuros", "only_future": "apenas eventos futuros",
"recurrent_description": "Escolha a frequência e selecione os dias", "recurrent_description": "Escolha a frequência e selecione os dias",
@ -230,55 +253,62 @@
"each_month": "Todo mês", "each_month": "Todo mês",
"recurrent_2w_days": "{days} a cada dois", "recurrent_2w_days": "{days} a cada dois",
"recurrent_2m_days": "Dia {days} a cada dois meses", "recurrent_2m_days": "Dia {days} a cada dois meses",
"recurrent_1m_ordinal": "{n} {days} de cada mês", "recurrent_1m_ordinal": "A cada {n} {days} dias do mês",
"recurrent_2m_ordinal": "{n} {days} a cada dois meses", "recurrent_2m_ordinal": "{n} {days} a cada dois meses",
"due": "até", "due": "até",
"from": "De", "from": "De",
"image_too_big": "A imagem não pode ser maior que 4MB", "image_too_big": "A imagem não pode ser maior que 4MB",
"interact_with_me_at": "Interaja comigo no Fediverso atráves de", "interact_with_me_at": "Interaja comigo no Fediverso atráves de",
"remove_recurrent_confirmation": "Você está certo que quer remover este evento recorrente?\nEventos passados serão mantidos, mas nenhum evento seguinte será criado.", "remove_recurrent_confirmation": "Têm a certeza que quer remover este evento recorrente?\nEventos passados serão mantidos, mas nenhum evento seguinte será criado.",
"import_URL": "Importar a partir de URL", "import_URL": "Importar a partir de URL",
"import_ICS": "Importar a partir de ICS", "import_ICS": "Importar a partir de ICS",
"import_description": "Você pode importar eventos de outras plataformas e outras instâncias através de formatos padrão (ics e h-event)", "import_description": "Pode importar eventos de outras plataformas e de outros domínios via formatos padrão (ICS e H-Event)",
"alt_text_description": "Descrição para pessoas com deficiências visuais", "alt_text_description": "Descrição para pessoas com deficiências visuais",
"choose_focal_point": "Escolha o ponto focal", "choose_focal_point": "Escolha o ponto focal",
"remove_media_confirmation": "Você confirma a remoção da imagem?", "remove_media_confirmation": "Confirma a remoção da imagem?",
"download_flyer": "Baixar flyer", "download_flyer": "Baixar flyer",
"address_description": "Qual é o endereço?", "address_description": "Qual é o endereço?",
"address_description_osm": "Qual é o endereço? (contribuidores do <a href='http://osm.org/copyright'>OpenStreetMap</a>)" "address_description_osm": "Procure as coordenadas escrevendo o endereço. (contribuidores do <a href='http://osm.org/copyright'>OpenStreetMap</a>)",
"show_multidate": "Eventos com múltiplas datas",
"where_advanced_options": "Lugar — Opções avançadas",
"where_advanced_options_description": "Defina aqui propriedades do local adicionais",
"online_locations": "Localizações online",
"address_geocoded_disclaimer": "Se não conseguir encontrar o <strong>endereço da rua</strong> ou a <strong>porta da casa</strong> que procura nos resultados da geocodificação, pode inseri-los manualmente no campo “Endereço” sem perder as coordenadas. Considere também que o projeto <a target=\"_blank\" href=\"https://www.openstreetmap.org/\">OpenStreetMap</a> está aberto a contribuições. Se tiver Android, recomendamos o <a target=\"_blank\" href=\"https://f-droid.org/en/packages/de.westnordost.streetcomplete/\">StreetComplete</a>. ",
"online_locations_help": "Por exemplo, um link para uma sala de video-conferência e um link para outros recursos (máx. 3)",
"online_locations_fallback_urls": "Links de retorno"
}, },
"confirm": { "confirm": {
"not_valid": "Algo deu errado.", "not_valid": "Algo deu errado.",
"title": "Confirmação de usuário", "title": "Confirmação de usuário",
"valid": "Sua conta está confirmada, você pode agora <a href=\"/login\">autenticar-se</a>" "valid": "A sua conta está confirmada, pode agora <a href=\"/login\">autenticar-se</a>"
}, },
"export": { "export": {
"intro": "Diferente de plataformas não-sociais que fazem tudo para manter os usuários e os dados sobre eles, nós acreditamos que a informação, como pessoas, deve ser livre. Para isso você se atualizar sobre os eventos de seu interesse, sem necessariamente entrar nesta página.", "intro": "Diferente de plataformas não sociais que fazem tudo para manter os utilizadores e os dados sobre eles, nós acreditamos que a informação, como pessoas, deve ser livre. Para isso deve atualizar-se sobre os eventos do seu interesse, sem necessariamente entrar nesta página.",
"insert_your_address": "Informe seu endereço de e-mail", "insert_your_address": "Informe seu endereço de e-mail",
"feed_description": "Para seguir as atualizações de um computador ou smartphone sem que você precise acessar essa página periodicamente, utilize um feeds RSS. </p>\n\n<p> Com feeds RSS você pode utilizar um app especial para receber atualizações de páginas que te interessam. É uma boa maneira de seguir muitas páginas rapidamente, sem a necessidade de criar contas de usuários ou outras complicações. </p>\n\n<li> Se você possui um Android, recomendamos <a href=\"https://f-droid.org/en/packages/net.frju.flym/\">Flym</a> ou Feeder </li>\n<li> Para iPhone / iPad você pode utilizar <a href=\"https://itunes.apple.com/ua/app/feeds4u/id1038456442?mt=8\"> Feed4U </a> </li>\n<li> Para desktop / laptop nós recomendamos Feedbro, que pode ser instalado no <a href=\"https://addons.mozilla.org/en-GB/firefox/addon/feedbroreader/\"> Firefox </a> ou <a href=\"https://chrome.google.com/webstore/detail/feedbro/mefgmmbdailogpfhfblcnnjfmnpnmdfa\"> Chrome </a>. </li>\n<br/>\nAdicionado este link ao seu leitor de RSS irá mantê-lo atualizado.", "feed_description": "Para seguir as atualizações de um computador ou telemóvel sem que precise de aceder a esta página periodicamente, utilize um leitor de feeds RSS. </p>\n\n<p> Com feeds RSS pode utilizar uma aplicação especial para receber atualizações de páginas que sejam do teu interesse. É uma boa maneira de seguir muitas páginas rapidamente, sem a necessidade de criar contas de utilizadores ou outras complicações. </p>\n\n<li> Se possui um Android, recomendamos <a href=\"https://f-droid.org/en/packages/net.frju.flym/\">Flym</a> ou Feeder </li>\n<li> Para iPhone / iPad pode utilizar <a href=\"https://itunes.apple.com/ua/app/feeds4u/id1038456442?mt=8\"> Feed4U </a> </li>\n<li> Para computador fixo/ portátil nós recomendamos Feedbro, que pode ser instalado no <a href=\"https://addons.mozilla.org/en-GB/firefox/addon/feedbroreader/\"> Firefox </a> ou <a href=\"https://chrome.google.com/webstore/detail/feedbro/mefgmmbdailogpfhfblcnnjfmnpnmdfa\"> Chrome </a>. </li>\n<br/>\nAdicionado este link ao seu leitor de RSS irá mantê-lo atualizado.",
"ical_description": "Computadores e smartphones normalmente possuem aplicações de calendário capazes de importar um calendário remoto.", "ical_description": "Computadores e smartphones normalmente possuem aplicações de calendário capazes de importar um calendário remoto.",
"list_description": "Se você tem uma página e quer exibir uma lista de eventos, use o seguinte código", "list_description": "Se m uma página e quer exibir uma lista de eventos, use o seguinte código",
"email_description": "Você pode obter os eventos que te interessam através de e-mail." "email_description": "Podes obter eventos que sejam do teu interesse via e-mail."
}, },
"oauth": { "oauth": {
"authorization_request": "A aplicação <code>{app}</code> solicita autorização em <code>{instance_name}</code>:", "authorization_request": "A aplicação <code>{app}</code> solicita autorização em <code>{instance_name}</code>:",
"scopes": { "scopes": {
"event:write": "Adicionar e editar os seus eventos" "event:write": "Adicionar e editar os seus eventos"
}, },
"redirected_to": "Depois da confirmação, você será redirecionado para <code>{url}</code>" "redirected_to": "Depois da confirmação, será redirecionado para <code>{url}</code>"
}, },
"ordinal": { "ordinal": {
"2": "segundo",
"1": "primeiro", "1": "primeiro",
"5": "quinto", "2": "segundo",
"-1": "último",
"3": "terceiro", "3": "terceiro",
"4": "quarto" "4": "quarto",
"5": "quinto",
"-1": "último"
}, },
"settings": { "settings": {
"remove_account": "Ao pressionar este botão sua conta de usuário será removida. Eventos que você publicou serão mantidos.", "remove_account": "Ao pressionar este botão a sua conta de utilizador será apagada. Eventos que publicou serão mantidos.",
"remove_account_confirm": "Você está prestes a remover sua conta de usuário permanentemente", "remove_account_confirm": "Está prestes a apagar a sua conta de utilizador permanentemente",
"update_confirm": "Você quer salvar sua modificação?", "update_confirm": "Quer salvar as suas alterações?",
"change_password": "Alterar sua senha", "change_password": "Alterar sua senha",
"password_updated": "Senha alterada.", "password_updated": "Senha alterada.",
"danger_section": "Seção perigosa" "danger_section": "Seção perigosa"
@ -288,15 +318,17 @@
"nick_taken": "Este nome de usuário já está em uso." "nick_taken": "Este nome de usuário já está em uso."
}, },
"setup": { "setup": {
"https_warning": "Você está acessando por HTTP, lembre-se de alterar o valor de baseurl em config.json se você mudar para HTTPS!", "https_warning": "Está a aceder por HTTP, lembre-se de alterar o valor de baseurl em config.json se mudar para HTTPS!",
"completed": "Configuração completa", "completed": "Configuração completa",
"start": "Iniciar", "start": "Iniciar",
"completed_description": "<p>Você pode agora autenticar-se com o seguinte usuário:<br/><br/>Usuário: <b>{email}</b><br/>Senha: <b>{password}<b/></p>", "completed_description": "<p>Pode agora autenticar-se com o seguinte utilizador:<br/><br/>Utilizador: <b>{email}</b><br/>Palavra-passe: <b>{password}<b/></p>",
"copy_password_dialog": "Sim, você precisa copiar a senha!" "copy_password_dialog": "Sim, precisa copiar a palavra-passe!"
}, },
"validators": { "validators": {
"email": "Insira um e-mail válido", "email": "Insira um e-mail válido",
"required": "{fieldName} é obrigatório" "required": "{fieldName} é obrigatório",
"longitude": "Insira uma longitude válida (-180 < longitude < 180)",
"latitude": "Insira uma latitude válida (90 < latitude < 90)"
}, },
"about": "\n <p><a href='https://gancio.org'>Gancio</a> é uma agenda compartilhada para comunidades locais.</p>\n ", "about": "\n <p><a href='https://gancio.org'>Gancio</a> é uma agenda compartilhada para comunidades locais.</p>\n ",
"login": { "login": {
@ -304,7 +336,7 @@
"forgot_password": "Esqueceu sua senha?", "forgot_password": "Esqueceu sua senha?",
"insert_email": "Informe seu endereço de e-mail", "insert_email": "Informe seu endereço de e-mail",
"ok": "Autenticado", "ok": "Autenticado",
"description": "Ao autenticar-se você pode publicar novos eventos.", "description": "Ao autenticar-se pode publicar novos eventos.",
"check_email": "Verifique sua caixa de entrada e de spam.", "check_email": "Verifique sua caixa de entrada e de spam.",
"error": "Autenticação não realizada. Verifique suas informações de autenticação." "error": "Autenticação não realizada. Verifique suas informações de autenticação."
}, },
@ -315,10 +347,10 @@
"error": "Erro: ", "error": "Erro: ",
"complete": "Registro precisa ser confirmado.", "complete": "Registro precisa ser confirmado.",
"first_user": "Administrador criado", "first_user": "Administrador criado",
"description": "Movimentos sociais devem se organizar e se auto financiar.<br/>\n<br/>Antes de poder publicar, <strong> a conta precisa ser aprovada</strong>, considere que <strong> atrás deste site você vai encontrar pessoas reais</strong>, então escreva duas linhas para nos informar que eventos você gostaria de publicar." "description": "Movimentos sociais devem se organizar e autofinanciar-se.<br/>\n<br/>Antes de poder publicar, <strong> a conta precisa ser aprovada por um administrador</strong>, considere que <strong> atrás deste site vai encontrar pessoas reais</strong>, então escreva duas linhas para nos informar que eventos teria interesse em publicar."
}, },
"auth": { "auth": {
"fail": "Autenticação não efetuada. Você está certo que sua senha está correta?", "fail": "Autenticação não efetuada. Têm a certeza que a sua palavra-passe está correta?",
"not_confirmed": "Não confirmado ainda…" "not_confirmed": "Não confirmado ainda…"
} }
} }

1
locales/pt_PT.json Normal file
View file

@ -0,0 +1 @@
{}

View file

@ -96,7 +96,8 @@
"tag": "Тег", "tag": "Тег",
"calendar": "Календарь", "calendar": "Календарь",
"next": "След.", "next": "След.",
"export": "Экспорт" "export": "Экспорт",
"clone": "Клон"
}, },
"login": { "login": {
"description": "Войдя в систему, вы можете публиковать новые события.", "description": "Войдя в систему, вы можете публиковать новые события.",

View file

@ -88,7 +88,8 @@
"copied": "Skopírované", "copied": "Skopírované",
"embed": "Vložiť", "embed": "Vložiť",
"instances": "Inštancie", "instances": "Inštancie",
"embed_title": "Vložiť toto podujatie na tvoju web stránku" "embed_title": "Vložiť toto podujatie na tvoju web stránku",
"clone": "Klonovať"
}, },
"login": { "login": {
"description": "Po prihlásení sa môžete publikovat nové podujatia.", "description": "Po prihlásení sa môžete publikovat nové podujatia.",

View file

@ -1,293 +1,294 @@
{ {
"common": { "common": {
"embed_help": "将以下代码复制并粘贴到你的网站,此事件将像这样显示", "embed_help": "将以下代码复制并粘贴到你的网站,此事件将像这样显示",
"follow": "关注", "follow": "关注",
"add_event": "添加事件", "add_event": "添加事件",
"send": "发送", "send": "发送",
"where": "地点", "where": "地点",
"address": "地址", "address": "地址",
"when": "时间", "when": "时间",
"what": "事件", "what": "事件",
"media": "媒体", "media": "媒体",
"login": "登录", "login": "登录",
"email": "电子邮箱", "email": "电子邮箱",
"register": "注册", "register": "注册",
"description": "描述", "description": "描述",
"hide": "隐藏", "hide": "隐藏",
"search": "搜索", "search": "搜索",
"confirm": "确认", "confirm": "确认",
"admin": "管理员", "admin": "管理员",
"users": "用户", "users": "用户",
"events": "事件", "events": "事件",
"actions": "操作", "actions": "操作",
"deactivate": "取消", "deactivate": "取消",
"remove_admin": "移除管理员", "remove_admin": "移除管理员",
"activate": "激活", "activate": "激活",
"save": "该村", "save": "该村",
"logout": "登出", "logout": "登出",
"name": "名称", "name": "名称",
"associate": "合作者", "associate": "合作者",
"add": "添加", "add": "添加",
"recover_password": "重置密码", "recover_password": "重置密码",
"enable": "启用", "enable": "启用",
"me": "你", "me": "你",
"ok": "完成", "ok": "完成",
"resources": "资源", "resources": "资源",
"n_resources": "无资源|1 个资源|{n} 个资源", "n_resources": "无资源|1 个资源|{n} 个资源",
"displayname": "显示名称", "displayname": "显示名称",
"copy_link": "复制链接", "copy_link": "复制链接",
"send_via_mail": "发送电子邮件", "send_via_mail": "发送电子邮件",
"embed": "嵌入式页面", "embed": "嵌入式页面",
"feed_url_copied": "在你的 RSS 阅读器中打开复制的链接", "feed_url_copied": "在你的 RSS 阅读器中打开复制的链接",
"follow_me_title": "在 Fediverse 网络中关注更新", "follow_me_title": "在 Fediverse 网络中关注更新",
"feed": "RSS 源", "feed": "RSS 源",
"moderation": "中等", "moderation": "中等",
"authorize": "认证", "authorize": "认证",
"title": "标题", "title": "标题",
"filter": "筛选", "filter": "筛选",
"pause": "暂停", "pause": "暂停",
"start": "开始", "start": "开始",
"announcements": "公告", "announcements": "公告",
"url": "URL", "url": "URL",
"place": "地点", "place": "地点",
"theme": "主题", "theme": "主题",
"label": "标签", "label": "标签",
"collections": "收藏", "collections": "收藏",
"max_events": "最大事件数", "max_events": "最大事件数",
"next": "下一个", "next": "下一个",
"export": "导出", "export": "导出",
"remove": "移除", "remove": "移除",
"settings": "选项", "settings": "选项",
"logout_ok": "已登出", "logout_ok": "已登出",
"new_password": "新密码", "new_password": "新密码",
"new_user": "新用户", "new_user": "新用户",
"places": "地点", "places": "地点",
"edit": "编辑", "edit": "编辑",
"cancel": "取消", "cancel": "取消",
"password": "密码", "password": "密码",
"info": "信息", "info": "信息",
"preview": "预览", "preview": "预览",
"share": "分享", "share": "分享",
"edit_event": "编辑事件", "edit_event": "编辑事件",
"copy": "复制", "copy": "复制",
"related": "相关", "related": "相关",
"set_password": "设置密码", "set_password": "设置密码",
"instances": "实例", "instances": "实例",
"activate_user": "已确认", "activate_user": "已确认",
"federation": "联盟", "federation": "联盟",
"add_to_calendar": "添加到日历", "add_to_calendar": "添加到日历",
"copied": "已复制", "copied": "已复制",
"embed_title": "在你的网页上嵌入此事件", "embed_title": "在你的网页上嵌入此事件",
"user": "用户", "user": "用户",
"event": "事件", "event": "事件",
"fediverse": "Fediverse 网络", "fediverse": "Fediverse 网络",
"skip": "跳过", "skip": "跳过",
"delete": "移除", "delete": "移除",
"import": "导入", "import": "导入",
"tags": "标签", "tags": "标签",
"close": "关闭", "close": "关闭",
"disable": "禁用", "disable": "禁用",
"password_updated": "密码已修改。", "password_updated": "密码已修改。",
"reset": "重置" "reset": "重置",
}, "clone": "克隆"
"export": { },
"list_description": "如果你有一个网站并希望展示一个事件列表,使用以下代码", "export": {
"email_description": "你可以通过发给你的电子邮件了解你感兴趣的事件。", "list_description": "如果你有一个网站并希望展示一个事件列表,使用以下代码",
"insert_your_address": "输入你的电子邮箱地址", "email_description": "你可以通过发给你的电子邮件了解你感兴趣的事件。",
"ical_description": "电脑和智能手机通常预装了能够导入远程日历的日历应用。", "insert_your_address": "输入你的电子邮箱地址",
"intro": "与那些竭尽全力保留用户和数据的非社交平台不同,我们认为信息和人一样,都必须是自由的。因此,即使不通过此网站,你仍可随时了解你想了解的事件之最新情况。", "ical_description": "电脑和智能手机通常预装了能够导入远程日历的日历应用。",
"feed_description": "要想从电脑或智能手机上关注更新而无需定期打开本网站请使用RSS订阅。</p>\n\n<p>通过RSS订阅您可以使用一个特殊的应用程序来接收你感兴趣的网站的更新。这是一个快速关注许多网站的好方法不需要创建账户或做其他事。</p>\n\n<li> 如果您使用 Android我们推荐 <a href=\"https://f-droid.org/en/packages/net.frju.flym/\">Flym</a> 或 Feeder。</li>\n<li> 对于iPhone/iPad您可以使用 <a href=\"https://itunes.apple.com/ua/app/feeds4u/id1038456442?mt=8\">Feed4U</a> </li>\n<li> 对于台式机/笔记本电脑,我们推荐可在 <a href=\"https://addons.mozilla.org/en-GB/firefox/addon/feedbroreader/\">Firefox</a> 或 <a href=\"https://chrome.google.com/webstore/detail/feedbro/mefgmmbdailogpfhfblcnnjfmnpnmdfa\">Chrome</a> 上安装的 Feedbro。</li>\n<br/>\n将此链接添加到你的RSS阅读器中以获得最新信息。" "intro": "与那些竭尽全力保留用户和数据的非社交平台不同,我们认为信息和人一样,都必须是自由的。因此,即使不通过此网站,你仍可随时了解你想了解的事件之最新情况。",
}, "feed_description": "要想从电脑或智能手机上关注更新而无需定期打开本网站请使用RSS订阅。</p>\n\n<p>通过RSS订阅您可以使用一个特殊的应用程序来接收你感兴趣的网站的更新。这是一个快速关注许多网站的好方法不需要创建账户或做其他事。</p>\n\n<li> 如果您使用 Android我们推荐 <a href=\"https://f-droid.org/en/packages/net.frju.flym/\">Flym</a> 或 Feeder。</li>\n<li> 对于iPhone/iPad您可以使用 <a href=\"https://itunes.apple.com/ua/app/feeds4u/id1038456442?mt=8\">Feed4U</a> </li>\n<li> 对于台式机/笔记本电脑,我们推荐可在 <a href=\"https://addons.mozilla.org/en-GB/firefox/addon/feedbroreader/\">Firefox</a> 或 <a href=\"https://chrome.google.com/webstore/detail/feedbro/mefgmmbdailogpfhfblcnnjfmnpnmdfa\">Chrome</a> 上安装的 Feedbro。</li>\n<br/>\n将此链接添加到你的RSS阅读器中以获得最新信息。"
"register": { },
"description": "社会运动应该组织起来,并自筹资金<br/>\n<br/>在你能发布内容之前,<strong>你的账户必须审核通过</strong>,考虑到<strong>你可以通过此网站发现现实中的人</strong>,请写一些东西告诉我们你希望发布什么。", "register": {
"error": "错误: ", "description": "社会运动应该组织起来,并自筹资金<br/>\n<br/>在你能发布内容之前,<strong>你的账户必须审核通过</strong>,考虑到<strong>你可以通过此网站发现现实中的人</strong>,请写一些东西告诉我们你希望发布什么。",
"complete": "注册必须经过确认。", "error": "错误: ",
"first_user": "管理员已创建" "complete": "注册必须经过确认。",
}, "first_user": "管理员已创建"
"event": { },
"anon_description": "即使不登录或注册,你也可以创建事件,但必须等待一些人看到它,\n并确认这是一个合适的事件。此外你也不能够修改它。<br/><br/>\n你也可以 <a href='/login'>登录</a> 或 <a href='/register'>注册</a>。或者继续浏览以得到答案。 ", "event": {
"anon": "匿名", "anon_description": "即使不登录或注册,你也可以创建事件,但必须等待一些人看到它,\n并确认这是一个合适的事件。此外你也不能够修改它。<br/><br/>\n你也可以 <a href='/login'>登录</a> 或 <a href='/register'>注册</a>。或者继续浏览以得到答案。 ",
"same_day": "在同一天", "anon": "匿名",
"what_description": "标题", "same_day": "在同一天",
"description_description": "描述", "what_description": "标题",
"added": "事件已添加", "description_description": "描述",
"saved": "事件已保存", "added": "事件已添加",
"added_anon": "事件已添加,等待确认。", "saved": "事件已保存",
"updated": "事件已更新", "added_anon": "事件已添加,等待确认。",
"where_description": "事件的地点在哪里?如果不存在,你可以创建一个。", "updated": "事件已更新",
"confirmed": "事件已确认", "where_description": "事件的地点在哪里?如果不存在,你可以创建一个。",
"not_found": "找不到事件", "confirmed": "事件已确认",
"recurrent": "日常事件", "not_found": "找不到事件",
"edit_recurrent": "编辑日常事件:", "recurrent": "日常事件",
"show_recurrent": "日常事件", "edit_recurrent": "编辑日常事件:",
"show_past": "以及过往的事件", "show_recurrent": "日常事件",
"multidate_description": "这是一个节日吗?选择它开始和结束的时间", "show_past": "以及过往的事件",
"multidate": "更多日期", "multidate_description": "这是一个节日吗?选择它开始和结束的时间",
"normal_description": "选择日期。", "multidate": "更多日期",
"recurrent_2w_days": "每 {days} 天一次", "normal_description": "选择日期。",
"each_week": "每周", "recurrent_2w_days": "每 {days} 天一次",
"each_2w": "隔周一次", "each_week": "每周",
"due": "直到", "each_2w": "隔周一次",
"from": "来自", "due": "直到",
"image_too_big": "图片不能大于 4MB", "from": "来自",
"interact_with_me_at": "在 Fediverse 网络上与我互动", "image_too_big": "图片不能大于 4MB",
"interact_with_me": "关注我", "interact_with_me_at": "在 Fediverse 网络上与我互动",
"remove_recurrent_confirmation": "你确定要移除这个日常事件吗?\n过去的事件仍将被维护但不会再添加新事件。", "interact_with_me": "关注我",
"import_URL": "从 URL 导入", "remove_recurrent_confirmation": "你确定要移除这个日常事件吗?\n过去的事件仍将被维护但不会再添加新事件。",
"import_ICS": "从 ICS 导入", "import_URL": "从 URL 导入",
"ics": "ICS", "import_ICS": "从 ICS 导入",
"alt_text_description": "为视觉障碍者提供的说明", "ics": "ICS",
"choose_focal_point": "选择联络点", "alt_text_description": "为视觉障碍者提供的说明",
"download_flyer": "下载传单", "choose_focal_point": "选择联络点",
"tag_description": "标签", "download_flyer": "下载传单",
"media_description": "你可以添加一份传单(可选)", "tag_description": "标签",
"recurrent_description": "选择频率和日期", "media_description": "你可以添加一份传单(可选)",
"only_future": "仅限即将到来的事件", "recurrent_description": "选择频率和日期",
"normal": "普通", "only_future": "仅限即将到来的事件",
"recurrent_1w_days": "每 {days} 天", "normal": "普通",
"recurrent_1m_days": "|每月的第 {days} 天|每月的第 {days} 天", "recurrent_1w_days": "每 {days} 天",
"recurrent_1m_ordinal": "每月的第 {n} 个 {days}", "recurrent_1m_days": "|每月的第 {days} 天|每月的第 {days} 天",
"each_month": "每月", "recurrent_1m_ordinal": "每月的第 {n} 个 {days}",
"follow_me_description": "一种对这里发布的 {title} 事件保持关注的方法,\n是在 Fediverse 网络,比如 Mastodon上关注 <u>{account}</u>,亦有可能通过此方式给此事件添加资源。<br/><br/>\n如果你没听说过 Mastodon 和 Fediverse我们建议你阅读 <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'>这篇文章</a>。<br/><br/>在下方输入你的实例名称例如mastodon.social", "each_month": "每月",
"import_description": "你可以从其他平台和实例通过标准格式ICS 和 hCalendar导入事件", "follow_me_description": "一种对这里发布的 {title} 事件保持关注的方法,\n是在 Fediverse 网络,比如 Mastodon上关注 <u>{account}</u>,亦有可能通过此方式给此事件添加资源。<br/><br/>\n如果你没听说过 Mastodon 和 Fediverse我们建议你阅读 <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'>这篇文章</a>。<br/><br/>在下方输入你的实例名称例如mastodon.social",
"remove_media_confirmation": "你确认要删除图片吗?", "import_description": "你可以从其他平台和实例通过标准格式ICS 和 hCalendar导入事件",
"remove_confirmation": "你确定要移除此事件吗?" "remove_media_confirmation": "你确认要删除图片吗?",
}, "remove_confirmation": "你确定要移除此事件吗?"
"login": { },
"check_email": "检查你的电子邮箱收件箱和垃圾邮件箱。", "login": {
"not_registered": "还未注册?", "check_email": "检查你的电子邮箱收件箱和垃圾邮件箱。",
"forgot_password": "忘记密码了?", "not_registered": "还未注册?",
"insert_email": "输入你的电子邮箱地址", "forgot_password": "忘记密码了?",
"error": "无法登录,检查你的登录信息。", "insert_email": "输入你的电子邮箱地址",
"ok": "已登录", "error": "无法登录,检查你的登录信息。",
"description": "登录以发布新事件。" "ok": "已登录",
}, "description": "登录以发布新事件。"
"recover": { },
"not_valid_code": "发生了一些错误。" "recover": {
}, "not_valid_code": "发生了一些错误。"
"admin": { },
"delete_user": "移除", "admin": {
"remove_admin": "移除管理员", "delete_user": "移除",
"disable_user_confirm": "你确定禁用 {user} 吗?", "remove_admin": "移除管理员",
"disable_admin_user_confirm": "你确定移除 {user} 的管理员权限吗?", "disable_user_confirm": "你确定禁用 {user} 吗?",
"user_remove_ok": "用户已移除", "disable_admin_user_confirm": "你确定移除 {user} 的管理员权限吗?",
"user_create_ok": "用户已创建", "user_remove_ok": "用户已移除",
"event_remove_ok": "事件已移除", "user_create_ok": "用户已创建",
"allow_registration_description": "允许公众注册?", "event_remove_ok": "事件已移除",
"allow_anon_event": "允许发布匿名事件(需要确认)?", "allow_registration_description": "允许公众注册?",
"allow_recurrent_event": "允许日常事件", "allow_anon_event": "允许发布匿名事件(需要确认)?",
"federation": "联邦社交网络 / ActivityPub", "allow_recurrent_event": "允许日常事件",
"enable_federation": "启用联邦社交网络", "federation": "联邦社交网络 / ActivityPub",
"add_instance": "添加实例", "enable_federation": "启用联邦社交网络",
"select_instance_timezone": "时区", "add_instance": "添加实例",
"enable_resources": "启用资源", "select_instance_timezone": "时区",
"hide_boost_bookmark": "隐藏助力/书签", "enable_resources": "启用资源",
"block": "屏蔽", "hide_boost_bookmark": "隐藏助力/书签",
"unblock": "解除屏蔽", "block": "屏蔽",
"instance_name": "实例名称", "unblock": "解除屏蔽",
"hide_resource": "隐藏资源", "instance_name": "实例名称",
"delete_resource_confirm": "你确定要删除此资源吗?", "hide_resource": "隐藏资源",
"filter_instances": "筛选实例", "delete_resource_confirm": "你确定要删除此资源吗?",
"resources": "资源", "filter_instances": "筛选实例",
"favicon": "图标", "resources": "资源",
"user_block_confirm": "你确定要屏蔽用户 {user} 吗?", "favicon": "图标",
"delete_announcement_confirm": "你确定要移除这个公告吗?", "user_block_confirm": "你确定要屏蔽用户 {user} 吗?",
"announcement_remove_ok": "公告已移除", "delete_announcement_confirm": "你确定要移除这个公告吗?",
"instance_locale": "默认语言", "announcement_remove_ok": "公告已移除",
"title_description": "这将被用作页面的标题和电子邮件的主题,以导出 RSS 和 ICS 源。", "instance_locale": "默认语言",
"description_description": "在标题旁的页眉中显示", "title_description": "这将被用作页面的标题和电子邮件的主题,以导出 RSS 和 ICS 源。",
"instance_place_help": "在其他的实例中显示的标签", "description_description": "在标题旁的页眉中显示",
"delete_trusted_instance_confirm": "你确定要从友好实例菜单中删除此项目吗?", "instance_place_help": "在其他的实例中显示的标签",
"edit_place": "编辑地点", "delete_trusted_instance_confirm": "你确定要从友好实例菜单中删除此项目吗?",
"new_announcement": "新公告", "edit_place": "编辑地点",
"show_smtp_setup": "电子邮件设置", "new_announcement": "新公告",
"smtp_port": "SMTP 端口", "show_smtp_setup": "电子邮件设置",
"smtp_secure": "SMTP 安全协议TLS 或 STARTTLS", "smtp_port": "SMTP 端口",
"smtp_test_success": "一封测试邮件已发送至 {admin_mail},请检查你的收件箱", "smtp_secure": "SMTP 安全协议TLS 或 STARTTLS",
"sender_email": "发件人", "smtp_test_success": "一封测试邮件已发送至 {admin_mail},请检查你的收件箱",
"widget": "小组件", "sender_email": "发件人",
"wrong_domain_warning": "在 config.json 中设置的 baseurl <b>{baseurl}</b> 与你正在访问的 <b>{url}</b> 不同", "widget": "小组件",
"edit_collection": "编辑收藏", "wrong_domain_warning": "在 config.json 中设置的 baseurl <b>{baseurl}</b> 与你正在访问的 <b>{url}</b> 不同",
"event_confirm_description": "你可以在此确认匿名用户提交的事件", "edit_collection": "编辑收藏",
"recurrent_event_visible": "默认显示日常事件", "event_confirm_description": "你可以在此确认匿名用户提交的事件",
"place_description": "如果你弄错了地点或地址,你可以修改。<br/>与这个地点相关的当前和过去的所有事件都会改变地址。", "recurrent_event_visible": "默认显示日常事件",
"delete_user_confirm": "你确定移除 {user} 吗?", "place_description": "如果你弄错了地点或地址,你可以修改。<br/>与这个地点相关的当前和过去的所有事件都会改变地址。",
"enable_admin_user_confirm": "你确定授予 {user} 管理员权限吗", "delete_user_confirm": "你确定移除 {user} 吗?",
"enable_federation_help": "这将允许从 Fediverse 上关注此实例", "enable_admin_user_confirm": "你确定授予 {user} 管理员权限吗",
"enable_resources_help": "允许从 Fediverse 为此事件添加资源", "enable_federation_help": "这将允许从 Fediverse 上关注此实例",
"hide_boost_bookmark_help": "隐藏来自 Fediverse 上的助力和书签数量图标", "enable_resources_help": "允许从 Fediverse 为此事件添加资源",
"block_user": "屏蔽用户", "hide_boost_bookmark_help": "隐藏来自 Fediverse 上的助力和书签数量图标",
"filter_users": "筛选用户", "block_user": "屏蔽用户",
"user_add_help": "一封带有确认订阅和设置密码指引的邮件将被发送给新用户", "filter_users": "筛选用户",
"show_resource": "显示资源", "user_add_help": "一封带有确认订阅和设置密码指引的邮件将被发送给新用户",
"delete_resource": "删除资源", "show_resource": "显示资源",
"user_blocked": "用户 {user} 已屏蔽", "delete_resource": "删除资源",
"instance_block_confirm": "你确定要屏蔽实例 {instance} 吗?", "user_blocked": "用户 {user} 已屏蔽",
"announcement_description": "你可以在此段落插入显示于首页的公告", "instance_block_confirm": "你确定要屏蔽实例 {instance} 吗?",
"instance_timezone_description": "Gancio 被设计用来收集特定区域,比如一座城市所发生的事件。这里的所有事件将以所选择的时区显示。", "announcement_description": "你可以在此段落插入显示于首页的公告",
"instance_locale_description": "特定页面偏好的用户语言。有时信息必须以相同的语言对所有人显示(比如通过 ActivityPub 发布内容或发送一些电子邮件时)。在这种情况下将使用上面选择的语言。", "instance_timezone_description": "Gancio 被设计用来收集特定区域,比如一座城市所发生的事件。这里的所有事件将以所选择的时区显示。",
"instance_place": "该实例的指示性位置", "instance_locale_description": "特定页面偏好的用户语言。有时信息必须以相同的语言对所有人显示(比如通过 ActivityPub 发布内容或发送一些电子邮件时)。在这种情况下将使用上面选择的语言。",
"trusted_instances_help": "友好实例的列表将被显示于页眉", "instance_place": "该实例的指示性位置",
"footer_links": "页脚链接", "trusted_instances_help": "友好实例的列表将被显示于页眉",
"smtp_description": "<ul><li>当匿名事件被添加时(如果启用),管理员应当收到邮件</li>管理员应当会受到注册请求邮件(如果启用)。<li></li><li>用户应当会受到注册请求邮件。</li><li>用户应当收到注册确认邮件。</li><li>当管理员直接订阅时,用户应当受到邮件。</li><li>用户忘记密码时应当收到密码重置邮件。</li></ul>", "footer_links": "页脚链接",
"smtp_use_sendmail": "使用 sendmail", "smtp_description": "<ul><li>当匿名事件被添加时(如果启用),管理员应当收到邮件</li>管理员应当会受到注册请求邮件(如果启用)。<li></li><li>用户应当会受到注册请求邮件。</li><li>用户应当收到注册确认邮件。</li><li>当管理员直接订阅时,用户应当受到邮件。</li><li>用户忘记密码时应当收到密码重置邮件。</li></ul>",
"smtp_test_button": "发送测试邮件", "smtp_use_sendmail": "使用 sendmail",
"new_collection": "新建收藏", "smtp_test_button": "发送测试邮件",
"collections_description": "收藏是按标签和地点分组的事件。它们将于主页上显示", "new_collection": "新建收藏",
"enable_trusted_instances": "启用友好实例", "collections_description": "收藏是按标签和地点分组的事件。它们将于主页上显示",
"add_trusted_instance": "添加一个友好实例", "enable_trusted_instances": "启用友好实例",
"add_link": "添加链接", "add_trusted_instance": "添加一个友好实例",
"delete_footer_link_confirm": "确定移除此链接吗?", "add_link": "添加链接",
"instance_name_help": "要关注的 ActivityPub 账号", "delete_footer_link_confirm": "确定移除此链接吗?",
"is_dark": "暗色主题", "instance_name_help": "要关注的 ActivityPub 账号",
"smtp_hostname": "SMTP 主机名" "is_dark": "暗色主题",
}, "smtp_hostname": "SMTP 主机名"
"auth": { },
"fail": "无法登录。你确定密码正确吗?", "auth": {
"not_confirmed": "尚未确认……" "fail": "无法登录。你确定密码正确吗?",
}, "not_confirmed": "尚未确认……"
"settings": { },
"change_password": "修改密码", "settings": {
"password_updated": "密码已修改。", "change_password": "修改密码",
"remove_account_confirm": "你即将永久删除你的账号", "password_updated": "密码已修改。",
"update_confirm": "你希望保存你的修改吗?", "remove_account_confirm": "你即将永久删除你的账号",
"remove_account": "按下下方的按钮后你的账号将被删除。你发布的事件不会删除。", "update_confirm": "你希望保存你的修改吗?",
"danger_section": "危险段落" "remove_account": "按下下方的按钮后你的账号将被删除。你发布的事件不会删除。",
}, "danger_section": "危险段落"
"error": { },
"email_taken": "此电子邮箱地址已被使用。", "error": {
"nick_taken": "此昵称已被使用。" "email_taken": "此电子邮箱地址已被使用。",
}, "nick_taken": "此昵称已被使用。"
"confirm": { },
"title": "用户确认", "confirm": {
"not_valid": "出现了一些错误。", "title": "用户确认",
"valid": "你的账户已被确认,你现在可以 <a href=\"/login\">登录</a>" "not_valid": "出现了一些错误。",
}, "valid": "你的账户已被确认,你现在可以 <a href=\"/login\">登录</a>"
"ordinal": { },
"4": "第四", "ordinal": {
"5": "第五", "1": "第一",
"2": "第二", "2": "第二",
"-1": "最后", "3": "第三",
"1": "第一", "4": "第四",
"3": "第三" "5": "第五",
}, "-1": "最后"
"validators": { },
"required": "{fieldName} 是必填项", "validators": {
"email": "输入有效的电子邮箱地址" "required": "{fieldName} 是必填项",
}, "email": "输入有效的电子邮箱地址"
"oauth": { },
"authorization_request": "应用 <code>{app}</code> 申请在 <code>{instance_name}</code> 上获得以下权限:", "oauth": {
"redirected_to": "在确认后你将被重定向到 <code>{url}</code>", "authorization_request": "应用 <code>{app}</code> 申请在 <code>{instance_name}</code> 上获得以下权限:",
"scopes": { "redirected_to": "在确认后你将被重定向到 <code>{url}</code>",
"event:write": "添加与编辑你的事件" "scopes": {
} "event:write": "添加与编辑你的事件"
}, }
"setup": { },
"completed_description": "<p>你现在可以以以下用户登录<br/><br/>用户名:<b>{email}</b><br/>密码:<b>{password}<b/></p>", "setup": {
"copy_password_dialog": "没错,你必须复制密码!", "completed_description": "<p>你现在可以以以下用户登录<br/><br/>用户名:<b>{email}</b><br/>密码:<b>{password}<b/></p>",
"start": "开始", "copy_password_dialog": "没错,你必须复制密码!",
"https_warning": "你正在使用 HTTP 访问,如果你切换到 HTTPS记得在 config.json 中修改 baseurl", "start": "开始",
"completed": "安装完成" "https_warning": "你正在使用 HTTP 访问,如果你切换到 HTTPS记得在 config.json 中修改 baseurl",
}, "completed": "安装完成"
"about": "\n <p><a href='https://gancio.org'>Gancio</a> 是为本地社区设计的的共享日程表。</p>\n " },
"about": "\n <p><a href='https://gancio.org'>Gancio</a> 是为本地社区设计的的共享日程表。</p>\n "
} }

View file

@ -1,6 +1,9 @@
const config = require('./server/config.js') const config = require('./server/config.js')
const locales = require('./locales/index') const locales = require('./locales/index')
import { ca, de, en, es, eu, fr, gl, it, nb, nl, pl, pt, sk, ru, zhHans } from 'vuetify/es5/locale' import { ca, cs, de, en, es, eu, fr, gl, it, nb, nl, pl, pt, sk, ru, zhHans } from 'vuetify/es5/locale'
const dns = require('node:dns')
dns.setDefaultResultOrder('ipv4first')
const isDev = (process.env.NODE_ENV !== 'production') const isDev = (process.env.NODE_ENV !== 'production')
module.exports = { module.exports = {
@ -141,7 +144,7 @@ module.exports = {
}, },
buildModules: ['@nuxtjs/vuetify'], buildModules: ['@nuxtjs/vuetify'],
vuetify: { vuetify: {
lang: { locales: { ca, de, en, es, eu, fr, gl, it, nb, nl, pl, pt, sk, ru, zhHans } }, lang: { locales: { ca, cs, de, en, es, eu, fr, gl, it, nb, nl, pl, pt, sk, ru, zhHans } },
treeShake: true, treeShake: true,
defaultAssets: false, defaultAssets: false,
optionsPath: './vuetify.options.js' }, optionsPath: './vuetify.options.js' },

View file

@ -1,6 +1,6 @@
{ {
"name": "gancio", "name": "gancio",
"version": "1.6.14-beta", "version": "1.6.19",
"description": "A shared agenda for local communities", "description": "A shared agenda for local communities",
"author": "lesion", "author": "lesion",
"scripts": { "scripts": {
@ -33,46 +33,45 @@
"yarn.lock" "yarn.lock"
], ],
"engines": { "engines": {
"node": ">=15 <=16" "node": ">=14 <=18"
}, },
"dependencies": { "dependencies": {
"@mdi/js": "^7.1.96", "@mdi/js": "^7.3.67",
"@nuxtjs/auth": "^4.9.1", "@nuxtjs/auth": "^4.9.1",
"@nuxtjs/axios": "^5.13.5", "@nuxtjs/axios": "^5.13.5",
"@nuxtjs/i18n": "^7.3.0", "@nuxtjs/i18n": "^7.3.0",
"@nuxtjs/sitemap": "^2.4.0", "@nuxtjs/sitemap": "^2.4.0",
"accept-language": "^3.0.18", "accept-language": "^3.0.18",
"axios": "^0.27.2",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"body-parser": "^1.20.2", "body-parser": "^1.20.2",
"cookie-parser": "^1.4.6", "cookie-parser": "^1.4.6",
"cookie-session": "^2.0.0", "cookie-session": "^2.0.0",
"cookie-universal-nuxt": "^2.2.2", "cookie-universal-nuxt": "^2.2.2",
"cors": "^2.8.5", "cors": "^2.8.5",
"dayjs": "^1.11.8", "dayjs": "^1.11.10",
"dompurify": "^3.0.3", "dompurify": "^3.0.6",
"email-templates": "^10.0.1", "email-templates": "^11.1.1",
"express": "^4.18.1", "express": "^4.18.1",
"express-rate-limit": "^6.7.0", "express-rate-limit": "^7.1.1",
"http-signature": "^1.3.6", "http-signature": "^1.3.6",
"https-proxy-agent": "^5.0.1", "https-proxy-agent": "^7.0.2",
"ical.js": "^1.5.0", "ical.js": "^1.5.0",
"ics": "^3.1.0", "ics": "^3.5.0",
"jsdom": "^21.1.0", "jsdom": "^22.1.0",
"leaflet": "^1.9.4", "leaflet": "^1.9.4",
"linkify-html": "^4.1.1", "linkify-html": "^4.1.1",
"linkifyjs": "4.1.1", "linkifyjs": "4.1.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"luxon": "^3.3.0", "luxon": "^3.4.3",
"mariadb": "^2.5.6", "mariadb": "^3.2.2",
"memory-cache": "^0.2.0", "memory-cache": "^0.2.0",
"microformat-node": "^2.0.1", "microformat-node": "^2.0.1",
"minify-css-string": "^1.0.0", "minify-css-string": "^1.0.0",
"mkdirp": "^2.1.6", "mkdirp": "^3.0.1",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"mysql2": "^2.3.3", "mysql2": "^2.3.3",
"nuxt-edge": "2.17.0-28098741.f3c5f95", "nuxt-edge": "2.17.2-28258581.6132947",
"oauth2orize": "^1.11.1", "oauth2orize": "^1.12.0",
"passport": "^0.6.0", "passport": "^0.6.0",
"passport-anonymous": "^1.0.1", "passport-anonymous": "^1.0.1",
"passport-custom": "^1.1.1", "passport-custom": "^1.1.1",
@ -80,32 +79,33 @@
"passport-http-bearer": "^1.0.1", "passport-http-bearer": "^1.0.1",
"passport-oauth2-client-password": "^0.1.2", "passport-oauth2-client-password": "^0.1.2",
"passport-oauth2-client-public": "^0.0.1", "passport-oauth2-client-public": "^0.0.1",
"pg": "^8.11.0", "pg": "^8.11.3",
"sequelize": "^6.32.0", "semver": "^7.5.4",
"sequelize": "^6.33.0",
"sequelize-slugify": "^1.6.2", "sequelize-slugify": "^1.6.2",
"sharp": "^0.27.2", "sharp": "^0.27.2",
"sqlite3": "^5.1.4", "sqlite3": "^5.1.4",
"telegraf": "^4.12.2", "telegraf": "^4.14.0",
"tiptap": "^1.32.0", "tiptap": "^1.32.0",
"tiptap-extensions": "^1.35.0", "tiptap-extensions": "^1.35.0",
"umzug": "^2.3.0", "umzug": "^2.3.0",
"v-calendar": "^2.4.1", "v-calendar": "^2.4.2",
"vue2-leaflet": "^2.7.1", "vue2-leaflet": "^2.7.1",
"vuetify": "2.6.14", "vuetify": "2.6.14",
"winston": "^3.8.2", "winston": "^3.11.0",
"winston-daily-rotate-file": "^4.7.1", "winston-daily-rotate-file": "^4.7.1",
"yargs": "^17.7.2" "yargs": "^17.7.2"
}, },
"devDependencies": { "devDependencies": {
"@nuxtjs/vuetify": "^1.12.3", "@nuxtjs/vuetify": "^1.12.3",
"@vue/language-plugin-pug": "^1.7.0", "@vue/language-plugin-pug": "^1.8.19",
"jest": "^29.5.0", "jest": "^29.7.0",
"jest-environment-node": "^29.5.0", "jest-environment-node": "^29.7.0",
"prettier": "^2.8.8", "prettier": "^2.8.8",
"pug": "^3.0.2", "pug": "^3.0.2",
"pug-plain-loader": "^1.1.0", "pug-plain-loader": "^1.1.0",
"sass": "^1.61.0", "sass": "^1.67.0",
"sequelize-cli": "^6.3.0", "sequelize-cli": "^6.6.1",
"supertest": "^6.3.3", "supertest": "^6.3.3",
"webpack": "4", "webpack": "4",
"webpack-cli": "^4.10.0" "webpack-cli": "^4.10.0"

View file

@ -3,7 +3,8 @@ v-container.container.pa-0.pa-md-3
v-card v-card
v-alert(v-if='url!==settings.baseurl' outlined type='warning' show-icon :icon='mdiAlert') v-alert(v-if='url!==settings.baseurl' outlined type='warning' show-icon :icon='mdiAlert')
span(v-html="$t('admin.wrong_domain_warning', { url, baseurl: settings.baseurl })") span(v-html="$t('admin.wrong_domain_warning', { url, baseurl: settings.baseurl })")
v-alert(v-if='!selfReachable' outlined type='warning' show-icon :icon='mdiAlert')
span(v-html="$t('admin.not_reachable')")
v-tabs(v-model='selectedTab' show-arrows :next-icon='mdiChevronRight' :prev-icon='mdiChevronLeft') v-tabs(v-model='selectedTab' show-arrows :next-icon='mdiChevronRight' :prev-icon='mdiChevronLeft')
//- SETTINGS //- SETTINGS
@ -102,9 +103,10 @@ export default {
try { try {
const users = await $axios.$get('/users') const users = await $axios.$get('/users')
const unconfirmedEvents = await $axios.$get('/event/unconfirmed') const unconfirmedEvents = await $axios.$get('/event/unconfirmed')
return { users, unconfirmedEvents, url } const selfReachable = await $axios.$get('/reachable')
return { users, unconfirmedEvents, url, selfReachable }
} catch (e) { } catch (e) {
return { users: [], unconfirmedEvents: [], url } return { users: [], unconfirmedEvents: [], url, selfReachable: false }
} }
}, },
data () { data () {
@ -113,6 +115,7 @@ export default {
users: [], users: [],
description: '', description: '',
unconfirmedEvents: [], unconfirmedEvents: [],
selfReachable: false
} }
}, },
head () { head () {

View file

@ -105,12 +105,12 @@ export default {
return true return true
}, },
async asyncData({ params, $axios, error, $auth, $time }) { async asyncData({ query, params, $axios, error, $auth, $time, store }) {
if (params.edit) { if (params.edit) {
const data = { event: { place: {}, media: [] } } const data = { event: { place: {}, media: [] } }
data.id = params.edit data.id = params.edit
data.edit = true data.edit = query.clone ? false : true
let event let event
try { try {
event = await $axios.$get('/event/detail/' + data.id) event = await $axios.$get('/event/detail/' + data.id)
@ -138,8 +138,13 @@ export default {
data.event.title = event.title data.event.title = event.title
data.event.description = event.description data.event.description = event.description
data.event.id = event.id if (data.edit) {
data.event.id = event.id
}
data.event.tags = event.tags data.event.tags = event.tags
if (event.media && event.media.length > 0 && !data.edit) {
event.media[0].url = `${store.state.settings.baseurl}/media/${event.media[0].url}`
}
data.event.media = event.media || [] data.event.media = event.media || []
data.event.parentId = event.parentId data.event.parentId = event.parentId
data.event.recurrent = event.recurrent data.event.recurrent = event.recurrent

View file

@ -1,10 +1,10 @@
<template lang="pug"> <template lang="pug">
v-container#event.h-event.pa-2.pa-sm-2(itemscope itemtype="https://schema.org/Event" v-touch="{ left: goNext, right: goPrev }") v-container#event.h-event.pa-2.pa-sm-2(v-touch="{ left: goNext, right: goPrev }")
//- EVENT PAGE //- EVENT PAGE
//- gancio supports microformats (http://microformats.org/wiki/h-event) //- gancio supports microformats (http://microformats.org/wiki/h-event)
//- and microdata https://schema.org/Event //- and microdata https://schema.org/Event
v-row v-row(itemscope itemtype="https://schema.org/Event")
v-col.col-12.col-md-8 v-col.col-12.col-md-8
MyPicture(v-if='hasMedia' :event='event') MyPicture(v-if='hasMedia' :event='event')
.p-description.text-body-1.pa-3.rounded(v-if='!hasMedia && event.description' itemprop='description' v-html='event.description') .p-description.text-body-1.pa-3.rounded(v-if='!hasMedia && event.description' itemprop='description' v-html='event.description')
@ -19,7 +19,7 @@ v-container#event.h-event.pa-2.pa-sm-2(itemscope itemtype="https://schema.org/Ev
v-container.eventDetails v-container.eventDetails
time.dt-start(:datetime='$time.unixFormat(event.start_datetime, "yyyy-MM-dd HH:mm")' itemprop="startDate" :content='$time.unixFormat(event.start_datetime, "yyyy-MM-dd\'T\'HH:mm")') time.dt-start(:datetime='$time.unixFormat(event.start_datetime, "yyyy-MM-dd HH:mm")' itemprop="startDate" :content='$time.unixFormat(event.start_datetime, "yyyy-MM-dd\'T\'HH:mm")')
v-icon(v-text='mdiCalendar' small) v-icon(v-text='mdiCalendar' small)
strong.ml-2.text-uppercase {{$time.when(event)}} span.ml-2.text-uppercase {{$time.when(event)}}
.d-none.dt-end(v-if='event.end_datetime' itemprop="endDate" :content='$time.unixFormat(event.end_datetime,"yyyy-MM-dd\'T\'HH:mm")') {{$time.unixFormat(event.end_datetime,"yyyy-MM-dd'T'HH:mm")}} .d-none.dt-end(v-if='event.end_datetime' itemprop="endDate" :content='$time.unixFormat(event.end_datetime,"yyyy-MM-dd\'T\'HH:mm")') {{$time.unixFormat(event.end_datetime,"yyyy-MM-dd'T'HH:mm")}}
div.font-weight-light.mb-3 {{$time.from(event.start_datetime)}} div.font-weight-light.mb-3 {{$time.from(event.start_datetime)}}
small(v-if='event.parentId') ({{$time.recurrentDetail(event)}}) small(v-if='event.parentId') ({{$time.recurrentDetail(event)}})
@ -46,9 +46,6 @@ v-container#event.h-event.pa-2.pa-sm-2(itemscope itemtype="https://schema.org/Ev
v-divider v-divider
//- info & actions //- info & actions
v-list(dense nav color='transparent') v-list(dense nav color='transparent')
//- v-list-group(:append-icon='mdiChevronUp' :value='true')
//- template(v-slot:activator)
//- v-list-item.text-overline {{$t('common.actions')}}
//- copy link //- copy link
v-list-item(@click='clipboard(`${settings.baseurl}/event/${event.slug || event.id}`)') v-list-item(@click='clipboard(`${settings.baseurl}/event/${event.slug || event.id}`)')
@ -190,8 +187,6 @@ import EventAdmin from '@/components/eventAdmin'
import EmbedEvent from '@/components/embedEvent' import EmbedEvent from '@/components/embedEvent'
import EventMapDialog from '@/components/EventMapDialog' import EventMapDialog from '@/components/EventMapDialog'
const { htmlToText } = require('html-to-text')
import { mdiArrowLeft, mdiArrowRight, mdiDotsVertical, mdiCodeTags, mdiClose, mdiMap, import { mdiArrowLeft, mdiArrowRight, mdiDotsVertical, mdiCodeTags, mdiClose, mdiMap,
mdiEye, mdiEyeOff, mdiDelete, mdiRepeat, mdiLock, mdiFileDownloadOutline, mdiShareAll, mdiEye, mdiEyeOff, mdiDelete, mdiRepeat, mdiLock, mdiFileDownloadOutline, mdiShareAll,
mdiCalendarExport, mdiCalendar, mdiContentCopy, mdiMapMarker, mdiChevronUp, mdiMonitorAccount, mdiBookmark } from '@mdi/js' mdiCalendarExport, mdiCalendar, mdiContentCopy, mdiMapMarker, mdiChevronUp, mdiMonitorAccount, mdiBookmark } from '@mdi/js'
@ -314,7 +309,7 @@ export default {
return this.event.media && this.event.media.length return this.event.media && this.event.media.length
}, },
plainDescription () { plainDescription () {
return htmlToText(this.event.description && this.event.description.replace('\n', '').slice(0, 1000)) return this.event.plain_description || ''
}, },
currentAttachmentLabel () { currentAttachmentLabel () {
return get(this.selectedResource, `data.attachment[${this.currentAttachment}].name`, '') return get(this.selectedResource, `data.attachment[${this.currentAttachment}].name`, '')

View file

@ -4,13 +4,11 @@ v-container.pa-0.pa-md-3
v-card-title {{$t('common.share')}} v-card-title {{$t('common.share')}}
v-card-text v-card-text
p.text-body-1 {{$t('export.intro')}} p.text-body-1 {{$t('export.intro')}}
v-row v-card(outlined :dark='is_dark' :color="is_dark ? '#333' : '#ececec'")
v-col(:md='2' :cols='12') v-card-title {{$t('common.filter')}}
v-card-title.py-0 {{$t('common.filter')}} v-card-subtitle {{$t('export.filter_description')}}
v-col v-card-text
Search( Search(v-model='filters')
:filters='filters'
@update='f => filters = f')
v-tabs(v-model='type' show-arrows :next-icon='mdiChevronRight' :prev-icon='mdiChevronLeft') v-tabs(v-model='type' show-arrows :next-icon='mdiChevronRight' :prev-icon='mdiChevronLeft')
//- TOFIX //- TOFIX
@ -52,13 +50,14 @@ v-container.pa-0.pa-md-3
v-col.col-12.col-lg-4 v-col.col-12.col-lg-4
v-text-field(v-model='list.title' :label='$t("common.title")') v-text-field(v-model='list.title' :label='$t("common.title")')
v-text-field(v-model='list.maxEvents' type='number' min='1' :label='$t("common.max_events")') v-text-field(v-model='list.maxEvents' type='number' min='1' :label='$t("common.max_events")')
v-switch(v-model='list.theme' inset true-value='dark' false-value='light' :label="$t('admin.is_dark')") v-switch(v-model='list.theme' hide-details inset true-value='dark' false-value='light' :label="$t('admin.is_dark')")
v-switch(v-model='list.sidebar' inset true-value='true' false-value='false' :label="$t('admin.widget')") v-switch(v-model='list.sidebar' inset true-value='true' false-value='false' :label="$t('admin.widget')")
v-col.col-12.col-lg-8 v-col.col-12.col-lg-8
gancio-events(:baseurl='settings.baseurl' gancio-events(:baseurl='settings.baseurl'
:maxlength='list.maxEvents && Number(list.maxEvents)' :maxlength='list.maxEvents && Number(list.maxEvents)'
:title='list.title' :title='list.title'
:theme='list.theme' :theme='list.theme'
:collection='filters.collection'
:places='filters.places.join(",")' :places='filters.places.join(",")'
:tags='filters.tags.join(",")' :tags='filters.tags.join(",")'
:show_recurrent='filters.show_recurrent' :show_recurrent='filters.show_recurrent'
@ -81,7 +80,7 @@ v-container.pa-0.pa-md-3
</template> </template>
<script> <script>
import { mapState } from 'vuex' import { mapState, mapGetters } from 'vuex'
import FollowMe from '../components/FollowMe' import FollowMe from '../components/FollowMe'
import Search from '@/components/Search' import Search from '@/components/Search'
import clipboard from '../assets/clipboard' import clipboard from '../assets/clipboard'
@ -112,7 +111,7 @@ export default {
theme: $store.state.settings['theme.is_dark'] ? 'dark' : 'light', theme: $store.state.settings['theme.is_dark'] ? 'dark' : 'light',
sidebar: 'true' sidebar: 'true'
}, },
filters: { tags: [], places: [], show_recurrent: $store.state.settings.recurrent_event_visible }, filters: { tags: [], places: [], collection: undefined, show_recurrent: $store.state.settings.recurrent_event_visible },
events: [] events: []
} }
}, },
@ -123,6 +122,7 @@ export default {
}, },
computed: { computed: {
...mapState(['settings']), ...mapState(['settings']),
...mapGetters(['is_dark']),
code () { code () {
const params = [`baseurl="${this.settings.baseurl}"`] const params = [`baseurl="${this.settings.baseurl}"`]
@ -130,12 +130,16 @@ export default {
params.push(`title="${this.list.title}"`) params.push(`title="${this.list.title}"`)
} }
if (this.filters.places.length) { if (this.filters.collection) {
params.push(`places="${this.filters.places.join(',')}"`) params.push(`collection="${this.filters.collection}"`)
} } else {
if (this.filters.places.length) {
params.push(`places="${this.filters.places.join(',')}"`)
}
if (this.filters.tags.length) { if (this.filters.tags.length) {
params.push(`tags="${this.filters.tags.join(',')}"`) params.push(`tags="${this.filters.tags.join(',')}"`)
}
} }
if (this.filters.show_recurrent) { if (this.filters.show_recurrent) {
@ -158,12 +162,17 @@ export default {
const typeMap = ['rss', 'ics'] const typeMap = ['rss', 'ics']
const params = [] const params = []
if (this.filters.tags.length) {
params.push(`tags=${this.filters.tags.map(encodeURIComponent).join(',')}`)
}
if (this.filters.places.length) { if (this.filters.collection) {
params.push(`places=${this.filters.places.join(',')}`) return `${this.settings.baseurl}/feed/${typeMap[this.type]}/collection/${encodeURIComponent(this.filters.collection)}`
} else {
if (this.filters.tags.length) {
params.push(`tags=${this.filters.tags.map(encodeURIComponent).join(',')}`)
}
if (this.filters.places.length) {
params.push(`places=${this.filters.places.join(',')}`)
}
} }
if (this.filters.show_recurrent) { if (this.filters.show_recurrent) {

View file

@ -1,24 +1,28 @@
<template lang='pug'> <template lang='pug'>
v-container v-container
v-row.mt-5(align='center' justify='center') v-form(@submit.prevent="change_password" v-model='valid')
v-col(cols='12' md="6" lg="5" xl="4") v-row.mt-5(align='center' justify='center')
v-card v-col(cols='12' md="6" lg="5" xl="4")
v-card-title {{$t('common.recover_password')}} v-card
template(v-if='user') v-card-title {{$t('common.recover_password')}}
v-card-subtitle {{user.email}} template(v-if='user')
v-card-text v-card-subtitle {{user.email}}
v-text-field(type='password' v-card-text
:rules="$validators.password" v-text-field(type='password'
autofocus :placeholder='$t("common.new_password")' :rules="$validators.password"
v-model='new_password') autofocus :placeholder='$t("common.new_password")'
div(v-else) {{$t('recover.not_valid_code')}} v-model='new_password')
template(v-else)
v-card-text
v-alert(type='error' :icon='mdiAlert') {{$t('recover.not_valid_code')}} <br/> {{ error }}
v-card-actions v-card-actions
v-spacer v-spacer
v-btn(v-if='user' text color='primary' @click='change_password') {{$t('common.send')}} v-btn(v-if='user' outlined color='primary' type='submit' :disabled='!valid') {{$t('common.send')}}
</template> </template>
<script> <script>
import { mapState } from 'vuex' import { mapState } from 'vuex'
import { mdiAlert } from '@mdi/js'
export default { export default {
name: 'Recover', name: 'Recover',
@ -28,11 +32,11 @@ export default {
const user = await $axios.$post('/user/check_recover_code', { recover_code: code }) const user = await $axios.$post('/user/check_recover_code', { recover_code: code })
return { user, code } return { user, code }
} catch (e) { } catch (e) {
return { user: false } return { user: false, error: String(e) }
} }
}, },
data () { data () {
return { new_password: '' } return { new_password: '', valid: false, mdiAlert }
}, },
computed: mapState(['settings']), computed: mapState(['settings']),
methods: { methods: {

View file

@ -62,4 +62,4 @@ export default {
} }
} }
} }
</script> </script>

View file

@ -15,10 +15,11 @@ v-container
v-btn(color="primary" type='submit' :disabled='!new_password' @click='change_password' outlined) {{$t('common.send')}} v-btn(color="primary" type='submit' :disabled='!new_password' @click='change_password' outlined) {{$t('common.send')}}
v-card-text(v-else) v-card-text(v-else)
v-alert.ma-5(type='error') {{$t('recover.not_valid_code')}} v-alert.ma-5(type='error' :icon='mdiAlert') {{$t('recover.not_valid_code')}} <br/> {{ error }}
</template> </template>
<script> <script>
import { mdiAlert } from '@mdi/js'
export default { export default {
name: 'Recover', name: 'Recover',
@ -28,11 +29,11 @@ export default {
const user = await $axios.$post('/user/check_recover_code', { recover_code: code }) const user = await $axios.$post('/user/check_recover_code', { recover_code: code })
return { user, code } return { user, code }
} catch (e) { } catch (e) {
return { user: false } return { user: false, error: String(e) }
} }
}, },
data () { data () {
return { new_password: '' } return { new_password: '', mdiAlert }
}, },
methods: { methods: {
async change_password () { async change_password () {

View file

@ -1,9 +1,62 @@
const express = require('express')
const myPluginRouter = express.Router()
// this will answer at http://localhost:13120/api/plugin/Example/test
myPluginRouter.get('/test', (req, res) => {
return res.json('OK!')
})
const plugin = { const plugin = {
routeAPI: myPluginRouter,
configuration: {
name: 'Example',
author: 'lesion',
url: 'https://framagit.org/les/gancio',
description: 'Example plugin',
settings: {
my_plugin_string_setting: {
type: 'TEXT',
description: 'My plugin string setting',
required: true,
hint: 'My plugin setting support <strong>html too</strong>'
},
enable_this_feature_in_my_plugin: {
type: 'CHECK',
description: 'My plugin best feature',
required: true,
hint: 'This feature is super dupe, enable it!'
},
min_post: {
type: 'NUMBER',
description: 'it supports number too'
},
my_default_language: {
description: 'My default language',
type: 'LIST',
items: ['it', 'en', 'fr']
}
}
},
gancio: null, gancio: null,
load (gancio) { settings: null,
load (gancio, settings) {
console.error('Plugin GancioPluginExample loaded!') console.error('Plugin GancioPluginExample loaded!')
console.error('Your settings are in ', settings)
console.error(`For example, you can access to your default language setting by using ${settings.my_default_language}`)
plugin.gancio = gancio plugin.gancio = gancio
plugin.settings = settings
// gancio.db.models.event.findAll({ where: })
// gancio.db.query('CREATE TABLE IF NOT EXISTS ()... ')
},
unload () {
console.error('Unload this plugin!')
},
onTest () {
console.error('called on "TEST" button pressed in admin interface')
}, },
onEventCreate (event) { onEventCreate (event) {

View file

@ -4,6 +4,22 @@ export default ({ app, store }, inject) => {
Settings.defaultLocale = app.i18n.locale || store.state.settings.instance_locale Settings.defaultLocale = app.i18n.locale || store.state.settings.instance_locale
const time = { const time = {
timeFormat () {
const time = DateTime.fromObject({ hour: 14 }, {
zone: store.state.settings.instance_timezone,
locale: app.i18n.locale || store.state.settings.instance_locale
}).toLocaleString({ hour: 'numeric'})
return time === '2 PM' ? 'ampm' : '24hr'
},
formatHour (value, format) {
if (!value) return ''
return DateTime.fromFormat(value, 'HH:mm', {
zone: store.state.settings.instance_timezone,
locale: app.i18n.locale || store.state.settings.instance_locale
}).toLocaleString({ hour: '2-digit', minute: '2-digit'})
},
format (date, format) { format (date, format) {
return DateTime.fromISO(date, { return DateTime.fromISO(date, {
zone: store.state.settings.instance_timezone, zone: store.state.settings.instance_timezone,
@ -46,11 +62,11 @@ export default ({ app, store }, inject) => {
} }
const start = DateTime.fromSeconds(event.start_datetime, opt) const start = DateTime.fromSeconds(event.start_datetime, opt)
let time = start.toFormat('EEEE d MMMM HH:mm') let time = start.toLocaleString({ weekday: 'long', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' })
const end = event.end_datetime && DateTime.fromSeconds(event.end_datetime, opt) const end = event.end_datetime && DateTime.fromSeconds(event.end_datetime, opt)
if (end) { if (end) {
time += event.multidate ? `${end.toFormat('EEEE d MMMM')}` : `-${end.toFormat('HH:mm')}` time += event.multidate ? `${end.toLocaleString({ weekday: 'long', month: 'short', day: '2-digit'})}` : `-${end.toLocaleString({hour: '2-digit', minute: '2-digit'})}`
} }
if (currentYear !== start.year) { if (currentYear !== start.year) {
@ -73,14 +89,18 @@ export default ({ app, store }, inject) => {
recurrentDetail (event) { recurrentDetail (event) {
const opt = {
zone,
locale: app.i18n.locale || store.state.settings.instance_locale
}
const parent = event.parent const parent = event.parent
if (!parent.recurrent || !parent.recurrent.frequency) return 'error!' if (!parent.recurrent || !parent.recurrent.frequency) return 'error!'
const { frequency, type } = parent.recurrent const { frequency, type } = parent.recurrent
let recurrent let recurrent
if (frequency === '1w' || frequency === '2w') { if (frequency === '1w' || frequency === '2w') {
recurrent = app.i18n.t(`event.recurrent_${frequency}_days`, { days: DateTime.fromSeconds(parent.start_datetime).toFormat('EEEE') }) recurrent = app.i18n.t(`event.recurrent_${frequency}_days`, { days: DateTime.fromSeconds(parent.start_datetime, opt).toFormat('EEEE')})
} else if (frequency === '1m' || frequency === '2m') { } else if (frequency === '1m' || frequency === '2m') {
const d = type === 'ordinal' ? DateTime.fromSeconds(parent.start_datetime).day : DateTime.fromSeconds(parent.start_datetime).toFormat('EEEE') const d = type === 'ordinal' ? DateTime.fromSeconds(parent.start_datetime, opt).day : DateTime.fromSeconds(parent.start_datetime, opt).toFormat('EEEE')
if (type === 'ordinal') { if (type === 'ordinal') {
recurrent = app.i18n.t(`event.recurrent_${frequency}_days`, { days: d }) recurrent = app.i18n.t(`event.recurrent_${frequency}_days`, { days: d })
} else { } else {
@ -116,6 +136,7 @@ export default ({ app, store }, inject) => {
const now = DateTime.local(opt).toUnixInteger() const now = DateTime.local(opt).toUnixInteger()
for (const e of events) { for (const e of events) {
const tmp = DateTime.fromSeconds(e.start_datetime, opt) const tmp = DateTime.fromSeconds(e.start_datetime, opt)
if (!tmp || !tmp.year) continue
const start = DateTime.local().set({ year: tmp.year, month: tmp.month, day: tmp.day }) const start = DateTime.local().set({ year: tmp.year, month: tmp.month, day: tmp.day })
// merge events with same date // merge events with same date
const key = `${start.month}${start.day}` const key = `${start.month}${start.day}`

View file

@ -1,14 +1,15 @@
const { Collection, Filter, Event, Tag, Place } = require('../models/models') const { Collection, Filter, Event, Tag, Place } = require('../models/models')
const exportController = require('./export')
const log = require('../../log') const log = require('../../log')
const { DateTime } = require('luxon') const { DateTime } = require('luxon')
const { col: Col } = require('../../helpers') const { col: Col, queryParamToBool } = require('../../helpers')
const { Op, Sequelize } = require('sequelize') const { Op, Sequelize } = require('sequelize')
const collectionController = { const collectionController = {
async getAll (req, res) { async getAll (req, res) {
const withFilters = req.query.withFilters const withFilters = queryParamToBool(req.query.withFilters)
let collections let collections
if (withFilters) { if (withFilters) {
collections = await Collection.findAll({ include: [ Filter ] }) collections = await Collection.findAll({ include: [ Filter ] })
@ -19,18 +20,39 @@ const collectionController = {
return res.json(collections) return res.json(collections)
}, },
// return events from collection
async getEvents (req, res) { async getEvents (req, res) {
const name = req.params.name const name = req.params.name
const format = req.params.format || 'json'
try {
const events = await collectionController._getEvents(name)
switch (format) {
case 'rss':
return exportController.feed(req, res, events,
`${res.locals.settings.title} - Collection @${name}`,
`${res.locals.settings.baseurl}/feed/rss/collection/${name}`)
case 'ics':
return exportController.ics(req, res, events)
default:
return res.json(events )
}
} catch (e) {
log.error(e)
return res.sendStatus(404)
}
},
// return events from collection
async _getEvents (name) {
const collection = await Collection.findOne({ where: { name } }) const collection = await Collection.findOne({ where: { name } })
if (!collection) { if (!collection) {
return res.sendStatus(404) throw new Error(`Collection ${name} not found`)
} }
const filters = await Filter.findAll({ where: { collectionId: collection.id } })
const filters = await Filter.findAll({ where: { collectionId: collection.id } })
if (!filters.length) { if (!filters.length) {
return res.json([]) return []
} }
const start = DateTime.local().toUnixInteger() const start = DateTime.local().toUnixInteger()
const where = { const where = {
@ -40,10 +62,7 @@ const collectionController = {
// confirmed event only // confirmed event only
is_visible: true, is_visible: true,
// [Op.or]: { start_datetime: { [Op.gte]: start },
start_datetime: { [Op.gte]: start },
// end_datetime: { [Op.gte]: start }
// }
} }
const replacements = [] const replacements = []
@ -67,7 +86,7 @@ const collectionController = {
const events = await Event.findAll({ const events = await Event.findAll({
where, where,
attributes: { attributes: {
exclude: ['likes', 'boost', 'userId', 'is_visible', 'createdAt', 'updatedAt', 'description', 'resources'] exclude: ['likes', 'boost', 'userId', 'is_visible', 'createdAt', 'description', 'resources']
}, },
order: ['start_datetime'], order: ['start_datetime'],
include: [ include: [
@ -86,14 +105,12 @@ const collectionController = {
return [] return []
}) })
const ret = events.map(e => { return events.map(e => {
e = e.get() e = e.get()
e.tags = e.tags ? e.tags.map(t => t && t.tag) : [] e.tags = e.tags ? e.tags.map(t => t && t.tag) : []
return e return e
}) })
return res.json(ret)
}, },
async add (req, res) { async add (req, res) {
@ -131,11 +148,11 @@ const collectionController = {
const collectionId = req.params.collection_id const collectionId = req.params.collection_id
const filters = await Filter.findAll({ where: { collectionId } }) const filters = await Filter.findAll({ where: { collectionId } })
return res.json(filters) return res.json(filters)
}, },
async addFilter (req, res) { async addFilter (req, res) {
const { collectionId, tags, places } = req.body const { collectionId, tags, places } = req.body
try { try {
filter = await Filter.create({ collectionId, tags, places }) filter = await Filter.create({ collectionId, tags, places })
return res.json(filter) return res.json(filter)
@ -165,4 +182,4 @@ const collectionController = {
} }
module.exports = collectionController module.exports = collectionController

View file

@ -9,8 +9,9 @@ const { DateTime } = require('luxon')
const helpers = require('../../helpers') const helpers = require('../../helpers')
const Col = helpers.col const Col = helpers.col
const notifier = require('../../notifier') const notifier = require('../../notifier')
const { htmlToText } = require('html-to-text')
const { Event, Resource, Tag, Place, Notification, APUser } = require('../models/models') const { Event, Resource, Tag, Place, Notification, APUser, Collection } = require('../models/models')
const exportController = require('./export') const exportController = require('./export')
@ -47,7 +48,7 @@ const eventController = {
}, },
async searchMeta(req, res) { async searchMeta(req, res) {
const search = req.query.search const search = req.query.search.toLocaleLowerCase()
const places = await Place.findAll({ const places = await Place.findAll({
order: [[Sequelize.col('w'), 'DESC']], order: [[Sequelize.col('w'), 'DESC']],
@ -74,6 +75,7 @@ const eventController = {
raw: true raw: true
}) })
const ret = places.map(p => { const ret = places.map(p => {
p.type = 'place' p.type = 'place'
return p return p
@ -181,6 +183,8 @@ const eventController = {
event.next = next && (next.slug || next.id) event.next = next && (next.slug || next.id)
event.prev = prev && (prev.slug || prev.id) event.prev = prev && (prev.slug || prev.id)
event.tags = event.tags.map(t => t.tag) event.tags = event.tags.map(t => t.tag)
event.plain_description = htmlToText(event.description, event.description.replace('\n', '').slice(0, 1000) )
if (format === 'json') { if (format === 'json') {
res.json(event) res.json(event)
} else if (format === 'ics') { } else if (format === 'ics') {
@ -315,6 +319,26 @@ const eventController = {
return res.status(400).send(`${missing_field} required`) return res.status(400).send(`${missing_field} required`)
} }
// validate start_datetime and end_datetime
if (body.end_datetime) {
if (body.start_datetime > body.end_datetime) {
return res.status(400).send(`start datetime is greater than end datetime`)
}
if (Number(body.end_datetime) > 1000*24*60*60*365) {
return res.status(400).send('are you sure?')
}
}
if (!Number(body.start_datetime)) {
return res.status(400).send(`Wrong format for start datetime`)
}
if (Number(body.start_datetime) > 1000*24*60*60*365) {
return res.status(400).send('are you sure?')
}
// find or create the place // find or create the place
let place let place
try { try {
@ -597,6 +621,8 @@ const eventController = {
} }
if (query) { if (query) {
query = query.toLocaleLowerCase()
replacements.push(query)
replacements.push(query) replacements.push(query)
where[Op.or] = where[Op.or] =
[ [
@ -690,7 +716,7 @@ const eventController = {
const parentStartDatetime = DateTime.fromSeconds(e.start_datetime) const parentStartDatetime = DateTime.fromSeconds(e.start_datetime)
// cursor is when start to count // cursor is when start to count
// sets it to // in case parent is in past, start to calculate from now
let cursor = parentStartDatetime > startAt ? parentStartDatetime : startAt let cursor = parentStartDatetime > startAt ? parentStartDatetime : startAt
startAt = cursor startAt = cursor
@ -711,6 +737,8 @@ const eventController = {
cursor = cursor.plus({ days: 7 * Number(frequency[0]) }) cursor = cursor.plus({ days: 7 * Number(frequency[0]) })
} }
} else if (frequency === '1m') { } else if (frequency === '1m') {
// day n.X each month
if (type === 'ordinal') { if (type === 'ordinal') {
cursor = cursor.set({ day: parentStartDatetime.day }) cursor = cursor.set({ day: parentStartDatetime.day })
@ -718,10 +746,10 @@ const eventController = {
cursor = cursor.plus({ months: 1 }) cursor = cursor.plus({ months: 1 })
} }
} else { // weekday } else { // weekday
// get weekday
// get recurrent freq details // get recurrent freq details
cursor = helpers.getWeekdayN(cursor, type, parentStartDatetime.weekday) cursor = helpers.getWeekdayN(cursor, type, parentStartDatetime.weekday)
if (cursor< startAt) { if (cursor < startAt) {
cursor = cursor.plus({ months: 1 }) cursor = cursor.plus({ months: 1 })
cursor = helpers.getWeekdayN(cursor, type, parentStartDatetime.weekday) cursor = helpers.getWeekdayN(cursor, type, parentStartDatetime.weekday)
} }

View file

@ -4,6 +4,7 @@ const { htmlToText } = require('html-to-text')
const { Op, literal } = require('sequelize') const { Op, literal } = require('sequelize')
const { DateTime } = require('luxon') const { DateTime } = require('luxon')
const ics = require('ics') const ics = require('ics')
const collectionController = require('./collection')
const exportController = { const exportController = {
@ -11,6 +12,7 @@ const exportController = {
const format = req.params.format const format = req.params.format
const tags = req.query.tags const tags = req.query.tags
const places = req.query.places const places = req.query.places
const collection = req.query.collection
const show_recurrent = !!req.query.show_recurrent const show_recurrent = !!req.query.show_recurrent
const opt = { const opt = {
@ -21,45 +23,55 @@ const exportController = {
const where = {} const where = {}
const yesterday = DateTime.local(opt).minus({day: 1}).toUnixInteger() const yesterday = DateTime.local(opt).minus({day: 1}).toUnixInteger()
if (!collection) {
if (tags && places) { if (tags && places) {
where[Op.or] = { where[Op.or] = {
placeId: places ? places.split(',') : [], placeId: places ? places.split(',') : [],
'$tags.tag$': tags.split(',') '$tags.tag$': tags.split(',')
}
} }
}
if (tags) { if (tags) {
where['$tags.tag$'] = tags.split(',') where['$tags.tag$'] = tags.split(',')
} }
if (places) {
where.placeId = places.split(',')
}
if (places) {
where.placeId = places.split(',')
} }
if (!show_recurrent) { if (!show_recurrent) {
where.parentId = null where.parentId = null
} }
const events = await Event.findAll({ let events = []
order: ['start_datetime'],
attributes: { exclude: ['is_visible', 'recurrent', 'createdAt', 'likes', 'boost', 'userId', 'placeId'] }, if (collection) {
where: { events = await collectionController._getEvents(collection)
is_visible: true, console.error(events.map(e => e))
recurrent: null, } else {
start_datetime: { [Op.gte]: yesterday }, events = await Event.findAll({
...where order: ['start_datetime'],
}, attributes: { exclude: ['is_visible', 'recurrent', 'createdAt', 'likes', 'boost', 'userId', 'placeId'] },
include: [ where: {
{ is_visible: true,
model: Tag, recurrent: null,
order: [literal('(SELECT COUNT("tagTag") FROM event_tags WHERE tagTag = tag) DESC')], start_datetime: { [Op.gte]: yesterday },
attributes: ['tag'], ...where
required: !!tags,
through: { attributes: [] }
}, },
{ model: Place, attributes: ['name', 'id', 'address'] }] include: [
}) {
model: Tag,
order: [literal('(SELECT COUNT("tagTag") FROM event_tags WHERE tagTag = tag) DESC')],
attributes: ['tag'],
required: !!tags,
through: { attributes: [] }
},
{ model: Place, attributes: ['name', 'id', 'address'] }]
})
}
switch (format) { switch (format) {
case 'rss': case 'rss':
@ -109,11 +121,11 @@ const exportController = {
endInputType: 'utc', endInputType: 'utc',
title: `[${settings.title}] ${e.title}`, title: `[${settings.title}] ${e.title}`,
description: htmlToText(e.description), description: htmlToText(e.description),
htmlContent: e.description.replace(/\n/g,"<br>"), htmlContent: e.description && e.description.replace(/\n/g,"<br>"),
location, location,
url: `${settings.baseurl}/event/${e.slug || e.id}`, url: `${settings.baseurl}/event/${e.slug || e.id}`,
status: 'CONFIRMED', status: 'CONFIRMED',
categories: e.tags.map(t => t.tag), categories: e.tags.map(t => t.tag || t),
alarms alarms
} }

View file

@ -4,6 +4,7 @@ const log = require('../../log')
const config = require('../../config') const config = require('../../config')
const settingsController = require('./settings') const settingsController = require('./settings')
const notifier = require('../../notifier') const notifier = require('../../notifier')
const db = require('../models/index.js')
const pluginController = { const pluginController = {
plugins: [], plugins: [],
@ -32,6 +33,22 @@ const pluginController = {
res.json() res.json()
}, },
async routeAPI (req, res, next) {
const pluginName = req.params.plugin
const plugin = pluginController.plugins.find(p => p.configuration.name === pluginName)
if (!plugin) {
log.warn(`Plugin ${pluginName} not found`)
return res.sendStatus(404)
}
if (typeof plugin.routeAPI !== 'function') {
log.warn(`Plugin ${pluginName} does not expose a 'routeAPI' function`)
return res.sendStatus(404)
}
return plugin.routeAPI(req, res, next)
},
async testPlugin (req, res) { async testPlugin (req, res) {
const pluginName = req.params.plugin const pluginName = req.params.plugin
const plugin = pluginController.plugins.find(p => p.configuration.name === pluginName) const plugin = pluginController.plugins.find(p => p.configuration.name === pluginName)
@ -39,7 +56,7 @@ const pluginController = {
log.warn(`Plugin ${pluginName} not found`) log.warn(`Plugin ${pluginName} not found`)
return res.sendStatus(404) return res.sendStatus(404)
} }
if (typeof plugin.onTest !== 'function') { if (typeof plugin.onTest !== 'function') {
log.warn(`Plugin ${pluginName} does not expose an 'onTest' function`) log.warn(`Plugin ${pluginName} does not expose an 'onTest' function`)
return res.sendStatus(404) return res.sendStatus(404)
@ -69,7 +86,7 @@ const pluginController = {
} }
if (plugin.unload && typeof plugin.unload === 'function') { if (plugin.unload && typeof plugin.unload === 'function') {
plugin.unload({ settings: settingsController.settings }, settings) plugin.unload()
} }
}, },
@ -96,7 +113,8 @@ const pluginController = {
plugin.load({ plugin.load({
helpers: require('../../helpers'), helpers: require('../../helpers'),
log, log,
settings: settingsController.settings settings: settingsController.settings,
db: db.sequelize
}, },
settings) settings)
} }
@ -116,13 +134,15 @@ const pluginController = {
const pluginSetting = settingsController.settings['plugin_' + name] const pluginSetting = settingsController.settings['plugin_' + name]
if (pluginSetting.enable) { if (pluginSetting.enable) {
pluginController.loadPlugin(name) pluginController.loadPlugin(name)
} else {
log.info(`Do not load plugin ${name} (${pluginFile}) as it is not enabled!`)
} }
} else { } else {
settingsController.set('plugin_' + name, { enable: false }) settingsController.set('plugin_' + name, { enable: false })
} }
} catch (e) { } catch (e) {
log.warn(`Unable to load plugin ${pluginFile}: ${String(e)}`) log.warn(`Unable to load plugin ${pluginFile}: ${String(e)}`)
} }
}, },
_load() { _load() {

View file

@ -11,7 +11,7 @@ const userController = {
async forgotPassword (req, res) { async forgotPassword (req, res) {
const email = req.body.email const email = req.body.email
const user = await User.findOne({ where: { email: { [Op.eq]: email } } }) const user = await User.findOne({ where: { email, is_active: true } })
if (!user) { return res.sendStatus(200) } if (!user) { return res.sendStatus(200) }
user.recover_code = crypto.randomBytes(16).toString('hex') user.recover_code = crypto.randomBytes(16).toString('hex')
@ -62,13 +62,9 @@ const userController = {
if (!user) { return res.status(404).json({ success: false, message: 'User not found!' }) } if (!user) { return res.status(404).json({ success: false, message: 'User not found!' }) }
if (req.body.id !== req.user.id && !req.user.is_admin) {
return res.status(400).json({ succes: false, message: 'Not allowed' })
}
if (!req.body.password) { delete req.body.password } if (!req.body.password) { delete req.body.password }
if (!user.is_active && req.body.is_active && user.recover_code) { if ((!user.is_active && req.body.is_active) || user.recover_code) {
mail.send(user.email, 'confirm', { user, config }, res.locals.settings.locale) mail.send(user.email, 'confirm', { user, config }, res.locals.settings.locale)
} }
@ -89,6 +85,7 @@ const userController = {
} }
req.body.is_active = false req.body.is_active = false
req.body.is_admin = false
// check email // check email
if (!linkify.test(req.body.email, 'email')) { if (!linkify.test(req.body.email, 'email')) {

View file

@ -70,6 +70,7 @@ module.exports = () => {
``` ```
*/ */
api.get('/ping', (_req, res) => res.sendStatus(200)) api.get('/ping', (_req, res) => res.sendStatus(200))
api.get('/reachable', helpers.reachable)
api.get('/user', isAuth, (req, res) => res.json(req.user)) api.get('/user', isAuth, (req, res) => res.json(req.user))
api.post('/user/recover', SPAMProtectionApiRateLimiter, userController.forgotPassword) api.post('/user/recover', SPAMProtectionApiRateLimiter, userController.forgotPassword)
@ -81,7 +82,7 @@ module.exports = () => {
api.post('/user', isAdmin, userController.create) api.post('/user', isAdmin, userController.create)
// update user // update user
api.put('/user', isAuth, userController.update) api.put('/user', isAdmin, userController.update)
// delete user // delete user
api.delete('/user/:id', isAdmin, userController.remove) api.delete('/user/:id', isAdmin, userController.remove)
@ -145,7 +146,7 @@ module.exports = () => {
// remove event // remove event
api.delete('/event/:id', isAuth, eventController.remove) api.delete('/event/:id', isAuth, eventController.remove)
// get tags/places // get tags/places/collection
api.get('/event/meta', eventController.searchMeta) api.get('/event/meta', eventController.searchMeta)
// add event notification TODO // add event notification TODO
@ -223,6 +224,8 @@ module.exports = () => {
api.post('/plugin/test/:plugin', isAdmin, pluginController.testPlugin) api.post('/plugin/test/:plugin', isAdmin, pluginController.testPlugin)
api.put('/plugin/:plugin', isAdmin, pluginController.togglePlugin) api.put('/plugin/:plugin', isAdmin, pluginController.togglePlugin)
api.use('/plugin/:plugin', pluginController.routeAPI)
// OAUTH // OAUTH
api.get('/clients', isAuth, oauthController.getClients) api.get('/clients', isAuth, oauthController.getClients)
api.get('/client/:client_id', isAuth, oauthController.getClient) api.get('/client/:client_id', isAuth, oauthController.getClient)

View file

@ -21,11 +21,11 @@ const instanceApiRateLimiter = {
* (used during the registration, pass recovery, posting events) */ * (used during the registration, pass recovery, posting events) */
SPAMProtectionApiRateLimiter: (process.env.NODE_ENV === 'test' ? next : rateLimit({ SPAMProtectionApiRateLimiter: (process.env.NODE_ENV === 'test' ? next : rateLimit({
windowMs: 5 * 60 * 1000, // 5 minutes windowMs: 5 * 60 * 1000, // 5 minutes
max: 3, // Limit each IP to 3 requests per `window` (here, per 5 minutes) max: 6, // Limit each IP to 3 requests per `window` (here, per 5 minutes)
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
legacyHeaders: false, // Disable the `X-RateLimit-*` headers legacyHeaders: false, // Disable the `X-RateLimit-*` headers
handler: (request, response, next, options) => { handler: (request, response, next, options) => {
log.warn(`SPAM protection api rate limiter: 3req/5min/ip ${request.ip}`) log.warn(`SPAM protection api rate limiter: 6req/5min/ip ${request.ip}`)
return response.status(options.statusCode).send(options.message) return response.status(options.statusCode).send(options.message)
} }
})) }))

View file

@ -37,7 +37,7 @@ const mail = {
} }
}, },
message: { message: {
from: `📅 ${settings.title} <${settings.admin_email}>` from: `"📅 ${settings.title}" <${settings.admin_email}>`
}, },
send: true, send: true,
i18n: { i18n: {
@ -49,7 +49,7 @@ const mail = {
locale, locale,
locales: Object.keys(locales) locales: Object.keys(locales)
}, },
transport: settings.smtp || {} transport: { ...settings.smtp, tls: { ciphers: 'SSLv3'}, requireTLS: true } || {}
}) })
const opt = { const opt = {

View file

@ -72,6 +72,7 @@ module.exports = (sequelize, DataTypes) => {
startTime: DateTime.fromSeconds(this.start_datetime, opt).toISO(), startTime: DateTime.fromSeconds(this.start_datetime, opt).toISO(),
...( this.end_datetime ? { endTime : DateTime.fromSeconds(this.end_datetime, opt).toISO() } : {} ), ...( this.end_datetime ? { endTime : DateTime.fromSeconds(this.end_datetime, opt).toISO() } : {} ),
location: { location: {
type: 'Place',
name: this.place.name, name: this.place.name,
address: this.place.address, address: this.place.address,
latitude: this.place.latitude, latitude: this.place.latitude,

View file

@ -6,7 +6,7 @@ const config = require('../../config')
const log = require('../../log') const log = require('../../log')
const SequelizeSlugify = require('sequelize-slugify') const SequelizeSlugify = require('sequelize-slugify')
const DB = require('./models') const DB = require('./models')
const semver = require('semver')
const models = { const models = {
Announcement: require('./announcement'), Announcement: require('./announcement'),
APUser: require('./ap_user'), APUser: require('./ap_user'),
@ -107,8 +107,39 @@ const db = {
return true return true
} }
}, },
async fixMariaDBJSON () {
// manually fix mariadb JSON wrong parse
if (db.sequelize.options.dialect === 'mariadb' && semver.lt('10.5.2', db.sequelize.options.databaseVersion)) {
try {
const ret = await db.sequelize.query('SHOW CREATE TABLE `settings`')
if (!ret[0][0]['Create Table'].toLowerCase().includes('json_valid')){
await db.sequelize.query('alter table settings modify `value` JSON')
await db.sequelize.query('alter table ap_users modify `object` JSON')
await db.sequelize.query('alter table events modify `recurrent` JSON')
await db.sequelize.query('alter table events modify `likes` JSON')
await db.sequelize.query('alter table events modify `boost` JSON')
await db.sequelize.query('alter table events modify `media` JSON')
await db.sequelize.query('alter table events modify `online_locations` JSON')
await db.sequelize.query('alter table filters modify `tags` JSON')
await db.sequelize.query('alter table filters modify `places` JSON')
await db.sequelize.query('alter table instances modify `data` JSON')
await db.sequelize.query('alter table notifications modify `filters` JSON')
await db.sequelize.query('alter table resources modify `data` JSON')
await db.sequelize.query('alter table users modify `settings` JSON')
await db.sequelize.query('alter table users modify `rsa` JSON')
log.info(`MariaDB JSON migrations done`)
} else {
log.debug('MariaDB JSON issue already fixed')
}
} catch (e) {
console.error(e)
}
}
},
async runMigrations() { async runMigrations() {
const logging = config.status !== 'READY' ? false : log.debug.bind(log) const logging = config.status !== 'READY' ? false : log.debug.bind(log)
const umzug = new Umzug({ const umzug = new Umzug({
storage: 'sequelize', storage: 'sequelize',
storageOptions: { sequelize: db.sequelize }, storageOptions: { sequelize: db.sequelize },

View file

@ -1,7 +1,7 @@
#!/usr/bin/env node #!/usr/bin/env node
const pkg = require('../package.json') const pkg = require('../package.json')
const path = require('path') const path = require('path')
const accountsCLI = require('./cli/accounts') const usersCLI = require('./cli/users')
process.env.cwd = process.env.GANCIO_DATA || path.resolve('./') process.env.cwd = process.env.GANCIO_DATA || path.resolve('./')
@ -29,7 +29,7 @@ require('yargs')
return absolute_config_path return absolute_config_path
}}) }})
.command(['start', 'run', '$0'], 'Start gancio', {}, start) .command(['start', 'run', '$0'], 'Start gancio', {}, start)
.command(['accounts'], 'Manage accounts', accountsCLI) .command(['users'], 'Manage users', usersCLI)
.help('h') .help('h')
.alias('h', 'help') .alias('h', 'help')
.epilog('Made with ❤ by underscore hacklab - https://gancio.org') .epilog('Made with ❤ by underscore hacklab - https://gancio.org')

View file

@ -1,92 +0,0 @@
let db
function _initializeDB () {
const config = require('../config')
config.log_level = 'error'
db = require('../api/models/index')
return db.initialize()
}
async function modify (args) {
await _initializeDB()
const helpers = require('../helpers')
const { User } = require('../api/models/models')
const user = await User.findOne({ where: { email: args.account } })
console.log()
if (!user) {
console.error(`User ${args.account} not found`)
return
}
if (args['reset-password']) {
const password = helpers.randomString()
user.password = password
await user.save()
console.log(`New password for user ${user.email} is '${password}'`)
}
if (args.admin) {
user.is_admin = true
await user.save()
}
await db.close()
}
async function create (args) {
await _initializeDB()
const { User } = require('../api/models/models')
const user = await User.create({
email: args.email,
is_active: true,
is_admin: args.admin || false
}).catch(e => console.error(String(e)))
console.error(JSON.stringify(user, null, 2))
await db.close()
}
async function remove (args) {
await _initializeDB()
const { User } = require('../api/models/models')
const user = await User.findOne({
where: { email: args.email }
})
if (user) {
await user.destroy()
}
await db.close()
}
async function list () {
await _initializeDB()
const { User } = require('../api/models/models')
const users = await User.findAll()
console.log()
users.forEach(u => console.log(`${u.id}\tadmin: ${u.is_admin}\tenabled: ${u.is_active}\temail: ${u.email}`))
console.log()
await db.close()
}
const accountsCLI = yargs => yargs
.command('list', 'List all accounts', list)
.command('modify', 'Modify', {
account: {
describe: 'Account to modify',
type: 'string',
demandOption: true
},
'reset-password': {
describe: 'Resets the password of the given account ',
type: 'boolean'
},
admin: { describe: 'Define this account as administrator', type: 'boolean' }
}, modify)
.command('create <email|username> [admin]', 'Create an account', {
admin: { describe: 'Define this account as administrator', type: 'boolean' }
}, create)
.command('remove <email|username>', 'Remove an account', {}, remove)
.positional('email', { describe: 'account email or username', type: 'string', demandOption: true })
.recommendCommands()
.demandCommand(1, '')
.argv
module.exports = accountsCLI

124
server/cli/users.js Normal file
View file

@ -0,0 +1,124 @@
let db
function _initializeDB () {
const config = require('../config')
if (config.status !== 'CONFIGURED') {
console.error(`> Cannot run CLI before setup (are you in the correct path?)`)
process.exit(1)
}
config.log_level = 'error'
db = require('../api/models/index')
return db.initialize()
}
async function setAdmin (args) {
await _initializeDB()
const { User } = require('../api/models/models')
const user = await User.findOne({ where: { email: args.email } })
console.log()
if (!user) {
console.error(`User ${args.email} not found`)
return
}
user.is_admin = true
await user.save()
console.log(`User ${user.email} is now an administrator!`)
await db.close()
}
async function unsetAdmin (args) {
await _initializeDB()
const helpers = require('../helpers')
const { User } = require('../api/models/models')
const user = await User.findOne({ where: { email: args.email } })
console.log()
if (!user) {
console.error(`User ${args.email} not found`)
return
}
user.is_admin = false
await user.save()
console.log(`User ${user.email} is not an administrator anymore!`)
await db.close()
}
async function resetPassword (args) {
await _initializeDB()
const helpers = require('../helpers')
const { User } = require('../api/models/models')
const user = await User.findOne({ where: { email: args.email } })
console.log()
if (!user) {
console.error(`User ${args.email} not found`)
return
}
const password = helpers.randomString()
user.password = password
await user.save()
console.log(`New password for user ${user.email} is '${password}'`)
await db.close()
}
async function create (args) {
await _initializeDB()
const { User } = require('../api/models/models')
try {
const user = await User.create({
email: args.email,
password: args.password,
is_active: true,
is_admin: args.admin || false
})
console.error(`User ${args.email} created`)
} catch(e) {
console.error(String(e))
}
await db.close()
}
async function remove (args) {
await _initializeDB()
const { User } = require('../api/models/models')
const user = await User.findOne({
where: { email: args.email }
})
if (user) {
await user.destroy()
console.error(`User "${args.email}" succesfully removed`)
} else {
console.error(`User "${args.email}" not found!`)
}
await db.close()
}
async function list () {
await _initializeDB()
const { User } = require('../api/models/models')
const users = await User.findAll()
console.log()
users.forEach(u => console.log(`${u.id}\tadmin: ${u.is_admin}\tenabled: ${u.is_active}\temail: ${u.email}`))
console.log()
await db.close()
}
const usersCLI = yargs => yargs
.command('list', 'List all users', list)
.command('reset-password <email|username>', 'Resets the password of the given user', {
}, resetPassword)
.command('set-admin <email|username>', 'Set administrator privileges to the given user', {}, setAdmin)
.command('unset-admin <email|username>', 'Remove administrator privileges to the given user', {}, unsetAdmin)
.command('create <email|username> [password] [admin]', 'Create an user', {
admin: { describe: 'Define this user as administrator', type: 'boolean' },
}, create)
.command('remove <email|username>', 'Remove an user', {}, remove)
.positional('email', { describe: 'user email or username', type: 'string', demandOption: true })
.positional('password', { describe: 'Password', type: 'string', demandOption: false })
.recommendCommands()
.demandCommand(1, '')
.argv
module.exports = usersCLI

View file

@ -44,7 +44,7 @@ let config = {
} }
} else { } else {
config.status = 'SETUP' config.status = 'SETUP'
console.info('> Configuration file does not exists, running setup..') console.info('> Configuration file does not exists...')
} }
} }
} }

View file

@ -36,7 +36,14 @@ router.get('/m/:event_id', async (req, res) => {
if (!event) { return res.status(404).send('Not found') } if (!event) { return res.status(404).send('Not found') }
const eventAp = event.toAP(settingsController.settings) const eventAp = event.toAP(settingsController.settings)
eventAp['@context'] = [ eventAp['@context'] = [
"https://www.w3.org/ns/activitystreams" "https://www.w3.org/ns/activitystreams",
{
"sc": "http://schema.org/",
"address": {
"@id": "sc:address",
"@type": "sc:Text"
}
}
] ]
res.type('application/activity+json; charset=utf-8') res.type('application/activity+json; charset=utf-8')

View file

@ -258,8 +258,8 @@ module.exports = {
} }
} else { } else {
cursor = date.startOf('month') cursor = date.startOf('month')
cursor = cursor.add(cursor.day() <= date.day() ? n - 1 : n, 'week') // cursor = cursor.add(cursor.day <= date.day ? n - 1 : n, 'week')
cursor = cursor.plus({ days: cursor.weekday <= date.weekday ? (n-1) * 7 : n * 7}) cursor = cursor.plus({ weeks: cursor.weekday <= weekday ? n-1 : n })
cursor = cursor.set({ weekday }) cursor = cursor.set({ weekday })
} }
cursor = cursor.set({ hour: date.hour, minute: date.minute, second: 0 }) cursor = cursor.set({ hour: date.hour, minute: date.minute, second: 0 })
@ -287,11 +287,26 @@ module.exports = {
next() next()
}, },
async reachable(req, res) {
try {
const response = await axios({ url: config.baseurl })
return res.sendStatus(200)
} catch(e) {
return res.status(400).json(e)
}
},
async isGeocodingEnabled(req, res, next) { async isGeocodingEnabled(req, res, next) {
if (res.locals.settings.allow_geolocation) { if (res.locals.settings.allow_geolocation) {
next() next()
} else { } else {
res.sendStatus(403) res.sendStatus(403)
} }
},
queryParamToBool (value, defaultValue) {
if (typeof value === 'undefined') return defaultValue
return (String(value).toLowerCase() === 'true')
} }
} }

View file

@ -30,6 +30,7 @@ const initialize = {
await db.sequelize.authenticate() await db.sequelize.authenticate()
log.debug('Running migrations') log.debug('Running migrations')
await db.runMigrations() await db.runMigrations()
await db.fixMariaDBJSON()
await settingsController.load() await settingsController.load()
config.status = 'READY' config.status = 'READY'
} else { } else {

View file

@ -25,10 +25,10 @@ function ye(t) {
function u(t, e) { function u(t, e) {
t.appendChild(e); t.appendChild(e);
} }
function p(t, e, i) { function k(t, e, i) {
t.insertBefore(e, i || null); t.insertBefore(e, i || null);
} }
function k(t) { function x(t) {
t.parentNode.removeChild(t); t.parentNode.removeChild(t);
} }
function be(t, e) { function be(t, e) {
@ -38,14 +38,14 @@ function be(t, e) {
function m(t) { function m(t) {
return document.createElement(t); return document.createElement(t);
} }
function $(t) { function z(t) {
return document.createTextNode(t); return document.createTextNode(t);
} }
function M() { function C() {
return $(" "); return z(" ");
} }
function pe() { function pe() {
return $(""); return z("");
} }
function a(t, e, i) { function a(t, e, i) {
i == null ? t.removeAttribute(e) : t.getAttribute(e) !== i && t.setAttribute(e, i); i == null ? t.removeAttribute(e) : t.getAttribute(e) !== i && t.setAttribute(e, i);
@ -69,25 +69,25 @@ let O;
function I(t) { function I(t) {
O = t; O = t;
} }
function $e() { function Ee() {
if (!O) if (!O)
throw new Error("Function called outside component initialization"); throw new Error("Function called outside component initialization");
return O; return O;
} }
function ke(t) { function ke(t) {
$e().$$.on_mount.push(t); Ee().$$.on_mount.push(t);
} }
const R = [], Z = [], P = [], ee = [], Ee = Promise.resolve(); const R = [], Z = [], P = [], ee = [], $e = Promise.resolve();
let K = !1; let K = !1;
function je() { function je() {
K || (K = !0, Ee.then(x)); K || (K = !0, $e.then(y));
} }
function Q(t) { function Q(t) {
P.push(t); P.push(t);
} }
const J = /* @__PURE__ */ new Set(); const J = /* @__PURE__ */ new Set();
let D = 0; let D = 0;
function x() { function y() {
const t = O; const t = O;
do { do {
for (; D < R.length; ) { for (; D < R.length; ) {
@ -120,8 +120,8 @@ function Ce(t, e) {
function Ae(t, e, i, l) { function Ae(t, e, i, l) {
const { fragment: n, on_mount: r, on_destroy: o, after_update: f } = t.$$; const { fragment: n, on_mount: r, on_destroy: o, after_update: f } = t.$$;
n && n.m(e, i), l || Q(() => { n && n.m(e, i), l || Q(() => {
const c = r.map(W).filter(ge); const s = r.map(W).filter(ge);
o ? o.push(...c) : U(c), t.$$.on_mount = []; o ? o.push(...s) : U(s), t.$$.on_mount = [];
}), f.forEach(Q); }), f.forEach(Q);
} }
function Me(t, e) { function Me(t, e) {
@ -132,9 +132,9 @@ function Ne(t, e) {
t.$$.dirty[0] === -1 && (R.push(t), je(), t.$$.dirty.fill(0)), t.$$.dirty[e / 31 | 0] |= 1 << e % 31; t.$$.dirty[0] === -1 && (R.push(t), je(), t.$$.dirty.fill(0)), t.$$.dirty[e / 31 | 0] |= 1 << e % 31;
} }
function we(t, e, i, l, n, r, o, f = [-1]) { function we(t, e, i, l, n, r, o, f = [-1]) {
const c = O; const s = O;
I(t); I(t);
const s = t.$$ = { const c = t.$$ = {
fragment: null, fragment: null,
ctx: null, ctx: null,
props: r, props: r,
@ -146,26 +146,26 @@ function we(t, e, i, l, n, r, o, f = [-1]) {
on_disconnect: [], on_disconnect: [],
before_update: [], before_update: [],
after_update: [], after_update: [],
context: new Map(e.context || (c ? c.$$.context : [])), context: new Map(e.context || (s ? s.$$.context : [])),
callbacks: Y(), callbacks: Y(),
dirty: f, dirty: f,
skip_bound: !1, skip_bound: !1,
root: e.target || c.$$.root root: e.target || s.$$.root
}; };
o && o(s.root); o && o(c.root);
let w = !1; let w = !1;
if (s.ctx = i ? i(t, e.props || {}, (g, _, ...A) => { if (c.ctx = i ? i(t, e.props || {}, (g, _, ...A) => {
const y = A.length ? A[0] : _; const E = A.length ? A[0] : _;
return s.ctx && n(s.ctx[g], s.ctx[g] = y) && (!s.skip_bound && s.bound[g] && s.bound[g](y), w && Ne(t, g)), _; return c.ctx && n(c.ctx[g], c.ctx[g] = E) && (!c.skip_bound && c.bound[g] && c.bound[g](E), w && Ne(t, g)), _;
}) : [], s.update(), w = !0, U(s.before_update), s.fragment = l ? l(s.ctx) : !1, e.target) { }) : [], c.update(), w = !0, U(c.before_update), c.fragment = l ? l(c.ctx) : !1, e.target) {
if (e.hydrate) { if (e.hydrate) {
const g = xe(e.target); const g = xe(e.target);
s.fragment && s.fragment.l(g), g.forEach(k); c.fragment && c.fragment.l(g), g.forEach(x);
} else } else
s.fragment && s.fragment.c(); c.fragment && c.fragment.c();
e.intro && Ce(t.$$.fragment), Ae(t, e.target, e.anchor, e.customElement), x(); e.intro && Ce(t.$$.fragment), Ae(t, e.target, e.anchor, e.customElement), y();
} }
I(c); I(s);
} }
let X; let X;
typeof HTMLElement == "function" && (X = class extends HTMLElement { typeof HTMLElement == "function" && (X = class extends HTMLElement {
@ -213,11 +213,11 @@ function V(t) {
} }
function te(t, e, i) { function te(t, e, i) {
const l = t.slice(); const l = t.slice();
return l[12] = e[i], l; return l[13] = e[i], l;
} }
function ie(t, e, i) { function ie(t, e, i) {
const l = t.slice(); const l = t.slice();
return l[15] = e[i], l; return l[16] = e[i], l;
} }
function le(t) { function le(t) {
let e; let e;
@ -226,13 +226,13 @@ function le(t) {
e = m("link"), a(e, "rel", "stylesheet"), a(e, "href", t[4]); e = m("link"), a(e, "rel", "stylesheet"), a(e, "href", t[4]);
}, },
m(i, l) { m(i, l) {
p(i, e, l); k(i, e, l);
}, },
p(i, l) { p(i, l) {
l & 16 && a(e, "href", i[4]); l & 16 && a(e, "href", i[4]);
}, },
d(i) { d(i) {
i && k(e); i && x(e);
} }
}; };
} }
@ -242,32 +242,32 @@ function ne(t) {
r[o] = fe(te(t, n, o)); r[o] = fe(te(t, n, o));
return { return {
c() { c() {
e = m("div"), l && l.c(), i = M(); e = m("div"), l && l.c(), i = C();
for (let o = 0; o < r.length; o += 1) for (let o = 0; o < r.length; o += 1)
r[o].c(); r[o].c();
a(e, "id", "gancioEvents"), L(e, "dark", t[2] === "dark"), L(e, "light", t[2] === "light"), L(e, "sidebar", t[3] === "true"), L(e, "nosidebar", t[3] !== "true"); a(e, "id", "gancioEvents"), L(e, "dark", t[2] === "dark"), L(e, "light", t[2] === "light"), L(e, "sidebar", t[3] === "true"), L(e, "nosidebar", t[3] !== "true");
}, },
m(o, f) { m(o, f) {
p(o, e, f), l && l.m(e, null), u(e, i); k(o, e, f), l && l.m(e, null), u(e, i);
for (let c = 0; c < r.length; c += 1) for (let s = 0; s < r.length; s += 1)
r[c].m(e, null); r[s].m(e, null);
}, },
p(o, f) { p(o, f) {
if (o[1] && o[3] === "true" ? l ? l.p(o, f) : (l = re(o), l.c(), l.m(e, i)) : l && (l.d(1), l = null), f & 41) { if (o[1] && o[3] === "true" ? l ? l.p(o, f) : (l = re(o), l.c(), l.m(e, i)) : l && (l.d(1), l = null), f & 41) {
n = o[5]; n = o[5];
let c; let s;
for (c = 0; c < n.length; c += 1) { for (s = 0; s < n.length; s += 1) {
const s = te(o, n, c); const c = te(o, n, s);
r[c] ? r[c].p(s, f) : (r[c] = fe(s), r[c].c(), r[c].m(e, null)); r[s] ? r[s].p(c, f) : (r[s] = fe(c), r[s].c(), r[s].m(e, null));
} }
for (; c < r.length; c += 1) for (; s < r.length; s += 1)
r[c].d(1); r[s].d(1);
r.length = n.length; r.length = n.length;
} }
f & 4 && L(e, "dark", o[2] === "dark"), f & 4 && L(e, "light", o[2] === "light"), f & 8 && L(e, "sidebar", o[3] === "true"), f & 8 && L(e, "nosidebar", o[3] !== "true"); f & 4 && L(e, "dark", o[2] === "dark"), f & 4 && L(e, "light", o[2] === "light"), f & 8 && L(e, "sidebar", o[3] === "true"), f & 8 && L(e, "nosidebar", o[3] !== "true");
}, },
d(o) { d(o) {
o && k(e), l && l.d(), be(r, o); o && x(e), l && l.d(), be(r, o);
} }
}; };
} }
@ -275,23 +275,23 @@ function re(t) {
let e, i, l, n, r, o, f; let e, i, l, n, r, o, f;
return { return {
c() { c() {
e = m("a"), i = m("div"), l = m("div"), n = $(t[1]), r = M(), o = m("img"), a(l, "class", "title"), a(o, "id", "logo"), a(o, "alt", "logo"), H(o.src, f = t[0] + "/logo.png") || a(o, "src", f), a(i, "class", "content"), a(e, "href", t[0]), a(e, "target", "_blank"), a(e, "id", "header"); e = m("a"), i = m("div"), l = m("div"), n = z(t[1]), r = C(), o = m("img"), a(l, "class", "title"), a(o, "id", "logo"), a(o, "alt", "logo"), H(o.src, f = t[0] + "/logo.png") || a(o, "src", f), a(i, "class", "content"), a(e, "href", t[0]), a(e, "target", "_blank"), a(e, "id", "header");
}, },
m(c, s) { m(s, c) {
p(c, e, s), u(e, i), u(i, l), u(l, n), u(i, r), u(i, o); k(s, e, c), u(e, i), u(i, l), u(l, n), u(i, r), u(i, o);
}, },
p(c, s) { p(s, c) {
s & 2 && T(n, c[1]), s & 1 && !H(o.src, f = c[0] + "/logo.png") && a(o, "src", f), s & 1 && a(e, "href", c[0]); c & 2 && T(n, s[1]), c & 1 && !H(o.src, f = s[0] + "/logo.png") && a(o, "src", f), c & 1 && a(e, "href", s[0]);
}, },
d(c) { d(s) {
c && k(e); s && x(e);
} }
}; };
} }
function oe(t) { function oe(t) {
let e; let e;
function i(r, o) { function i(r, o) {
return r[12].media.length ? Le : Te; return r[13].media.length ? Le : Te;
} }
let l = i(t), n = l(t); let l = i(t), n = l(t);
return { return {
@ -299,13 +299,13 @@ function oe(t) {
e = m("div"), n.c(), a(e, "class", "img"); e = m("div"), n.c(), a(e, "class", "img");
}, },
m(r, o) { m(r, o) {
p(r, e, o), n.m(e, null); k(r, e, o), n.m(e, null);
}, },
p(r, o) { p(r, o) {
l === (l = i(r)) && n ? n.p(r, o) : (n.d(1), n = l(r), n && (n.c(), n.m(e, null))); l === (l = i(r)) && n ? n.p(r, o) : (n.d(1), n = l(r), n && (n.c(), n.m(e, null)));
}, },
d(r) { d(r) {
r && k(e), n.d(); r && x(e), n.d();
} }
}; };
} }
@ -313,16 +313,16 @@ function Te(t) {
let e, i, l; let e, i, l;
return { return {
c() { c() {
e = m("img"), a(e, "style", "aspect-ratio=1.7778;"), a(e, "alt", i = t[12].title), H(e.src, l = t[0] + "/fallbackimage.png") || a(e, "src", l), a(e, "loading", "lazy"); e = m("img"), a(e, "style", "aspect-ratio=1.7778;"), a(e, "alt", i = t[13].title), H(e.src, l = t[0] + "/fallbackimage.png") || a(e, "src", l), a(e, "loading", "lazy");
}, },
m(n, r) { m(n, r) {
p(n, e, r); k(n, e, r);
}, },
p(n, r) { p(n, r) {
r & 32 && i !== (i = n[12].title) && a(e, "alt", i), r & 1 && !H(e.src, l = n[0] + "/fallbackimage.png") && a(e, "src", l); r & 32 && i !== (i = n[13].title) && a(e, "alt", i), r & 1 && !H(e.src, l = n[0] + "/fallbackimage.png") && a(e, "src", l);
}, },
d(n) { d(n) {
n && k(e); n && x(e);
} }
}; };
} }
@ -330,38 +330,38 @@ function Le(t) {
let e, i, l, n; let e, i, l, n;
return { return {
c() { c() {
e = m("img"), a(e, "style", i = "object-position: " + ue(t[12]) + "; aspect-ratio=1.7778;"), a(e, "alt", l = t[12].media[0].name), H(e.src, n = t[0] + "/media/thumb/" + t[12].media[0].url) || a(e, "src", n), a(e, "loading", "lazy"); e = m("img"), a(e, "style", i = "object-position: " + ue(t[13]) + "; aspect-ratio=1.7778;"), a(e, "alt", l = t[13].media[0].name), H(e.src, n = t[0] + "/media/thumb/" + t[13].media[0].url) || a(e, "src", n), a(e, "loading", "lazy");
}, },
m(r, o) { m(r, o) {
p(r, e, o); k(r, e, o);
}, },
p(r, o) { p(r, o) {
o & 32 && i !== (i = "object-position: " + ue(r[12]) + "; aspect-ratio=1.7778;") && a(e, "style", i), o & 32 && l !== (l = r[12].media[0].name) && a(e, "alt", l), o & 33 && !H(e.src, n = r[0] + "/media/thumb/" + r[12].media[0].url) && a(e, "src", n); o & 32 && i !== (i = "object-position: " + ue(r[13]) + "; aspect-ratio=1.7778;") && a(e, "style", i), o & 32 && l !== (l = r[13].media[0].name) && a(e, "alt", l), o & 33 && !H(e.src, n = r[0] + "/media/thumb/" + r[13].media[0].url) && a(e, "src", n);
}, },
d(r) { d(r) {
r && k(e); r && x(e);
} }
}; };
} }
function ae(t) { function ae(t) {
let e, i = t[12].place.address + "", l; let e, i = t[13].place.address + "", l;
return { return {
c() { c() {
e = m("span"), l = $(i), a(e, "class", "subtitle"); e = m("span"), l = z(i), a(e, "class", "subtitle");
}, },
m(n, r) { m(n, r) {
p(n, e, r), u(e, l); k(n, e, r), u(e, l);
}, },
p(n, r) { p(n, r) {
r & 32 && i !== (i = n[12].place.address + "") && T(l, i); r & 32 && i !== (i = n[13].place.address + "") && T(l, i);
}, },
d(n) { d(n) {
n && k(e); n && x(e);
} }
}; };
} }
function se(t) { function se(t) {
let e, i = t[12].tags, l = []; let e, i = t[13].tags, l = [];
for (let n = 0; n < i.length; n += 1) for (let n = 0; n < i.length; n += 1)
l[n] = ce(ie(t, i, n)); l[n] = ce(ie(t, i, n));
return { return {
@ -372,13 +372,13 @@ function se(t) {
a(e, "class", "tags"); a(e, "class", "tags");
}, },
m(n, r) { m(n, r) {
p(n, e, r); k(n, e, r);
for (let o = 0; o < l.length; o += 1) for (let o = 0; o < l.length; o += 1)
l[o].m(e, null); l[o].m(e, null);
}, },
p(n, r) { p(n, r) {
if (r & 32) { if (r & 32) {
i = n[12].tags; i = n[13].tags;
let o; let o;
for (o = 0; o < i.length; o += 1) { for (o = 0; o < i.length; o += 1) {
const f = ie(n, i, o); const f = ie(n, i, o);
@ -390,42 +390,41 @@ function se(t) {
} }
}, },
d(n) { d(n) {
n && k(e), be(l, n); n && x(e), be(l, n);
} }
}; };
} }
function ce(t) { function ce(t) {
let e, i, l = t[15] + "", n; let e, i, l = t[16] + "", n;
return { return {
c() { c() {
e = m("span"), i = $("#"), n = $(l), a(e, "class", "tag"); e = m("span"), i = z("#"), n = z(l), a(e, "class", "tag");
}, },
m(r, o) { m(r, o) {
p(r, e, o), u(e, i), u(e, n); k(r, e, o), u(e, i), u(e, n);
}, },
p(r, o) { p(r, o) {
o & 32 && l !== (l = r[15] + "") && T(n, l); o & 32 && l !== (l = r[16] + "") && T(n, l);
}, },
d(r) { d(r) {
r && k(e); r && x(e);
} }
}; };
} }
function fe(t) { function fe(t) {
let e, i, l, n, r = V(t[12]) + "", o, f, c, s = t[12].title + "", w, g, _, A, y = t[12].place.name + "", d, z, h, v, C, q, E = t[3] !== "true" && oe(t), j = t[12].place.name !== "online" && ae(t), S = t[12].tags.length && se(t); let e, i, l, n, r = V(t[13]) + "", o, f, s, c = t[13].title + "", w, g, _, A, E = t[13].place.name + "", M, d, h, p, v, q, $ = t[3] !== "true" && oe(t), j = t[13].place.name !== "online" && ae(t), S = t[13].tags.length && se(t);
return { return {
c() { c() {
e = m("a"), E && E.c(), i = M(), l = m("div"), n = m("div"), o = $(r), f = M(), c = m("div"), w = $(s), g = M(), _ = m("span"), A = $('@"'), d = $(y), z = $(`" e = m("a"), $ && $.c(), i = C(), l = m("div"), n = m("div"), o = z(r), f = C(), s = m("div"), w = z(c), g = C(), _ = m("span"), A = z("@"), M = z(E), d = C(), j && j.c(), h = C(), S && S.c(), p = C(), a(n, "class", "subtitle"), a(s, "class", "title"), a(_, "class", "place"), a(l, "class", "content"), a(e, "href", v = t[0] + "/event/" + (t[13].slug || t[13].id)), a(e, "class", "event"), a(e, "title", q = t[13].title), a(e, "target", "_blank");
`), j && j.c(), h = M(), S && S.c(), v = M(), a(n, "class", "subtitle"), a(c, "class", "title"), a(_, "class", "place"), a(l, "class", "content"), a(e, "href", C = t[0] + "/event/" + (t[12].slug || t[12].id)), a(e, "class", "event"), a(e, "title", q = t[12].title), a(e, "target", "_blank");
}, },
m(b, N) { m(b, N) {
p(b, e, N), E && E.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, c), u(c, w), u(l, g), u(l, _), u(_, A), u(_, d), u(_, z), j && j.m(_, null), u(l, h), S && S.m(l, null), u(e, v); k(b, e, N), $ && $.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, s), u(s, w), u(l, g), u(l, _), u(_, A), u(_, M), u(_, d), j && j.m(_, null), u(l, h), S && S.m(l, null), u(e, p);
}, },
p(b, N) { p(b, N) {
b[3] !== "true" ? E ? E.p(b, N) : (E = oe(b), E.c(), E.m(e, i)) : E && (E.d(1), E = null), N & 32 && r !== (r = V(b[12]) + "") && T(o, r), N & 32 && s !== (s = b[12].title + "") && T(w, s), N & 32 && y !== (y = b[12].place.name + "") && T(d, y), b[12].place.name !== "online" ? j ? j.p(b, N) : (j = ae(b), j.c(), j.m(_, null)) : j && (j.d(1), j = null), b[12].tags.length ? S ? S.p(b, N) : (S = se(b), S.c(), S.m(l, null)) : S && (S.d(1), S = null), N & 33 && C !== (C = b[0] + "/event/" + (b[12].slug || b[12].id)) && a(e, "href", C), N & 32 && q !== (q = b[12].title) && a(e, "title", q); b[3] !== "true" ? $ ? $.p(b, N) : ($ = oe(b), $.c(), $.m(e, i)) : $ && ($.d(1), $ = null), N & 32 && r !== (r = V(b[13]) + "") && T(o, r), N & 32 && c !== (c = b[13].title + "") && T(w, c), N & 32 && E !== (E = b[13].place.name + "") && T(M, E), b[13].place.name !== "online" ? j ? j.p(b, N) : (j = ae(b), j.c(), j.m(_, null)) : j && (j.d(1), j = null), b[13].tags.length ? S ? S.p(b, N) : (S = se(b), S.c(), S.m(l, null)) : S && (S.d(1), S = null), N & 33 && v !== (v = b[0] + "/event/" + (b[13].slug || b[13].id)) && a(e, "href", v), N & 32 && q !== (q = b[13].title) && a(e, "title", q);
}, },
d(b) { d(b) {
b && k(e), E && E.d(), j && j.d(), S && S.d(); b && x(e), $ && $.d(), j && j.d(), S && S.d();
} }
}; };
} }
@ -433,10 +432,10 @@ function Ge(t) {
let e, i, l = t[4] && le(t), n = t[5].length && ne(t); let e, i, l = t[4] && le(t), n = t[5].length && ne(t);
return { return {
c() { c() {
l && l.c(), e = M(), n && n.c(), i = pe(), this.c = G; l && l.c(), e = C(), n && n.c(), i = pe(), this.c = G;
}, },
m(r, o) { m(r, o) {
l && l.m(r, o), p(r, e, o), n && n.m(r, o), p(r, i, o); l && l.m(r, o), k(r, e, o), n && n.m(r, o), k(r, i, o);
}, },
p(r, [o]) { p(r, [o]) {
r[4] ? l ? l.p(r, o) : (l = le(r), l.c(), l.m(e.parentNode, e)) : l && (l.d(1), l = null), r[5].length ? n ? n.p(r, o) : (n = ne(r), n.c(), n.m(i.parentNode, i)) : n && (n.d(1), n = null); r[4] ? l ? l.p(r, o) : (l = le(r), l.c(), l.m(e.parentNode, e)) : l && (l.d(1), l = null), r[5].length ? n ? n.p(r, o) : (n = ne(r), n.c(), n.m(i.parentNode, i)) : n && (n.d(1), n = null);
@ -444,7 +443,7 @@ function Ge(t) {
i: G, i: G,
o: G, o: G,
d(r) { d(r) {
l && l.d(r), r && k(e), n && n.d(r), r && k(i); l && l.d(r), r && x(e), n && n.d(r), r && x(i);
} }
}; };
} }
@ -456,34 +455,37 @@ function ue(t) {
return "center center"; return "center center";
} }
function He(t, e, i) { function He(t, e, i) {
let { baseurl: l = "" } = e, { title: n = "" } = e, { maxlength: r = !1 } = e, { tags: o = "" } = e, { places: f = "" } = e, { theme: c = "light" } = e, { show_recurrent: s = !1 } = e, { sidebar: w = "true" } = e, { external_style: g = "" } = e, _ = !1, A = []; let { baseurl: l = "" } = e, { title: n = "" } = e, { maxlength: r = !1 } = e, { collection: o = "" } = e, { tags: f = "" } = e, { places: s = "" } = e, { theme: c = "light" } = e, { show_recurrent: w = !1 } = e, { sidebar: g = "true" } = e, { external_style: _ = "" } = e, A = !1, E = [];
function y(d) { function M(d) {
if (!_) if (!A)
return; return;
const z = []; const h = [];
r && z.push(`max=${r}`), o && z.push(`tags=${o}`), f && z.push(`places=${f}`), z.push(`show_recurrent=${s ? "true" : "false"}`), fetch(`${l}/api/events?${z.join("&")}`).then((h) => h.json()).then((h) => { r && h.push(`max=${r}`);
i(5, A = h); let p = "/api/events";
}).catch((h) => { o ? p = `/api/collections/${o}` : (f && h.push(`tags=${f}`), s && h.push(`places=${s}`)), h.push(`show_recurrent=${w ? "true" : "false"}`), fetch(`${l}${p}?${h.join("&")}`).then((v) => v.json()).then((v) => {
console.error("Error loading Gancio API -> ", h); i(5, E = v.events || v);
}).catch((v) => {
console.error("Error loading Gancio API -> ", v);
}); });
} }
return ke(() => { return ke(() => {
_ = !0, y(); A = !0, M();
}), t.$$set = (d) => { }), t.$$set = (d) => {
"baseurl" in d && i(0, l = d.baseurl), "title" in d && i(1, n = d.title), "maxlength" in d && i(6, r = d.maxlength), "tags" in d && i(7, o = d.tags), "places" in d && i(8, f = d.places), "theme" in d && i(2, c = d.theme), "show_recurrent" in d && i(9, s = d.show_recurrent), "sidebar" in d && i(3, w = d.sidebar), "external_style" in d && i(4, g = d.external_style); "baseurl" in d && i(0, l = d.baseurl), "title" in d && i(1, n = d.title), "maxlength" in d && i(6, r = d.maxlength), "collection" in d && i(7, o = d.collection), "tags" in d && i(8, f = d.tags), "places" in d && i(9, s = d.places), "theme" in d && i(2, c = d.theme), "show_recurrent" in d && i(10, w = d.show_recurrent), "sidebar" in d && i(3, g = d.sidebar), "external_style" in d && i(4, _ = d.external_style);
}, t.$$.update = () => { }, t.$$.update = () => {
t.$$.dirty & 975 && y(); t.$$.dirty & 1999 && M();
}, [ }, [
l, l,
n, n,
c, c,
w,
g, g,
A, _,
E,
r, r,
o, o,
f, f,
s s,
w
]; ];
} }
class Re extends X { class Re extends X {
@ -508,21 +510,23 @@ class Re extends X {
baseurl: 0, baseurl: 0,
title: 1, title: 1,
maxlength: 6, maxlength: 6,
tags: 7, collection: 7,
places: 8, tags: 8,
places: 9,
theme: 2, theme: 2,
show_recurrent: 9, show_recurrent: 10,
sidebar: 3, sidebar: 3,
external_style: 4 external_style: 4
}, },
null null
), e && (e.target && p(e.target, this, e.anchor), e.props && (this.$set(e.props), x())); ), e && (e.target && k(e.target, this, e.anchor), e.props && (this.$set(e.props), y()));
} }
static get observedAttributes() { static get observedAttributes() {
return [ return [
"baseurl", "baseurl",
"title", "title",
"maxlength", "maxlength",
"collection",
"tags", "tags",
"places", "places",
"theme", "theme",
@ -535,72 +539,78 @@ class Re extends X {
return this.$$.ctx[0]; return this.$$.ctx[0];
} }
set baseurl(e) { set baseurl(e) {
this.$$set({ baseurl: e }), x(); this.$$set({ baseurl: e }), y();
} }
get title() { get title() {
return this.$$.ctx[1]; return this.$$.ctx[1];
} }
set title(e) { set title(e) {
this.$$set({ title: e }), x(); this.$$set({ title: e }), y();
} }
get maxlength() { get maxlength() {
return this.$$.ctx[6]; return this.$$.ctx[6];
} }
set maxlength(e) { set maxlength(e) {
this.$$set({ maxlength: e }), x(); this.$$set({ maxlength: e }), y();
} }
get tags() { get collection() {
return this.$$.ctx[7]; return this.$$.ctx[7];
} }
set tags(e) { set collection(e) {
this.$$set({ tags: e }), x(); this.$$set({ collection: e }), y();
} }
get places() { get tags() {
return this.$$.ctx[8]; return this.$$.ctx[8];
} }
set tags(e) {
this.$$set({ tags: e }), y();
}
get places() {
return this.$$.ctx[9];
}
set places(e) { set places(e) {
this.$$set({ places: e }), x(); this.$$set({ places: e }), y();
} }
get theme() { get theme() {
return this.$$.ctx[2]; return this.$$.ctx[2];
} }
set theme(e) { set theme(e) {
this.$$set({ theme: e }), x(); this.$$set({ theme: e }), y();
} }
get show_recurrent() { get show_recurrent() {
return this.$$.ctx[9]; return this.$$.ctx[10];
} }
set show_recurrent(e) { set show_recurrent(e) {
this.$$set({ show_recurrent: e }), x(); this.$$set({ show_recurrent: e }), y();
} }
get sidebar() { get sidebar() {
return this.$$.ctx[3]; return this.$$.ctx[3];
} }
set sidebar(e) { set sidebar(e) {
this.$$set({ sidebar: e }), x(); this.$$set({ sidebar: e }), y();
} }
get external_style() { get external_style() {
return this.$$.ctx[4]; return this.$$.ctx[4];
} }
set external_style(e) { set external_style(e) {
this.$$set({ external_style: e }), x(); this.$$set({ external_style: e }), y();
} }
} }
customElements.define("gancio-events", Re); customElements.define("gancio-events", Re);
function de(t) { function de(t) {
let e, i, l, n, r = t[1].title + "", o, f, c, s = V(t[1]) + "", w, g, _, A, y = t[1].place.name + "", d, z, h = t[1].media.length && he(t); let e, i, l, n, r = t[1].title + "", o, f, s, c = V(t[1]) + "", w, g, _, A, E = t[1].place.name + "", M, d, h = t[1].media.length && he(t);
return { return {
c() { c() {
e = m("a"), h && h.c(), i = M(), l = m("div"), n = m("strong"), o = $(r), f = M(), c = m("div"), w = $(s), g = M(), _ = m("div"), A = $("@"), d = $(y), a(_, "class", "place"), a(l, "class", "container"), a(e, "href", z = t[0] + "/event/" + (t[1].slug || t[1].id)), a(e, "class", "card"), a(e, "target", "_blank"); e = m("a"), h && h.c(), i = C(), l = m("div"), n = m("strong"), o = z(r), f = C(), s = m("div"), w = z(c), g = C(), _ = m("div"), A = z("@"), M = z(E), a(_, "class", "place"), a(l, "class", "container"), a(e, "href", d = t[0] + "/event/" + (t[1].slug || t[1].id)), a(e, "class", "card"), a(e, "target", "_blank");
}, },
m(v, C) { m(p, v) {
p(v, e, C), h && h.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, c), u(c, w), u(l, g), u(l, _), u(_, A), u(_, d); k(p, e, v), h && h.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, s), u(s, w), u(l, g), u(l, _), u(_, A), u(_, M);
}, },
p(v, C) { p(p, v) {
v[1].media.length ? h ? h.p(v, C) : (h = he(v), h.c(), h.m(e, i)) : h && (h.d(1), h = null), C & 2 && r !== (r = v[1].title + "") && T(o, r), C & 2 && s !== (s = V(v[1]) + "") && T(w, s), C & 2 && y !== (y = v[1].place.name + "") && T(d, y), C & 3 && z !== (z = v[0] + "/event/" + (v[1].slug || v[1].id)) && a(e, "href", z); p[1].media.length ? h ? h.p(p, v) : (h = he(p), h.c(), h.m(e, i)) : h && (h.d(1), h = null), v & 2 && r !== (r = p[1].title + "") && T(o, r), v & 2 && c !== (c = V(p[1]) + "") && T(w, c), v & 2 && E !== (E = p[1].place.name + "") && T(M, E), v & 3 && d !== (d = p[0] + "/event/" + (p[1].slug || p[1].id)) && a(e, "href", d);
}, },
d(v) { d(p) {
v && k(e), h && h.d(); p && x(e), h && h.d();
} }
}; };
} }
@ -611,13 +621,13 @@ function he(t) {
e = m("img"), H(e.src, i = t[2](t[1])) || a(e, "src", i), a(e, "alt", l = t[1].media[0].name), a(e, "style", n = "object-position: " + me(t[1]) + "; aspect-ratio=1.7778;"); e = m("img"), H(e.src, i = t[2](t[1])) || a(e, "src", i), a(e, "alt", l = t[1].media[0].name), a(e, "style", n = "object-position: " + me(t[1]) + "; aspect-ratio=1.7778;");
}, },
m(r, o) { m(r, o) {
p(r, e, o); k(r, e, o);
}, },
p(r, o) { p(r, o) {
o & 2 && !H(e.src, i = r[2](r[1])) && a(e, "src", i), o & 2 && l !== (l = r[1].media[0].name) && a(e, "alt", l), o & 2 && n !== (n = "object-position: " + me(r[1]) + "; aspect-ratio=1.7778;") && a(e, "style", n); o & 2 && !H(e.src, i = r[2](r[1])) && a(e, "src", i), o & 2 && l !== (l = r[1].media[0].name) && a(e, "alt", l), o & 2 && n !== (n = "object-position: " + me(r[1]) + "; aspect-ratio=1.7778;") && a(e, "style", n);
}, },
d(r) { d(r) {
r && k(e); r && x(e);
} }
}; };
} }
@ -628,7 +638,7 @@ function Ie(t) {
i && i.c(), e = pe(), this.c = G; i && i.c(), e = pe(), this.c = G;
}, },
m(l, n) { m(l, n) {
i && i.m(l, n), p(l, e, n); i && i.m(l, n), k(l, e, n);
}, },
p(l, [n]) { p(l, [n]) {
l[1] ? i ? i.p(l, n) : (i = de(l), i.c(), i.m(e.parentNode, e)) : i && (i.d(1), i = null); l[1] ? i ? i.p(l, n) : (i = de(l), i.c(), i.m(e.parentNode, e)) : i && (i.d(1), i = null);
@ -636,7 +646,7 @@ function Ie(t) {
i: G, i: G,
o: G, o: G,
d(l) { d(l) {
i && i.d(l), l && k(e); i && i.d(l), l && x(e);
} }
}; };
} }
@ -649,20 +659,20 @@ function me(t) {
} }
function Oe(t, e, i) { function Oe(t, e, i) {
let { baseurl: l = "https://demo.gancio.org" } = e, { id: n } = e, r = !1, o; let { baseurl: l = "https://demo.gancio.org" } = e, { id: n } = e, r = !1, o;
function f(s, w) { function f(c, w) {
r && fetch(`${w}/api/event/detail/${s}`).then((g) => g.json()).then((g) => i(1, o = g)); r && fetch(`${w}/api/event/detail/${c}`).then((g) => g.json()).then((g) => i(1, o = g));
} }
ke(() => { ke(() => {
r = !0, f(n, l); r = !0, f(n, l);
}); });
function c(s) { function s(c) {
return `${l}/media/thumb/${s.media[0].url}`; return `${l}/media/thumb/${c.media[0].url}`;
} }
return t.$$set = (s) => { return t.$$set = (c) => {
"baseurl" in s && i(0, l = s.baseurl), "id" in s && i(3, n = s.id); "baseurl" in c && i(0, l = c.baseurl), "id" in c && i(3, n = c.id);
}, t.$$.update = () => { }, t.$$.update = () => {
t.$$.dirty & 9 && f(n, l); t.$$.dirty & 9 && f(n, l);
}, [l, o, c, n]; }, [l, o, s, n];
} }
class Ue extends X { class Ue extends X {
constructor(e) { constructor(e) {
@ -679,7 +689,7 @@ class Ue extends X {
_e, _e,
{ baseurl: 0, id: 3 }, { baseurl: 0, id: 3 },
null null
), e && (e.target && p(e.target, this, e.anchor), e.props && (this.$set(e.props), x())); ), e && (e.target && k(e.target, this, e.anchor), e.props && (this.$set(e.props), y()));
} }
static get observedAttributes() { static get observedAttributes() {
return ["baseurl", "id"]; return ["baseurl", "id"];
@ -688,13 +698,13 @@ class Ue extends X {
return this.$$.ctx[0]; return this.$$.ctx[0];
} }
set baseurl(e) { set baseurl(e) {
this.$$set({ baseurl: e }), x(); this.$$set({ baseurl: e }), y();
} }
get id() { get id() {
return this.$$.ctx[3]; return this.$$.ctx[3];
} }
set id(e) { set id(e) {
this.$$set({ id: e }), x(); this.$$set({ id: e }), y();
} }
} }
customElements.define("gancio-event", Ue); customElements.define("gancio-event", Ue);

View file

@ -207,6 +207,49 @@ describe('Events', () => {
}) })
test('should not allow start_datetime greater than end_datetime', async () => {
const event = {
title: ' test title 5',
place_id: places[0],
start_datetime: dayjs().unix() + 1000,
end_datetime: dayjs().unix(),
}
const response = await request(app).post('/api/event')
.send(event)
.expect(400)
expect(response.text).toBe('start datetime is greater than end datetime')
})
test('should not allow start_datetime greater than 3000', async () => {
const event = {
title: ' test title 5',
start_datetime: dayjs().set('year', 4000).unix(),
place_id: places[0],
}
const response = await request(app).post('/api/event')
.send(event)
.expect(400)
expect(response.text).toBe('are you sure?')
})
test('should validate start_datime', async () => {
const event = {
title: ' test title 5',
start_datetime: "antani",
place_id: places[0],
}
const response = await request(app).post('/api/event')
.send(event)
.expect(400)
})
test('should trim tags and title', async () => { test('should trim tags and title', async () => {
const event = { const event = {
title: ' test title 4 ', title: ' test title 4 ',
@ -239,9 +282,9 @@ describe('Events', () => {
.send(event) .send(event)
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
expect(response.body.description).toBe(`<p>inside paragraph</p><a href="https://test.com/?query=true">link with fb reference</a>`) expect(response.body.description).toBe(`<p>inside paragraph</p><a href="https://test.com/?query=true">link with fb reference</a>`)
}) })
}) })
@ -384,7 +427,7 @@ describe('Collection', () => {
}) })
test('shoud get collection\'s filters using withFilters parameter', async () => { test('shoud get collection\'s filters using withFilters parameter', async () => {
const response = await request(app) let response = await request(app)
.get('/api/collections?withFilters=true') .get('/api/collections?withFilters=true')
.expect(200) .expect(200)
@ -393,6 +436,18 @@ describe('Collection', () => {
expect(response.body[0].filters.length).toBe(1) expect(response.body[0].filters.length).toBe(1)
expect(response.body[0].filters[0].tags.length).toBe(1) expect(response.body[0].filters[0].tags.length).toBe(1)
expect(response.body[0].filters[0].tags[0]).toBe('test') expect(response.body[0].filters[0].tags[0]).toBe('test')
response = await request(app)
.get('/api/collections')
.expect(200)
expect(response.body[0].filters).toBeUndefined()
response = await request(app)
.get('/api/collections?withFilters=false')
.expect(200)
expect(response.body[0].filters).toBeUndefined()
}) })
test('should get collection events', async () => { test('should get collection events', async () => {

View file

@ -29,8 +29,8 @@ beforeAll(async () => {
await sequelize.query('DELETE FROM collections') await sequelize.query('DELETE FROM collections')
} catch (e) { } catch (e) {
console.error(e) console.error(e)
} }
}) })
afterAll(async () => { afterAll(async () => {
@ -50,13 +50,14 @@ describe('Recurrent events', () => {
start_datetime: DateTime.local(2023, 3, 27, 8).toUnixInteger(), start_datetime: DateTime.local(2023, 3, 27, 8).toUnixInteger(),
}) })
// 27 March 2023 08:00 -> 1w -> 3 April 2023 08:00 // 27 March 2023 08:00 -> 1w
let ev = await eventController._createRecurrentOccurrence(ret) let ev = await eventController._createRecurrentOccurrence(ret)
expect(ev.start_datetime).toBe(DateTime.local(2023, 4, 3, 8).toUnixInteger()) expect(ev.start_datetime).toBeGreaterThan(DateTime.local().toUnixInteger())
expect(DateTime.fromSeconds(ev.start_datetime).hour).toBe(8)
// 3 April 2023 08:00 -> 1w -> 10 April 2023 08:00 // 3 April 2023 08:00 -> 1w -> 10 April 2023 08:00
ev = await eventController._createRecurrentOccurrence(ret, DateTime.fromSeconds(ev.start_datetime+1), false) // ev = await eventController._createRecurrentOccurrence(ret, DateTime.fromSeconds(ev.start_datetime+1), false)
expect(ev.start_datetime).toBe(DateTime.local(2023, 4, 10, 8).toUnixInteger()) // expect(ev.start_datetime).
// weekly test // weekly test
// data di inizio prima di oggi // data di inizio prima di oggi
@ -75,7 +76,7 @@ describe('Recurrent events', () => {
test('shoud create an occurrence when start date time is in future', async () => { test('shoud create an occurrence when start date time is in future', async () => {
const eventController = require('../server/api/controller/event') const eventController = require('../server/api/controller/event')
const { Event } = require('../server/api/models/models') const { Event } = require('../server/api/models/models')
// each week starting from future // each week starting from future
ret = await Event.create({ ret = await Event.create({
title: 'each week starting from future', title: 'each week starting from future',
@ -94,27 +95,6 @@ describe('Recurrent events', () => {
}) })
test('shoud create a 2 week occurrence in future when start date time is in past', async () => {
const eventController = require('../server/api/controller/event')
const { Event } = require('../server/api/models/models')
// each week starting from past
let ret = await Event.create({
title: 'each 2 weeks starting from past',
is_visible: true,
recurrent: { frequency: '2w' },
start_datetime: DateTime.local(2023, 3, 27, 8).toUnixInteger(),
})
// 27 March 2023 08:00 -> 2w -> 10 April 2023 08:00
let ev = await eventController._createRecurrentOccurrence(ret)
expect(ev.start_datetime).toBe(DateTime.local(2023, 4, 10, 8).toUnixInteger())
// 10 April 2023 08:00 -> 2w -> 24 April 2023 08:00
ev = await eventController._createRecurrentOccurrence(ret, DateTime.fromSeconds(ev.start_datetime+1), false)
expect(ev.start_datetime).toBe(DateTime.local(2023, 4, 24, 8).toUnixInteger())
})
test('shoud create a 2 week occurrence in future when start date time is in future', async () => { test('shoud create a 2 week occurrence in future when start date time is in future', async () => {
const eventController = require('../server/api/controller/event') const eventController = require('../server/api/controller/event')
const { Event } = require('../server/api/models/models') const { Event } = require('../server/api/models/models')
@ -163,22 +143,60 @@ describe('Recurrent events', () => {
const eventController = require('../server/api/controller/event') const eventController = require('../server/api/controller/event')
const { Event } = require('../server/api/models/models') const { Event } = require('../server/api/models/models')
// each week starting from past // each week
let ret = await Event.create({ let ret = await Event.create({
title: 'each last monday starting from past', title: 'each last monday starting',
is_visible: true, is_visible: true,
recurrent: { frequency: '1m', type: -1 }, recurrent: { frequency: '1m', type: -1 },
start_datetime: DateTime.local(2023, 3, 27, 8).toUnixInteger(), start_datetime: DateTime.local(2033, 3, 27, 8).toUnixInteger(),
}) })
// 27 March 2033 08:00 -> 1m -> 24 April 2033 08:00
ev = await eventController._createRecurrentOccurrence(ret) ev = await eventController._createRecurrentOccurrence(ret)
expect(ev.start_datetime).toBe(DateTime.local(2023, 4, 24, 8).toUnixInteger()) expect(ev.start_datetime).toBe(DateTime.local(2033, 3, 27, 8).toUnixInteger())
// 27 March 2033 08:00 -> 1m -> 24 April 2033 08:00
ev = await eventController._createRecurrentOccurrence(ret, DateTime.fromSeconds(ev.start_datetime+1), false)
expect(ev.start_datetime).toBe(DateTime.local(2033, 4, 24, 8).toUnixInteger())
// 24 April 2033 08:00 -> 1m -> 29 May 2033 08:00 // 24 April 2033 08:00 -> 1m -> 29 May 2033 08:00
ev = await eventController._createRecurrentOccurrence(ret, DateTime.fromSeconds(ev.start_datetime+1), false) ev = await eventController._createRecurrentOccurrence(ret, DateTime.fromSeconds(ev.start_datetime+1), false)
expect(ev.start_datetime).toBe(DateTime.local(2023, 5, 29, 8).toUnixInteger()) expect(ev.start_datetime).toBe(DateTime.local(2033, 5, 29, 8).toUnixInteger())
})
}) })
test('shoud create an occurrence each second tuesday', async () => {
const eventController = require('../server/api/controller/event')
const { Event } = require('../server/api/models/models')
// each week starting from past
let ret = await Event.create({
title: 'each second tuesday',
is_visible: true,
recurrent: { frequency: '1m', type: 2 },
start_datetime: DateTime.local(2033, 2, 8, 8).toUnixInteger(),
})
ev = await eventController._createRecurrentOccurrence(ret)
expect(ev.start_datetime).toBe(DateTime.local(2033, 2, 8, 8).toUnixInteger())
ev = await eventController._createRecurrentOccurrence(ret, DateTime.fromSeconds(ev.start_datetime+1), false)
expect(ev.start_datetime).toBe(DateTime.local(2033, 3, 8, 8).toUnixInteger())
// 8 March 2033 08:00 -> 1m -> 12 April 2033 08:00
ev = await eventController._createRecurrentOccurrence(ret, DateTime.fromSeconds(ev.start_datetime+1), false)
expect(ev.start_datetime).toBe(DateTime.local(2033, 4, 12, 8).toUnixInteger())
// 12 Apr 2033 08:00 -> 1m -> 10 May 2033 08:00
ev = await eventController._createRecurrentOccurrence(ret, DateTime.fromSeconds(ev.start_datetime+1), false)
expect(ev.start_datetime).toBe(DateTime.local(2033, 5, 10, 8).toUnixInteger())
// 10 May 2033 08:00 -> 1m -> 9 June 2033 08:00
ev = await eventController._createRecurrentOccurrence(ret, DateTime.fromSeconds(ev.start_datetime+1), false)
expect(ev.start_datetime).toBe(DateTime.local(2033, 6, 14, 8).toUnixInteger())
})
})

View file

@ -9,10 +9,10 @@ rss(version='2.0' xmlns:atom="http://www.w3.org/2005/Atom")
item item
if (event.media && event.media.length) if (event.media && event.media.length)
<enclosure url="#{settings.baseurl}/media/#{event.media[0].url}" type='image/jpeg' length="#{event.media[0].size||1}"></enclosure> <enclosure url="#{settings.baseurl}/media/#{event.media[0].url}" type='image/jpeg' length="#{event.media[0].size||1}"></enclosure>
title [#{unixFormat(event.start_datetime,"yy-MM-dd")}] #{event.title} @ #{event.place.name} title [#{unixFormat(event.start_datetime,"yyyy-MM-dd")}] #{event.title} @ #{event.place.name}
link #{settings.baseurl}/event/#{event.slug || event.id} link #{settings.baseurl}/event/#{event.slug || event.id}
each tag in event.tags each tag in event.tags
category #{tag.tag} category #{tag.tag || tag}
description description
| <![CDATA[ | <![CDATA[
| <h4>#{event.title}</h4> | <h4>#{event.title}</h4>

View file

@ -1,12 +1,12 @@
const minifyTheme = require('minify-css-string').default const minifyTheme = require('minify-css-string').default
import { ca, de, en, es, eu, fr, gl, it, nb, nl, pl, pt, sk, ru, zhHans } from 'vuetify/es5/locale' import { ca, cs, de, en, es, eu, fr, gl, it, nb, nl, pl, pt, sk, ru, zhHans } from 'vuetify/es5/locale'
export default ({ res, nuxtState }) => { export default ({ res, nuxtState }) => {
const settings = process.server ? res.locals.settings : nuxtState.state.settings const settings = process.server ? (res.locals.settings || {}) : nuxtState.state.settings || {}
return { return {
lang: { locales: { ca, de, en, es, eu, fr, gl, it, nb, nl, pl, pt, sk, ru, zhHans } }, lang: { locales: { ca, cs, de, en, es, eu, fr, gl, it, nb, nl, pl, pt, sk, ru, zhHans } },
treeShake: true, treeShake: true,
theme: { theme: {
options: { options: {

View file

@ -6,6 +6,7 @@
export let baseurl = '' export let baseurl = ''
export let title = '' export let title = ''
export let maxlength = false export let maxlength = false
export let collection = ''
export let tags = '' export let tags = ''
export let places = '' export let places = ''
export let theme = 'light' export let theme = 'light'
@ -24,20 +25,24 @@
params.push(`max=${maxlength}`) params.push(`max=${maxlength}`)
} }
if (tags) { let api = '/api/events'
params.push(`tags=${tags}`) if (collection) {
} api = `/api/collections/${collection}`
} else {
if (tags) {
params.push(`tags=${tags}`)
}
if (places) { if (places) {
params.push(`places=${places}`) params.push(`places=${places}`)
}
} }
params.push(`show_recurrent=${show_recurrent ? 'true' : 'false'}`) params.push(`show_recurrent=${show_recurrent ? 'true' : 'false'}`)
fetch(`${baseurl}/api/events?${params.join('&')}`) fetch(`${baseurl}${api}?${params.join('&')}`)
.then((res) => res.json()) .then((res) => res.json())
.then((e) => { .then((e) => {
events = e events = e.events || e
}) })
.catch((e) => { .catch((e) => {
console.error('Error loading Gancio API -> ', e) console.error('Error loading Gancio API -> ', e)
@ -57,7 +62,7 @@
update() update()
}) })
$: update( $: update(
maxlength && title && places && tags && theme && show_recurrent && sidebar && baseurl maxlength && title && places && tags && theme && show_recurrent && sidebar && baseurl && collection
) )
</script> </script>

View file

@ -25,10 +25,10 @@ function ye(t) {
function u(t, e) { function u(t, e) {
t.appendChild(e); t.appendChild(e);
} }
function p(t, e, i) { function k(t, e, i) {
t.insertBefore(e, i || null); t.insertBefore(e, i || null);
} }
function k(t) { function x(t) {
t.parentNode.removeChild(t); t.parentNode.removeChild(t);
} }
function be(t, e) { function be(t, e) {
@ -38,14 +38,14 @@ function be(t, e) {
function m(t) { function m(t) {
return document.createElement(t); return document.createElement(t);
} }
function $(t) { function z(t) {
return document.createTextNode(t); return document.createTextNode(t);
} }
function M() { function C() {
return $(" "); return z(" ");
} }
function pe() { function pe() {
return $(""); return z("");
} }
function a(t, e, i) { function a(t, e, i) {
i == null ? t.removeAttribute(e) : t.getAttribute(e) !== i && t.setAttribute(e, i); i == null ? t.removeAttribute(e) : t.getAttribute(e) !== i && t.setAttribute(e, i);
@ -69,25 +69,25 @@ let O;
function I(t) { function I(t) {
O = t; O = t;
} }
function $e() { function Ee() {
if (!O) if (!O)
throw new Error("Function called outside component initialization"); throw new Error("Function called outside component initialization");
return O; return O;
} }
function ke(t) { function ke(t) {
$e().$$.on_mount.push(t); Ee().$$.on_mount.push(t);
} }
const R = [], Z = [], P = [], ee = [], Ee = Promise.resolve(); const R = [], Z = [], P = [], ee = [], $e = Promise.resolve();
let K = !1; let K = !1;
function je() { function je() {
K || (K = !0, Ee.then(x)); K || (K = !0, $e.then(y));
} }
function Q(t) { function Q(t) {
P.push(t); P.push(t);
} }
const J = /* @__PURE__ */ new Set(); const J = /* @__PURE__ */ new Set();
let D = 0; let D = 0;
function x() { function y() {
const t = O; const t = O;
do { do {
for (; D < R.length; ) { for (; D < R.length; ) {
@ -120,8 +120,8 @@ function Ce(t, e) {
function Ae(t, e, i, l) { function Ae(t, e, i, l) {
const { fragment: n, on_mount: r, on_destroy: o, after_update: f } = t.$$; const { fragment: n, on_mount: r, on_destroy: o, after_update: f } = t.$$;
n && n.m(e, i), l || Q(() => { n && n.m(e, i), l || Q(() => {
const c = r.map(W).filter(ge); const s = r.map(W).filter(ge);
o ? o.push(...c) : U(c), t.$$.on_mount = []; o ? o.push(...s) : U(s), t.$$.on_mount = [];
}), f.forEach(Q); }), f.forEach(Q);
} }
function Me(t, e) { function Me(t, e) {
@ -132,9 +132,9 @@ function Ne(t, e) {
t.$$.dirty[0] === -1 && (R.push(t), je(), t.$$.dirty.fill(0)), t.$$.dirty[e / 31 | 0] |= 1 << e % 31; t.$$.dirty[0] === -1 && (R.push(t), je(), t.$$.dirty.fill(0)), t.$$.dirty[e / 31 | 0] |= 1 << e % 31;
} }
function we(t, e, i, l, n, r, o, f = [-1]) { function we(t, e, i, l, n, r, o, f = [-1]) {
const c = O; const s = O;
I(t); I(t);
const s = t.$$ = { const c = t.$$ = {
fragment: null, fragment: null,
ctx: null, ctx: null,
props: r, props: r,
@ -146,26 +146,26 @@ function we(t, e, i, l, n, r, o, f = [-1]) {
on_disconnect: [], on_disconnect: [],
before_update: [], before_update: [],
after_update: [], after_update: [],
context: new Map(e.context || (c ? c.$$.context : [])), context: new Map(e.context || (s ? s.$$.context : [])),
callbacks: Y(), callbacks: Y(),
dirty: f, dirty: f,
skip_bound: !1, skip_bound: !1,
root: e.target || c.$$.root root: e.target || s.$$.root
}; };
o && o(s.root); o && o(c.root);
let w = !1; let w = !1;
if (s.ctx = i ? i(t, e.props || {}, (g, _, ...A) => { if (c.ctx = i ? i(t, e.props || {}, (g, _, ...A) => {
const y = A.length ? A[0] : _; const E = A.length ? A[0] : _;
return s.ctx && n(s.ctx[g], s.ctx[g] = y) && (!s.skip_bound && s.bound[g] && s.bound[g](y), w && Ne(t, g)), _; return c.ctx && n(c.ctx[g], c.ctx[g] = E) && (!c.skip_bound && c.bound[g] && c.bound[g](E), w && Ne(t, g)), _;
}) : [], s.update(), w = !0, U(s.before_update), s.fragment = l ? l(s.ctx) : !1, e.target) { }) : [], c.update(), w = !0, U(c.before_update), c.fragment = l ? l(c.ctx) : !1, e.target) {
if (e.hydrate) { if (e.hydrate) {
const g = xe(e.target); const g = xe(e.target);
s.fragment && s.fragment.l(g), g.forEach(k); c.fragment && c.fragment.l(g), g.forEach(x);
} else } else
s.fragment && s.fragment.c(); c.fragment && c.fragment.c();
e.intro && Ce(t.$$.fragment), Ae(t, e.target, e.anchor, e.customElement), x(); e.intro && Ce(t.$$.fragment), Ae(t, e.target, e.anchor, e.customElement), y();
} }
I(c); I(s);
} }
let X; let X;
typeof HTMLElement == "function" && (X = class extends HTMLElement { typeof HTMLElement == "function" && (X = class extends HTMLElement {
@ -213,11 +213,11 @@ function V(t) {
} }
function te(t, e, i) { function te(t, e, i) {
const l = t.slice(); const l = t.slice();
return l[12] = e[i], l; return l[13] = e[i], l;
} }
function ie(t, e, i) { function ie(t, e, i) {
const l = t.slice(); const l = t.slice();
return l[15] = e[i], l; return l[16] = e[i], l;
} }
function le(t) { function le(t) {
let e; let e;
@ -226,13 +226,13 @@ function le(t) {
e = m("link"), a(e, "rel", "stylesheet"), a(e, "href", t[4]); e = m("link"), a(e, "rel", "stylesheet"), a(e, "href", t[4]);
}, },
m(i, l) { m(i, l) {
p(i, e, l); k(i, e, l);
}, },
p(i, l) { p(i, l) {
l & 16 && a(e, "href", i[4]); l & 16 && a(e, "href", i[4]);
}, },
d(i) { d(i) {
i && k(e); i && x(e);
} }
}; };
} }
@ -242,32 +242,32 @@ function ne(t) {
r[o] = fe(te(t, n, o)); r[o] = fe(te(t, n, o));
return { return {
c() { c() {
e = m("div"), l && l.c(), i = M(); e = m("div"), l && l.c(), i = C();
for (let o = 0; o < r.length; o += 1) for (let o = 0; o < r.length; o += 1)
r[o].c(); r[o].c();
a(e, "id", "gancioEvents"), L(e, "dark", t[2] === "dark"), L(e, "light", t[2] === "light"), L(e, "sidebar", t[3] === "true"), L(e, "nosidebar", t[3] !== "true"); a(e, "id", "gancioEvents"), L(e, "dark", t[2] === "dark"), L(e, "light", t[2] === "light"), L(e, "sidebar", t[3] === "true"), L(e, "nosidebar", t[3] !== "true");
}, },
m(o, f) { m(o, f) {
p(o, e, f), l && l.m(e, null), u(e, i); k(o, e, f), l && l.m(e, null), u(e, i);
for (let c = 0; c < r.length; c += 1) for (let s = 0; s < r.length; s += 1)
r[c].m(e, null); r[s].m(e, null);
}, },
p(o, f) { p(o, f) {
if (o[1] && o[3] === "true" ? l ? l.p(o, f) : (l = re(o), l.c(), l.m(e, i)) : l && (l.d(1), l = null), f & 41) { if (o[1] && o[3] === "true" ? l ? l.p(o, f) : (l = re(o), l.c(), l.m(e, i)) : l && (l.d(1), l = null), f & 41) {
n = o[5]; n = o[5];
let c; let s;
for (c = 0; c < n.length; c += 1) { for (s = 0; s < n.length; s += 1) {
const s = te(o, n, c); const c = te(o, n, s);
r[c] ? r[c].p(s, f) : (r[c] = fe(s), r[c].c(), r[c].m(e, null)); r[s] ? r[s].p(c, f) : (r[s] = fe(c), r[s].c(), r[s].m(e, null));
} }
for (; c < r.length; c += 1) for (; s < r.length; s += 1)
r[c].d(1); r[s].d(1);
r.length = n.length; r.length = n.length;
} }
f & 4 && L(e, "dark", o[2] === "dark"), f & 4 && L(e, "light", o[2] === "light"), f & 8 && L(e, "sidebar", o[3] === "true"), f & 8 && L(e, "nosidebar", o[3] !== "true"); f & 4 && L(e, "dark", o[2] === "dark"), f & 4 && L(e, "light", o[2] === "light"), f & 8 && L(e, "sidebar", o[3] === "true"), f & 8 && L(e, "nosidebar", o[3] !== "true");
}, },
d(o) { d(o) {
o && k(e), l && l.d(), be(r, o); o && x(e), l && l.d(), be(r, o);
} }
}; };
} }
@ -275,23 +275,23 @@ function re(t) {
let e, i, l, n, r, o, f; let e, i, l, n, r, o, f;
return { return {
c() { c() {
e = m("a"), i = m("div"), l = m("div"), n = $(t[1]), r = M(), o = m("img"), a(l, "class", "title"), a(o, "id", "logo"), a(o, "alt", "logo"), H(o.src, f = t[0] + "/logo.png") || a(o, "src", f), a(i, "class", "content"), a(e, "href", t[0]), a(e, "target", "_blank"), a(e, "id", "header"); e = m("a"), i = m("div"), l = m("div"), n = z(t[1]), r = C(), o = m("img"), a(l, "class", "title"), a(o, "id", "logo"), a(o, "alt", "logo"), H(o.src, f = t[0] + "/logo.png") || a(o, "src", f), a(i, "class", "content"), a(e, "href", t[0]), a(e, "target", "_blank"), a(e, "id", "header");
}, },
m(c, s) { m(s, c) {
p(c, e, s), u(e, i), u(i, l), u(l, n), u(i, r), u(i, o); k(s, e, c), u(e, i), u(i, l), u(l, n), u(i, r), u(i, o);
}, },
p(c, s) { p(s, c) {
s & 2 && T(n, c[1]), s & 1 && !H(o.src, f = c[0] + "/logo.png") && a(o, "src", f), s & 1 && a(e, "href", c[0]); c & 2 && T(n, s[1]), c & 1 && !H(o.src, f = s[0] + "/logo.png") && a(o, "src", f), c & 1 && a(e, "href", s[0]);
}, },
d(c) { d(s) {
c && k(e); s && x(e);
} }
}; };
} }
function oe(t) { function oe(t) {
let e; let e;
function i(r, o) { function i(r, o) {
return r[12].media.length ? Le : Te; return r[13].media.length ? Le : Te;
} }
let l = i(t), n = l(t); let l = i(t), n = l(t);
return { return {
@ -299,13 +299,13 @@ function oe(t) {
e = m("div"), n.c(), a(e, "class", "img"); e = m("div"), n.c(), a(e, "class", "img");
}, },
m(r, o) { m(r, o) {
p(r, e, o), n.m(e, null); k(r, e, o), n.m(e, null);
}, },
p(r, o) { p(r, o) {
l === (l = i(r)) && n ? n.p(r, o) : (n.d(1), n = l(r), n && (n.c(), n.m(e, null))); l === (l = i(r)) && n ? n.p(r, o) : (n.d(1), n = l(r), n && (n.c(), n.m(e, null)));
}, },
d(r) { d(r) {
r && k(e), n.d(); r && x(e), n.d();
} }
}; };
} }
@ -313,16 +313,16 @@ function Te(t) {
let e, i, l; let e, i, l;
return { return {
c() { c() {
e = m("img"), a(e, "style", "aspect-ratio=1.7778;"), a(e, "alt", i = t[12].title), H(e.src, l = t[0] + "/fallbackimage.png") || a(e, "src", l), a(e, "loading", "lazy"); e = m("img"), a(e, "style", "aspect-ratio=1.7778;"), a(e, "alt", i = t[13].title), H(e.src, l = t[0] + "/fallbackimage.png") || a(e, "src", l), a(e, "loading", "lazy");
}, },
m(n, r) { m(n, r) {
p(n, e, r); k(n, e, r);
}, },
p(n, r) { p(n, r) {
r & 32 && i !== (i = n[12].title) && a(e, "alt", i), r & 1 && !H(e.src, l = n[0] + "/fallbackimage.png") && a(e, "src", l); r & 32 && i !== (i = n[13].title) && a(e, "alt", i), r & 1 && !H(e.src, l = n[0] + "/fallbackimage.png") && a(e, "src", l);
}, },
d(n) { d(n) {
n && k(e); n && x(e);
} }
}; };
} }
@ -330,38 +330,38 @@ function Le(t) {
let e, i, l, n; let e, i, l, n;
return { return {
c() { c() {
e = m("img"), a(e, "style", i = "object-position: " + ue(t[12]) + "; aspect-ratio=1.7778;"), a(e, "alt", l = t[12].media[0].name), H(e.src, n = t[0] + "/media/thumb/" + t[12].media[0].url) || a(e, "src", n), a(e, "loading", "lazy"); e = m("img"), a(e, "style", i = "object-position: " + ue(t[13]) + "; aspect-ratio=1.7778;"), a(e, "alt", l = t[13].media[0].name), H(e.src, n = t[0] + "/media/thumb/" + t[13].media[0].url) || a(e, "src", n), a(e, "loading", "lazy");
}, },
m(r, o) { m(r, o) {
p(r, e, o); k(r, e, o);
}, },
p(r, o) { p(r, o) {
o & 32 && i !== (i = "object-position: " + ue(r[12]) + "; aspect-ratio=1.7778;") && a(e, "style", i), o & 32 && l !== (l = r[12].media[0].name) && a(e, "alt", l), o & 33 && !H(e.src, n = r[0] + "/media/thumb/" + r[12].media[0].url) && a(e, "src", n); o & 32 && i !== (i = "object-position: " + ue(r[13]) + "; aspect-ratio=1.7778;") && a(e, "style", i), o & 32 && l !== (l = r[13].media[0].name) && a(e, "alt", l), o & 33 && !H(e.src, n = r[0] + "/media/thumb/" + r[13].media[0].url) && a(e, "src", n);
}, },
d(r) { d(r) {
r && k(e); r && x(e);
} }
}; };
} }
function ae(t) { function ae(t) {
let e, i = t[12].place.address + "", l; let e, i = t[13].place.address + "", l;
return { return {
c() { c() {
e = m("span"), l = $(i), a(e, "class", "subtitle"); e = m("span"), l = z(i), a(e, "class", "subtitle");
}, },
m(n, r) { m(n, r) {
p(n, e, r), u(e, l); k(n, e, r), u(e, l);
}, },
p(n, r) { p(n, r) {
r & 32 && i !== (i = n[12].place.address + "") && T(l, i); r & 32 && i !== (i = n[13].place.address + "") && T(l, i);
}, },
d(n) { d(n) {
n && k(e); n && x(e);
} }
}; };
} }
function se(t) { function se(t) {
let e, i = t[12].tags, l = []; let e, i = t[13].tags, l = [];
for (let n = 0; n < i.length; n += 1) for (let n = 0; n < i.length; n += 1)
l[n] = ce(ie(t, i, n)); l[n] = ce(ie(t, i, n));
return { return {
@ -372,13 +372,13 @@ function se(t) {
a(e, "class", "tags"); a(e, "class", "tags");
}, },
m(n, r) { m(n, r) {
p(n, e, r); k(n, e, r);
for (let o = 0; o < l.length; o += 1) for (let o = 0; o < l.length; o += 1)
l[o].m(e, null); l[o].m(e, null);
}, },
p(n, r) { p(n, r) {
if (r & 32) { if (r & 32) {
i = n[12].tags; i = n[13].tags;
let o; let o;
for (o = 0; o < i.length; o += 1) { for (o = 0; o < i.length; o += 1) {
const f = ie(n, i, o); const f = ie(n, i, o);
@ -390,42 +390,41 @@ function se(t) {
} }
}, },
d(n) { d(n) {
n && k(e), be(l, n); n && x(e), be(l, n);
} }
}; };
} }
function ce(t) { function ce(t) {
let e, i, l = t[15] + "", n; let e, i, l = t[16] + "", n;
return { return {
c() { c() {
e = m("span"), i = $("#"), n = $(l), a(e, "class", "tag"); e = m("span"), i = z("#"), n = z(l), a(e, "class", "tag");
}, },
m(r, o) { m(r, o) {
p(r, e, o), u(e, i), u(e, n); k(r, e, o), u(e, i), u(e, n);
}, },
p(r, o) { p(r, o) {
o & 32 && l !== (l = r[15] + "") && T(n, l); o & 32 && l !== (l = r[16] + "") && T(n, l);
}, },
d(r) { d(r) {
r && k(e); r && x(e);
} }
}; };
} }
function fe(t) { function fe(t) {
let e, i, l, n, r = V(t[12]) + "", o, f, c, s = t[12].title + "", w, g, _, A, y = t[12].place.name + "", d, z, h, v, C, q, E = t[3] !== "true" && oe(t), j = t[12].place.name !== "online" && ae(t), S = t[12].tags.length && se(t); let e, i, l, n, r = V(t[13]) + "", o, f, s, c = t[13].title + "", w, g, _, A, E = t[13].place.name + "", M, d, h, p, v, q, $ = t[3] !== "true" && oe(t), j = t[13].place.name !== "online" && ae(t), S = t[13].tags.length && se(t);
return { return {
c() { c() {
e = m("a"), E && E.c(), i = M(), l = m("div"), n = m("div"), o = $(r), f = M(), c = m("div"), w = $(s), g = M(), _ = m("span"), A = $('@"'), d = $(y), z = $(`" e = m("a"), $ && $.c(), i = C(), l = m("div"), n = m("div"), o = z(r), f = C(), s = m("div"), w = z(c), g = C(), _ = m("span"), A = z("@"), M = z(E), d = C(), j && j.c(), h = C(), S && S.c(), p = C(), a(n, "class", "subtitle"), a(s, "class", "title"), a(_, "class", "place"), a(l, "class", "content"), a(e, "href", v = t[0] + "/event/" + (t[13].slug || t[13].id)), a(e, "class", "event"), a(e, "title", q = t[13].title), a(e, "target", "_blank");
`), j && j.c(), h = M(), S && S.c(), v = M(), a(n, "class", "subtitle"), a(c, "class", "title"), a(_, "class", "place"), a(l, "class", "content"), a(e, "href", C = t[0] + "/event/" + (t[12].slug || t[12].id)), a(e, "class", "event"), a(e, "title", q = t[12].title), a(e, "target", "_blank");
}, },
m(b, N) { m(b, N) {
p(b, e, N), E && E.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, c), u(c, w), u(l, g), u(l, _), u(_, A), u(_, d), u(_, z), j && j.m(_, null), u(l, h), S && S.m(l, null), u(e, v); k(b, e, N), $ && $.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, s), u(s, w), u(l, g), u(l, _), u(_, A), u(_, M), u(_, d), j && j.m(_, null), u(l, h), S && S.m(l, null), u(e, p);
}, },
p(b, N) { p(b, N) {
b[3] !== "true" ? E ? E.p(b, N) : (E = oe(b), E.c(), E.m(e, i)) : E && (E.d(1), E = null), N & 32 && r !== (r = V(b[12]) + "") && T(o, r), N & 32 && s !== (s = b[12].title + "") && T(w, s), N & 32 && y !== (y = b[12].place.name + "") && T(d, y), b[12].place.name !== "online" ? j ? j.p(b, N) : (j = ae(b), j.c(), j.m(_, null)) : j && (j.d(1), j = null), b[12].tags.length ? S ? S.p(b, N) : (S = se(b), S.c(), S.m(l, null)) : S && (S.d(1), S = null), N & 33 && C !== (C = b[0] + "/event/" + (b[12].slug || b[12].id)) && a(e, "href", C), N & 32 && q !== (q = b[12].title) && a(e, "title", q); b[3] !== "true" ? $ ? $.p(b, N) : ($ = oe(b), $.c(), $.m(e, i)) : $ && ($.d(1), $ = null), N & 32 && r !== (r = V(b[13]) + "") && T(o, r), N & 32 && c !== (c = b[13].title + "") && T(w, c), N & 32 && E !== (E = b[13].place.name + "") && T(M, E), b[13].place.name !== "online" ? j ? j.p(b, N) : (j = ae(b), j.c(), j.m(_, null)) : j && (j.d(1), j = null), b[13].tags.length ? S ? S.p(b, N) : (S = se(b), S.c(), S.m(l, null)) : S && (S.d(1), S = null), N & 33 && v !== (v = b[0] + "/event/" + (b[13].slug || b[13].id)) && a(e, "href", v), N & 32 && q !== (q = b[13].title) && a(e, "title", q);
}, },
d(b) { d(b) {
b && k(e), E && E.d(), j && j.d(), S && S.d(); b && x(e), $ && $.d(), j && j.d(), S && S.d();
} }
}; };
} }
@ -433,10 +432,10 @@ function Ge(t) {
let e, i, l = t[4] && le(t), n = t[5].length && ne(t); let e, i, l = t[4] && le(t), n = t[5].length && ne(t);
return { return {
c() { c() {
l && l.c(), e = M(), n && n.c(), i = pe(), this.c = G; l && l.c(), e = C(), n && n.c(), i = pe(), this.c = G;
}, },
m(r, o) { m(r, o) {
l && l.m(r, o), p(r, e, o), n && n.m(r, o), p(r, i, o); l && l.m(r, o), k(r, e, o), n && n.m(r, o), k(r, i, o);
}, },
p(r, [o]) { p(r, [o]) {
r[4] ? l ? l.p(r, o) : (l = le(r), l.c(), l.m(e.parentNode, e)) : l && (l.d(1), l = null), r[5].length ? n ? n.p(r, o) : (n = ne(r), n.c(), n.m(i.parentNode, i)) : n && (n.d(1), n = null); r[4] ? l ? l.p(r, o) : (l = le(r), l.c(), l.m(e.parentNode, e)) : l && (l.d(1), l = null), r[5].length ? n ? n.p(r, o) : (n = ne(r), n.c(), n.m(i.parentNode, i)) : n && (n.d(1), n = null);
@ -444,7 +443,7 @@ function Ge(t) {
i: G, i: G,
o: G, o: G,
d(r) { d(r) {
l && l.d(r), r && k(e), n && n.d(r), r && k(i); l && l.d(r), r && x(e), n && n.d(r), r && x(i);
} }
}; };
} }
@ -456,34 +455,37 @@ function ue(t) {
return "center center"; return "center center";
} }
function He(t, e, i) { function He(t, e, i) {
let { baseurl: l = "" } = e, { title: n = "" } = e, { maxlength: r = !1 } = e, { tags: o = "" } = e, { places: f = "" } = e, { theme: c = "light" } = e, { show_recurrent: s = !1 } = e, { sidebar: w = "true" } = e, { external_style: g = "" } = e, _ = !1, A = []; let { baseurl: l = "" } = e, { title: n = "" } = e, { maxlength: r = !1 } = e, { collection: o = "" } = e, { tags: f = "" } = e, { places: s = "" } = e, { theme: c = "light" } = e, { show_recurrent: w = !1 } = e, { sidebar: g = "true" } = e, { external_style: _ = "" } = e, A = !1, E = [];
function y(d) { function M(d) {
if (!_) if (!A)
return; return;
const z = []; const h = [];
r && z.push(`max=${r}`), o && z.push(`tags=${o}`), f && z.push(`places=${f}`), z.push(`show_recurrent=${s ? "true" : "false"}`), fetch(`${l}/api/events?${z.join("&")}`).then((h) => h.json()).then((h) => { r && h.push(`max=${r}`);
i(5, A = h); let p = "/api/events";
}).catch((h) => { o ? p = `/api/collections/${o}` : (f && h.push(`tags=${f}`), s && h.push(`places=${s}`)), h.push(`show_recurrent=${w ? "true" : "false"}`), fetch(`${l}${p}?${h.join("&")}`).then((v) => v.json()).then((v) => {
console.error("Error loading Gancio API -> ", h); i(5, E = v.events || v);
}).catch((v) => {
console.error("Error loading Gancio API -> ", v);
}); });
} }
return ke(() => { return ke(() => {
_ = !0, y(); A = !0, M();
}), t.$$set = (d) => { }), t.$$set = (d) => {
"baseurl" in d && i(0, l = d.baseurl), "title" in d && i(1, n = d.title), "maxlength" in d && i(6, r = d.maxlength), "tags" in d && i(7, o = d.tags), "places" in d && i(8, f = d.places), "theme" in d && i(2, c = d.theme), "show_recurrent" in d && i(9, s = d.show_recurrent), "sidebar" in d && i(3, w = d.sidebar), "external_style" in d && i(4, g = d.external_style); "baseurl" in d && i(0, l = d.baseurl), "title" in d && i(1, n = d.title), "maxlength" in d && i(6, r = d.maxlength), "collection" in d && i(7, o = d.collection), "tags" in d && i(8, f = d.tags), "places" in d && i(9, s = d.places), "theme" in d && i(2, c = d.theme), "show_recurrent" in d && i(10, w = d.show_recurrent), "sidebar" in d && i(3, g = d.sidebar), "external_style" in d && i(4, _ = d.external_style);
}, t.$$.update = () => { }, t.$$.update = () => {
t.$$.dirty & 975 && y(); t.$$.dirty & 1999 && M();
}, [ }, [
l, l,
n, n,
c, c,
w,
g, g,
A, _,
E,
r, r,
o, o,
f, f,
s s,
w
]; ];
} }
class Re extends X { class Re extends X {
@ -508,21 +510,23 @@ class Re extends X {
baseurl: 0, baseurl: 0,
title: 1, title: 1,
maxlength: 6, maxlength: 6,
tags: 7, collection: 7,
places: 8, tags: 8,
places: 9,
theme: 2, theme: 2,
show_recurrent: 9, show_recurrent: 10,
sidebar: 3, sidebar: 3,
external_style: 4 external_style: 4
}, },
null null
), e && (e.target && p(e.target, this, e.anchor), e.props && (this.$set(e.props), x())); ), e && (e.target && k(e.target, this, e.anchor), e.props && (this.$set(e.props), y()));
} }
static get observedAttributes() { static get observedAttributes() {
return [ return [
"baseurl", "baseurl",
"title", "title",
"maxlength", "maxlength",
"collection",
"tags", "tags",
"places", "places",
"theme", "theme",
@ -535,72 +539,78 @@ class Re extends X {
return this.$$.ctx[0]; return this.$$.ctx[0];
} }
set baseurl(e) { set baseurl(e) {
this.$$set({ baseurl: e }), x(); this.$$set({ baseurl: e }), y();
} }
get title() { get title() {
return this.$$.ctx[1]; return this.$$.ctx[1];
} }
set title(e) { set title(e) {
this.$$set({ title: e }), x(); this.$$set({ title: e }), y();
} }
get maxlength() { get maxlength() {
return this.$$.ctx[6]; return this.$$.ctx[6];
} }
set maxlength(e) { set maxlength(e) {
this.$$set({ maxlength: e }), x(); this.$$set({ maxlength: e }), y();
} }
get tags() { get collection() {
return this.$$.ctx[7]; return this.$$.ctx[7];
} }
set tags(e) { set collection(e) {
this.$$set({ tags: e }), x(); this.$$set({ collection: e }), y();
} }
get places() { get tags() {
return this.$$.ctx[8]; return this.$$.ctx[8];
} }
set tags(e) {
this.$$set({ tags: e }), y();
}
get places() {
return this.$$.ctx[9];
}
set places(e) { set places(e) {
this.$$set({ places: e }), x(); this.$$set({ places: e }), y();
} }
get theme() { get theme() {
return this.$$.ctx[2]; return this.$$.ctx[2];
} }
set theme(e) { set theme(e) {
this.$$set({ theme: e }), x(); this.$$set({ theme: e }), y();
} }
get show_recurrent() { get show_recurrent() {
return this.$$.ctx[9]; return this.$$.ctx[10];
} }
set show_recurrent(e) { set show_recurrent(e) {
this.$$set({ show_recurrent: e }), x(); this.$$set({ show_recurrent: e }), y();
} }
get sidebar() { get sidebar() {
return this.$$.ctx[3]; return this.$$.ctx[3];
} }
set sidebar(e) { set sidebar(e) {
this.$$set({ sidebar: e }), x(); this.$$set({ sidebar: e }), y();
} }
get external_style() { get external_style() {
return this.$$.ctx[4]; return this.$$.ctx[4];
} }
set external_style(e) { set external_style(e) {
this.$$set({ external_style: e }), x(); this.$$set({ external_style: e }), y();
} }
} }
customElements.define("gancio-events", Re); customElements.define("gancio-events", Re);
function de(t) { function de(t) {
let e, i, l, n, r = t[1].title + "", o, f, c, s = V(t[1]) + "", w, g, _, A, y = t[1].place.name + "", d, z, h = t[1].media.length && he(t); let e, i, l, n, r = t[1].title + "", o, f, s, c = V(t[1]) + "", w, g, _, A, E = t[1].place.name + "", M, d, h = t[1].media.length && he(t);
return { return {
c() { c() {
e = m("a"), h && h.c(), i = M(), l = m("div"), n = m("strong"), o = $(r), f = M(), c = m("div"), w = $(s), g = M(), _ = m("div"), A = $("@"), d = $(y), a(_, "class", "place"), a(l, "class", "container"), a(e, "href", z = t[0] + "/event/" + (t[1].slug || t[1].id)), a(e, "class", "card"), a(e, "target", "_blank"); e = m("a"), h && h.c(), i = C(), l = m("div"), n = m("strong"), o = z(r), f = C(), s = m("div"), w = z(c), g = C(), _ = m("div"), A = z("@"), M = z(E), a(_, "class", "place"), a(l, "class", "container"), a(e, "href", d = t[0] + "/event/" + (t[1].slug || t[1].id)), a(e, "class", "card"), a(e, "target", "_blank");
}, },
m(v, C) { m(p, v) {
p(v, e, C), h && h.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, c), u(c, w), u(l, g), u(l, _), u(_, A), u(_, d); k(p, e, v), h && h.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, s), u(s, w), u(l, g), u(l, _), u(_, A), u(_, M);
}, },
p(v, C) { p(p, v) {
v[1].media.length ? h ? h.p(v, C) : (h = he(v), h.c(), h.m(e, i)) : h && (h.d(1), h = null), C & 2 && r !== (r = v[1].title + "") && T(o, r), C & 2 && s !== (s = V(v[1]) + "") && T(w, s), C & 2 && y !== (y = v[1].place.name + "") && T(d, y), C & 3 && z !== (z = v[0] + "/event/" + (v[1].slug || v[1].id)) && a(e, "href", z); p[1].media.length ? h ? h.p(p, v) : (h = he(p), h.c(), h.m(e, i)) : h && (h.d(1), h = null), v & 2 && r !== (r = p[1].title + "") && T(o, r), v & 2 && c !== (c = V(p[1]) + "") && T(w, c), v & 2 && E !== (E = p[1].place.name + "") && T(M, E), v & 3 && d !== (d = p[0] + "/event/" + (p[1].slug || p[1].id)) && a(e, "href", d);
}, },
d(v) { d(p) {
v && k(e), h && h.d(); p && x(e), h && h.d();
} }
}; };
} }
@ -611,13 +621,13 @@ function he(t) {
e = m("img"), H(e.src, i = t[2](t[1])) || a(e, "src", i), a(e, "alt", l = t[1].media[0].name), a(e, "style", n = "object-position: " + me(t[1]) + "; aspect-ratio=1.7778;"); e = m("img"), H(e.src, i = t[2](t[1])) || a(e, "src", i), a(e, "alt", l = t[1].media[0].name), a(e, "style", n = "object-position: " + me(t[1]) + "; aspect-ratio=1.7778;");
}, },
m(r, o) { m(r, o) {
p(r, e, o); k(r, e, o);
}, },
p(r, o) { p(r, o) {
o & 2 && !H(e.src, i = r[2](r[1])) && a(e, "src", i), o & 2 && l !== (l = r[1].media[0].name) && a(e, "alt", l), o & 2 && n !== (n = "object-position: " + me(r[1]) + "; aspect-ratio=1.7778;") && a(e, "style", n); o & 2 && !H(e.src, i = r[2](r[1])) && a(e, "src", i), o & 2 && l !== (l = r[1].media[0].name) && a(e, "alt", l), o & 2 && n !== (n = "object-position: " + me(r[1]) + "; aspect-ratio=1.7778;") && a(e, "style", n);
}, },
d(r) { d(r) {
r && k(e); r && x(e);
} }
}; };
} }
@ -628,7 +638,7 @@ function Ie(t) {
i && i.c(), e = pe(), this.c = G; i && i.c(), e = pe(), this.c = G;
}, },
m(l, n) { m(l, n) {
i && i.m(l, n), p(l, e, n); i && i.m(l, n), k(l, e, n);
}, },
p(l, [n]) { p(l, [n]) {
l[1] ? i ? i.p(l, n) : (i = de(l), i.c(), i.m(e.parentNode, e)) : i && (i.d(1), i = null); l[1] ? i ? i.p(l, n) : (i = de(l), i.c(), i.m(e.parentNode, e)) : i && (i.d(1), i = null);
@ -636,7 +646,7 @@ function Ie(t) {
i: G, i: G,
o: G, o: G,
d(l) { d(l) {
i && i.d(l), l && k(e); i && i.d(l), l && x(e);
} }
}; };
} }
@ -649,20 +659,20 @@ function me(t) {
} }
function Oe(t, e, i) { function Oe(t, e, i) {
let { baseurl: l = "https://demo.gancio.org" } = e, { id: n } = e, r = !1, o; let { baseurl: l = "https://demo.gancio.org" } = e, { id: n } = e, r = !1, o;
function f(s, w) { function f(c, w) {
r && fetch(`${w}/api/event/detail/${s}`).then((g) => g.json()).then((g) => i(1, o = g)); r && fetch(`${w}/api/event/detail/${c}`).then((g) => g.json()).then((g) => i(1, o = g));
} }
ke(() => { ke(() => {
r = !0, f(n, l); r = !0, f(n, l);
}); });
function c(s) { function s(c) {
return `${l}/media/thumb/${s.media[0].url}`; return `${l}/media/thumb/${c.media[0].url}`;
} }
return t.$$set = (s) => { return t.$$set = (c) => {
"baseurl" in s && i(0, l = s.baseurl), "id" in s && i(3, n = s.id); "baseurl" in c && i(0, l = c.baseurl), "id" in c && i(3, n = c.id);
}, t.$$.update = () => { }, t.$$.update = () => {
t.$$.dirty & 9 && f(n, l); t.$$.dirty & 9 && f(n, l);
}, [l, o, c, n]; }, [l, o, s, n];
} }
class Ue extends X { class Ue extends X {
constructor(e) { constructor(e) {
@ -679,7 +689,7 @@ class Ue extends X {
_e, _e,
{ baseurl: 0, id: 3 }, { baseurl: 0, id: 3 },
null null
), e && (e.target && p(e.target, this, e.anchor), e.props && (this.$set(e.props), x())); ), e && (e.target && k(e.target, this, e.anchor), e.props && (this.$set(e.props), y()));
} }
static get observedAttributes() { static get observedAttributes() {
return ["baseurl", "id"]; return ["baseurl", "id"];
@ -688,13 +698,13 @@ class Ue extends X {
return this.$$.ctx[0]; return this.$$.ctx[0];
} }
set baseurl(e) { set baseurl(e) {
this.$$set({ baseurl: e }), x(); this.$$set({ baseurl: e }), y();
} }
get id() { get id() {
return this.$$.ctx[3]; return this.$$.ctx[3];
} }
set id(e) { set id(e) {
this.$$set({ id: e }), x(); this.$$set({ id: e }), y();
} }
} }
customElements.define("gancio-event", Ue); customElements.define("gancio-event", Ue);

4334
yarn.lock

File diff suppressed because it is too large Load diff