Skip to content
Snippets Groups Projects
Commit 0afb9c16 authored by Jan-Hendrik Willms's avatar Jan-Hendrik Willms
Browse files

allow abstract api to work with real promises instead of deferreds and use it, fixes #3643

Closes #3643

Merge request studip/studip!2885
parent fe2b584c
No related branches found
No related tags found
No related merge requests found
...@@ -10,9 +10,9 @@ $(document).on('click', '.consultation-delete-check:not(.ignore)', event => { ...@@ -10,9 +10,9 @@ $(document).on('click', '.consultation-delete-check:not(.ignore)', event => {
} }
let requests = ids.map(id => { let requests = ids.map(id => {
return STUDIP.jsonapi.GET(`consultation-slots/${id}/bookings`).then(result => result.data.length); return STUDIP.jsonapi.withPromises().get(`consultation-slots/${id}/bookings`).then(response => response.data.length);
}); });
$.when(...requests).done((...results) => { Promise.all(requests).then((...results) => {
if (results.some(result => result > 0)) { if (results.some(result => result > 0)) {
$(event.target).addClass('ignore').click().removeClass('ignore'); $(event.target).addClass('ignore').click().removeClass('ignore');
} else { } else {
......
...@@ -38,7 +38,7 @@ import HeaderMagic from './lib/header_magic.js'; ...@@ -38,7 +38,7 @@ import HeaderMagic from './lib/header_magic.js';
import i18n from './lib/i18n.js'; import i18n from './lib/i18n.js';
import Instschedule from './lib/instschedule.js'; import Instschedule from './lib/instschedule.js';
import InlineEditing from './lib/inline-editing.js'; import InlineEditing from './lib/inline-editing.js';
import JSONAPI, { jsonapi } from './lib/jsonapi.js'; import JSONAPI, { jsonapi } from './lib/jsonapi.ts';
import JSUpdater from './lib/jsupdater.js'; import JSUpdater from './lib/jsupdater.js';
import Lightbox from './lib/lightbox.js'; import Lightbox from './lib/lightbox.js';
import Markup from './lib/markup.js'; import Markup from './lib/markup.js';
......
import Overlay from './overlay.js'; import Overlay from './overlay.js';
class APIError extends Error
{
static createWithJqXhr(message, jqXhr) {
const error = new APIError(message);
error.setJqXhr(jqXhr);
return error;
}
jqXhr = null;
setJqXhr(jqXhr) {
this.jqXhr = jqXhr;
}
}
class AbstractAPI class AbstractAPI
{ {
static get supportedMethods() { static get supportedMethods() {
...@@ -118,6 +133,31 @@ class AbstractAPI ...@@ -118,6 +133,31 @@ class AbstractAPI
} }
}).join('&'); }).join('&');
} }
withPromises() {
return new Proxy(this, {
get(target, prop, receiver) {
// This will allow http methods to be written as lowercase when called as methods
// (e.g. api.patch() instead of api.PATCH())
if (target[prop] === undefined && AbstractAPI.supportedMethods.includes(prop.toUpperCase())) {
prop = prop.toUpperCase();
}
// Only handle calls to request methods
if (prop !== 'request') {
return Reflect.get(target, prop, receiver);
}
// Return a wrapped promise that handles the deferred
return (url, options = {}) => new Promise((resolve, reject) => {
target[prop].apply(target, [url, options]).then(
(response) => resolve(response),
(jqXhr, textStatus, errorThrown) => reject(APIError.createWithJqXhr(errorThrown || textStatus, jqXhr))
);
});
}
})
}
} }
// Create shortcut methods for easier access by method // Create shortcut methods for easier access by method
......
...@@ -3,11 +3,11 @@ import AbstractAPI from './abstract-api.js'; ...@@ -3,11 +3,11 @@ import AbstractAPI from './abstract-api.js';
// Actual JSONAPI object // Actual JSONAPI object
class JSONAPI extends AbstractAPI class JSONAPI extends AbstractAPI
{ {
constructor(version = 1) { constructor(version: number = 1) {
super(`jsonapi.php/v${version}`); super(`jsonapi.php/v${version}`);
} }
encodeData (data, method) { encodeData (data: any, method: string): any {
data = super.encodeData(data); data = super.encodeData(data);
if (['DELETE', 'GET', 'HEAD'].includes(method)) { if (['DELETE', 'GET', 'HEAD'].includes(method)) {
...@@ -21,11 +21,11 @@ class JSONAPI extends AbstractAPI ...@@ -21,11 +21,11 @@ class JSONAPI extends AbstractAPI
return JSON.stringify(data); return JSON.stringify(data);
} }
request (url, options = {}) { request (url: string, options: any = {}) {
options.contentType = 'application/vnd.api+json'; options.contentType = 'application/vnd.api+json';
return super.request(url, options); return super.request(url, options);
} }
} }
export default JSONAPI; export default JSONAPI;
export const jsonapi = new JSONAPI(); export const jsonapi: JSONAPI = new JSONAPI();
...@@ -33,9 +33,9 @@ import eventBus from "./lib/event-bus.ts"; ...@@ -33,9 +33,9 @@ import eventBus from "./lib/event-bus.ts";
if (STUDIP.UI.restrictedDates[year] === undefined) { if (STUDIP.UI.restrictedDates[year] === undefined) {
STUDIP.UI.restrictedDates[year] = {}; STUDIP.UI.restrictedDates[year] = {};
STUDIP.jsonapi.GET('holidays', {data: { STUDIP.jsonapi.withPromises().get('holidays', {data: {
'filter[year]': year 'filter[year]': year
}}).done(response => { }}).then(response => {
// Since PHP will return an empty object as an array, // Since PHP will return an empty object as an array,
// we need to check // we need to check
if (Array.isArray(response)) { if (Array.isArray(response)) {
......
...@@ -136,7 +136,7 @@ export default { ...@@ -136,7 +136,7 @@ export default {
return this.shownColorPicker === course.id; return this.shownColorPicker === course.id;
}, },
changeColor(course, index) { changeColor(course, index) {
STUDIP.jsonapi.PATCH(`course-memberships/${course.id}_${this.userid}`, { STUDIP.jsonapi.withPromises().patch(`course-memberships/${course.id}_${this.userid}`, {
data: { data: {
data: { data: {
type: 'course-memberships', type: 'course-memberships',
...@@ -145,9 +145,9 @@ export default { ...@@ -145,9 +145,9 @@ export default {
} }
} }
} }
}).done(() => { }).then(() => {
course.group = index; course.group = index;
}).always(() => { }).finally(() => {
this.shownColorPicker = null; this.shownColorPicker = null;
}); });
}, },
......
...@@ -52,7 +52,7 @@ export default { ...@@ -52,7 +52,7 @@ export default {
attributes: { value: view === 'tiles' } attributes: { value: view === 'tiles' }
}; };
return STUDIP.jsonapi.PATCH(`config-values/${documentId}`, { data: { data } }) ; return STUDIP.jsonapi.withPromises().patch(`config-values/${documentId}`, { data: { data } }) ;
}, },
exchangeModules({ commit, state }, modules) { exchangeModules({ commit, state }, modules) {
const order = modules.filter(module => module.active) const order = modules.filter(module => module.active)
......
...@@ -71,7 +71,7 @@ export default { ...@@ -71,7 +71,7 @@ export default {
attributes: { value: configValue[configKey] } attributes: { value: configValue[configKey] }
}; };
return STUDIP.jsonapi.PATCH(`config-values/${documentId}`, { data: { data } }) return STUDIP.jsonapi.withPromises().patch(`config-values/${documentId}`, { data: { data } })
}, },
toggleOpenGroup ({ state, dispatch }, group) { toggleOpenGroup ({ state, dispatch }, group) {
let open_groups = [ ...state.config.open_groups ]; let open_groups = [ ...state.config.open_groups ];
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment