<commit_before>// This file is part of Indico.
// Copyright (C) 2002 - 2022 CERN
//
// Indico is free software; you can redistribute it and/or
// modify it under the terms of the MIT License; see the
// LICENSE file for more details.

import {createHash} from 'crypto';
import fs from 'fs';
import path from 'path';

import autoprefixer from 'autoprefixer';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import importOnce from 'node-sass-import-once';
import postcssURL from 'postcss-url';
import TerserPlugin from 'terser-webpack-plugin';
import webpack from 'webpack';
import {WebpackManifestPlugin} from 'webpack-manifest-plugin';

function _resolveTheme(rootPath, indicoClientPath, filePath) {
  const indicoRelativePath = path.resolve(indicoClientPath, filePath);

  if (
    indicoClientPath &&
    !fs.existsSync(path.resolve(rootPath, filePath)) &&
    fs.existsSync(indicoRelativePath)
  ) {
    return path.resolve(indicoClientPath, filePath);
  }

  return path.resolve(rootPath, filePath);
}

function _importOnce(...args) {
  // Due to https://github.com/webpack-contrib/sass-loader/pull/958/files we need to
  // use a different context for the importOnce plugin in order to keep the cache
  // between calls to this function.
  // Using a global one might work as well but like this it's scoped with the same
  // lifetime which we had before the sass-loader update as `options` is cloned at
  // the same time the object previously used in `this` was created (`context` in
  // `getOptions`).
  this.options._ctx = this.options._ctx || {options: this.options};
  return importOnce.apply(this.options._ctx, args);
}

export function getThemeEntryPoints(config, prefix) {
  const themes = config.themes;
  const indicoClientPath = path.join(
    config.isPlugin ? config.indico.build.clientPath : config.build.clientPath,
    'styles'
  );
  const rootPath = path.join(config.build.rootPath);

  return Object.assign(
    ...Object.keys(themes).map(k => {
      const returnValue = {};
      const escapedKey = k.replace('-', '_');

      returnValue[`themes_${escapedKey}`] = [
        _resolveTheme(rootPath, indicoClientPath, prefix + themes[k].stylesheet),
      ];

      if (themes[k].print_stylesheet) {
        returnValue[`themes_${escapedKey}.print`] = [
          _resolveTheme(rootPath, indicoClientPath, prefix + themes[k].print_stylesheet),
        ];
      }
      return returnValue;
    })
  );
}

export function generateAssetPath(config, virtualVersion = false) {
  // /css/whatever.css => /css/whatever__v123abcdef.css
  return file => {
    const relPath = path.relative(config.build.staticPath, file);
    const {dir, name, ext} = path.parse(relPath);
    const h = createHash('md5');
    h.update(fs.readFileSync(file));
    const hash = h.digest('hex').slice(0, 8);
    // the "virtual version" is used for files that are loaded as-is from the
    // static folder and thus do not actually get the hash in the physical
    // file name. it is distinct from the normal version style so a rule on
    // the web server can strip that version segment
    const fileName = virtualVersion ? `${name}__v${hash}${ext}` : `${name}.${hash}${ext}`;
    // .. -> _, like file-loader does
    return dir.replace(/\.\./g, '_') + path.sep + fileName;
  };
}

export function webpackDefaults(env, config, bundles, isPlugin = false) {
  const globalBuildConfig = config.indico ? config.indico.build : config.build;
  const currentEnv = (env ? env.NODE_ENV : null) || 'development';
  const nodeModules = [
    path.join(
      config.build.indicoSourcePath || path.resolve(config.build.rootPath, '..'),
      'node_modules'
    ),
  ];

  if (config.isPlugin) {
    // add plugin's node_modules in addition to the core's
    nodeModules.push(path.resolve(config.build.rootPath, '../node_modules'));
  }

  const _cssLoaderOptions = {
    url: true,
  };

  const scssIncludePath = path.join(
    config.isPlugin
      ? path.resolve(config.build.indicoSourcePath, './indico/web/client')
      : path.join(config.build.clientPath),
    'styles'
  );

  function getDevtoolFilename(info) {
    const root = path.resolve(globalBuildConfig.rootPath, '..');
    return path.relative(root, info.absoluteResourcePath);
  }

  /**
   * This function resolves SASS files using a [~][module:]path syntax
   */
  function sassResolver(url) {
    const match = url.match(/^(~?)(?:(\w+):)?([\w/_-]+)/);
    if (match) {
      const skipOverride = match[1] === '~';
      const mod = match[2];
      const file = match[3];
      if (config.isPlugin) {
        const {sassOverrides} = bundles;
        if (skipOverride) {
          if (!mod) {
            return {file: path.join(config.indico.build.clientPath, 'styles', file)};
          }
        } else if (sassOverrides && sassOverrides[url]) {
          return {file: path.join(config.build.clientPath, sassOverrides[url])};
        }
      }
      if (!mod) {
        return null;
      }
      const modPath = path.join(globalBuildConfig.rootPath, 'modules', mod);
      return {file: path.join(modPath, 'client', file)};
    }
    return null;
  }

  /**
   * This function resolves url(...)s in CSS files using a plugin:path syntax
   */
  function postCSSURLResolver({url}) {
    const m = url.match(/^(\w+):(.*)$/);

    if (!m) {
      return url;
    }

    const [name, relPath] = m.slice(1);
    let prefix;

    if (name === 'static') {
      prefix = globalBuildConfig.staticURL;
    } else {
      prefix = path.join(globalBuildConfig.staticURL, 'static/plugins', name);
    }
    return path.join(prefix, relPath);
  }

  function buildSCSSLoader(cssLoaderOptions = {}) {
    return [
      {
        loader: MiniCssExtractPlugin.loader,
        options: {
          publicPath: config.build.distURL,
        },
      },
      {
        loader: 'css-loader',
        options: {
          sourceMap: true,
          url: !config.isPlugin,
          ...cssLoaderOptions,
        },
      },
      {
        loader: 'resolve-url-loader',
        options: {
          root: config.isPlugin ? false : config.build.staticPath,
        },
      },
      {
        loader: 'postcss-loader',
        options: {
          sourceMap: true,
          postcssOptions: {
            plugins: [
              autoprefixer,
              postcssURL({
                url: postCSSURLResolver,
              }),
            ],
          },
        },
      },
      {
        loader: 'sass-loader',
        options: {
          sourceMap: true,
          sassOptions: {
            includePaths: [scssIncludePath],
            outputStyle: 'compact',
            importer: [sassResolver, _importOnce],
          },
        },
      },
    ];
  }

  const indicoClientPath = globalBuildConfig.clientPath;

  // Do not load moment locales (we'll load them explicitly)
  // We have to disable this for plugins since for some weird reason
  // that probably not even that webpack maintainers know, it breaks
  // certain plugins (burotel) in obscure ways as soon as exports.js
  // in the core is used...
  const ignorePlugin = isPlugin
    ? null
    : new webpack.IgnorePlugin({
        resourceRegExp: /^\.\/locale$/,
        contextRegExp: /moment$/,
      });

  return {
    devtool: 'source-map',
    cache: true,
    context: config.build.clientPath,
    output: {
      path: config.build.distPath,
      filename: 'js/[name].[chunkhash:8].bundle.js',
      publicPath: config.build.distURL,
      devtoolModuleFilenameTemplate: info => `webpack:///${getDevtoolFilename(info)}`,
      devtoolFallbackModuleFilenameTemplate: info =>
        `webpack:///${getDevtoolFilename(info)}?${info.hash}`,
    },
    module: {
      rules: [
        {
          test: /outdatedbrowser\/.+\.js$/,
          loader: 'babel-loader',
          options: {
            // build JS targetting old browsers so they get the warning as well
            presets: [['@babel/preset-env', {targets: {browsers: ['last 5 years', 'ie > 6']}}]],
          },
        },
        {
          test: /\.js$/,
          loader: 'babel-loader',
          exclude: /node_modules/,
        },
        {
          test: /\.jsx$/,
          loader: 'babel-loader',
          exclude: /node_modules/,
        },
        {
          oneOf: [
            {
              test: /\.css$/,
              use: [
                {
                  loader: MiniCssExtractPlugin.loader,
                },
                {
                  loader: 'css-loader',
                  options: _cssLoaderOptions,
                },
              ],
            },
            {
              test: /\.module\.scss$/,
              use: buildSCSSLoader({
                modules: {
                  localIdentContext: path.resolve(globalBuildConfig.clientPath, '../../modules'),
                  localIdentName: '[path]___[name]__[local]___[contenthash:base64:5]',
                },
                importLoaders: 1,
              }),
            },
            {
              test: /\.scss$/,
              use: buildSCSSLoader(),
            },
          ],
        },
      ],
    },
    plugins: [
      new WebpackManifestPlugin({
        fileName: 'manifest.json',
        publicPath: config.build.distURL,
      }),
      ...(ignorePlugin ? [ignorePlugin] : []),
      new MiniCssExtractPlugin({
        filename: 'css/[name].[contenthash:8].css',
      }),
      new webpack.ProvidePlugin({
        process: 'process/browser',
      }),
    ],
    resolve: {
      alias: [{name: 'indico', alias: path.join(indicoClientPath, 'js/')}],
      // Webpack 5 does not include polyfills for node.js core modules by default
      fallback: {path: require.resolve('path-browserify')},
      symlinks: false,
      extensions: ['.js', '.json', '.jsx'],
      modules: nodeModules,
    },
    resolveLoader: {
      modules: nodeModules,
    },
    externals: ({context, request}, callback) => {
      // tell webpack to make certain packages use window.jQuery (and not load it again)
      if (/^jquery$/.test(request) && /fullcalendar/.test(context)) {
        return callback(null, 'jQuery');
      }
      return callback();
    },
    stats: {
      assets: false,
      children: false,
      modules: false,
      chunks: true,
      chunkModules: false,
      chunkOrigins: false,
      chunksSort: 'name',
    },
    mode: currentEnv,
    optimization: {
      runtimeChunk: isPlugin ? false : {name: 'common-runtime'},
      splitChunks: {
        cacheGroups: isPlugin
          ? {}
          : {
              // 'common' chunk, which should include common dependencies
              common: {
                name: 'common',
                chunks: chunk =>
                  chunk.canBeInitial() &&
                  // outdatedbrowser must be fully standalone since we can assume all other
                  // bundles to be broken in legacy browsers
                  chunk.name !== 'outdatedbrowser' &&
                  // having theme/print css in the common css bundle would break the interface
                  !/\.print$|^themes_/.test(chunk.name),
                minChunks: 2,
              },
              // react/redux and friends since they are pretty big
              react: {
                test: /\/node_modules\/(react|redux|prop-types\/|lodash-es\/|fbjs\/)/,
                name: 'react',
                chunks: 'initial',
                priority: 10,
              },
              semanticui: {
                test: /node_modules\/(semantic-ui|indico-sui-theme)/,
                name: 'semantic-ui',
                chunks: 'initial',
                priority: 10,
              },
            },
      },
      minimizer: [
        new TerserPlugin({
          exclude: [
            // "Unexpected token: punc (:) [js/mathjax/extensions/a11y/mathmaps/fr.js:2,25]"
            /js\/mathjax(\/unpacked)?\/extensions\/a11y\/mathmaps\/.+\.js$/,
          ],
          extractComments: false,
        }),
      ],
    },
  };
}

export function indicoStaticLoader(config) {
  return {
    test: /\/static\/(images|fonts)\/.*\.(jpe?g|png|gif|svg|woff2?|ttf|eot)$/,
    use: {
      loader: 'file-loader',
      options: {
        name: generateAssetPath(config, true),
        context: config.build.staticPath,
        emitFile: false,
        publicPath: config.build.staticURL,
      },
    },
  };
}
<commit_msg>Add relative 'node_modules' to webpack resolve paths<commit_after>// This file is part of Indico.
// Copyright (C) 2002 - 2022 CERN
//
// Indico is free software; you can redistribute it and/or
// modify it under the terms of the MIT License; see the
// LICENSE file for more details.

import {createHash} from 'crypto';
import fs from 'fs';
import path from 'path';

import autoprefixer from 'autoprefixer';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import importOnce from 'node-sass-import-once';
import postcssURL from 'postcss-url';
import TerserPlugin from 'terser-webpack-plugin';
import webpack from 'webpack';
import {WebpackManifestPlugin} from 'webpack-manifest-plugin';

function _resolveTheme(rootPath, indicoClientPath, filePath) {
  const indicoRelativePath = path.resolve(indicoClientPath, filePath);

  if (
    indicoClientPath &&
    !fs.existsSync(path.resolve(rootPath, filePath)) &&
    fs.existsSync(indicoRelativePath)
  ) {
    return path.resolve(indicoClientPath, filePath);
  }

  return path.resolve(rootPath, filePath);
}

function _importOnce(...args) {
  // Due to https://github.com/webpack-contrib/sass-loader/pull/958/files we need to
  // use a different context for the importOnce plugin in order to keep the cache
  // between calls to this function.
  // Using a global one might work as well but like this it's scoped with the same
  // lifetime which we had before the sass-loader update as `options` is cloned at
  // the same time the object previously used in `this` was created (`context` in
  // `getOptions`).
  this.options._ctx = this.options._ctx || {options: this.options};
  return importOnce.apply(this.options._ctx, args);
}

export function getThemeEntryPoints(config, prefix) {
  const themes = config.themes;
  const indicoClientPath = path.join(
    config.isPlugin ? config.indico.build.clientPath : config.build.clientPath,
    'styles'
  );
  const rootPath = path.join(config.build.rootPath);

  return Object.assign(
    ...Object.keys(themes).map(k => {
      const returnValue = {};
      const escapedKey = k.replace('-', '_');

      returnValue[`themes_${escapedKey}`] = [
        _resolveTheme(rootPath, indicoClientPath, prefix + themes[k].stylesheet),
      ];

      if (themes[k].print_stylesheet) {
        returnValue[`themes_${escapedKey}.print`] = [
          _resolveTheme(rootPath, indicoClientPath, prefix + themes[k].print_stylesheet),
        ];
      }
      return returnValue;
    })
  );
}

export function generateAssetPath(config, virtualVersion = false) {
  // /css/whatever.css => /css/whatever__v123abcdef.css
  return file => {
    const relPath = path.relative(config.build.staticPath, file);
    const {dir, name, ext} = path.parse(relPath);
    const h = createHash('md5');
    h.update(fs.readFileSync(file));
    const hash = h.digest('hex').slice(0, 8);
    // the "virtual version" is used for files that are loaded as-is from the
    // static folder and thus do not actually get the hash in the physical
    // file name. it is distinct from the normal version style so a rule on
    // the web server can strip that version segment
    const fileName = virtualVersion ? `${name}__v${hash}${ext}` : `${name}.${hash}${ext}`;
    // .. -> _, like file-loader does
    return dir.replace(/\.\./g, '_') + path.sep + fileName;
  };
}

export function webpackDefaults(env, config, bundles, isPlugin = false) {
  const globalBuildConfig = config.indico ? config.indico.build : config.build;
  const currentEnv = (env ? env.NODE_ENV : null) || 'development';
  const nodeModules = [
    // Pass relative 'node_modules' first, so that nested node_modules are checked first.
    // https://webpack.js.org/configuration/resolve/#resolvemodules
    'node_modules',
    path.join(
      config.build.indicoSourcePath || path.resolve(config.build.rootPath, '..'),
      'node_modules'
    ),
  ];

  if (config.isPlugin) {
    // add plugin's node_modules in addition to the core's
    nodeModules.push(path.resolve(config.build.rootPath, '../node_modules'));
  }

  const _cssLoaderOptions = {
    url: true,
  };

  const scssIncludePath = path.join(
    config.isPlugin
      ? path.resolve(config.build.indicoSourcePath, './indico/web/client')
      : path.join(config.build.clientPath),
    'styles'
  );

  function getDevtoolFilename(info) {
    const root = path.resolve(globalBuildConfig.rootPath, '..');
    return path.relative(root, info.absoluteResourcePath);
  }

  /**
   * This function resolves SASS files using a [~][module:]path syntax
   */
  function sassResolver(url) {
    const match = url.match(/^(~?)(?:(\w+):)?([\w/_-]+)/);
    if (match) {
      const skipOverride = match[1] === '~';
      const mod = match[2];
      const file = match[3];
      if (config.isPlugin) {
        const {sassOverrides} = bundles;
        if (skipOverride) {
          if (!mod) {
            return {file: path.join(config.indico.build.clientPath, 'styles', file)};
          }
        } else if (sassOverrides && sassOverrides[url]) {
          return {file: path.join(config.build.clientPath, sassOverrides[url])};
        }
      }
      if (!mod) {
        return null;
      }
      const modPath = path.join(globalBuildConfig.rootPath, 'modules', mod);
      return {file: path.join(modPath, 'client', file)};
    }
    return null;
  }

  /**
   * This function resolves url(...)s in CSS files using a plugin:path syntax
   */
  function postCSSURLResolver({url}) {
    const m = url.match(/^(\w+):(.*)$/);

    if (!m) {
      return url;
    }

    const [name, relPath] = m.slice(1);
    let prefix;

    if (name === 'static') {
      prefix = globalBuildConfig.staticURL;
    } else {
      prefix = path.join(globalBuildConfig.staticURL, 'static/plugins', name);
    }
    return path.join(prefix, relPath);
  }

  function buildSCSSLoader(cssLoaderOptions = {}) {
    return [
      {
        loader: MiniCssExtractPlugin.loader,
        options: {
          publicPath: config.build.distURL,
        },
      },
      {
        loader: 'css-loader',
        options: {
          sourceMap: true,
          url: !config.isPlugin,
          ...cssLoaderOptions,
        },
      },
      {
        loader: 'resolve-url-loader',
        options: {
          root: config.isPlugin ? false : config.build.staticPath,
        },
      },
      {
        loader: 'postcss-loader',
        options: {
          sourceMap: true,
          postcssOptions: {
            plugins: [
              autoprefixer,
              postcssURL({
                url: postCSSURLResolver,
              }),
            ],
          },
        },
      },
      {
        loader: 'sass-loader',
        options: {
          sourceMap: true,
          sassOptions: {
            includePaths: [scssIncludePath],
            outputStyle: 'compact',
            importer: [sassResolver, _importOnce],
          },
        },
      },
    ];
  }

  const indicoClientPath = globalBuildConfig.clientPath;

  // Do not load moment locales (we'll load them explicitly)
  // We have to disable this for plugins since for some weird reason
  // that probably not even that webpack maintainers know, it breaks
  // certain plugins (burotel) in obscure ways as soon as exports.js
  // in the core is used...
  const ignorePlugin = isPlugin
    ? null
    : new webpack.IgnorePlugin({
        resourceRegExp: /^\.\/locale$/,
        contextRegExp: /moment$/,
      });

  return {
    devtool: 'source-map',
    cache: true,
    context: config.build.clientPath,
    output: {
      path: config.build.distPath,
      filename: 'js/[name].[chunkhash:8].bundle.js',
      publicPath: config.build.distURL,
      devtoolModuleFilenameTemplate: info => `webpack:///${getDevtoolFilename(info)}`,
      devtoolFallbackModuleFilenameTemplate: info =>
        `webpack:///${getDevtoolFilename(info)}?${info.hash}`,
    },
    module: {
      rules: [
        {
          test: /outdatedbrowser\/.+\.js$/,
          loader: 'babel-loader',
          options: {
            // build JS targetting old browsers so they get the warning as well
            presets: [['@babel/preset-env', {targets: {browsers: ['last 5 years', 'ie > 6']}}]],
          },
        },
        {
          test: /\.js$/,
          loader: 'babel-loader',
          exclude: /node_modules/,
        },
        {
          test: /\.jsx$/,
          loader: 'babel-loader',
          exclude: /node_modules/,
        },
        {
          oneOf: [
            {
              test: /\.css$/,
              use: [
                {
                  loader: MiniCssExtractPlugin.loader,
                },
                {
                  loader: 'css-loader',
                  options: _cssLoaderOptions,
                },
              ],
            },
            {
              test: /\.module\.scss$/,
              use: buildSCSSLoader({
                modules: {
                  localIdentContext: path.resolve(globalBuildConfig.clientPath, '../../modules'),
                  localIdentName: '[path]___[name]__[local]___[contenthash:base64:5]',
                },
                importLoaders: 1,
              }),
            },
            {
              test: /\.scss$/,
              use: buildSCSSLoader(),
            },
          ],
        },
      ],
    },
    plugins: [
      new WebpackManifestPlugin({
        fileName: 'manifest.json',
        publicPath: config.build.distURL,
      }),
      ...(ignorePlugin ? [ignorePlugin] : []),
      new MiniCssExtractPlugin({
        filename: 'css/[name].[contenthash:8].css',
      }),
      new webpack.ProvidePlugin({
        process: 'process/browser',
      }),
    ],
    resolve: {
      alias: [{name: 'indico', alias: path.join(indicoClientPath, 'js/')}],
      // Webpack 5 does not include polyfills for node.js core modules by default
      fallback: {path: require.resolve('path-browserify')},
      symlinks: false,
      extensions: ['.js', '.json', '.jsx'],
      modules: nodeModules,
    },
    resolveLoader: {
      modules: nodeModules,
    },
    externals: ({context, request}, callback) => {
      // tell webpack to make certain packages use window.jQuery (and not load it again)
      if (/^jquery$/.test(request) && /fullcalendar/.test(context)) {
        return callback(null, 'jQuery');
      }
      return callback();
    },
    stats: {
      assets: false,
      children: false,
      modules: false,
      chunks: true,
      chunkModules: false,
      chunkOrigins: false,
      chunksSort: 'name',
    },
    mode: currentEnv,
    optimization: {
      runtimeChunk: isPlugin ? false : {name: 'common-runtime'},
      splitChunks: {
        cacheGroups: isPlugin
          ? {}
          : {
              // 'common' chunk, which should include common dependencies
              common: {
                name: 'common',
                chunks: chunk =>
                  chunk.canBeInitial() &&
                  // outdatedbrowser must be fully standalone since we can assume all other
                  // bundles to be broken in legacy browsers
                  chunk.name !== 'outdatedbrowser' &&
                  // having theme/print css in the common css bundle would break the interface
                  !/\.print$|^themes_/.test(chunk.name),
                minChunks: 2,
              },
              // react/redux and friends since they are pretty big
              react: {
                test: /\/node_modules\/(react|redux|prop-types\/|lodash-es\/|fbjs\/)/,
                name: 'react',
                chunks: 'initial',
                priority: 10,
              },
              semanticui: {
                test: /node_modules\/(semantic-ui|indico-sui-theme)/,
                name: 'semantic-ui',
                chunks: 'initial',
                priority: 10,
              },
            },
      },
      minimizer: [
        new TerserPlugin({
          exclude: [
            // "Unexpected token: punc (:) [js/mathjax/extensions/a11y/mathmaps/fr.js:2,25]"
            /js\/mathjax(\/unpacked)?\/extensions\/a11y\/mathmaps\/.+\.js$/,
          ],
          extractComments: false,
        }),
      ],
    },
  };
}

export function indicoStaticLoader(config) {
  return {
    test: /\/static\/(images|fonts)\/.*\.(jpe?g|png|gif|svg|woff2?|ttf|eot)$/,
    use: {
      loader: 'file-loader',
      options: {
        name: generateAssetPath(config, true),
        context: config.build.staticPath,
        emitFile: false,
        publicPath: config.build.staticURL,
      },
    },
  };
}
<|endoftext|>


<commit_before>"use strict";

module.exports = (sequelize, DataTypes) => {
  const AcList = sequelize.define("AcList", {
    data: DataTypes.JSONB,
    user_id: { type: DataTypes.INTEGER, allowNull: false },
    group_id: { type: DataTypes.INTEGER, allowNull: true },
    community_id: { type: DataTypes.INTEGER, allowNull: true },
    post_id: { type: DataTypes.INTEGER, allowNull: true }
  }, {
    underscored: true,

    timestamps: true,
    createdAt: 'created_at',
    updatedAt: 'updated_at',

    tableName: 'ac_lists'
  });

  AcList.associate = (models) => {
    AcList.belongsTo(models.Post,{ foreignKey: 'post_id' });
    AcList.belongsTo(models.Community,{ foreignKey: 'community_id' });
    AcList.belongsTo(models.Group,{ foreignKey: 'group_id' });
    AcList.belongsTo(models.User,{ foreignKey: 'user_id' });
  };

  AcList.getList = (groupId, done) => {
    models.AcList.findOrCreate({
      where: {
        group_id: groupId
      },
      defaults: {
        data: {
          openCount: 0,
          completeCount: 0,
          lastError: null,
        }
      }
    }).then(list=>{
      done(null, list);
    }).catch(error=>{
      done(error);
    });
  };

  AcList.addListUsers = async (listId, body, done) => {
    const t = await sequelize.transaction();
    try {
      async.eachSeries(body.listUsersEntries, (listUserEntry, seriesCallback) => {
        models.AcListUser.findOrCreate({
          where: {
            sms: listUserEntry.sms
          },
          defaults: {
            ac_list_id: listId,
            data: {
              openCount: 0,
              completeCount: 0
            }
          },
          transaction: t
        }).then(list=>{
          seriesCallback();
        }).catch(error=>{
          seriesCallback(error);
        });
      }, (error) => {
        done(error);
      });
    } catch (error) {
      await t.rollback();
      done();
    }
  return AcList;
};
<commit_msg>Work on marketing app<commit_after>"use strict";

module.exports = (sequelize, DataTypes) => {
  const AcList = sequelize.define("AcList", {
    data: DataTypes.JSONB,
    user_id: { type: DataTypes.INTEGER, allowNull: false },
    group_id: { type: DataTypes.INTEGER, allowNull: true },
    community_id: { type: DataTypes.INTEGER, allowNull: true },
    post_id: { type: DataTypes.INTEGER, allowNull: true }
  }, {
    underscored: true,

    timestamps: true,
    createdAt: 'created_at',
    updatedAt: 'updated_at',

    tableName: 'ac_lists'
  });

  AcList.associate = (models) => {
    AcList.belongsTo(models.Post,{ foreignKey: 'post_id' });
    AcList.belongsTo(models.Community,{ foreignKey: 'community_id' });
    AcList.belongsTo(models.Group,{ foreignKey: 'group_id' });
    AcList.belongsTo(models.User,{ foreignKey: 'user_id' });
  };

  AcList.getList = (groupId, done) => {
    models.AcList.findOrCreate({
      where: {
        group_id: groupId
      },
      defaults: {
        group_id: groupId
      }
    }).then(list=>{
      done(null, list);
    }).catch(error=>{
      done(error);
    });
  };

  AcList.addListUsers = async (listId, body, done) => {
    const t = await sequelize.transaction();
    try {
      async.eachSeries(body.listUsersEntries, (listUserEntry, seriesCallback) => {
        models.AcListUser.findOrCreate({
          where: {
            sms: listUserEntry.sms
          },
          defaults: {
            ac_list_id: listId,
            data: {
              openCount: 0,
              sentCount: 0,
              completeCount: 0
            }
          },
          transaction: t
        }).then(() => {
          seriesCallback();
        }).catch(error => {
          seriesCallback(error);
        });
      }, (error) => {
        done(error);
      });
    } catch (error) {
      await t.rollback();
      done(error);
    }
  };

  return AcList;
};
<|endoftext|>


<commit_before>var base = require('./base-module');

var appPros = {};

for(var i in base){
    appPros[i] = base[i];
}
appPros.collection = "appPros";
appPros.column = {
    name         : 'name',
    description  : 'description',
    user         : 'user',
    sizes        : 'sizes',
    createDate   : 'createDate',
    stars        : 'stars',
    type         : 'type',
    files        : 'files',
    route        : 'route',
    entrance      : 'entrance'
};
appPros.subTidy ={
    id:'id',
    parentId:'parentId',
    name:'name',
    url:'url',
    content:'content'
};

//新增app
appPros.add = function(data,fn){
    if(!data.files) data.files = [];
    var d = base.tidy(appPros.column,data);

    base.dbClient.connect([
        function(db,callback){
            db.collection(appPros.collection).insert(d,function(err,data){
                callback(err,data);
            });
        }
    ],fn);
}

//查询
appPros.operaQuery = function(data, fn, filter, opera){
    var d = base.tidy(appPros.column,data);
    base.dbClient.connect([
        function(db,callback){
            if(opera){
                var o = db.collection(appPros.collection).find(d,{fields:filter});
                for(var n in opera){
                    o = o[n](opera[n]);
                }
                o.toArray(function(err,data){
                    callback(err,data);
                });
            }else{
                db.collection(appPros.collection).find(d,{fields:filter}).toArray(function(err,data){
                    callback(err,data);
                });
            }
        }
    ],fn);
}

//查询接口文档
appPros.queryItem = function(data,fn,filter){
    var d = base.tidy(appPros.column, data);
    base.dbClient.connect([
        function(db,callback){
            db.collection(appPros.collection).aggregate(
                {'$match':d},
                {'$project':{'files':'$files'}},
                {'$unwind':'$files'},
                {'$match':data.search},
                function(err,data){
                    callback(err,data);
                }
            );
        }
    ],fn);
};

//新增接口文档
appPros.addItem = function(data,fn){
    var parentId = data.parentId;
    var d = base.dbClient.split(base.tidy(appPros.column,data));
    d.data.parentId = parentId;
    base.dbClient.connect([
        function(db,callback){
            db.collection(appPros.collection).find(d.search).toArray(function(err,data){
                var list = data[0].files;
                var id = 1;

                if(list && list.length){
                    id = (list[list.length - 1].id || 0) + 1;
                }

                callback(err,id,db);
            });
        },
        function(id,db,callback){
            d.data.id = id;
            db.collection(appPros.collection).update(d.search,{$push:{'files':d.data}},function(err,data){
                callback(err,{id:id});
            });
        }
    ],fn);
}

//更新接口文档
appPros.updateItem = function(data,fn){
    var list = base.tidy(appPros.subTidy,data);
    var d = base.dbClient.split(base.tidy(appPros.column,data));
    var set = {};
    d.search['files.id'] = data.id;

    delete list._id;

    if(data.updateKeys){
        for(var n in data.updateKeys){
            set['files.$.' + data.updateKeys[n]] = list[data.updateKeys[n]];
        }
    }else{
        set['files.$'] = list;
    }

    base.dbClient.connect([
        function(db,callback){
            db.collection(appPros.collection).update(d.search, {$set: set},function(err,data){
                callback(err,data);
            });
        }
    ],fn);
}

//删除接口文档
appPros.deleteItem = function(data,fn){
    data.files = {
        $or:[
            {id: data.id},
            {parentId: data.id}
        ]
    };
    var d = base.dbClient.split(base.tidy(appPros.column,data));

    base.dbClient.connect([
        function(db,callback){
            db.collection(appPros.collection).update(d.search, {$pull: d.data},function(err,data){
                callback(err,data);
            });
        }
    ],fn);
}

module.exports = appPros;<commit_msg>add back end route for app-pro<commit_after>var base = require('./base-module');

var appPros = {};

for(var i in base){
    appPros[i] = base[i];
}
appPros.collection = "appPros";
appPros.column = {
    name         : 'name',
    description  : 'description',
    user         : 'user',
    sizes        : 'sizes',
    createDate   : 'createDate',
    stars        : 'stars',
    type         : 'type',
    files        : 'files',
    route        : 'route',
    entrance      : 'entrance'
};
appPros.subTidy ={
    id:'id',
    parentId:'parentId',
    name:'name',
    url:'url',
    content:'content'
};

//新增app
appPros.add = function(data,fn){
    if(!data.files) data.files = [];
    var d = base.tidy(appPros.column,data);

    base.dbClient.connect([
        function(db,callback){
            db.collection(appPros.collection).insert(d,function(err,data){
                callback(err,data);
            });
        }
    ],fn);
}

//查询
appPros.operaQuery = function(data, fn, filter, opera){
    var d = base.tidy(appPros.column,data);
    base.dbClient.connect([
        function(db,callback){
            if(opera){
                var o = db.collection(appPros.collection).find(d,{fields:filter});
                for(var n in opera){
                    o = o[n](opera[n]);
                }
                o.toArray(function(err,data){
                    callback(err,data);
                });
            }else{
                db.collection(appPros.collection).find(d,{fields:filter}).toArray(function(err,data){
                    callback(err,data);
                });
            }
        }
    ],fn);
}

//查询接口文档
appPros.queryItem = function(data,fn,filter){
    var d = base.tidy(appPros.column, data);
    base.dbClient.connect([
        function(db,callback){
            db.collection(appPros.collection).aggregate(
                {'$match':d},
                {'$project':{'files':'$files'}},
                {'$unwind':'$files'},
                {'$match':data.search},
                function(err,data){
                    callback(err,data);
                }
            );
        }
    ],fn);
};

//新增接口文档
appPros.addItem = function(data,fn){
    var parentId = data.parentId;
    var d = base.dbClient.split(base.tidy(appPros.column,data));
    d.data.parentId = parentId;
    base.dbClient.connect([
        function(db,callback){
            db.collection(appPros.collection).find(d.search).toArray(function(err,data){
                var list = data[0].files;
                var id = 1;

                if(list && list.length){
                    id = (list[list.length - 1].id || 0) + 1;
                }

                callback(err,id,db);
            });
        },
        function(id,db,callback){
            d.data.id = id;
            db.collection(appPros.collection).update(d.search,{$push:{'files':d.data}},function(err,data){
                callback(err,{id:id});
            });
        }
    ],fn);
}

//更新接口文档
appPros.updateItem = function(data,fn){
    var list = base.tidy(appPros.subTidy,data);
    var d = base.dbClient.split(base.tidy(appPros.column,data));
    var setMap = {};
    d.search['files.id'] = data.id;

    delete list._id;

    if(data.updateKeys){
        for(var n in data.updateKeys){
            setMap['files.$.' + data.updateKeys[n]] = list[data.updateKeys[n]];
        }
    }else{
        setMap['files.$'] = list;
    }

    base.dbClient.connect([
        function(db,callback){
            db.collection(appPros.collection).update(d.search, {$set: setMap},function(err,data){
                callback(err,data);
            });
        }
    ],fn);
}

//删除接口文档
appPros.deleteItem = function(data,fn){
    data.files = {
        $or:[
            {id: data.id},
            {parentId: data.id}
        ]
    };
    var d = base.dbClient.split(base.tidy(appPros.column,data));

    base.dbClient.connect([
        function(db,callback){
            db.collection(appPros.collection).update(d.search, {$pull: d.data},function(err,data){
                callback(err,data);
            });
        }
    ],fn);
}

module.exports = appPros;<|endoftext|>


<commit_before>//live ticks
(function () {
    "use strict";
    //script for live ticks
    function loadLive(e) {
        e.fail(function(jqXHR, textStatus, errorThrown) {
            console.error(jqXHR.responseJSON.msg);
        });
        e.done(function(e, textStatus, jqXHR) {
            let actions = e.actions;
            if (actions !== null) {
    //                actions.reverse();
                for (let i = 0; i < actions.length; i++) {
    //                    var dateRaw = new Date (actions[i].time*1000);
    //                    var hours = '0' + dateRaw.getHours();
    //                    var minutes = '0' + dateRaw.getMinutes();
    //                    var date = hours.substr(-2) + ':' + minutes.substr(-2);
                    $('#dashLiveList').prepend("
" +
                        actions[i].dateTime + ": " + actions[i].userName + " ...called: " + actions[i].url + "
");
                }
            }
            setTimeout(function() {
                let ele =  $('#dashLiveList li:nth-child(1)');
                let since = ele.data('timestamp');
                livereload(since);
            }, 4500);
        });
    }
    function livereload(since) {
        let data = {
            method: "getLiveActions",
            since: since,
        };
        $.ajax({
            url: "/system/json",
            type: "POST",
            data: JSON.stringify(data),
            complete: loadLive,
        });
    }
    livereload( $('#dashLiveList li:nth-child(1)').data('timestamp'), 0);
})();
//
(function () {
    "use strict";
    //script for live ticks
    function loadActive(e) {
        e.fail(function(jqXHR, textStatus, errorThrown) {
            console.error(jqXHR.responseJSON.msg);
        });
        e.done(function(e, textStatus, jqXHR) {
            let user = e.users;
            // active users
            if (user !== null) {
                // user.reverse();
                for (let c = 0; c < user.length; c++){
                    // remove updated user
                    if (user[c].userId == $('li[data-userId="' + user[c].userId + '"]').data('userId') ) {
                        if (user[c].microtime == $('li[data-microtime="' + user[c].microtime + '"]').data('microtime')) continue;
                    }
                    $('li[data-firstCall="' + user[c].firstCall + '"]').remove();
                    // prepend updated user
                    $('#users').prepend("
" +
                        user[c].userName + ": " + user[c].url + " @ " + user[c].dateTime + "
");
                }
            }
            setTimeout(function() {
                let elm = $('#users li:nth-child(1)');
                let microtime = elm.data('microtime');
                activereload(microtime);
            }, 4500);
        });
    }
    function activereload(microtime) {
        let data = {
            method: "getActiveUsers",
            microtime: microtime,
        };
        $.ajax({
            url: "/system/json",
            type: "POST",
            data: JSON.stringify(data),
            complete: loadActive
        });
    }
    activereload( 1 );
})();
//
(function(){
    var html = $('.dashboard.systemLog boxcontent').html();

    $('.systemLog').on('click', function(){
        // html = $('.dashboard.systemLog boxcontent').html();
        // html = $('#sysTable').html();
        $('

').dialog({
            width: "100%",
            onLoad: function (html) {
            }
        });
        $('#pop').append(html);
        $('#pop ul').css('max-height', '60vh');
    });
})();
//system config control
(function () {
    "use strict";
    //scan system vars and register handler
    var $systemPanel = $('.systemPanel'),
        $cachePanel = $('.cachePanel');

    $("button", $systemPanel).on('click', function(e) {
        let type = $(this).data('type');
        if (type === 'function') {
            let valueName = $(this).attr('name');
            //handle function
            console.log(valueName, type);
            setSystemConfig(valueName, []);
        } else if (type === 'boolean') {
            //handle string, number
            let $input = $(this).parent().children('input');
            let valueName = $input.attr('name');
            let value = $input.prop('checked');
            //handle checkbox
            console.log(valueName, value, type);
            setSystemConfig(valueName, value);
        } else {
            let $input = $(this).parent().children('input');
            let valueName = $input.attr('name');
            let value = $input.val();
            console.log(valueName, value, type);
            setSystemConfig(valueName, value);
        }
    });

    $("button", $cachePanel).on('click', function(e) {
        let cacheName = $(this).data('name');
        console.log(cacheName);
        // clearCache(cacheName);
    });

    function getSystemConfig() {
        send({
            method: 'getSystemConfig'
        }).fail(function() {
            console.log('######### fail');
        }).done(function() {
            console.log('############ nice');
        });
    }
    function setSystemConfig(key, value) {
        send({
            method: 'setSystemConfig',
            valueName: key,
            value: value,
        }).fail(function() {
            console.log('fail setting system config');
        }).done(function() {
            console.log('set system config');
        });
    }
    function clearCache(name) {
        send({
            method: 'clearCache',
            name: name,
        }).fail(function() {
            console.log('failed clearing cache');
        }).done(function() {
            console.log('Cache cleared');
        });
    }
    function send(data) {
        return $.ajax({
            url: "/system/json",
            type: "POST",
            data: JSON.stringify(data),
        });
    }
})();<commit_msg>fix cache js<commit_after>//live ticks
(function () {
    "use strict";
    //script for live ticks
    function loadLive(e) {
        e.fail(function(jqXHR, textStatus, errorThrown) {
            console.error(jqXHR.responseJSON.msg);
        });
        e.done(function(e, textStatus, jqXHR) {
            let actions = e.actions;
            if (actions !== null) {
    //                actions.reverse();
                for (let i = 0; i < actions.length; i++) {
    //                    var dateRaw = new Date (actions[i].time*1000);
    //                    var hours = '0' + dateRaw.getHours();
    //                    var minutes = '0' + dateRaw.getMinutes();
    //                    var date = hours.substr(-2) + ':' + minutes.substr(-2);
                    $('#dashLiveList').prepend("
" +
                        actions[i].dateTime + ": " + actions[i].userName + " ...called: " + actions[i].url + "
");
                }
            }
            setTimeout(function() {
                let ele =  $('#dashLiveList li:nth-child(1)');
                let since = ele.data('timestamp');
                livereload(since);
            }, 4500);
        });
    }
    function livereload(since) {
        let data = {
            method: "getLiveActions",
            since: since,
        };
        $.ajax({
            url: "/system/json",
            type: "POST",
            data: JSON.stringify(data),
            complete: loadLive,
        });
    }
    livereload( $('#dashLiveList li:nth-child(1)').data('timestamp'), 0);
})();
//
(function () {
    "use strict";
    //script for live ticks
    function loadActive(e) {
        e.fail(function(jqXHR, textStatus, errorThrown) {
            console.error(jqXHR.responseJSON.msg);
        });
        e.done(function(e, textStatus, jqXHR) {
            let user = e.users;
            // active users
            if (user !== null) {
                // user.reverse();
                for (let c = 0; c < user.length; c++){
                    // remove updated user
                    if (user[c].userId == $('li[data-userId="' + user[c].userId + '"]').data('userId') ) {
                        if (user[c].microtime == $('li[data-microtime="' + user[c].microtime + '"]').data('microtime')) continue;
                    }
                    $('li[data-firstCall="' + user[c].firstCall + '"]').remove();
                    // prepend updated user
                    $('#users').prepend("
" +
                        user[c].userName + ": " + user[c].url + " @ " + user[c].dateTime + "
");
                }
            }
            setTimeout(function() {
                let elm = $('#users li:nth-child(1)');
                let microtime = elm.data('microtime');
                activereload(microtime);
            }, 4500);
        });
    }
    function activereload(microtime) {
        let data = {
            method: "getActiveUsers",
            microtime: microtime,
        };
        $.ajax({
            url: "/system/json",
            type: "POST",
            data: JSON.stringify(data),
            complete: loadActive
        });
    }
    activereload( 1 );
})();
//
(function(){
    var html = $('.dashboard.systemLog boxcontent').html();

    $('.systemLog').on('click', function(){
        // html = $('.dashboard.systemLog boxcontent').html();
        // html = $('#sysTable').html();
        $('

').dialog({
            width: "100%",
            onLoad: function (html) {
            }
        });
        $('#pop').append(html);
        $('#pop ul').css('max-height', '60vh');
    });
})();
//system config control
(function () {
    "use strict";
    //scan system vars and register handler
    var $systemPanel = $('.systemPanel'),
        $cachePanel = $('.cachePanel');

    $("button", $systemPanel).on('click', function(e) {
        let type = $(this).data('type');
        if (type === 'function') {
            let valueName = $(this).attr('name');
            //handle function
            console.log(valueName, type);
            setSystemConfig(valueName, []);
        } else if (type === 'boolean') {
            //handle string, number
            let $input = $(this).parent().children('input');
            let valueName = $input.attr('name');
            let value = $input.prop('checked');
            //handle checkbox
            console.log(valueName, value, type);
            setSystemConfig(valueName, value);
        } else {
            let $input = $(this).parent().children('input');
            let valueName = $input.attr('name');
            let value = $input.val();
            console.log(valueName, value, type);
            setSystemConfig(valueName, value);
        }
    });

    $("button", $cachePanel).on('click', function(e) {
        let cacheName = $(this).data('name');
        clearCache(cacheName);
    });

    function getSystemConfig() {
        send({
            method: 'getSystemConfig'
        }).fail(function() {
            console.log('######### fail');
        }).done(function() {
            console.log('############ nice');
        });
    }
    function setSystemConfig(key, value) {
        send({
            method: 'setSystemConfig',
            valueName: key,
            value: value,
        }).fail(function() {
            console.log('fail setting system config');
        }).done(function() {
            console.log('set system config');
        });
    }
    function clearCache(name) {
        send({
            method: 'clearCache',
            name: name,
        }).fail(function() {
            console.log('failed clearing cache');
        }).done(function() {
            console.log('Cache cleared');
        });
    }
    function send(data) {
        return $.ajax({
            url: "/system/json",
            type: "POST",
            data: JSON.stringify(data),
        });
    }
})();<|endoftext|>


<commit_before>'use strict';

var log4js = require('log4js');
var logger = log4js.getLogger('controllers/user');

var UserModel = require('../models/user');
var Session = require('../util/session');

var CLIENT_ID = 'ramRPsEprwFt2FOzrHzg';
var CLIENT_SECRET = '5KYRbJV1Tw';

function UserController() {

}

UserController.prototype.readUser = function(req, res) {
  var userPromise = UserModel.findOne({_id: req.params.id});
  var postPromise = UserModel.model('Post').find({author: req.params.id});
  var result = null;
  //if (!Session.isAllow(req, req.params.id)) {
  //  return res.status(401).send('permission denied');
  //}
  userPromise.then(function(user) {
    if (!user) {
      throw 'not exist user';
    }
    result = user;
    return postPromise;
  }).then(function(posts) {
    result.posts = posts || [];
    res.status(200).send(result);
  }).catch(function(err) {
    logger.error(err);
    return res.status(400).send(err);
  });
};

UserController.prototype.login = function(req, res) {
  if (Session.hasSession(req)) {
    return res.redirect('/user/'+req.session.userId);
  }
  var request = require('request');
  request('https://nid.naver.com/oauth2.0/token?grant_type=authorization_code&' +
    'client_id=' + CLIENT_ID +
    '&client_secret=' + CLIENT_SECRET +
    '&code=' + req.query.code + '&state=' + req.query.state,
    function (error, response, body) {
      var tokenResult, result, options, newUser;
      if (!error && response.statusCode == 200) {
        try {
          tokenResult = JSON.parse(body);
        } catch (e) {
          logger.error(e);
          return res.status(400).send(e);
        }

        options = {
          url: 'https://openapi.naver.com/v1/nid/me',
          headers: {
            'Authorization': 'Bearer ' + tokenResult.access_token
          }
        };

        request(options, function (error, response, body) {
          try {
            result = JSON.parse(body);
          } catch (e) {
            logger.error(e);
            return res.status(400).send(e);
          }

          newUser = {
            nickname: result.response.nickname,
            email: result.response.email,
            birthday: result.response.birthday,
            accessToken: tokenResult.access_token,
            refreshToken: tokenResult.refresh_token
          };

          UserModel.findOne({nickname: newUser.nickname}, function(err, user) {
            if (user) {
              Session.registerSession(req, user);
              return res.redirect('/user/'+req.session.userId);
            }
            UserModel.create(newUser, function(err, user) {
              if (err) {
                logger.error(err);
                return res.status(400).send(err);
              }
              Session.registerSession(req, user);
              res.redirect('/user/'+req.session.userId);
            });
          });
        });
      }
    });
};

module.exports = new UserController();<commit_msg>Update user<commit_after>'use strict';

var log4js = require('log4js');
var logger = log4js.getLogger('controllers/user');

var UserModel = require('../models/user');
var Session = require('../util/session');

var CLIENT_ID = 'ramRPsEprwFt2FOzrHzg';
var CLIENT_SECRET = '5KYRbJV1Tw';

function UserController() {

}

UserController.prototype.readUser = function(req, res) {
  var userPromise = UserModel.findOne({_id: req.params.id});
  var postPromise = UserModel.model('Post').find({author: req.params.id});
  var result = null;
  //if (!Session.isAllow(req, req.params.id)) {
  //  return res.status(401).send('permission denied');
  //}
  userPromise.then(function(user) {
    if (!user) {
      throw 'not exist user';
    }
    result = user;
    return postPromise;
  }).then(function(posts) {
    result.posts = posts || [];
    res.status(200).send(result);
  }).catch(function(err) {
    logger.error(err);
    return res.status(400).send(err);
  });
};

UserController.prototype.login = function(req, res) {
  if (Session.hasSession(req)) {
    return res.redirect('/user/'+req.session.userId);
  }
  var request = require('request');
  request('https://nid.naver.com/oauth2.0/token?grant_type=authorization_code&' +
    'client_id=' + CLIENT_ID +
    '&client_secret=' + CLIENT_SECRET +
    '&code=' + req.query.code + '&state=' + req.query.state,
    function (error, response, body) {
      var tokenResult, result, options, newUser;
      if (!error && response.statusCode == 200) {
        try {
          tokenResult = JSON.parse(body);
        } catch (e) {
          logger.error(e);
          return res.status(400).send(e);
        }

        options = {
          url: 'https://openapi.naver.com/v1/nid/me',
          headers: {
            'Authorization': 'Bearer ' + tokenResult.access_token
          }
        };

        request(options, function (error, response, body) {
          try {
            result = JSON.parse(body);
          } catch (e) {
            logger.error(e);
            return res.status(400).send(e);
          }

          newUser = {
            nickname: result.response.nickname,
            email: result.response.email,
            birthday: result.response.birthday,
            accessToken: tokenResult.access_token,
            refreshToken: tokenResult.refresh_token
          };

          logger.debug("newUser:", newUser);
          UserModel.findOne({nickname: newUser.nickname}, function(err, user) {
            if (user) {
              Session.registerSession(req, user);
              return res.redirect('/user/'+req.session.userId);
            }
            UserModel.create(newUser, function(err, user) {
              if (err) {
                logger.error(err);
                return res.status(400).send(err);
              }
              Session.registerSession(req, user);
              res.redirect('/user/'+req.session.userId);
            });
          });
        });
      }
    });
};

module.exports = new UserController();<|endoftext|>


<commit_before>var utils = require('../lib/utils'),
    getLogin = require('../lib/get-user-login'),
    db = require('../lib/db');

// Builds an object representation of a row in the DB `pulls` table
// from the data returned by GitHub's API.
function DBPull(pull) {
   var pullData = pull.data;
   this.data = {
      repo: pullData.repo,
      number: pullData.number,
      state: pullData.state,
      title: pullData.title,
      body: pullData.body,
      draft: pullData.draft === 1,
      date: utils.toUnixTime(pullData.created_at),
      date_updated: utils.toUnixTime(pullData.updated_at),
      date_closed: utils.toUnixTime(pullData.closed_at),
      date_merged: utils.toUnixTime(pullData.merged_at),
      difficulty: pullData.difficulty,
      milestone_title: pullData.milestone.title,
      milestone_due_on: utils.toUnixTime(pullData.milestone.due_on),
      head_branch: pullData.head.ref,
      head_sha: pullData.head.sha,
      base_branch: pullData.base.ref,
      owner: getLogin(pullData.user),
      cr_req: pullData.cr_req,
      qa_req: pullData.qa_req,
      closes: pullData.closes,
      connects: pullData.connects,
      commits: pullData.commits,
      additions: pullData.additions,
      deletions: pullData.deletions,
      changed_files: pullData.changed_files
   };
}

DBPull.prototype.save = function() {
   var pullData = this.data;
   var q_update = 'REPLACE INTO pulls SET ?';

   return db.query(q_update, pullData);
};

module.exports = DBPull;
<commit_msg>use ternary for 'draft' value assignment<commit_after>var utils = require('../lib/utils'),
    getLogin = require('../lib/get-user-login'),
    db = require('../lib/db');

// Builds an object representation of a row in the DB `pulls` table
// from the data returned by GitHub's API.
function DBPull(pull) {
   var pullData = pull.data;
   this.data = {
      repo: pullData.repo,
      number: pullData.number,
      state: pullData.state,
      title: pullData.title,
      body: pullData.body,
      draft: pullData.draft ? 1 : 0,
      date: utils.toUnixTime(pullData.created_at),
      date_updated: utils.toUnixTime(pullData.updated_at),
      date_closed: utils.toUnixTime(pullData.closed_at),
      date_merged: utils.toUnixTime(pullData.merged_at),
      difficulty: pullData.difficulty,
      milestone_title: pullData.milestone.title,
      milestone_due_on: utils.toUnixTime(pullData.milestone.due_on),
      head_branch: pullData.head.ref,
      head_sha: pullData.head.sha,
      base_branch: pullData.base.ref,
      owner: getLogin(pullData.user),
      cr_req: pullData.cr_req,
      qa_req: pullData.qa_req,
      closes: pullData.closes,
      connects: pullData.connects,
      commits: pullData.commits,
      additions: pullData.additions,
      deletions: pullData.deletions,
      changed_files: pullData.changed_files
   };
}

DBPull.prototype.save = function() {
   var pullData = this.data;
   var q_update = 'REPLACE INTO pulls SET ?';

   return db.query(q_update, pullData);
};

module.exports = DBPull;
<|endoftext|>


<commit_before>module.exports = package

var LRU = require("lru-cache")
, regData = new LRU(10000)
, marked = require("marked")
, callresp = require("cluster-callresp")
, gravatar = require('gravatar').url

function package (params, cb) {
  var name, version

  if (typeof params === 'object') {
    name = params.name
    version = params.version
  } else {
    var p = params.split('@')
    name = p.shift()
    version = p.join('@')
  }
  version = version || 'latest'

  var k = name + '/' + version
  , data = regData.get(k)

  // remove excessively stale data
  // ignore anything over 10 minutes old
  if (data) {
    var age = Date.now() - data._time
    if (age > 10 * 60 * 1000) {
      regData.del(k)
      data = null
    }
  }

  if (data) return cb(null, data)

  callresp({ cmd: 'registry.get'
           , name: name
           , version: version }, function (er, data) {
    if (er) return cb(er)

    data._time = Date.now()
    if (data.readme) data.readme = parseReadme(data.readme)
    gravatarPeople(data)
    regData.set(k, data)
    return cb(null, data)
  })
}

function parseReadme (readme) {
  // allow <url>, but not arbitrary html tags.
  // any < must be the start of a <url> or <email@address>
  var e = /^<(?![^ >]+(@|:\/)[^ >]+>)/g
  readme = readme.replace(e, '<')
  return marked.parse(readme)
}

function gravatarPeople (data) {
  gravatarPerson(data.author)
  if (data.maintainers) data.maintainers.forEach(function (m) {
    gravatarPerson(m)
  })
  if (data.contributors) data.contributors.forEach(function (m) {
    gravatarPerson(m)
  })
}

function gravatarPerson (p) {
  if (!p || typeof p !== 'object' || !p.email) {
    return
  }
  p.gravatar = gravatar(p.email, {s:50, d:'retro'})
}
<commit_msg>missed a ssl gravatar<commit_after>module.exports = package

var LRU = require("lru-cache")
, regData = new LRU(10000)
, marked = require("marked")
, callresp = require("cluster-callresp")
, gravatar = require('gravatar').url

function package (params, cb) {
  var name, version

  if (typeof params === 'object') {
    name = params.name
    version = params.version
  } else {
    var p = params.split('@')
    name = p.shift()
    version = p.join('@')
  }
  version = version || 'latest'

  var k = name + '/' + version
  , data = regData.get(k)

  // remove excessively stale data
  // ignore anything over 10 minutes old
  if (data) {
    var age = Date.now() - data._time
    if (age > 10 * 60 * 1000) {
      regData.del(k)
      data = null
    }
  }

  if (data) return cb(null, data)

  callresp({ cmd: 'registry.get'
           , name: name
           , version: version }, function (er, data) {
    if (er) return cb(er)

    data._time = Date.now()
    if (data.readme) data.readme = parseReadme(data.readme)
    gravatarPeople(data)
    regData.set(k, data)
    return cb(null, data)
  })
}

function parseReadme (readme) {
  // allow <url>, but not arbitrary html tags.
  // any < must be the start of a <url> or <email@address>
  var e = /^<(?![^ >]+(@|:\/)[^ >]+>)/g
  readme = readme.replace(e, '<')
  return marked.parse(readme)
}

function gravatarPeople (data) {
  gravatarPerson(data.author)
  if (data.maintainers) data.maintainers.forEach(function (m) {
    gravatarPerson(m)
  })
  if (data.contributors) data.contributors.forEach(function (m) {
    gravatarPerson(m)
  })
}

function gravatarPerson (p) {
  if (!p || typeof p !== 'object' || !p.email) {
    return
  }
  p.gravatar = gravatar(p.email, {s:50, d:'retro'}, true)
}
<|endoftext|>


<commit_before>'use strict';
var inherits = require('inherits');

inherits(APIError, Error);
module.exports = APIError;
function APIError (error, request) {
  if (!(this instanceof APIError)) {
    return new APIError(error);
  }
  this.name = error.sys.id;
  this.message = [request.method, request.uri, formatMessage(error)].join(' ');
  this.request = request;
  if (Error.captureStackTrace) {
    Error.captureStackTrace(this, this.constructor);
  }
}

var customFormatters = {
  ValidationFailed: function (error) {
    if (!(error.details && error.details.errors)) {
      return JSON.stringify(error);
    }
    return error.details.errors.reduce(function (messages, validationError) {
      var message = '(' + validationError.name +
                    ' path=' + validationError.path.join('.') +
                    ' value=' + JSON.stringify(validationError.value) + ')';
      return messages.concat(message);
    }, []).join(', ');
  }
};

function formatMessage (error) {
  if ('message' in error) {
    return error.message;
  }

  if (customFormatters[error.sys.id]) {
    return customFormatters[error.sys.id](error);
  }

  // stringify on one line
  return JSON.stringify(error);
}
<commit_msg>Add single-line-stringified error to error.message case<commit_after>'use strict';
var inherits = require('inherits');

inherits(APIError, Error);
module.exports = APIError;
function APIError (error, request) {
  if (!(this instanceof APIError)) {
    return new APIError(error);
  }
  this.name = error.sys.id;
  this.message = [request.method, request.uri, formatMessage(error)].join(' ');
  this.request = request;
  if (Error.captureStackTrace) {
    Error.captureStackTrace(this, this.constructor);
  }
}

var customFormatters = {
  ValidationFailed: function (error) {
    if (!(error.details && error.details.errors)) {
      return JSON.stringify(error);
    }
    return error.details.errors.reduce(function (messages, validationError) {
      var message = '(' + validationError.name +
                    ' path=' + validationError.path.join('.') +
                    ' value=' + JSON.stringify(validationError.value) + ')';
      return messages.concat(message);
    }, []).join(', ');
  }
};

function formatMessage (error) {
  if ('message' in error) {
    return error.message + ' ' + JSON.stringify(error);
  }

  if (customFormatters[error.sys.id]) {
    return customFormatters[error.sys.id](error);
  }

  // stringify on one line
  return JSON.stringify(error);
}
<|endoftext|>


<commit_before>var Namespace = (function (window, document, undefined) {
    // Constants

    // Configuration
    var config = {

    };

    // Fields

    // Methods
    function init() {
        // Empty
    };

    // Public API
    return {
        // outer: inner
    };
})(window, document);<commit_msg>Removed semi-colon<commit_after>var Namespace = (function (window, document, undefined) {
    // Constants

    // Configuration
    var config = {

    };

    // Fields

    // Methods
    function init() {
        // Empty
    }

    // Public API
    return {
        // outer: inner
    };
})(window, document);
<|endoftext|>


<commit_before>'use strict';

var GCE = require('./index');
var Auth = require('./Auth');
var fs = require('fs');
var uuid = require('uuid');
var path = require('path');
var ursa = require('ursa');

var buildTypes = {
  slave: {
    instance: fs.readFileSync(path.join(__dirname, 'instances', 'slave.json'), 'utf8')
  },
  github: {
    instance: fs.readFileSync(path.join(__dirname, 'instances', 'github.json'), 'utf8'),
    script: fs.readFileSync(path.join(__dirname, 'instances', 'github_startup.sh'), 'utf8')
  },
  ui: {
    instance: fs.readFileSync(path.join(__dirname, 'instances', 'ui.json'), 'utf8'),
    script: fs.readFileSync(path.join(__dirname, 'instances', 'ui_startup.sh'), 'utf8')
  },
  'slave-snapshot': {
    instance: fs.readFileSync(path.join(__dirname, 'images', 'slave.json'), 'utf8'),
    script: fs.readFileSync(path.join(__dirname, 'images', 'slave_startup.sh'), 'utf8')
  },
  'github-snapshot': {
    instance: fs.readFileSync(path.join(__dirname, 'images', 'github.json'), 'utf8'),
    script: fs.readFileSync(path.join(__dirname, 'images', 'github_startup.sh'), 'utf8')
  }
};

function Instance(projectId, zone, instanceName, type) {
  this.projectId = projectId;
  this.instanceName = instanceName;
  this.zone = zone;
  this.gce = new GCE(projectId, zone);

  if (type) {
    this.type = type;
    this.instanceBuildInfo = JSON.parse(buildTypes[this.type].instance);
    this.diskName = this.instanceBuildInfo.disks[0].deviceName;
    this.instanceBuildInfo.name = this.instanceName;
  }
}

// TODO(trostler): only export this function
Instance.Factory = function(type, xtra) {
  switch (type) {
    case 'slave':
      return Instance.Slave(xtra);
      break;
    case 'github':
      return Instance.GithubListener();
      break;
    case 'ui':
      return Instance.UI();
      break;
    case 'slave-snapshot':
      return Instance.SlaveSnapshot();
      break;
    case 'github-snapshot':
      return Instance.GithubSnapshot();
      break;
    default:
      throw new Error('I do not know instance type ' + type);
      break;
  }
};

Instance.Slave = function(iName) {
  // some krazy random name
  var instanceName = iName || ['x', new Date().getTime(), uuid.v4()].join('-').slice(0, 63);
  var newSlave = new Instance(Auth.projectId, Auth.zone, instanceName, 'slave');
  if (!iName) {
    // Generate a new pub/priv key pair
    var keys = ursa.generatePrivateKey();
    var pubSsh = keys.toPublicSsh('base64');
    this.instanceBuildInfo.metadata.items.push({
      key: 'sshKeys',
      value: [ 'sivart:ssh-rsa', pubSsh, 'sivart'].join(' ')
    });
    this.privateKey = keys.toPrivatePem('base64');
  }
  return newSlave;
};

Instance.SlaveSnapshot = function() {
  return new Instance(Auth.projectId, Auth.zone, 'slave-snapshot', 'slave-snapshot');
};

Instance.GithubListener = function() {
  return new Instance(Auth.projectId, Auth.zone, 'github', 'github');
};

Instance.UI = function() {
  return new Instance(Auth.projectId, Auth.zone, 'ui', 'ui');
};

Instance.GithubSnapshot = function() {
  return new Instance(Auth.projectId, Auth.zone, 'github-snapshot', 'github-snapshot');
};

Instance.prototype.build = function(script, cb) {

  if (typeof script === 'function') {
    cb = script;
    script = buildTypes[this.type].script;
  }

  this.instanceBuildInfo.metadata.items[0].value = script;
  this.create({ instance: this.instanceBuildInfo }, cb);
};

/*
 * Create a GCE VM instance
 */
Instance.prototype.create = function(args, cb) {
  var me = this;
  this.gce.start(function() {
    var data = args.instance;

    if (args.file) {
      data = JSON.parse(fs.readFileSync(args.file));
    }

    me.gce.createInstance(data, cb);
  });
};

/*
 * Delete a GCE VM instance
 */
Instance.prototype.delete = function(cb) {
  var me = this;
  this.gce.start(function() {
    me.gce.deleteInstance(me.instanceName, cb);
  });
};

Instance.prototype.get = function(cb) {
  this.gce.getInstance({ instance: this.instanceName }, cb);
};

Instance.prototype.getSerialConsoleOutput = function(cb) {
  var me = this;
  this.gce.start(function() {
    me.gce.getSerialConsoleOutput({ instance: me.instanceName }, cb);
  });
};

// Send console lines while still wanted.
Instance.prototype.tail_gce_console = function(cb) {
    var me = this;
    var seen_length = 0;
    this.gce.start(function() {
      function getout() {
        me.gce.getSerialConsoleOutput({ instance: me.instanceName }, function(err, total_output) {
          if (!err) {
            var contents = total_output.contents;
            contents = contents.slice(seen_length);
            seen_length += contents.length;
            var stop = cb(null, contents);
            if (!stop) {
              setTimeout(getout, 5000);
            }
          } else {
            cb('error getting serial console output: ' + err);
          }
        });
      }
      getout();
    });
};

module.exports = Instance;
<commit_msg>bug fix<commit_after>'use strict';

var GCE = require('./index');
var Auth = require('./Auth');
var fs = require('fs');
var uuid = require('uuid');
var path = require('path');
var ursa = require('ursa');

var buildTypes = {
  slave: {
    instance: fs.readFileSync(path.join(__dirname, 'instances', 'slave.json'), 'utf8')
  },
  github: {
    instance: fs.readFileSync(path.join(__dirname, 'instances', 'github.json'), 'utf8'),
    script: fs.readFileSync(path.join(__dirname, 'instances', 'github_startup.sh'), 'utf8')
  },
  ui: {
    instance: fs.readFileSync(path.join(__dirname, 'instances', 'ui.json'), 'utf8'),
    script: fs.readFileSync(path.join(__dirname, 'instances', 'ui_startup.sh'), 'utf8')
  },
  'slave-snapshot': {
    instance: fs.readFileSync(path.join(__dirname, 'images', 'slave.json'), 'utf8'),
    script: fs.readFileSync(path.join(__dirname, 'images', 'slave_startup.sh'), 'utf8')
  },
  'github-snapshot': {
    instance: fs.readFileSync(path.join(__dirname, 'images', 'github.json'), 'utf8'),
    script: fs.readFileSync(path.join(__dirname, 'images', 'github_startup.sh'), 'utf8')
  }
};

function Instance(projectId, zone, instanceName, type) {
  this.projectId = projectId;
  this.instanceName = instanceName;
  this.zone = zone;
  this.gce = new GCE(projectId, zone);

  if (type) {
    this.type = type;
    this.instanceBuildInfo = JSON.parse(buildTypes[this.type].instance);
    this.diskName = this.instanceBuildInfo.disks[0].deviceName;
    this.instanceBuildInfo.name = this.instanceName;
  }
}

// TODO(trostler): only export this function
Instance.Factory = function(type, xtra) {
  switch (type) {
    case 'slave':
      return Instance.Slave(xtra);
      break;
    case 'github':
      return Instance.GithubListener();
      break;
    case 'ui':
      return Instance.UI();
      break;
    case 'slave-snapshot':
      return Instance.SlaveSnapshot();
      break;
    case 'github-snapshot':
      return Instance.GithubSnapshot();
      break;
    default:
      throw new Error('I do not know instance type ' + type);
      break;
  }
};

Instance.Slave = function(iName) {
  // some krazy random name
  var instanceName = iName || ['x', new Date().getTime(), uuid.v4()].join('-').slice(0, 63);
  var newSlave = new Instance(Auth.projectId, Auth.zone, instanceName, 'slave');
  if (!iName) {
    // Generate a new pub/priv key pair
    var keys = ursa.generatePrivateKey();
    var pubSsh = keys.toPublicSsh('base64');
    newSlave.instanceBuildInfo.metadata.items.push({
      key: 'sshKeys',
      value: [ 'sivart:ssh-rsa', pubSsh, 'sivart'].join(' ')
    });
    newSlave.privateKey = keys.toPrivatePem('base64');
  }
  return newSlave;
};

Instance.SlaveSnapshot = function() {
  return new Instance(Auth.projectId, Auth.zone, 'slave-snapshot', 'slave-snapshot');
};

Instance.GithubListener = function() {
  return new Instance(Auth.projectId, Auth.zone, 'github', 'github');
};

Instance.UI = function() {
  return new Instance(Auth.projectId, Auth.zone, 'ui', 'ui');
};

Instance.GithubSnapshot = function() {
  return new Instance(Auth.projectId, Auth.zone, 'github-snapshot', 'github-snapshot');
};

Instance.prototype.build = function(script, cb) {

  if (typeof script === 'function') {
    cb = script;
    script = buildTypes[this.type].script;
  }

  this.instanceBuildInfo.metadata.items[0].value = script;
  this.create({ instance: this.instanceBuildInfo }, cb);
};

/*
 * Create a GCE VM instance
 */
Instance.prototype.create = function(args, cb) {
  var me = this;
  this.gce.start(function() {
    var data = args.instance;

    if (args.file) {
      data = JSON.parse(fs.readFileSync(args.file));
    }

    me.gce.createInstance(data, cb);
  });
};

/*
 * Delete a GCE VM instance
 */
Instance.prototype.delete = function(cb) {
  var me = this;
  this.gce.start(function() {
    me.gce.deleteInstance(me.instanceName, cb);
  });
};

Instance.prototype.get = function(cb) {
  this.gce.getInstance({ instance: this.instanceName }, cb);
};

Instance.prototype.getSerialConsoleOutput = function(cb) {
  var me = this;
  this.gce.start(function() {
    me.gce.getSerialConsoleOutput({ instance: me.instanceName }, cb);
  });
};

// Send console lines while still wanted.
Instance.prototype.tail_gce_console = function(cb) {
    var me = this;
    var seen_length = 0;
    this.gce.start(function() {
      function getout() {
        me.gce.getSerialConsoleOutput({ instance: me.instanceName }, function(err, total_output) {
          if (!err) {
            var contents = total_output.contents;
            contents = contents.slice(seen_length);
            seen_length += contents.length;
            var stop = cb(null, contents);
            if (!stop) {
              setTimeout(getout, 5000);
            }
          } else {
            cb('error getting serial console output: ' + err);
          }
        });
      }
      getout();
    });
};

module.exports = Instance;
<|endoftext|>


<commit_before>import Auth0Lock from 'auth0-lock'
import fetch from 'isomorphic-fetch'
import { browserHistory } from 'react-router'

import { isTokenExpired } from '../util/jwtHelper'
import UserPermissions from './UserPermissions'
import { getConfigProperty } from '../util/config'

// TODO: Fix PNG import
const icon = '' // import icon from '../../assets/application_logo.png'

export default class Auth0Manager {

  constructor (props) {
    this.props = props
    this.lock = new Auth0Lock(props.client_id, props.domain)
    // this.auth0 = new Auth0({clientID: props.client_id, domain: props.domain})
  }

  loggedIn () {
    // Checks if there is a saved token and it's still valid
    const token = this.getToken()
    return !!token && !isTokenExpired(token)
  }

  getToken () {
    // Retrieves the user token from localStorage
    return window.localStorage.getItem('userToken')
  }

  checkExistingLogin () {
    // Get the user token if we've saved it in localStorage before
    var userToken = this.getToken()

    if (userToken) return this.loginFromToken(userToken)

    // check if we have returned from an SSO redirect
    var hash = this.lock.parseHash()
    if (hash && hash.id_token) { // the user came back from the login (either SSO or regular login)
      // save the token
      window.localStorage.setItem('userToken', hash.id_token)

      // redirect to "targetUrl" if any
      let newLocation = hash.state || ''
      browserHistory.push(newLocation)
    } else {
      // check if logged in elsewhere via SSO
      this.lock.$auth0.getSSOData((err, data) => {
        if (!err && data.sso) {
          // there is! redirect to Auth0 for SSO
          this.lock.$auth0.signin({
            callbackOnLocationHash: true
          })
        } else { // assume that we are not logged in
        }
      })
    }

    return null
  }

  loginFromToken (token) {
    return fetch('https://' + this.props.domain + '/tokeninfo?id_token=' + token, {
      method: 'post'
    }).then(res => res.json()).then((profile) => {
      return constructUserObj(token, profile)
    }).catch((err) => {
      console.log('error getting profile', err)
      return this.loginViaLock({closable: false})
    })
  }

  loginViaLock (additionalLockOptions) {
    return new Promise((resolve, reject) => {
      var lockOptions = {
        connections: ['Username-Password-Authentication'],
        // callbackURL: getConfigProperty('application.url'),
        icon: getConfigProperty('application.logo') ? getConfigProperty('application.logo') : icon,
        disableSignupAction: true,
        // disableResetAction: true,
        authParams: {
          state: window.location.href
        },
        ...additionalLockOptions
      }
      if (this.props.logo) lockOptions.icon = this.props.logo
      this.lock.show(lockOptions, (err, profile, token) => {
        if (err) {
          console.log('Error w/ lock login', err)
          reject(err)
        }
        // save token to localStorage
        window.localStorage.setItem('userToken', token)

        // initialize auto log out check
        // this.setupSingleLogout()
        console.log(token, profile)
        // this.userLoggedIn(token, profile)
        resolve(constructUserObj(token, profile))
      })
    })
  }

  logout () {
    window.localStorage.removeItem('userToken')
    var redirect = window.location.protocol + '//' + window.location.hostname + (window.location.port ? ':' + window.location.port : '')
    window.location.replace('https://' + this.props.domain + '/v2/logout?returnTo=' + redirect)
  }

  resetPassword () {
    this.lock.showReset((err) => {
      if (!err) this.lock.hide()
    })
  }

  setupSingleLogout () {
    setInterval(() => {
      // if the token is not in local storage, there is nothing to check (i.e. the user is already logged out)
      if (!window.localStorage.getItem('userToken')) return

      this.auth0.getSSOData((err, data) => {
        // if there is still a session, do nothing
        if (err || (data && data.sso)) return

        // if we get here, it means there is no session on Auth0,
        // then remove the token and redirect to #login
        window.localStorage.removeItem('userToken')
        window.location.href = '/'
      })
    }, 5000)
  }
}

function constructUserObj (token, profile) {
  return {
    token,
    profile,
    permissions: new UserPermissions(profile.app_metadata.datatools)
  }
}

module.exports = Auth0Manager
<commit_msg>add props to login func<commit_after>import Auth0Lock from 'auth0-lock'
import fetch from 'isomorphic-fetch'
import { browserHistory } from 'react-router'

import { isTokenExpired } from '../util/jwtHelper'
import UserPermissions from './UserPermissions'
import { getConfigProperty } from '../util/config'

// TODO: Fix PNG import
const icon = '' // import icon from '../../assets/application_logo.png'

export default class Auth0Manager {

  constructor (props) {
    this.props = props
    this.lock = new Auth0Lock(props.client_id, props.domain)
    // this.auth0 = new Auth0({clientID: props.client_id, domain: props.domain})
  }

  loggedIn () {
    // Checks if there is a saved token and it's still valid
    const token = this.getToken()
    return !!token && !isTokenExpired(token)
  }

  getToken () {
    // Retrieves the user token from localStorage
    return window.localStorage.getItem('userToken')
  }

  checkExistingLogin (props) {
    // Get the user token if we've saved it in localStorage before
    var userToken = this.getToken()

    if (userToken) return this.loginFromToken(userToken, props)

    // TODO: remove code if no longer SSO
    // check if we have returned from an SSO redirect
    var hash = this.lock.parseHash()
    if (hash && hash.id_token) { // the user came back from the login (either SSO or regular login)
      // save the token
      window.localStorage.setItem('userToken', hash.id_token)

      // redirect to "targetUrl" if any
      let newLocation = hash.state || ''
      browserHistory.push(newLocation)
    } else {
      // check if logged in elsewhere via SSO
      this.lock.$auth0.getSSOData((err, data) => {
        if (!err && data.sso) {
          // there is! redirect to Auth0 for SSO
          this.lock.$auth0.signin({
            callbackOnLocationHash: true
          })
        } else { // assume that we are not logged in
        }
      })
    }

    return null
  }

  loginFromToken (token, props) {
    return fetch('https://' + this.props.domain + '/tokeninfo?id_token=' + token, {
      method: 'post'
    }).then(res => res.json()).then((profile) => {
      return constructUserObj(token, profile)
    }).catch((err) => {
      console.log('error getting profile', err)
      if (props && props.required) {
        return this.loginViaLock({closable: false})
      } else {
        this.logout()
      }
    })
  }

  loginViaLock (additionalLockOptions) {
    return new Promise((resolve, reject) => {
      var lockOptions = {
        connections: ['Username-Password-Authentication'],
        // callbackURL: getConfigProperty('application.url'),
        icon: getConfigProperty('application.logo') ? getConfigProperty('application.logo') : icon,
        disableSignupAction: true,
        // disableResetAction: true,
        authParams: {
          state: window.location.href
        },
        ...additionalLockOptions
      }
      if (this.props.logo) lockOptions.icon = this.props.logo
      this.lock.show(lockOptions, (err, profile, token) => {
        if (err) {
          console.log(err)
          return null
        }
        // save token to localStorage
        window.localStorage.setItem('userToken', token)

        // initialize auto log out check
        // this.setupSingleLogout()
        console.log(token, profile)
        // this.userLoggedIn(token, profile)
        resolve(constructUserObj(token, profile))
      })
    })
  }

  logout () {
    window.localStorage.removeItem('userToken')
    var redirect = window.location.protocol + '//' + window.location.hostname + (window.location.port ? ':' + window.location.port : '')
    window.location.replace('https://' + this.props.domain + '/v2/logout?returnTo=' + redirect)
  }

  resetPassword () {
    this.lock.showReset((err) => {
      if (!err) this.lock.hide()
    })
  }

  setupSingleLogout () {
    setInterval(() => {
      // if the token is not in local storage, there is nothing to check (i.e. the user is already logged out)
      if (!window.localStorage.getItem('userToken')) return

      this.auth0.getSSOData((err, data) => {
        // if there is still a session, do nothing
        if (err || (data && data.sso)) return

        // if we get here, it means there is no session on Auth0,
        // then remove the token and redirect to #login
        window.localStorage.removeItem('userToken')
        window.location.href = '/'
      })
    }, 5000)
  }
}

function constructUserObj (token, profile) {
  return {
    token,
    profile,
    permissions: new UserPermissions(profile.app_metadata.datatools)
  }
}

module.exports = Auth0Manager
<|endoftext|>