From 56080ddd0f65daf5df5d8b94d38a5f47f4408139 Mon Sep 17 00:00:00 2001 From: Cellule Date: Sat, 29 Nov 2014 18:55:00 -0500 Subject: [PATCH 1/3] added endpoints for mailing list configuration --- components/MailingListAdminPage.jsx | 45 +++++++-- components/MailingListConfig.jsx | 23 +++++ lib/controllers/index.js | 29 ++++++ lib/controllers/index.ts | 50 ++++++++++ lib/module.js | 56 +++++++++++ lib/module.ts | 95 +++++++++++++++++++ metadata/endpoints.js | 14 +++ metadata/endpoints.ts | 14 +++ typings/mykoop-mailing-list/interfaces.d.ts | 28 ++++++ .../mykoop-mailing-list.d.ts | 29 ++++++ 10 files changed, 375 insertions(+), 8 deletions(-) create mode 100644 components/MailingListConfig.jsx diff --git a/components/MailingListAdminPage.jsx b/components/MailingListAdminPage.jsx index 2b7b8cb..80fcd6a 100644 --- a/components/MailingListAdminPage.jsx +++ b/components/MailingListAdminPage.jsx @@ -8,11 +8,13 @@ var BSPanel = require("react-bootstrap/Panel"); var MKAlertTrigger = require("mykoop-core/components/AlertTrigger"); var MKIcon = require("mykoop-core/components/Icon"); var MKMailingListEditPanel = require("./MailingListEditPanel"); +var MKMailingListConfig = require("./MailingListConfig") var __ = require("language").__; var _ = require("lodash"); var actions = require("actions"); +var showPerRow = 2; var MailingListAdminPage = React.createClass({ getInitialState: function() { return { @@ -81,7 +83,7 @@ var MailingListAdminPage = React.createClass({ var self = this; var mailingLists = _.map(this.state.mailingLists, function(mailingList, i) { return ( - + ); }); + + mailingLists.push( + + + + + + ); + + if(showPerRow <= 1) { + mailingLists = ( + + {mailingLists} + + ); + } else { + var panels = mailingLists; + var curSlice = 0; + mailingLists = []; + while(!_.isEmpty(panels)) { + var rowContent = _.first(panels, showPerRow); + panels = _.rest(panels, showPerRow); + mailingLists.push( + + {rowContent} + + ); + curSlice++; + } + } + return (

{__("mailinglist::adminEditWelcome")}

- - {mailingLists} - - - - - + + + {mailingLists}
); } diff --git a/components/MailingListConfig.jsx b/components/MailingListConfig.jsx new file mode 100644 index 0000000..58b6435 --- /dev/null +++ b/components/MailingListConfig.jsx @@ -0,0 +1,23 @@ +var React = require('react'); + +var BSCol = require("react-bootstrap/Col"); +var BSPanel = require("react-bootstrap/Panel"); + +var MailingListConfig = React.createClass({ + + componentWillMount: function () { + + }, + + render: function () { + return ( + + + MailingListConfig + + + ); + } +}); + +module.exports = MailingListConfig; diff --git a/lib/controllers/index.js b/lib/controllers/index.js index c92fc6e..a5355df 100644 --- a/lib/controllers/index.js +++ b/lib/controllers/index.js @@ -4,6 +4,7 @@ var _ = require("lodash"); // Controllers. function attachControllers(binder) { var mailingList = binder.moduleInstance; + // Add new Mailing list binder.attach({ endPoint: endpoints.mailinglist.add, validation: validation.mailingListDefinition @@ -15,6 +16,7 @@ function attachControllers(binder) { }; return params; })); + // Update Mailing list binder.attach({ endPoint: endpoints.mailinglist.update, validation: validation.mailingListDefinition @@ -27,6 +29,7 @@ function attachControllers(binder) { }; return params; })); + // Delete Mailing list binder.attach({ endPoint: endpoints.mailinglist.delete, validation: validation.mailinglistId @@ -36,12 +39,15 @@ function attachControllers(binder) { }; return params; })); + // Get all mailing lists binder.attach({ endPoint: endpoints.mailinglist.list }, binder.makeSimpleController(mailingList.getMailingLists)); + // Get mailing for registration only binder.attach({ endPoint: endpoints.mailinglist.registration }, binder.makeSimpleController(mailingList.getMailingLists, function () { return { inRegistration: true }; })); + // Register a user to multiple mailing lists binder.attach({ endPoint: endpoints.user.mailinglist.register }, binder.makeSimpleController(mailingList.registerToMailingLists, function (req) { @@ -53,6 +59,7 @@ function attachControllers(binder) { }; return params; })); + // Unregister a user to multiple mailing lists binder.attach({ endPoint: endpoints.user.mailinglist.unregister }, binder.makeSimpleController(mailingList.unregisterToMailingLists, function (req) { @@ -64,6 +71,7 @@ function attachControllers(binder) { }; return params; })); + // Get mailing list the user is registered to binder.attach({ endPoint: endpoints.user.mailinglist.list, validation: validation.mailinglistId @@ -73,5 +81,26 @@ function attachControllers(binder) { }; return params; })); + // Set mailing list configuration + binder.attach({ + endPoint: endpoints.mailinglist.config.set + }, binder.makeSimpleController(mailingList.setConfigurations, function (req) { + return { + globalSender: req.param("globalSender", "") + }; + })); + // Get mailing list configuration + binder.attach({ + endPoint: endpoints.mailinglist.config.get + }, binder.makeSimpleController(mailingList.getConfigurations)); + // Send email to the mailing list + binder.attach({ + endPoint: endpoints.mailinglist.send + }, binder.makeSimpleController(mailingList.sendEmail, function (req) { + return { + id: parseInt(req.param("id")) || 0, + content: req.param("content", "") + }; + })); } exports.attachControllers = attachControllers; diff --git a/lib/controllers/index.ts b/lib/controllers/index.ts index b34c717..5aff158 100644 --- a/lib/controllers/index.ts +++ b/lib/controllers/index.ts @@ -10,6 +10,8 @@ export function attachControllers( binder: utils.ModuleControllersBinder ) { var mailingList = binder.moduleInstance; + + // Add new Mailing list binder.attach( { endPoint: endpoints.mailinglist.add, @@ -25,6 +27,7 @@ export function attachControllers( }) ); + // Update Mailing list binder.attach( { endPoint: endpoints.mailinglist.update, @@ -41,6 +44,7 @@ export function attachControllers( }) ); + // Delete Mailing list binder.attach( { endPoint: endpoints.mailinglist.delete, @@ -54,11 +58,13 @@ export function attachControllers( }) ); + // Get all mailing lists binder.attach( {endPoint: endpoints.mailinglist.list}, binder.makeSimpleController(mailingList.getMailingLists) ); + // Get mailing for registration only binder.attach( {endPoint: endpoints.mailinglist.registration}, binder.makeSimpleController( @@ -71,6 +77,7 @@ export function attachControllers( ) ); + // Register a user to multiple mailing lists binder.attach( { endPoint: endpoints.user.mailinglist.register @@ -86,6 +93,7 @@ export function attachControllers( }) ); + // Unregister a user to multiple mailing lists binder.attach( { endPoint: endpoints.user.mailinglist.unregister @@ -101,6 +109,7 @@ export function attachControllers( }) ); + // Get mailing list the user is registered to binder.attach( { endPoint: endpoints.user.mailinglist.list, @@ -113,4 +122,45 @@ export function attachControllers( return params; }) ); + + // Set mailing list configuration + binder.attach( + { + endPoint: endpoints.mailinglist.config.set + }, + binder.makeSimpleController( + mailingList.setConfigurations, + function(req) { + return { + globalSender: req.param("globalSender", "") + } + } + ) + ); + + // Get mailing list configuration + binder.attach( + { + endPoint: endpoints.mailinglist.config.get + }, + binder.makeSimpleController( + mailingList.getConfigurations + ) + ); + + // Send email to the mailing list + binder.attach( + { + endPoint: endpoints.mailinglist.send + }, + binder.makeSimpleController( + mailingList.sendEmail, + function(req) { + return { + id: parseInt(req.param("id")) || 0, + content: req.param("content","") + } + } + ) + ); } diff --git a/lib/module.js b/lib/module.js index 61be8e8..c7369ee 100644 --- a/lib/module.js +++ b/lib/module.js @@ -191,6 +191,62 @@ var Module = (function (_super) { })); }); }; + Module.prototype.getConfigurations = function (params, callback) { + this.callWithConnection(this.__getConfigurations, params, callback); + }; + Module.prototype.__getConfigurations = function (connection, params, callback) { + connection.query("SELECT value FROM configuration WHERE `key` = ?", ["mailingList"], function (err, res) { + callback(err && new DatabaseError(err), (res && res.length === 1 && JSON.parse(res[0].value)) || null); + }); + }; + Module.prototype.setConfigurations = function (params, callback) { + this.callWithConnection(this.__setConfigurations, params, callback); + }; + Module.prototype.__setConfigurations = function (connection, params, callback) { + var self = this; + logger.debug("Set configurations"); + async.waterfall([ + function (next) { + self.__getConfigurations(connection, {}, next); + }, + function (configs, next) { + logger.debug("Get current configurations", configs); + var newConfigs = { + globalSender: params.globalSender + }; + var newConfigsString = JSON.stringify(newConfigs); + // First time setting the config + if (!configs) { + logger.debug("No configs, attempt to insert", newConfigsString); + return connection.query("INSERT INTO configuration SET `key` = ?, value = ?", ["mailingList", newConfigsString], function (err) { + if (err) { + logger.debug(err); + } + // Ignore this error, the databse might be corrupted + // try to update the config if there's an error + next(null, newConfigsString, !!err); + }); + } + next(null, newConfigsString, true); + }, + function (newConfigsString, tryUpdate, next) { + if (tryUpdate) { + logger.debug("Update configurations", newConfigsString); + return connection.query("UPDATE configuration SET value = ? WHERE `key` = ?", [newConfigsString, "mailingList"], function (err) { + next(err && new DatabaseError(err)); + }); + } + // we inserted a new value and it didn't return an error + next(); + } + ], callback); + }; + Module.prototype.sendEmail = function (params, callback) { + this.callWithConnection(this.__sendEmail, params, callback); + }; + Module.prototype.__sendEmail = function (connection, params, callback) { + // TODO:: + }; return Module; })(utils.BaseModule); module.exports = Module; diff --git a/lib/module.ts b/lib/module.ts index ce1df2a..f7341be 100644 --- a/lib/module.ts +++ b/lib/module.ts @@ -327,6 +327,101 @@ class Module extends utils.BaseModule implements mkmailinglist.Module { ) } + getConfigurations( + params: MailingList.GetConfigurations.Params, + callback: MailingList.GetConfigurations.Callback + ) { + this.callWithConnection(this.__getConfigurations, params, callback); + } + __getConfigurations( + connection: mysql.IConnection, + params: MailingList.GetConfigurations.Params, + callback: MailingList.GetConfigurations.Callback + ) { + connection.query( + "SELECT value FROM configuration WHERE `key` = ?", + ["mailingList"], + function(err, res) { + callback( + err && new DatabaseError(err), + (res && res.length === 1 && JSON.parse(res[0].value)) || + null + ); + } + ); + } + + setConfigurations( + params: MailingList.SetConfigurations.Params, + callback: MailingList.SetConfigurations.Callback + ) { + this.callWithConnection(this.__setConfigurations, params, callback); + } + __setConfigurations( + connection: mysql.IConnection, + params: MailingList.SetConfigurations.Params, + callback: MailingList.SetConfigurations.Callback + ) { + var self = this; + logger.debug("Set configurations"); + async.waterfall([ + function(next) { + self.__getConfigurations(connection, {}, next); + }, + function(configs, next) { + logger.debug("Get current configurations", configs); + var newConfigs: MailingList.MailingListConfiguration = { + globalSender: params.globalSender + }; + var newConfigsString = JSON.stringify(newConfigs); + // First time setting the config + if(!configs) { + logger.debug("No configs, attempt to insert", newConfigsString); + return connection.query( + "INSERT INTO configuration SET `key` = ?, value = ?", + ["mailingList", newConfigsString], + function(err) { + if(err) { + logger.debug(err); + } + // Ignore this error, the databse might be corrupted + // try to update the config if there's an error + next(null, newConfigsString, !!err); + } + ); + } + next(null, newConfigsString, true); + }, function(newConfigsString, tryUpdate, next) { + if(tryUpdate) { + logger.debug("Update configurations", newConfigsString); + return connection.query( + "UPDATE configuration SET value = ? WHERE `key` = ?", + [newConfigsString, "mailingList"], + function(err) { + next(err && new DatabaseError(err)); + } + ); + } + // we inserted a new value and it didn't return an error + next(); + } + ], callback); + } + + sendEmail( + params: MailingList.SendEmail.Params, + callback: MailingList.SendEmail.Callback + ) { + this.callWithConnection(this.__sendEmail, params, callback); + } + __sendEmail( + connection: mysql.IConnection, + params: MailingList.SendEmail.Params, + callback: MailingList.SendEmail.Callback + ) { + // TODO:: + } + } export = Module; diff --git a/metadata/endpoints.js b/metadata/endpoints.js index 8e45bf2..f993d51 100644 --- a/metadata/endpoints.js +++ b/metadata/endpoints.js @@ -31,6 +31,20 @@ var endpoints = { resolve: "validation", value: "mailinglistId" } + }, + send: { + path: "/mailinglists/:id/send", + method: "post" + }, + config: { + get: { + path: "/mailinglists/config/all", + method: "get" + }, + set: { + path: "/mailinglists/config/all", + method: "put" + } } }, user: { diff --git a/metadata/endpoints.ts b/metadata/endpoints.ts index f8e083d..500a864 100644 --- a/metadata/endpoints.ts +++ b/metadata/endpoints.ts @@ -31,6 +31,20 @@ var endpoints = { resolve: "validation", value: "mailinglistId" } + }, + send: { + path: "/mailinglists/:id/send", + method: "post" + }, + config: { + get: { + path: "/mailinglists/config/all", + method: "get" + }, + set: { + path: "/mailinglists/config/all", + method: "put" + } } }, user: { diff --git a/typings/mykoop-mailing-list/interfaces.d.ts b/typings/mykoop-mailing-list/interfaces.d.ts index f8f7bdc..3e398e5 100644 --- a/typings/mykoop-mailing-list/interfaces.d.ts +++ b/typings/mykoop-mailing-list/interfaces.d.ts @@ -69,4 +69,32 @@ declare module MailingList { (err?, result?: {id: number;}[]) : void; } } + + export interface MailingListConfiguration { + globalSender: string; + } + module GetConfigurations { + export interface Params {} + export interface CallbackResult extends MailingListConfiguration {} + export interface Callback { + (err: Error, result?: CallbackResult): void; + } + } + + module SetConfigurations { + export interface Params extends MailingListConfiguration {} + export interface Callback { + (err: Error): void; + } + } + + module SendEmail { + export interface Params { + id: number; //mailing list id + content: string; + } + export interface Callback { + (err: Error): void; + } + } } diff --git a/typings/mykoop-mailing-list/mykoop-mailing-list.d.ts b/typings/mykoop-mailing-list/mykoop-mailing-list.d.ts index c343c26..ab38ed0 100644 --- a/typings/mykoop-mailing-list/mykoop-mailing-list.d.ts +++ b/typings/mykoop-mailing-list/mykoop-mailing-list.d.ts @@ -79,6 +79,35 @@ declare module mkmailinglist { callback: MailingList.UnregisterToMailingLists.Callback ); + getConfigurations( + params: MailingList.GetConfigurations.Params, + callback: MailingList.GetConfigurations.Callback + ); + __getConfigurations( + connection: mysql.IConnection, + params: MailingList.GetConfigurations.Params, + callback: MailingList.GetConfigurations.Callback + ); + + setConfigurations( + params: MailingList.SetConfigurations.Params, + callback: MailingList.SetConfigurations.Callback + ); + __setConfigurations( + connection: mysql.IConnection, + params: MailingList.SetConfigurations.Params, + callback: MailingList.SetConfigurations.Callback + ); + + sendEmail( + params: MailingList.SendEmail.Params, + callback: MailingList.SendEmail.Callback + ); + __sendEmail( + connection: mysql.IConnection, + params: MailingList.SendEmail.Params, + callback: MailingList.SendEmail.Callback + ); } } From aad7d3e241b14b2dd9f1b5656d2fd6daea7a2356 Mon Sep 17 00:00:00 2001 From: Cellule Date: Sat, 29 Nov 2014 19:36:07 -0500 Subject: [PATCH 2/3] can now edit the mailing list configurations in the frontend --- components/MailingListConfig.jsx | 61 +++++++++++++++++++++++++++++--- locales/en/mailinglist.json5 | 3 ++ locales/fr/mailinglist.json5 | 3 ++ 3 files changed, 62 insertions(+), 5 deletions(-) diff --git a/components/MailingListConfig.jsx b/components/MailingListConfig.jsx index 58b6435..66c2055 100644 --- a/components/MailingListConfig.jsx +++ b/components/MailingListConfig.jsx @@ -1,20 +1,71 @@ var React = require('react'); -var BSCol = require("react-bootstrap/Col"); -var BSPanel = require("react-bootstrap/Panel"); +var BSCol = require("react-bootstrap/Col"); +var BSInput = require("react-bootstrap/Input"); +var BSButton = require("react-bootstrap/Button"); + +var MKCollapsablePanel = require("mykoop-core/components/CollapsablePanel"); +var MKFeedbacki18nMixin = require("mykoop-core/components/Feedbacki18nMixin"); + +var actions = require("actions"); +var __ = require("language").__; var MailingListConfig = React.createClass({ + mixins: [React.addons.LinkedStateMixin, MKFeedbacki18nMixin], + + getInitialState: function() { + return { + globalSender: "" + }; + }, componentWillMount: function () { + var self = this; + actions.mailinglist.config.get({ + i18nErrors: {} + },function(err, res) { + if(err) { + return self.setFeedback(err.i18n, "danger"); + } + self.setState({ + globalSender: res.globalSender + }); + }); + }, + saveConfig: function() { + var self = this; + self.clearFeedback(); + actions.mailinglist.config.set({ + i18nErrors: {}, + data: { + globalSender: this.state.globalSender + } + },function(err, res) { + if(err) { + return self.setFeedback(err.i18n, "danger"); + } + self.setFeedback({key: "success"}, "success"); + }); }, render: function () { return ( - - MailingListConfig - + + {this.renderFeedback()} + + + {__("update")} + + ); } diff --git a/locales/en/mailinglist.json5 b/locales/en/mailinglist.json5 index 6c647ba..b83c185 100644 --- a/locales/en/mailinglist.json5 +++ b/locales/en/mailinglist.json5 @@ -10,6 +10,9 @@ showAtRegistrationTooltip: "Show this mailing in the registration form for new users", registerError: "Error registering user to mailing lists", + config: "Configurations", + globalEmail: "Primary email", + errors: { app: { name: { diff --git a/locales/fr/mailinglist.json5 b/locales/fr/mailinglist.json5 index a239213..6d5a049 100644 --- a/locales/fr/mailinglist.json5 +++ b/locales/fr/mailinglist.json5 @@ -10,6 +10,9 @@ showAtRegistrationTooltip: "Afficher cette liste de diffusion dans le formulaire d'inscription des nouveaux utilisateurs", registerError: "Erreur survenue pendant l'inscription aux listes de diffusion", + config: "Configurations", + globalEmail: "Courriel principal", + errors: { app: { name: { From dad1ddddff395a7d2e652c623f96bae9ae4fbc50 Mon Sep 17 00:00:00 2001 From: Cellule Date: Mon, 1 Dec 2014 16:33:54 -0500 Subject: [PATCH 3/3] CR Fixes --- components/MailingListAdminPage.jsx | 13 +++++++------ components/MailingListConfig.jsx | 2 +- lib/controllers/index.js | 2 +- lib/controllers/index.ts | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/components/MailingListAdminPage.jsx b/components/MailingListAdminPage.jsx index 80fcd6a..5bf7f7c 100644 --- a/components/MailingListAdminPage.jsx +++ b/components/MailingListAdminPage.jsx @@ -14,7 +14,8 @@ var __ = require("language").__; var _ = require("lodash"); var actions = require("actions"); -var showPerRow = 2; +var itemsPerRow = 2; +var panelMdSize = Math.floor(12/itemsPerRow); var MailingListAdminPage = React.createClass({ getInitialState: function() { return { @@ -83,7 +84,7 @@ var MailingListAdminPage = React.createClass({ var self = this; var mailingLists = _.map(this.state.mailingLists, function(mailingList, i) { return ( - + + ); - if(showPerRow <= 1) { + if(itemsPerRow <= 1) { mailingLists = ( {mailingLists} @@ -120,8 +121,8 @@ var MailingListAdminPage = React.createClass({ var curSlice = 0; mailingLists = []; while(!_.isEmpty(panels)) { - var rowContent = _.first(panels, showPerRow); - panels = _.rest(panels, showPerRow); + var rowContent = _.first(panels, itemsPerRow); + panels = _.rest(panels, itemsPerRow); mailingLists.push( {rowContent} diff --git a/components/MailingListConfig.jsx b/components/MailingListConfig.jsx index 66c2055..de58ceb 100644 --- a/components/MailingListConfig.jsx +++ b/components/MailingListConfig.jsx @@ -1,4 +1,4 @@ -var React = require('react'); +var React = require("react"); var BSCol = require("react-bootstrap/Col"); var BSInput = require("react-bootstrap/Input"); diff --git a/lib/controllers/index.js b/lib/controllers/index.js index a5355df..6158f82 100644 --- a/lib/controllers/index.js +++ b/lib/controllers/index.js @@ -98,7 +98,7 @@ function attachControllers(binder) { endPoint: endpoints.mailinglist.send }, binder.makeSimpleController(mailingList.sendEmail, function (req) { return { - id: parseInt(req.param("id")) || 0, + id: parseInt(req.param("id", 0)), content: req.param("content", "") }; })); diff --git a/lib/controllers/index.ts b/lib/controllers/index.ts index 5aff158..de925df 100644 --- a/lib/controllers/index.ts +++ b/lib/controllers/index.ts @@ -157,7 +157,7 @@ export function attachControllers( mailingList.sendEmail, function(req) { return { - id: parseInt(req.param("id")) || 0, + id: parseInt(req.param("id", 0)), content: req.param("content","") } }