<commit_before>import * as store from 'store';
import * as Toaster from 'components/toaster';

export interface User {
  email: string;
  uuid: string;
}

interface Preferences {
  hideMenu: boolean;
}

let cachedUser: User = null;

// AuthController is a super class for controllers which may require auth
export class AuthController {
  user: Mithril.BasicProperty<User>;
  _userPromise: Mithril.Promise<User>;

  constructor(user: User = null) {
    this.user = m.prop<User>(user || cachedUser);
    if (this.user()) {
      var deferred = m.deferred<User>();
      deferred.resolve(this.user());
      this._userPromise = deferred.promise;
    } else {
      this._userPromise = m.request({
        method: 'GET',
        url: '/api/v1/user',
        background: false,
      }).then((res: User) => {
        if (!res.uuid) {
          throw new Error('not logged in');
        }
        this.user(res);
        cachedUser = res;
        return res;
      }).catch(() => {
        cachedUser = null;
        return null;
      });
    }
  }

  logout() {
    m.request({
      method: 'GET',
      url: '/api/v1/logout',
      background: false
    }).then(() => {
      Toaster.add('logged out');
      setTimeout(() => {
        location.reload();
      }, 2000);
    });
  }

  private get storeKey(): string {
    if (!this.user()) {
      return null;
    }
    return `user-${this.user().uuid}`;
  }

  private getPrefs(): Preferences {
    if (!this.user()) {
      return null;
    }
    let prefs: Preferences = store.get(this.storeKey);
    if (!prefs) {
      prefs = {
        hideMenu: false,
      };
      store.set(this.storeKey, prefs);
    }
    return prefs;
  }

  pref<K extends keyof Preferences>(key: K): Preferences[K] {
    if (!this.user()) {
      return; // error
    }
    let prefs: Preferences = this.getPrefs();
    if (!prefs) {
      return; // error
    }
    return prefs[key];
  }

  setPref<K extends keyof Preferences>(key: K, val: Preferences[K]) {
    if (!this.user()) {
      return; // error
    }
    let prefs: Preferences = this.getPrefs();
    prefs[key] = val;
    store.set(this.storeKey, prefs);
  }
}

export class MustAuthController extends AuthController {
  ready: boolean;
  constructor() {
    super();
    this.ready = false;
    this._userPromise.then((user) => {
      if (!user || !user.uuid) {
        window.location.assign(`/admin/login?next=${window.location.pathname}`);
      } else {
        this.ready = true;
      }
    });
  }
}
<commit_msg>admin: Allow dummy store for browsers which don't support it (safari private mode).<commit_after>import * as store from 'store';
import * as Toaster from 'components/toaster';

export interface User {
  email: string;
  uuid: string;
}

interface Preferences {
  hideMenu: boolean;
}

interface Storer {
  get(key: string): any;
  set(key: string, val: any): void;
}

class DummyStore {
  data: any;

  constructor() {
    this.data = {};
  }

  get(key: string): any {
    return this.data[key];
  }

  set(key: string, val: any) {
    this.data[key] = val;
  }
}

let cachedUser: User = null;

// AuthController is a super class for controllers which may require auth
export class AuthController {
  user: Mithril.BasicProperty<User>;
  _userPromise: Mithril.Promise<User>;
  store: Storer;


  constructor(user: User = null) {
    this.store = store.disabled ? new DummyStore() : store;
    this.user = m.prop<User>(user || cachedUser);
    if (this.user()) {
      var deferred = m.deferred<User>();
      deferred.resolve(this.user());
      this._userPromise = deferred.promise;
    } else {
      this._userPromise = m.request({
        method: 'GET',
        url: '/api/v1/user',
        background: false,
      }).then((res: User) => {
        if (!res.uuid) {
          throw new Error('not logged in');
        }
        this.user(res);
        cachedUser = res;
        return res;
      }).catch(() => {
        cachedUser = null;
        return null;
      });
    }
  }

  logout() {
    m.request({
      method: 'GET',
      url: '/api/v1/logout',
      background: false
    }).then(() => {
      Toaster.add('logged out');
      setTimeout(() => {
        location.reload();
      }, 2000);
    });
  }

  private get storeKey(): string {
    if (!this.user()) {
      return null;
    }
    return `user-${this.user().uuid}`;
  }

  private getPrefs(): Preferences {
    if (!this.user()) {
      return null;
    }
    let prefs: Preferences = this.store.get(this.storeKey);
    if (!prefs) {
      prefs = {
        hideMenu: false,
      };
      this.store.set(this.storeKey, prefs);
    }
    return prefs;
  }

  pref<K extends keyof Preferences>(key: K): Preferences[K] {
    if (!this.user()) {
      return; // error
    }
    let prefs: Preferences = this.getPrefs();
    if (!prefs) {
      return; // error
    }
    return prefs[key];
  }

  setPref<K extends keyof Preferences>(key: K, val: Preferences[K]) {
    if (!this.user()) {
      return; // error
    }
    let prefs: Preferences = this.getPrefs();
    prefs[key] = val;
    this.store.set(this.storeKey, prefs);
  }
}

export class MustAuthController extends AuthController {
  ready: boolean;
  constructor() {
    super();
    this.ready = false;
    this._userPromise.then((user) => {
      if (!user || !user.uuid) {
        window.location.assign(`/admin/login?next=${window.location.pathname}`);
      } else {
        this.ready = true;
      }
    });
  }
}

{'fraction_non_alphanumeric': 0.15425337714494342, 'fraction_numerical': 0.002190580503833516, 'mean_word_length': 2.304583835946924, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4111079', 'n_tokens_mistral': 1807, 'n_tokens_neox': 1780, 'n_words': 420}