Merge pull request #842 from andresmrm/list-api-endpoints
Add API enpoints to create, delete and get lists.
This commit is contained in:
commit
ebfbe30aa0
4 changed files with 187 additions and 0 deletions
|
@ -342,6 +342,109 @@ export default class API extends Component {
|
||||||
<pre>curl -XGET '{getUrl(`api/lists/test@example.com?access_token=${accessToken}`)}'</pre>
|
<pre>curl -XGET '{getUrl(`api/lists/test@example.com?access_token=${accessToken}`)}'</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<h4>GET /api/lists-by-namespace/:namespaceId – {t('getListsInNamespace')}</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{t('retrieveTheListsThatTheNamespaceHas')}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{t('Query params')}
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>access_token</strong> – {t('yourPersonalAccessToken')}</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<strong>{t('example')}</strong>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>curl -XGET '{getUrl(`api/lists-by-namespace/1?access_token=${accessToken}`)}'</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<h4>POST /api/lists – {t('createList')}</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{t('createListDescription')}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{t('Query params')}
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>access_token</strong> – {t('yourPersonalAccessToken')}</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<strong>POST</strong> {t('arguments')}
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>NAMESPACE</strong> – {t('namespace')} (<em>{t('required')}</em>)</li>
|
||||||
|
<li><strong>UNSUBSCRIPTION_MODE</strong> – {t('unsubscription')} (<em>{t('required')}</em>):
|
||||||
|
<ul>
|
||||||
|
<li><strong>0</strong> - {t('onestepIeNoEmailWithConfirmationLink')}</li>
|
||||||
|
<li><strong>1</strong> - {t('onestepWithUnsubscriptionFormIeNoEmail')}</li>
|
||||||
|
<li><strong>2</strong> - {t('twostepIeAnEmailWithConfirmationLinkWill')}</li>
|
||||||
|
<li><strong>3</strong> - {t('twostepWithUnsubscriptionFormIeAnEmail')}</li>
|
||||||
|
<li><strong>4</strong> - {t('manualIeUnsubscriptionHasToBePerformedBy')}</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><strong>NAME</strong> – {t('name')}</li>
|
||||||
|
<li><strong>DESCRIPTION</strong> – {t('description')}</li>
|
||||||
|
<li><strong>HOMEPAGE</strong> – {t('homepage')}</li>
|
||||||
|
<li><strong>CONTACT_EMAIL</strong> – {t('contactEmail')}</li>
|
||||||
|
<li><strong>DEFAULT_FORM</strong> – {t('webAndEmailFormsAndTemplatesUsedIn')}</li>
|
||||||
|
<li><strong>FIELDWIZARD</strong> – {t('representationOfSubscribersName')}:
|
||||||
|
<ul>
|
||||||
|
<li><strong>none</strong> - {t('emptyCustomNoFields')}</li>
|
||||||
|
<li><strong>full_name</strong> - {t('nameOneField')}</li>
|
||||||
|
<li><strong>first_last_name</strong> - {t('firstNameAndLastNameTwoFields')}</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><strong>TO_NAME</strong> – {t('recipientsNameTemplate')}</li>
|
||||||
|
<li><strong>LISTUNSUBSCRIBE_DISABLED</strong> – {t('doNotSendListUnsubscribeHeaders')}</li>
|
||||||
|
<li><strong>PUBLIC_SUBSCRIBE</strong> – {t('allowPublicUsersToSubscribeThemselves')}</li>
|
||||||
|
<li><strong>SEND_CONFIGURATION</strong> – {t('sendConfiguration-1')}</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<strong>{t('example')}</strong>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>curl -XPOST '{getUrl(`api/list?access_token=${accessToken}`)}' \<br/>
|
||||||
|
-d 'NAMESPACE=1' \<br/>
|
||||||
|
-d 'UNSUBSCRIPTION_MODE=0' \<br/>
|
||||||
|
-d 'NAME=list1' \<br/>
|
||||||
|
-d 'DESCRIPTION=a very nice list' \<br/>
|
||||||
|
-d 'CONTACT_EMAIL=test@example.com' \<br/>
|
||||||
|
-d 'HOMEPAGE=example.com' \<br/>
|
||||||
|
-d 'FIELDWIZARD=first_last_name' \<br/>
|
||||||
|
-d 'SEND_CONFIGURATION=1' \<br/>
|
||||||
|
-d 'PUBLIC_SUBSCRIBE=1' \<br/>
|
||||||
|
-d 'LISTUNSUBSCRIBE_DISABLED=0'
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<h4>DELETE /api/lists/:listId – {t('deleteList')}</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{t('deleteListDescription')}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{t('Query params')}
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>access_token</strong> – {t('yourPersonalAccessToken')}</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<strong>{t('example')}</strong>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>curl -XDELETE '{getUrl(`api/list/B16uVTdW?access_token=${accessToken}`)}'</pre>
|
||||||
|
|
||||||
|
|
||||||
<h4>GET /api/rss/fetch/:campaignCid – {t('triggerFetchOfACampaign')}</h4>
|
<h4>GET /api/rss/fetch/:campaignCid – {t('triggerFetchOfACampaign')}</h4>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -72,6 +72,8 @@
|
||||||
"thisApiCallEitherDeleteEmailsFrom": "This API call either delete emails from blacklist",
|
"thisApiCallEitherDeleteEmailsFrom": "This API call either delete emails from blacklist",
|
||||||
"getTheListsAUserHasSubscribedTo": "Get the lists a user has subscribed to",
|
"getTheListsAUserHasSubscribedTo": "Get the lists a user has subscribed to",
|
||||||
"retrieveTheListsThatTheUserWithEmailHas": "Retrieve the lists that the user with :email has subscribed to.",
|
"retrieveTheListsThatTheUserWithEmailHas": "Retrieve the lists that the user with :email has subscribed to.",
|
||||||
|
"getListsInNamespace": "Get the lists in a namespace",
|
||||||
|
"retrieveTheListsThatTheNamespaceHas": "Retrieve the lists that the namespace with :namespaceId has.",
|
||||||
"triggerFetchOfACampaign": "Trigger fetch of a campaign",
|
"triggerFetchOfACampaign": "Trigger fetch of a campaign",
|
||||||
"forcesTheRssFeedCheckToImmediatelyCheck": "Forces the RSS feed check to immediately check the campaign with the given CID (in :campaignCid). It works only for RSS campaigns.",
|
"forcesTheRssFeedCheckToImmediatelyCheck": "Forces the RSS feed check to immediately check the campaign with the given CID (in :campaignCid). It works only for RSS campaigns.",
|
||||||
"sendTransactionalEmail": "Send transactional email",
|
"sendTransactionalEmail": "Send transactional email",
|
||||||
|
@ -378,6 +380,9 @@
|
||||||
"listDeleted": "List deleted",
|
"listDeleted": "List deleted",
|
||||||
"editList": "Edit List",
|
"editList": "Edit List",
|
||||||
"createList": "Create List",
|
"createList": "Create List",
|
||||||
|
"deleteList": "Delete List",
|
||||||
|
"createListDescription": "Creates a new list of subscribers.",
|
||||||
|
"deleteListDescription": "Deletes a list of subscribers.",
|
||||||
"thisIsTheListIdDisplayedToTheSubscribers": "This is the list ID displayed to the subscribers",
|
"thisIsTheListIdDisplayedToTheSubscribers": "This is the list ID displayed to the subscribers",
|
||||||
"contactEmail": "Contact email",
|
"contactEmail": "Contact email",
|
||||||
"contactEmailUsedInSubscriptionFormsAnd": "Contact email used in subscription forms and emails that are sent out. If not filled in, the admin email from the global settings will be used.",
|
"contactEmailUsedInSubscriptionFormsAnd": "Contact email used in subscription forms and emails that are sent out. If not filled in, the admin email from the global settings will be used.",
|
||||||
|
|
|
@ -121,6 +121,32 @@ async function getByCid(context, cid) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getByNamespaceIdTx(tx, context, namespaceId) {
|
||||||
|
// FIXME - this methods is rather suboptimal if there are many lists. It quite needs permission caching in shares.js
|
||||||
|
|
||||||
|
const rows = await tx('lists').where('namespace', namespaceId);
|
||||||
|
await shares.enforceEntityPermissionTx(tx, context, 'namespace', namespaceId, 'view');
|
||||||
|
|
||||||
|
const allowed = [];
|
||||||
|
|
||||||
|
for (const list of rows) {
|
||||||
|
try {
|
||||||
|
await shares.enforceEntityPermissionTx(tx, context, 'list', list.id, 'view');
|
||||||
|
} catch(e) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
allowed.push(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
return allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getByNamespaceId(context, namespaceId) {
|
||||||
|
return await knex.transaction(async tx => {
|
||||||
|
return getByNamespaceIdTx(tx, context, namespaceId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function _validateAndPreprocess(tx, entity) {
|
async function _validateAndPreprocess(tx, entity) {
|
||||||
await namespaceHelpers.validateEntity(tx, entity);
|
await namespaceHelpers.validateEntity(tx, entity);
|
||||||
enforce(entity.unsubscription_mode >= UnsubscriptionMode.MIN && entity.unsubscription_mode <= UnsubscriptionMode.MAX, 'Unknown unsubscription mode');
|
enforce(entity.unsubscription_mode >= UnsubscriptionMode.MIN && entity.unsubscription_mode <= UnsubscriptionMode.MAX, 'Unknown unsubscription mode');
|
||||||
|
@ -283,6 +309,7 @@ module.exports.getById = getById;
|
||||||
module.exports.getByIdWithListFields = getByIdWithListFields;
|
module.exports.getByIdWithListFields = getByIdWithListFields;
|
||||||
module.exports.getByCidTx = getByCidTx;
|
module.exports.getByCidTx = getByCidTx;
|
||||||
module.exports.getByCid = getByCid;
|
module.exports.getByCid = getByCid;
|
||||||
|
module.exports.getByNamespaceId = getByNamespaceId;
|
||||||
module.exports.create = create;
|
module.exports.create = create;
|
||||||
module.exports.updateWithConsistencyCheck = updateWithConsistencyCheck;
|
module.exports.updateWithConsistencyCheck = updateWithConsistencyCheck;
|
||||||
module.exports.remove = remove;
|
module.exports.remove = remove;
|
||||||
|
|
|
@ -140,6 +140,7 @@ router.postAsync('/delete/:listCid', passport.loggedIn, async (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: document endpoint
|
||||||
router.getAsync('/subscriptions/:listCid', passport.loggedIn, async (req, res) => {
|
router.getAsync('/subscriptions/:listCid', passport.loggedIn, async (req, res) => {
|
||||||
const list = await lists.getByCid(req.context, req.params.listCid);
|
const list = await lists.getByCid(req.context, req.params.listCid);
|
||||||
const start = parseInt(req.query.start || 0, 10);
|
const start = parseInt(req.query.start || 0, 10);
|
||||||
|
@ -167,6 +168,57 @@ router.getAsync('/lists/:email', passport.loggedIn, async (req, res) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// get lists by namespace
|
||||||
|
router.getAsync(
|
||||||
|
"/lists-by-namespace/:namespaceId",
|
||||||
|
passport.loggedIn,
|
||||||
|
async (req, res) => {
|
||||||
|
const _lists = await lists.getByNamespaceId(
|
||||||
|
req.context,
|
||||||
|
castToInteger(req.params.namespaceId),
|
||||||
|
);
|
||||||
|
|
||||||
|
res.status(200);
|
||||||
|
res.json({
|
||||||
|
data: _lists.map(l => ({id: l.id, cid: l.cid, name: l.name}))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// create list
|
||||||
|
router.postAsync('/list', passport.loggedIn, async (req, res) => {
|
||||||
|
const input = {};
|
||||||
|
Object.keys(req.body).forEach(key => {
|
||||||
|
input[(key || '').toString().trim().toLowerCase()] = (req.body[key] || '').toString().trim();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (input.fieldwizard) {
|
||||||
|
input.fieldWizard = input.fieldwizard
|
||||||
|
delete input.fieldwizard
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!input.namespace) {
|
||||||
|
throw new APIError('Missing namespace', 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = await lists.create(req.context, input);
|
||||||
|
|
||||||
|
var list = await lists.getById(req.context, id)
|
||||||
|
|
||||||
|
res.status(200);
|
||||||
|
res.json({
|
||||||
|
data: {id: list.cid}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// delete list
|
||||||
|
router.deleteAsync('/list/:listCid', passport.loggedIn, async (req, res) => {
|
||||||
|
const list = await lists.getByCid(req.context, req.params.listCid);
|
||||||
|
await lists.remove(req.context, list.id);
|
||||||
|
|
||||||
|
res.status(200);
|
||||||
|
res.json({});
|
||||||
|
});
|
||||||
|
|
||||||
router.postAsync('/field/:listCid', passport.loggedIn, async (req, res) => {
|
router.postAsync('/field/:listCid', passport.loggedIn, async (req, res) => {
|
||||||
const list = await lists.getByCid(req.context, req.params.listCid);
|
const list = await lists.getByCid(req.context, req.params.listCid);
|
||||||
|
|
Loading…
Reference in a new issue