Skip to content
Snippets Groups Projects
auth.js 8.01 KiB
Newer Older
import m from 'mithril';
import axios from 'axios';
import ClientOAuth2 from 'client-oauth2';
import { apiUrl, ownUrl, oAuthID } from 'networkConfig';
import * as localStorage from './localStorage';
import config from './resourceConfig.json';
// Object which stores the current login-state
const APISession = {
  authenticated: false,
  token: '',
};

// OAuth Handler
const oauth = new ClientOAuth2({
  clientId: oAuthID,
  authorizationUri: `${apiUrl}/oauth`,
  redirectUri: `${ownUrl}/oauthcallback`,
export function resetSession() {
  APISession.authenticated = false;
  APISession.token = '';
  localStorage.remove('token');
  window.location.replace(oauth.token.getUri());
const amivapi = axios.create({
  timeout: 10000,
  headers: { 'Content-Type': 'application/json' },
});

function checkToken(token) {
  // check if a token is still valid
  return new Promise((resolve, reject) => {
    amivapi.get('users', {
      headers: {
        'Content-Type': 'application/json',
        Authorization: token,
      },
    }).then((response) => {
      console.log(response.data);
      if (response.status === 200) resolve();
      else reject();
    }).catch(reject);
  });
}

export function checkAuthenticated() {
  // return a promise that resolves always, with a bool that shows whether
  // the user is authenticated
  return new Promise((resolve) => {
    if (APISession.authenticated) resolve();
    else {
      // let's see if we have a stored token
      const token = localStorage.get('token');
      console.log(`found this token: ${token}`);
      if (token !== '') {
        // check of token is valid
        checkToken(token).then(() => {
          APISession.token = token;
          APISession.authenticated = true;
          resolve();
        }).catch(resetSession);
      } else resetSession();
    }
  });
}

export function getSession() {
  // Promise resolves with authenticated axios-session or fails
  return new Promise((resolve) => {
    checkAuthenticated().then(() => {
      const authenticatedSession = axios.create({
        timeout: 10000,
        headers: {
          'Content-Type': 'application/json',
          Authorization: APISession.token,
        },
      });
      resolve(authenticatedSession);
    }).catch(resetSession);
export class ResourceHandler {
Hermann's avatar
Hermann committed
  /* Handler to get and manipulate resource items
   *
   * resource: String of the resource to accessm e,g, 'events'
   * searchKeys: keys in the resource item on which to perform search, i.e.
   *   when search is set, any of these keys may match the search pattern
   *   E.g. for an event, this may be ['title_de', 'title_en', 'location']
   * updateCallback: method with argument of newData
   *   is called additionally to the promise resolve at any time that data of an item is
   *   changed
   */
  constructor(resource, searchKeys = false, updateCallback = () => {}) {
    this.resource = resource;
    this.searchKeys = searchKeys || config[resource].searchKeys;
Hermann's avatar
Hermann committed
    this.updateCallback = updateCallback;
    this.noPatchKeys = [
      '_etag', '_id', '_created', '_links', '_updated',
      ...(config[resource].notPatchableKeys || [])];
    checkAuthenticated();
  }

  // definitions of query parameters in addition to API go here
  buildQuerystring(query) {
    const queryKeys = Object.keys(query);

    if (queryKeys.length === 0) return '';

    const fullQuery = {};

    if ('search' in query && query.search.length > 0) {
      // translate search into where, we just look if any field contains search
      const searchQuery = {
        $or: this.searchKeys.map((key) => {
          const fieldQuery = {};
          fieldQuery[key] = query.search;
          return fieldQuery;
        }),
      };

      // if there exists already a where-filter, AND them together
      if ('where' in query) {
        fullQuery.where = JSON.stringify({ $and: [searchQuery, query.where] });
      } else {
        fullQuery.where = JSON.stringify(searchQuery);
      }
Hermann's avatar
Hermann committed
    } else if (query.where) {
      fullQuery.where = JSON.stringify(query.where);
    }

    // add all other keys
    queryKeys.filter(key => (key !== 'where' && key !== 'search'))
      .forEach((key) => { fullQuery[key] = JSON.stringify(query[key]); });

    // now we can acutally build the query string
    return `?${m.buildQueryString(fullQuery)}`;
  }

  get(query) {
    return new Promise((resolve, reject) => {
      getSession().then((api) => {
        let url = this.resource;
        if (Object.keys(query).length > 0) url += this.buildQuerystring(query);
        api.get(url).then((response) => {
          if (response.status >= 400) {
            resetSession();
            reject();
          } else {
            resolve(response.data);
          }
        }).catch((e) => {
          console.log(e);
          reject(e);
        });
      });
    });
  }

  getItem(id, embedded = {}) {
    return new Promise((resolve, reject) => {
      getSession().then((api) => {
        let url = `${this.resource}/${id}`;
        // in case embedded is specified, append to url
        if (Object.keys(embedded).length > 0) {
          url += `?${m.buildQueryString({
Hermann's avatar
Hermann committed
            embedded: JSON.stringify(embedded),
          })}`;
        }
        api.get(url).then((response) => {
          if (response.status >= 400) {
            resetSession();
            reject();
          } else {
            resolve(response.data);
          }
        }).catch((e) => {
          console.log(e);
          reject(e);
        });
      });
    });
  }

  post(item) {
    return new Promise((resolve, reject) => {
      getSession().then((api) => {
        api.post(this.resource, item).then((response) => {
          if (response.code === 201) {
            resolve({});
          } else if (response.status === 422) {
            reject(response.data);
          } else if (response.status >= 400) {
            resetSession();
            reject();
          } else {
Hermann's avatar
Hermann committed
            this.updateCallback(response.data);
            resolve(response.data);
          }
        }).catch((e) => {
          console.log(e);
          reject(e);
        });
      });
    });
  }

  patch(item, formData = false) {
    return new Promise((resolve, reject) => {
      getSession().then((api) => {
        // not all fields in the item can be patched. We filter out the fields
        // we are allowed to send
        let submitData;
        if (formData) {
          submitData = new FormData();
          Object.keys(item).forEach((key) => {
            if (!this.noPatchKeys.includes(key)) {
              submitData.append(key, item[key]);
            }
          });
        } else {
          submitData = Object.assign({}, item);
          this.noPatchKeys.forEach((key) => { delete submitData[key]; });
        }
        api.patch(`${this.resource}/${item._id}`, submitData, {
          headers: { 'If-Match': item._etag },
        }).then((response) => {
          if (response.status === 422) {
            reject(response.data);
          } else if (response.status >= 400) {
            resetSession();
            reject();
          } else {
Hermann's avatar
Hermann committed
            this.updateCallback(response.data);
            resolve(response.data);
          }
        }).catch((e) => {
          console.log(e);
          reject(e);
        });
      });
    });
  }

  delete(item) {
    return new Promise((resolve, reject) => {
      getSession().then((api) => {
        api.delete(`${this.resource}/${item._id}`, {
          headers: { 'If-Match': item._etag },
        }).then((response) => {
          if (response.status >= 400) {
            resetSession();
            reject();
          } else {
            resolve();
          }
        }).catch((e) => {
          console.log(e);
          reject(e);
        });
      });
    });
  }
}

export class OauthRedirect {
  view() {
    oauth.token.getToken(m.route.get()).then((response) => {
      APISession.authenticated = true;
      APISession.token = response.accessToken;
      localStorage.set('token', response.accessToken);
      m.route.set('/users');
    });
    return 'redirecting...';
  }
}