diff --git a/server/api/controller/event.js b/server/api/controller/event.js index 4522386d..f2a75226 100644 --- a/server/api/controller/event.js +++ b/server/api/controller/event.js @@ -236,6 +236,8 @@ const eventController = { if (req.file) { eventDetails.image_path = req.file.filename + } else if (body.image_url) { + eventDetails.image_path = await helpers.getImageFromURL(body.image_url) } const event = await Event.create(eventDetails) @@ -289,6 +291,7 @@ const eventController = { } const body = req.body const event = await Event.findByPk(body.id) + if (!event) return res.sendStatus(404) if (!req.user.is_admin && event.userId !== req.user.id) { return res.sendStatus(403) } @@ -316,6 +319,8 @@ const eventController = { } } eventDetails.image_path = req.file.filename + } else if (body.image_url) { + eventDetails.image_path = await helpers.getImageFromURL(body.image_url) } await event.update(eventDetails) diff --git a/server/api/index.js b/server/api/index.js index 5d85bc9f..00d423d8 100644 --- a/server/api/index.js +++ b/server/api/index.js @@ -86,8 +86,7 @@ api.put('/place', isAdmin, eventController.updatePlace) * @param {array} [recurrent.days] - array of days * @param {image} [image] - Image */ -api.post('/event', upload.single('image'), eventController.add) - +api.post('/event', hasPerm('event:write'), upload.single('image'), eventController.add) api.put('/event', hasPerm('event:write'), upload.single('image'), eventController.update) // remove event diff --git a/server/api/storage.js b/server/api/storage.js index 5f425f74..5557848e 100644 --- a/server/api/storage.js +++ b/server/api/storage.js @@ -45,7 +45,7 @@ const DiskStorage = { .pipe(outStream) .on('error', err) - outStream.on('finish', function () { + outStream.on('finish', () => { cb(null, { destination: config.upload_path, filename, diff --git a/server/helpers.js b/server/helpers.js index ea742192..a41ceab5 100644 --- a/server/helpers.js +++ b/server/helpers.js @@ -2,7 +2,13 @@ const settingsController = require('./api/controller/settings') const acceptLanguage = require('accept-language') const moment = require('moment-timezone') const config = require('config') +const debug = require('debug')('helpers') const pkg = require('../package.json') +const fs = require('fs') +const path = require('path') +const sharp = require('sharp') +const axios = require('axios') +const crypto = require('crypto') const DOMPurify = require('dompurify') const { JSDOM } = require('jsdom') @@ -59,6 +65,45 @@ module.exports = { moment.locale(req.settings.locale) moment.tz.setDefault(req.settings.instance_timezone) next() + }, + + async getImageFromURL (url) { + debug(`getImageFromURL ${url}`) + const filename = crypto.randomBytes(16).toString('hex') + '.webp' + const finalPath = path.resolve(config.upload_path, filename) + const thumbPath = path.resolve(config.upload_path, 'thumb', filename) + const outStream = fs.createWriteStream(finalPath) + const thumbStream = fs.createWriteStream(thumbPath) + + const resizer = sharp().resize(1200).webp({ quality: 95 }) + const thumbnailer = sharp().resize(400).webp({ quality: 90 }) + + const response = await axios({ method: 'GET', url, responseType: 'stream' }) + + return new Promise((resolve, reject) => { + let onError = false + const err = e => { + if (onError) { + return + } + onError = true + reject(e) + } + + response.data + .pipe(thumbnailer) + .on('error', err) + .pipe(thumbStream) + .on('error', err) + + response.data + .pipe(resizer) + .on('error', err) + .pipe(outStream) + .on('error', err) + + outStream.on('finish', () => resolve(filename)) + }) } } diff --git a/wp-plugin/gancio.php b/wp-plugin/gancio.php index 5a3bf4e4..b39d0f1b 100644 --- a/wp-plugin/gancio.php +++ b/wp-plugin/gancio.php @@ -2,244 +2,41 @@ /* Plugin Name: WPGancio Plugin URI: https://gancio.org -Description: +Description: Connects an user of a gancio instance to a Wordpress user so that published events are automatically pushed with Gancio API. Version: 1.0 -Author: +Author: Gancio Author URI: https://gancio.org -License: GPL2 -License URI: https:// +License: AGPL 3.0 -Copyright YEAR PLUGIN_AUTHOR_NAME (email : your email address) -(Plugin Name) is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -any later version. - -(Plugin Name) is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with (WPGancio). If not, see (http://link to your plugin license). +WPGancio is free software: you can redistribute it and/or modify it under the +terms of the GNU Affero General Public License as published by the Free +Software Foundation, either version 3 of the license, or any later version. + +WPGancio is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with (WPGancio). If not, see (https://www.gnu.org/licenses/agpl-3.0.html). */ - defined( 'ABSPATH' ) or die( 'Nope, not accessing this' ); +require_once('settings.php'); + +require_once('oauth.php'); + + /** - * @internal never define functions inside callbacks. - * these functions could be run multiple times; this would result in a fatal error. + * What does WPGancio do? + * This plugin connects a user of a gancio instance to a Wordpress user so that events published + * on Wordpress are automatically inserted. + * It requires an event manager plugin, only Event Organiser (https://wp-event-organiser.com/) is + * supported until now but to add another plugin it's easy. */ /** - * custom option and settings + * - Add Gancio Settings page to select an instance URL and... + * - start an OAuth 2.0 authentication flow with the selected instance + * - Send each new / updated events to the selected instance via Gancio API */ -function wpgancio_settings_init() { - // register a new setting for "wpgancio" page - register_setting( 'wpgancio', 'wpgancio_options' ); - - // register a new section in the "wpgancio" page - add_settings_section( - 'wpgancio_section_developers', - __( 'Gancio settings.', 'wpgancio' ), - 'wpgancio_section_developers_cb', - 'wpgancio'); - - // register a new field in the "wporg_section_developers" section, inside the "wporg" page - add_settings_field( - 'wpgancio_field_url', // as of WP 4.6 this value is used only internally - // use $args' label_for to populate the id inside the callback - __( 'Instance URL', 'wpgancio' ), - 'wpgancio_field_url_cb', - 'wpgancio', - 'wpgancio_section_developers', - [ - 'label_for' => 'wpgancio_field_url', - 'class' => 'wpgancio_row', - 'wpgancio_custom_data' => 'custom', - ] - ); -} - -/** - * register our wpgancio_settings_init to the admin_init action hook - */ -add_action( 'admin_init', 'wpgancio_settings_init' ); -add_action( 'update_option_wpgancio_options', 'wpgancio_update_options', 15, 2); - -function wpgancio_update_options ($old_value, $new_value) { - $instance_url = $new_value['wpgancio_field_url']; - $redirect_uri = get_site_url(null, '/wp-admin/options-general.php?page=wpgancio' ); - // wp_redirect(get_option('wpgancio_field_url')); - $response = wp_remote_post( "$instance_url/api/client", array( - 'method' => 'POST', - 'body' => array( - 'client_name' => 'WPGancio', - 'redirect_uris' => $redirect_uri, - 'scopes' => 'event:write', - 'website' => 'https://gancio.org' - ) - )); - - if ( is_wp_error( $response ) ) { - $error_message = $response->get_error_message(); - echo "Something went wrong: $error_message"; - exit; - } - $data = json_decode( wp_remote_retrieve_body($response), true); - // var_dump($data); - update_option('wpgancio_client_secret', $data['client_secret']); - update_option('wpgancio_client_id', $data['client_id']); - wp_redirect($instance_url . "/authorize?response_type=code&redirect_uri=$redirect_uri&scope=event:write&client_id=" . get_option('wpgancio_client_id')); - exit; -}; - -function wpgancio_update_event ($post_id) { - $event = get_post( $post_id ); - $date = eo_get_schedule_start( 'U', $post_id ); - $venue_id = eo_get_venue($post_id); - $place_name = eo_get_venue_name($venue_id); - $place_address = eo_get_venue_address($venue_id); - $options = get_option( 'wpgancio_options' ); - $instance_url = $options['wpgancio_field_url']; - $response = wp_remote_post($instance_url . '/api/event', array( - 'headers' => array ( - 'Authorization' => 'Bearer ' . get_option('wpgancio_token') - ), - 'body' => array( - 'title' => $event->post_title, - 'description' => $event->post_content, - 'start_datetime' => intval($date), - 'place_name' => $place_name, - 'place_address' => $place_address - ) - )); - if ( is_wp_error( $response ) ) { - $error_message = $response->get_error_message(); - echo "Something went wrong: $error_message"; - exit; - } - var_dump($response); - $data = wp_remote_retrieve_body($response); - // syslog(1, "sono qua!"); -} - -add_action('eventorganiser_save_event', 'wpgancio_update_event', 15); - -/** - * custom option and settings: - * callback functions - */ - -// developers section cb -// section callbacks can accept an $args parameter, which is an array. -// $args have the following keys defined: title, id, callback. -// the values are defined at the add_settings_section() function. -function wpgancio_section_developers_cb( $args ) { - ?> -
- . -// the "class" key value is used for the "class" attribute of the- -
- array( - 'client_id' => get_option('wpgancio_client_id'), - 'client_secret' => get_option('wpgancio_client_secret'), - 'scope' => 'event:write', - 'grant_type' => 'authorization_code', - 'code' => $code, - 'state' => 'antani' - ))); - if ( is_wp_error( $response ) ) { - $error_message = $response->get_error_message(); - echo "Something went wrong: $error_message"; - exit; - } - $data = json_decode( wp_remote_retrieve_body($response), true); - update_option('wpgancio_token', $data['access_token']); - update_option('wpgancio_refresh', $data['refresh_token']); - } - - // check user capabilities - if ( ! current_user_can( 'manage_options' ) ) { return; } - - // add error/update messages - // check if the user have submitted the settings - // wordpress will add the "settings-updated" $_GET parameter to the url - if ( isset( $_GET['settings-updated'] ) ) { - // add settings saved message with the class of "updated" - add_settings_error( 'wpgancio_messages', 'wpgancio_message', __( 'Settings Saved', 'wpgancio' ), 'updated' ); - } - - // show error/update messages - settings_errors( 'wpgancio_messages' ); - -?> - -${error_message}