toggle plugins / save dynamic plugin settings

This commit is contained in:
lesion 2022-08-31 11:16:42 +02:00
parent 982db2b51d
commit 246f1dfb20
No known key found for this signature in database
GPG key ID: 352918250B012177
7 changed files with 433 additions and 377 deletions

View file

@ -10,7 +10,10 @@ v-container
v-card-text
v-form(v-model='valid' ref='form' lazy-validation)
div(v-for='(setting, name) in selectedPlugin.settings')
v-text-field(v-model='pluginSettings[name]' type='text' :label='setting.description')
v-text-field(v-if='setting.type === "TEXT"' v-model='selectedPlugin.settingsValue[name]' type='text' :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-select(v-if='setting.type === "LIST"' v-model='selectedPlugin.settingsValue[name]' :items='setting.items' :label='setting.description')
v-card-actions
v-spacer
@ -19,9 +22,9 @@ v-container
:disable='!valid || loading') {{ $t('common.save') }}
v-card-text
v-card(v-for='plugin in plugins' :key='plugin.name' max-width="400" elevation='10' color='secondary')
v-card(v-for='plugin in plugins' :key='plugin.name' max-width="400" elevation='10' color='secondary' dark)
v-card-title.d-block {{ plugin.name }}
v-switch.float-right(:label="$t('common.enable')" @change='toggleEnable(plugin)')
v-switch.float-right(:label="$t('common.enable')" v-model='plugin.settingsValue.enable' @change='toggleEnable(plugin)')
v-card-text
p {{ plugin.description }}
blockquote author: {{ plugin.author }}
@ -33,6 +36,7 @@ v-container
</template>
<script>
import { mdiPencil, mdiChevronLeft, mdiChevronRight, mdiMagnify, mdiEye } from '@mdi/js'
import { mapActions, mapState } from 'vuex'
export default {
data() {
@ -42,7 +46,6 @@ export default {
dialog: false,
valid: false,
selectedPlugin: {},
pluginSettings: {},
plugins: [],
headers: [
{ value: 'name', text: 'Name' },
@ -51,22 +54,26 @@ export default {
]
}
},
async fetch() {
async mounted() {
this.plugins = await this.$axios.$get('/plugins')
},
computed: mapState(['settings']),
methods: {
saveSettings() {
console.error(this.pluginSettings)
this.setSetting({ key: 'plugin_' + this.selectedPlugin.name, value: this.pluginSettings })
...mapActions(['setSetting']),
async saveSettings() {
this.loading = true
this.setSetting({
key: 'plugin_' + this.selectedPlugin.name,
value: this.selectedPlugin.settingsValue
})
this.loading = false
this.dialog = false
},
toggleEnable(plugin) {
this.pluginSettings.enable = !this.pluginSettings.enable
this.setSetting({ key: 'plugin_' + this.selectedPlugin.name, value: this.pluginSettings })
async toggleEnable(plugin) {
await this.$axios.$put(`/plugin/${plugin.name}`)
},
setOptions(plugin) {
console.error(plugin)
this.selectedPlugin = plugin
console.error(plugin)
this.dialog = true
}
}

View file

@ -1,295 +1,298 @@
{
"common": {
"add_event": "Add event",
"next": "Next",
"export": "Export",
"send": "Send",
"where": "Where",
"address": "Address",
"when": "When",
"what": "What",
"media": "Media",
"login": "Login",
"email": "E-mail",
"password": "Password",
"register": "Register",
"description": "Description",
"remove": "Remove",
"hide": "Hide",
"search": "Search",
"edit": "Edit",
"info": "Info",
"confirm": "Confirm",
"admin": "Admin",
"users": "Users",
"events": "Events",
"places": "Places",
"settings": "Options",
"actions": "Actions",
"deactivate": "Turn off",
"remove_admin": "Remove admin",
"activate": "Activate",
"save": "Save",
"preview": "Preview",
"logout": "Log out",
"share": "Share",
"name": "Name",
"associate": "Associate",
"edit_event": "Edit event",
"related": "Related",
"add": "Add",
"logout_ok": "Logged out",
"copy": "Copy",
"recover_password": "Recover password",
"new_password": "New password",
"new_user": "New user",
"ok": "Ok",
"cancel": "Cancel",
"enable": "Enable",
"disable": "Disable",
"me": "You",
"password_updated": "Password changed.",
"resources": "Resources",
"n_resources": "no resource|a resource|{n} resources",
"activate_user": "Confirmed",
"displayname": "Display name",
"federation": "Federation",
"set_password": "Set password",
"copy_link": "Copy link",
"send_via_mail": "Send e-mail",
"add_to_calendar": "Add to calendar",
"instances": "Instances",
"copied": "Copied",
"embed": "Embed",
"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",
"feed": "RSS Feed",
"feed_url_copied": "Open the copied feed URL in your RSS feed reader",
"follow_me_title": "Follow updates from fediverse",
"follow": "Follow",
"moderation": "Moderation",
"user": "User",
"authorize": "Authorize",
"title": "Title",
"filter": "Filter",
"event": "Event",
"pause": "Pause",
"start": "Start",
"fediverse": "Fediverse",
"skip": "Skip",
"delete": "Remove",
"announcements": "Announcements",
"url": "URL",
"place": "Place",
"tags": "Tags",
"theme": "Theme",
"reset": "Reset",
"import": "Import",
"max_events": "N. max events",
"label": "Label",
"collections": "Collections",
"close": "Close"
},
"login": {
"description": "By logging in you can publish new events.",
"check_email": "Check your e-mail inbox and spam.",
"not_registered": "Not registered?",
"forgot_password": "Forgot your password?",
"error": "Could not log in. Check your login info.",
"insert_email": "Enter your e-mail address",
"ok": "Logged in"
},
"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.",
"email_description": "You can get events that interest sent via e-mail.",
"insert_your_address": "Enter your e-mail address",
"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.",
"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": {
"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: ",
"complete": "Registration has to be confirmed.",
"first_user": "Administrator created"
},
"event": {
"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. ",
"same_day": "on same day",
"what_description": "Title",
"description_description": "Description",
"tag_description": "Tag",
"media_description": "You can add a flyer (optional)",
"added": "Event added",
"saved": "Event saved",
"added_anon": "Event added, but has yet to be confirmed.",
"updated": "Event updated",
"where_description": "Where's the event? If not present you can create it.",
"confirmed": "Event confirmed",
"not_found": "Could not find event",
"remove_confirmation": "Are you sure you want to remove this event?",
"recurrent": "Recurring",
"edit_recurrent": "Edit recurring event:",
"show_recurrent": "recurring events",
"show_past": "also prior events",
"only_future": "only upcoming events",
"recurrent_description": "Choose frequency and select days",
"multidate_description": "Is it a festival? Choose when it starts and ends",
"multidate": "More days",
"normal": "Normal",
"normal_description": "Choose the day.",
"recurrent_1w_days": "Each {days}",
"recurrent_2w_days": "A {days} every other",
"recurrent_1m_days": "|The {days} of each month|{days} of each month",
"recurrent_2m_days": "|The {days} a month every other|The {days} a month every other",
"recurrent_1m_ordinal": "The {n} {days} of each month",
"recurrent_2m_ordinal": "|The {n} {days} a month every other|The {n} {days} a month every other",
"each_week": "Each week",
"each_2w": "Every other weeks",
"each_month": "Each month",
"due": "until",
"from": "From",
"image_too_big": "The image can't be bigger than 4MB",
"interact_with_me_at": "Interact with me on fediverse at",
"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)",
"interact_with_me": "Follow me",
"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.",
"import_URL": "Import from URL",
"import_ICS": "Import from ICS",
"ics": "ICS",
"import_description": "You can import events from other platforms and other instances through standard formats (ics and h-event)",
"alt_text_description": "Description for people with visual impairments",
"choose_focal_point": "Choose the focal point",
"remove_media_confirmation": "Do you confirm the image removal?",
"download_flyer": "Download flyer"
},
"admin": {
"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",
"delete_user": "Remove",
"remove_admin": "Remove admin",
"disable_user_confirm": "Are you sure you want to disable {user}?",
"delete_user_confirm": "Are you sure you want to remove {user}?",
"disable_admin_user_confirm": "Are you sure to remove admin permissions from {user}?",
"enable_admin_user_confirm": "Are sure to add admin permissions to {user}",
"user_remove_ok": "User removed",
"user_create_ok": "User created",
"event_remove_ok": "Event removed",
"allow_registration_description": "Allow open registrations?",
"allow_anon_event": "Allow anonymous events (has to be confirmed)?",
"allow_recurrent_event": "Allow recurring events",
"recurrent_event_visible": "Show recurring events by default",
"federation": "Federation / ActivityPub",
"enable_federation": "Turn on federation",
"enable_federation_help": "It will be possible to follow this instance from the fediverse",
"add_instance": "Add instance",
"select_instance_timezone": "Time zone",
"enable_resources": "Turn on resources",
"enable_resources_help": "Allows adding resources to the event from the fediverse",
"hide_boost_bookmark": "Hides boost/bookmarks",
"hide_boost_bookmark_help": "Hides the small icons showing the number of boosts and bookmarks coming from the fediverse",
"block": "Block",
"unblock": "Unblock",
"user_add_help": "An e-mail with instructions on confirming the subscription and choosing a password will be sent to the new user",
"instance_name": "Instance name",
"show_resource": "Show resource",
"hide_resource": "Hide resource",
"delete_resource": "Delete resource",
"delete_resource_confirm": "Are you sure you want to delete this resource?",
"block_user": "Block user",
"filter_instances": "Filter instances",
"filter_users": "Filter users",
"resources": "Resources",
"user_blocked": "User {user} blocked",
"favicon": "Logo",
"user_block_confirm": "Are you sure you want to block user {user}?",
"instance_block_confirm": "Are you sure you want block instance {instance}?",
"delete_announcement_confirm": "Are you sure you want to remove the announcement?",
"announcement_remove_ok": "Announce removed",
"announcement_description": "In this section you can insert announcements to remain on the homepage",
"instance_locale": "Default language",
"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.",
"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.",
"title_description": "It is used in the title of the page, in the subject of the e-mail to export RSS and ICS feeds.",
"description_description": "Appears in the header next to the title",
"instance_place": "Indicative place of this instance",
"instance_name_help": "ActivityPub's account to follow",
"enable_trusted_instances": "Turn on friendly instances",
"trusted_instances_help": "The list of friendly instances will be shown in the header",
"add_trusted_instance": "Add a friendly instance",
"instance_place_help": "The label to show in instances of others",
"delete_trusted_instance_confirm": "Do you really want to delete this item from the friend instance menu?",
"is_dark": "Dark theme",
"add_link": "Add link",
"footer_links": "Footer links",
"delete_footer_link_confirm": "Sure to remove this link?",
"edit_place": "Edit place",
"new_announcement": "New announcement",
"show_smtp_setup": "Email settings",
"smtp_hostname": "SMTP Hostname",
"smtp_port": "SMTP Port",
"smtp_secure": "SMTP Secure (TLS or STARTTLS)",
"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_test_success": "A test email is sent to {admin_email}, please check your inbox",
"smtp_test_button": "Send a test email",
"smtp_use_sendmail": "Use sendmail",
"sender_email": "Sender e-mail",
"widget": "Widget",
"wrong_domain_warning": "The baseurl configured in config.json <b>({baseurl})</b> differs from the one you're visiting <b>({url})</b>",
"new_collection": "New collection",
"collections_description": "Collections are groupings of events by tags and places. They will be displayed on the home page",
"edit_collection": "Edit Collection"
},
"auth": {
"not_confirmed": "Not confirmed yet…",
"fail": "Could not log in. Are you sure the password is correct?"
},
"settings": {
"update_confirm": "Do you want to save your modification?",
"change_password": "Change your password",
"password_updated": "Password changed.",
"danger_section": "Dangerous section",
"remove_account": "By pressing the following button your user account will be deleted. Events you published won't be.",
"remove_account_confirm": "You are about to permanently delete your account"
},
"error": {
"nick_taken": "This nickname is already in use.",
"email_taken": "This e-mail is already in use."
},
"confirm": {
"title": "User confirmation",
"not_valid": "Something went wrong.",
"valid": "Your account is confirmed, you can now <a href=\"/login\">log in</a>"
},
"ordinal": {
"1": "first",
"2": "second",
"3": "third",
"4": "fourth",
"5": "fifth",
"-1": "last"
},
"validators": {
"required": "{fieldName} is required",
"email": "Insert a valid email"
},
"about": "\n <p><a href='https://gancio.org'>Gancio</a> is a shared agenda for local communities.</p>\n ",
"oauth": {
"authorization_request": "The application <code>{app}</code> asks for the following authorization on <code>{instance_name}</code>:",
"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!"
"common": {
"add_event": "Add event",
"next": "Next",
"export": "Export",
"send": "Send",
"where": "Where",
"address": "Address",
"when": "When",
"what": "What",
"media": "Media",
"login": "Login",
"email": "E-mail",
"password": "Password",
"register": "Register",
"description": "Description",
"remove": "Remove",
"hide": "Hide",
"search": "Search",
"edit": "Edit",
"info": "Info",
"confirm": "Confirm",
"admin": "Admin",
"users": "Users",
"events": "Events",
"places": "Places",
"settings": "Options",
"actions": "Actions",
"deactivate": "Turn off",
"remove_admin": "Remove admin",
"activate": "Activate",
"save": "Save",
"preview": "Preview",
"logout": "Log out",
"share": "Share",
"name": "Name",
"associate": "Associate",
"edit_event": "Edit event",
"related": "Related",
"add": "Add",
"logout_ok": "Logged out",
"copy": "Copy",
"recover_password": "Recover password",
"new_password": "New password",
"new_user": "New user",
"ok": "Ok",
"cancel": "Cancel",
"enable": "Enable",
"disable": "Disable",
"me": "You",
"password_updated": "Password changed.",
"resources": "Resources",
"n_resources": "no resource|a resource|{n} resources",
"activate_user": "Confirmed",
"displayname": "Display name",
"federation": "Federation",
"set_password": "Set password",
"copy_link": "Copy link",
"send_via_mail": "Send e-mail",
"add_to_calendar": "Add to calendar",
"instances": "Instances",
"copied": "Copied",
"embed": "Embed",
"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",
"feed": "RSS Feed",
"feed_url_copied": "Open the copied feed URL in your RSS feed reader",
"follow_me_title": "Follow updates from fediverse",
"follow": "Follow",
"moderation": "Moderation",
"user": "User",
"authorize": "Authorize",
"title": "Title",
"filter": "Filter",
"event": "Event",
"pause": "Pause",
"start": "Start",
"fediverse": "Fediverse",
"skip": "Skip",
"delete": "Remove",
"announcements": "Announcements",
"url": "URL",
"place": "Place",
"tags": "Tags",
"theme": "Theme",
"reset": "Reset",
"import": "Import",
"max_events": "N. max events",
"label": "Label",
"collections": "Collections",
"close": "Close",
"plugins": "Plugins"
},
"login": {
"description": "By logging in you can publish new events.",
"check_email": "Check your e-mail inbox and spam.",
"not_registered": "Not registered?",
"forgot_password": "Forgot your password?",
"error": "Could not log in. Check your login info.",
"insert_email": "Enter your e-mail address",
"ok": "Logged in"
},
"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.",
"email_description": "You can get events that interest sent via e-mail.",
"insert_your_address": "Enter your e-mail address",
"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.",
"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": {
"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: ",
"complete": "Registration has to be confirmed.",
"first_user": "Administrator created"
},
"event": {
"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. ",
"same_day": "on same day",
"what_description": "Title",
"description_description": "Description",
"tag_description": "Tag",
"media_description": "You can add a flyer (optional)",
"added": "Event added",
"saved": "Event saved",
"added_anon": "Event added, but has yet to be confirmed.",
"updated": "Event updated",
"where_description": "Where's the event? If not present you can create it.",
"confirmed": "Event confirmed",
"not_found": "Could not find event",
"remove_confirmation": "Are you sure you want to remove this event?",
"recurrent": "Recurring",
"edit_recurrent": "Edit recurring event:",
"show_recurrent": "recurring events",
"show_past": "also prior events",
"only_future": "only upcoming events",
"recurrent_description": "Choose frequency and select days",
"multidate_description": "Is it a festival? Choose when it starts and ends",
"multidate": "More days",
"normal": "Normal",
"normal_description": "Choose the day.",
"recurrent_1w_days": "Each {days}",
"recurrent_2w_days": "A {days} every other",
"recurrent_1m_days": "|The {days} of each month|{days} of each month",
"recurrent_2m_days": "|The {days} a month every other|The {days} a month every other",
"recurrent_1m_ordinal": "The {n} {days} of each month",
"recurrent_2m_ordinal": "|The {n} {days} a month every other|The {n} {days} a month every other",
"each_week": "Each week",
"each_2w": "Every other weeks",
"each_month": "Each month",
"due": "until",
"from": "From",
"image_too_big": "The image can't be bigger than 4MB",
"interact_with_me_at": "Interact with me on fediverse at",
"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)",
"interact_with_me": "Follow me",
"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.",
"import_URL": "Import from URL",
"import_ICS": "Import from ICS",
"ics": "ICS",
"import_description": "You can import events from other platforms and other instances through standard formats (ics and h-event)",
"alt_text_description": "Description for people with visual impairments",
"choose_focal_point": "Choose the focal point",
"remove_media_confirmation": "Do you confirm the image removal?",
"download_flyer": "Download flyer"
},
"admin": {
"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",
"delete_user": "Remove",
"remove_admin": "Remove admin",
"disable_user_confirm": "Are you sure you want to disable {user}?",
"delete_user_confirm": "Are you sure you want to remove {user}?",
"disable_admin_user_confirm": "Are you sure to remove admin permissions from {user}?",
"enable_admin_user_confirm": "Are sure to add admin permissions to {user}",
"user_remove_ok": "User removed",
"user_create_ok": "User created",
"event_remove_ok": "Event removed",
"allow_registration_description": "Allow open registrations?",
"allow_anon_event": "Allow anonymous events (has to be confirmed)?",
"allow_recurrent_event": "Allow recurring events",
"recurrent_event_visible": "Show recurring events by default",
"federation": "Federation / ActivityPub",
"enable_federation": "Turn on federation",
"enable_federation_help": "It will be possible to follow this instance from the fediverse",
"add_instance": "Add instance",
"select_instance_timezone": "Time zone",
"enable_resources": "Turn on resources",
"enable_resources_help": "Allows adding resources to the event from the fediverse",
"hide_boost_bookmark": "Hides boost/bookmarks",
"hide_boost_bookmark_help": "Hides the small icons showing the number of boosts and bookmarks coming from the fediverse",
"block": "Block",
"unblock": "Unblock",
"user_add_help": "An e-mail with instructions on confirming the subscription and choosing a password will be sent to the new user",
"instance_name": "Instance name",
"show_resource": "Show resource",
"hide_resource": "Hide resource",
"delete_resource": "Delete resource",
"delete_resource_confirm": "Are you sure you want to delete this resource?",
"block_user": "Block user",
"filter_instances": "Filter instances",
"filter_users": "Filter users",
"resources": "Resources",
"user_blocked": "User {user} blocked",
"favicon": "Logo",
"user_block_confirm": "Are you sure you want to block user {user}?",
"instance_block_confirm": "Are you sure you want block instance {instance}?",
"delete_announcement_confirm": "Are you sure you want to remove the announcement?",
"announcement_remove_ok": "Announce removed",
"announcement_description": "In this section you can insert announcements to remain on the homepage",
"instance_locale": "Default language",
"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.",
"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.",
"title_description": "It is used in the title of the page, in the subject of the e-mail to export RSS and ICS feeds.",
"description_description": "Appears in the header next to the title",
"instance_place": "Indicative place of this instance",
"instance_name_help": "ActivityPub's account to follow",
"enable_trusted_instances": "Turn on friendly instances",
"trusted_instances_help": "The list of friendly instances will be shown in the header",
"add_trusted_instance": "Add a friendly instance",
"instance_place_help": "The label to show in instances of others",
"delete_trusted_instance_confirm": "Do you really want to delete this item from the friend instance menu?",
"is_dark": "Dark theme",
"add_link": "Add link",
"footer_links": "Footer links",
"delete_footer_link_confirm": "Sure to remove this link?",
"edit_place": "Edit place",
"new_announcement": "New announcement",
"show_smtp_setup": "Email settings",
"smtp_hostname": "SMTP Hostname",
"smtp_port": "SMTP Port",
"smtp_secure": "SMTP Secure (TLS or STARTTLS)",
"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_test_success": "A test email is sent to {admin_email}, please check your inbox",
"smtp_test_button": "Send a test email",
"smtp_use_sendmail": "Use sendmail",
"sender_email": "Sender e-mail",
"widget": "Widget",
"wrong_domain_warning": "The baseurl configured in config.json <b>({baseurl})</b> differs from the one you're visiting <b>({url})</b>",
"new_collection": "New collection",
"collections_description": "Collections are groupings of events by tags and places. They will be displayed on the home page",
"edit_collection": "Edit Collection",
"config_plugin": "Plugin configuration",
"plugins_description": ""
},
"auth": {
"not_confirmed": "Not confirmed yet…",
"fail": "Could not log in. Are you sure the password is correct?"
},
"settings": {
"update_confirm": "Do you want to save your modification?",
"change_password": "Change your password",
"password_updated": "Password changed.",
"danger_section": "Dangerous section",
"remove_account": "By pressing the following button your user account will be deleted. Events you published won't be.",
"remove_account_confirm": "You are about to permanently delete your account"
},
"error": {
"nick_taken": "This nickname is already in use.",
"email_taken": "This e-mail is already in use."
},
"confirm": {
"title": "User confirmation",
"not_valid": "Something went wrong.",
"valid": "Your account is confirmed, you can now <a href=\"/login\">log in</a>"
},
"ordinal": {
"1": "first",
"2": "second",
"3": "third",
"4": "fourth",
"5": "fifth",
"-1": "last"
},
"validators": {
"required": "{fieldName} is required",
"email": "Insert a valid email"
},
"about": "\n <p><a href='https://gancio.org'>Gancio</a> is a shared agenda for local communities.</p>\n ",
"oauth": {
"authorization_request": "The application <code>{app}</code> asks for the following authorization on <code>{instance_name}</code>:",
"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!"
}
}

View file

@ -69,7 +69,7 @@
"sequelize-slugify": "^1.6.1",
"sharp": "^0.27.2",
"sqlite3": "^5.0.11",
"telegraf": "^4.9.0",
"telegraf": "^4.9.1",
"tiptap": "^1.32.0",
"tiptap-extensions": "^1.35.0",
"umzug": "^2.3.0",

View file

@ -5,28 +5,69 @@ const config = require('../../config')
const pluginController = {
plugins: [],
getAll(req, res, next) {
res.json(pluginController.plugins)
getAll(_req, res) {
const settingsController = require('./settings')
// return plugins and inner settings
const plugins = pluginController.plugins.map(p => {
if (settingsController.settings['plugin_' + p.name]) {
p.settingsValue = settingsController.settings['plugin_' + p.name]
}
return p
})
return res.json(plugins)
},
togglePlugin(req, res, next) {
const plugin = req.params.plugin
if (this.plugins[plugin].enable) {
togglePlugin(req, res) {
const settingsController = require('./settings')
const pluginName = req.params.plugin
const pluginSettings = settingsController.settings['plugin_' + pluginName]
if (!pluginSettings) { return res.sendStatus(404) }
if (!pluginSettings.enable) {
pluginController.loadPlugin(pluginName)
} else {
pluginController.unloadPlugin(pluginName)
}
settingsController.set('plugin_' + pluginName,
{ ...pluginSettings, enable: !pluginSettings.enable })
res.json()
},
unloadPlugin(plugin) {
log.info('Unload plugin ' + plugin)
},
loadPlugin(pluginName) {
const plugin = this.plugins[pluginName]
unloadPlugin(pluginName) {
const settingsController = require('./settings')
const plugin = pluginController.plugins.find(p => p.name === pluginName)
const settings = settingsController.settings['plugin_' + pluginName]
if (!plugin) {
log.warn(`Plugin ${pluginName} not found`)
return
}
const notifier = require('../../notifier')
log.info('Unload plugin ' + plugin)
if (typeof plugin.onEventCreate === 'function') {
notifier.emitter.off('Create', plugin.onEventCreate)
}
if (typeof plugin.onEventDelete === 'function') {
notifier.emitter.off('Delete', plugin.onEventDelete)
}
if (typeof plugin.onEventUpdate === 'function') {
notifier.emitter.off('Update', plugin.onEventUpdate)
}
if (plugin.unload && typeof plugin.unload === 'function') {
plugin.unload({ settings: settingsController.settings }, settings)
}
},
loadPlugin(pluginName) {
const settingsController = require('./settings')
const plugin = pluginController.plugins.find(p => p.name === pluginName)
const settings = settingsController.settings['plugin_' + pluginName]
if (!plugin) {
log.warn(`Plugin ${pluginName} not found`)
return
}
const notifier = require('../../notifier')
log.info('Load plugin ' + plugin)
if (typeof plugin.onEventCreate === 'function') {
notifier.emitter.on('Create', plugin.onEventCreate)
}
@ -37,7 +78,9 @@ const pluginController = {
notifier.emitter.on('Update', plugin.onEventUpdate)
}
plugin.load({ settings: settingsController.settings }, settingsController.settings.plugins)
if (plugin.unload && typeof plugin.unload === 'function') {
plugin.load({ settings: settingsController.settings }, settings)
}
},
_load() {
@ -46,7 +89,6 @@ const pluginController = {
const plugins_path = config.plugins_path || path.resolve(process.env.cwd || '', 'gancio_plugins')
log.info(`Loading plugin ${plugins_path}`)
if (fs.existsSync(plugins_path)) {
const notifier = require('../../notifier')
const plugins = fs.readdirSync(plugins_path)
.map(e => path.resolve(plugins_path, e, 'index.js'))
.filter(index => fs.existsSync(index))
@ -57,19 +99,11 @@ const pluginController = {
const name = plugin.configuration.name
console.log(`Found plugin '${name}'`)
pluginController.plugins.push(plugin.configuration)
console.error(settingsController.settings['plugin_' + name])
if (settingsController.settings['plugin_' + name]) {
const pluginSetting = settingsController.settings['plugin_' + name]
if (pluginSetting.enable) {
plugin.load({ settings: settingsController.settings }, settingsController.settings.plugins)
if (typeof plugin.onEventCreate === 'function') {
notifier.emitter.on('Create', plugin.onEventCreate)
}
if (typeof plugin.onEventDelete === 'function') {
notifier.emitter.on('Delete', plugin.onEventDelete)
}
if (typeof plugin.onEventUpdate === 'function') {
notifier.emitter.on('Update', plugin.onEventUpdate)
}
pluginController.loadPlugin(name)
}
} else {
settingsController.set('plugin_' + name, { enable: false })

View file

@ -99,7 +99,7 @@ if (config.status !== 'READY') {
* [usage example](https://framagit.org/les/gancio/-/blob/master/webcomponents/src/GancioEvents.svelte#L18-42)
*/
api.get('/events', cors, eventController.select)
api.get('/events', cors, eventController.select)
/**
* Add a new event
@ -192,6 +192,7 @@ if (config.status !== 'READY') {
// - PLUGINS
api.get('/plugins', isAdmin, pluginController.getAll)
api.put('/plugin/:plugin', isAdmin, pluginController.togglePlugin)
// OAUTH
api.get('/clients', isAuth, oauthController.getClients)

View file

@ -48,14 +48,14 @@ domPurify.addHook('beforeSanitizeElements', node => {
module.exports = {
randomString (length = 12) {
randomString(length = 12) {
const wishlist = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
return Array.from(crypto.randomFillSync(new Uint32Array(length)))
.map(x => wishlist[x % wishlist.length])
.join('')
},
sanitizeHTML (html) {
sanitizeHTML(html) {
return domPurify.sanitize(html, {
ALLOWED_TAGS: ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'br', 'i', 'span',
'h6', 'b', 'a', 'li', 'ul', 'ol', 'code', 'blockquote', 'u', 's', 'strong'],
@ -63,7 +63,7 @@ module.exports = {
})
},
async setUserLocale (req, res, next) {
async setUserLocale(req, res, next) {
// select locale based on cookie? and accept-language header
acceptLanguage.languages(Object.keys(locales))
res.locals.acceptedLocale = acceptLanguage.get(req.headers['accept-language'])
@ -71,28 +71,45 @@ module.exports = {
next()
},
async initSettings (_req, res, next) {
async initSettings(_req, res, next) {
// initialize settings
res.locals.settings = cloneDeep(settingsController.settings)
delete res.locals.settings.smtp
delete res.locals.settings.publicKey
res.locals.settings.baseurl = config.baseurl
res.locals.settings.hostname = config.hostname
res.locals.settings.title = res.locals.settings.title || config.title
res.locals.settings.description = res.locals.settings.description || config.description
res.locals.settings.version = pkg.version
// res.locals.settings = cloneDeep(settingsController.settings)
const settings = settingsController.settings
res.locals.settings = {
title: settings.title || config.title,
description: settings.description || config.description,
baseurl: config.baseurl,
hostname: config.hostname,
version: pkg.version,
instance_timezone: settings.instance_timezone,
instance_locale: settings.instance_locale,
instance_name: settings.instance_name,
instance_place: settings.instance_place,
allow_registration: settings.allow_registration,
allow_anon_event: settings.allow_anon_event,
allow_recurrent_event: settings.allow_recurrent_event,
recurrent_event_visible: settings.recurrent_event_visible,
enable_federation: settings.enable_federation,
enable_resources: settings.enable_resources,
hide_boosts: settings.hide_boosts,
enable_trusted_instances: settings.enable_trusted_instances,
trusted_instances: settings.trusted_instances,
'theme.is_dark': settings['theme.is_dark'],
'theme.primary': settings['theme.primary'],
footerLinks: settings.footerLinks
}
// set user locale
res.locals.user_locale = settingsController.user_locale[res.locals.acceptedLocale]
dayjs.tz.setDefault(res.locals.settings.instance_timezone)
next()
},
serveStatic () {
serveStatic() {
const router = express.Router()
// serve images/thumb
router.use('/media/', express.static(config.upload_path, { immutable: true, maxAge: '1y' } ), (_req, res) => res.sendStatus(404))
router.use('/media/', express.static(config.upload_path, { immutable: true, maxAge: '1y' }), (_req, res) => res.sendStatus(404))
router.use('/noimg.svg', express.static('./static/noimg.svg'))
router.use('/logo.png', (req, res, next) => {
const logoPath = res.locals.settings.logo || './static/gancio'
return express.static(logoPath + '.png')(req, res, next)
@ -106,12 +123,12 @@ module.exports = {
return router
},
logRequest (req, _res, next) {
logRequest(req, _res, next) {
log.debug(`${req.method} ${req.path}`)
next()
},
col (field) {
col(field) {
if (config.db.dialect === 'postgres') {
return '"' + field.split('.').join('"."') + '"'
} else if (config.db.dialect === 'mariadb') {
@ -121,14 +138,14 @@ module.exports = {
}
},
async getImageFromURL (url) {
async getImageFromURL(url) {
log.debug(`getImageFromURL ${url}`)
const filename = crypto.randomBytes(16).toString('hex')
const sharpStream = sharp({ failOnError: true })
const promises = [
sharpStream.clone().resize(500, null, { withoutEnlargement: true }).jpeg({ effort: 6, mozjpeg: true }).toFile(path.resolve(config.upload_path, 'thumb', filename + '.jpg')),
sharpStream.clone().resize(1200, null, { withoutEnlargement: true } ).jpeg({ quality: 95, effort: 6, mozjpeg: true}).toFile(path.resolve(config.upload_path, filename + '.jpg')),
sharpStream.clone().resize(1200, null, { withoutEnlargement: true }).jpeg({ quality: 95, effort: 6, mozjpeg: true }).toFile(path.resolve(config.upload_path, filename + '.jpg')),
]
const response = await axios({ method: 'GET', url: encodeURI(url), responseType: 'stream' })
@ -157,7 +174,7 @@ module.exports = {
* Import events from url
* It does supports ICS and H-EVENT
*/
async importURL (req, res) {
async importURL(req, res) {
const URL = req.query.URL
try {
const response = await axios.get(URL)
@ -210,7 +227,7 @@ module.exports = {
}
},
getWeekdayN (date, n, weekday) {
getWeekdayN(date, n, weekday) {
let cursor
if (n === -1) {
cursor = date.endOf('month')
@ -227,8 +244,8 @@ module.exports = {
log.debug(cursor)
return cursor
},
async APRedirect (req, res, next) {
async APRedirect(req, res, next) {
const acceptJson = req.accepts('html', 'application/activity+json') === 'application/activity+json'
if (acceptJson) {
const eventController = require('../server/api/controller/event')
@ -240,7 +257,7 @@ module.exports = {
next()
},
async feedRedirect (req, res, next) {
async feedRedirect(req, res, next) {
const accepted = req.accepts('html', 'application/rss+xml', 'text/calendar')
if (['application/rss+xml', 'text/calendar'].includes(accepted) && /^\/(tag|place|collection)\/.*/.test(req.path)) {
return res.redirect((accepted === 'application/rss+xml' ? '/feed/rss' : '/feed/ics') + req.path)

View file

@ -4846,11 +4846,6 @@ es-array-method-boxes-properly@^1.0.0:
resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e"
integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==
es-main@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/es-main/-/es-main-1.2.0.tgz#b85954f1d9d9f542fcb08685ec19515f969bad16"
integrity sha512-A4tCSY43O/mH4rHjG1n0mI4DhK2BmKDr8Lk8PXK/GBB6zxGFGmIW4bbkbTQ2Gi9iNamMZ9vbGrwjZOIeiM7vMw==
es-to-primitive@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
@ -8109,11 +8104,6 @@ mkdirp@^1.0.3, mkdirp@^1.0.4:
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
module-alias@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/module-alias/-/module-alias-2.2.2.tgz#151cdcecc24e25739ff0aa6e51e1c5716974c0e0"
integrity sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q==
moment-timezone@^0.5.34:
version "0.5.37"
resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.37.tgz#adf97f719c4e458fdb12e2b4e87b8bec9f4eef1e"
@ -8143,6 +8133,11 @@ move-concurrently@^1.0.1:
rimraf "^2.5.4"
run-queue "^1.0.3"
mri@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b"
integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==
mrmime@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.1.tgz#5f90c825fad4bdd41dc914eff5d1a8cfdaf24f27"
@ -11672,21 +11667,19 @@ tar@^6.0.2, tar@^6.1.11, tar@^6.1.2:
mkdirp "^1.0.3"
yallist "^4.0.0"
telegraf@^4.9.0:
version "4.9.0"
resolved "https://registry.yarnpkg.com/telegraf/-/telegraf-4.9.0.tgz#30997bf6cbc941bff0bb698b13154647fc918032"
integrity sha512-fL+KLaYRElo4aNtrqAHmFdVsAMHHOHbmdTsAAzMJafhXJu1oYKTRMNipJ/YUvwNd5DnZY+zmGMgVVe1M/dkN4w==
telegraf@^4.9.1:
version "4.9.1"
resolved "https://registry.yarnpkg.com/telegraf/-/telegraf-4.9.1.tgz#bc12e98ea75f2aaf72c5c4a8a0d49c68837bf0b7"
integrity sha512-MukWpKvAZ6/HpT3yHXz+jwUf2HsPa9TcsqPLQjJ+kHNGUS2PLgaNX690ExdWmWPuxjVjC4wNHmZ9JetO3C/tVA==
dependencies:
abort-controller "^3.0.0"
debug "^4.3.3"
es-main "^1.2.0"
minimist "^1.2.6"
module-alias "^2.2.2"
mri "^1.2.0"
node-fetch "^2.6.7"
p-timeout "^4.1.0"
safe-compare "^1.1.4"
sandwich-stream "^2.0.2"
typegram "github:MKRhere/typegram#e2ba9f01f14b96c6dbb1c617e66692a3cc776cf6"
typegram "^3.11.0"
terminal-link@^2.0.0:
version "2.1.1"
@ -12069,9 +12062,10 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
"typegram@github:MKRhere/typegram#e2ba9f01f14b96c6dbb1c617e66692a3cc776cf6":
version "3.10.0"
resolved "https://codeload.github.com/MKRhere/typegram/tar.gz/e2ba9f01f14b96c6dbb1c617e66692a3cc776cf6"
typegram@^3.11.0:
version "3.11.0"
resolved "https://registry.yarnpkg.com/typegram/-/typegram-3.11.0.tgz#72e3a8ed0d77864916af465d2c809adf2353ee96"
integrity sha512-4p6u+AFognlsDgBue8Hla2jO7Ax+UQXcLa27LC7xDdAeR9LTe+Cr4vJrYpoO1wgj/BFWgXTeboaH/+1YgWyfpA==
ua-parser-js@^1.0.2:
version "1.0.2"