text: /**
   * Copyright 2004-present Facebook. All Rights Reserved.
   *
   * This source code is licensed under the BSD-style license found in the
   * LICENSE file in the root directory of this source tree.
   *
   * @flow
   * @format
   */
  
  jest.mock('@fbcnms/sequelize-models');
  
  import OrganizationLocalStrategy from '@fbcnms/auth/strategies/OrganizationLocalStrategy';
  
  import express from 'express';
  import fbcPassport from '../passport';
  import nock from 'nock';
  import passport from 'passport';
  import path from 'path';
  import request from 'supertest';
  import routes from '@fbcnms/platform-server/apicontroller/routes';
  import userMiddleware from '../express';
  import {API_HOST} from '../../fbcnms-platform-server/config';
  import {USERS, USERS_EXPECTED} from '../test/UserModel';
  import {User} from '@fbcnms/sequelize-models';
  
  import {configureAccess} from '../access';
  
  import type {FBCNMSRequest} from '../access';
  
  function stripDatesMany(res) {
    res.body.users.map(u => {
      delete u['createdAt'];
      delete u['updatedAt'];
    });
  }
  
  function stripDates(res) {
    delete res.body.user['createdAt'];
    delete res.body.user['updatedAt'];
  }
  
  function mockOrgMiddleware(orgName: string) {
    return (req: FBCNMSRequest, _res, next) => {
      if (orgName) {
        // $FlowIgnore we know this is wrong, and that's okay for this test.
        req.organization = async () => {
          return {name: orgName};
        };
      }
      next();
    };
  }
  
  function mockUserMiddleware(where) {
    return async (req: FBCNMSRequest, _res, next) => {
      req.isAuthenticated = () => true;
      const user = await User.findOne({where});
      if (!user) {
        throw new Error('Could not find a user');
      }
      req.user = user;
      next();
    };
  }
  
  function mockCsrfMiddleware() {
    return async (req: FBCNMSRequest, _res, next) => {
      req.csrfToken = () => 'myCsrfToken';
      next();
    };
  }
  
  function getApp(orgName: string, loggedInEmail: ?string, loginView: ?string) {
    const app = express();
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'pug');
    app.use(express.json());
    app.use(express.urlencoded({extended: true}));
    fbcPassport.use();
    passport.use(new OrganizationLocalStrategy());
    app.use(passport.initialize());
    app.use(passport.session());
    app.use(configureAccess({loginUrl: '/user/login'}));
    app.use(mockOrgMiddleware(orgName));
    app.use(mockCsrfMiddleware());
    if (loggedInEmail) {
      app.use(mockUserMiddleware({email: loggedInEmail}));
    }
    app.use(
      '/user',
      userMiddleware({
        loginFailureUrl: '/failure',
        loginSuccessUrl: '/success',
        loginView: loginView || 'index',
      }),
    );
    app.use('/nms/apicontroller', routes);
    return app;
  }
  
  describe('user tests', () => {
    beforeEach(async () => {
      USERS.forEach(async user => await User.create(user));
    });
    afterEach(async () => {
      await User.destroy({where: {}, truncate: true});
    });
  
    describe('login page renders', () => {
      it('displays login page', async () => {
        const app = getApp('validorg');
        const expected = {
          appData: {
            csrfToken: 'myCsrfToken',
            ssoEnabled: false,
            ssoSelectedType: 'none',
            csvCharset: null,
            enabledFeatures: [],
            tabs: [],
            user: {
              tenant: '',
              email: '',
              isSuperUser: false,
              isReadOnlyUser: false,
            },
          },
        };
        await request(app)
          .get('/user/login')
          .expect('<script>' + JSON.stringify(expected) + ';</script>');
      });
      it('returns 500 when invalid view', async () => {
        const app = getApp('validorg', null, 'badView');
        await request(app).get('/user/login').expect(500);
      });
    });
  
    describe('login', () => {
      describe('with organization', () => {
        it('valid user can login', async () => {
          const app = getApp('validorg');
          await request(app)
            .post('/user/login')
            .type('form')
            .send({email: 'valid@123.com', password: 'password1234'})
            .expect(302)
            .expect('Location', '/success');
        });
  
        it('valid user can login (redirected)', async () => {
          const app = getApp('validorg');
          await request(app)
            .post('/user/login')
            .type('form')
            .send({
              email: 'valid@123.com',
              password: 'password1234',
              to: '/other/success',
            })
            .expect(302)
            .expect('Location', '/other/success');
        });
  
        it('valid user can login (non-relative redirect)', async () => {
          const app = getApp('validorg');
          await request(app)
            .post('/user/login')
            .type('form')
            .send({
              email: 'valid@123.com',
              password: 'password1234',
              to: 'http://evilsite.com/other/success',
            })
            .expect(302)
            .expect('Location', '/success');
  
          await request(app)
            .post('/user/login')
            .type('form')
            .send({
              email: 'valid@123.com',
              password: 'password1234',
              to: '//evilsite.com/other/success',
            })
            .expect(302)
            .expect('Location', '/success');
        });
  
        it('valid user, invalid org cant login', async () => {
          const app = getApp('invalidorg');
          await request(app)
            .post('/user/login')
            .type('form')
            .send({email: 'valid@123.com', password: 'password1234'})
            .expect(302)
            .expect('Location', '/failure');
        });
  
        it('invalid user cant login', async () => {
          const app = getApp('validorg');
          await request(app)
            .post('/user/login')
            .type('form')
            .send({email: 'invalid@123.com', password: 'password1234'})
            .expect(302)
            .expect('Location', '/failure');
        });
      });
  
      describe('no organization', () => {
        it('valid user can login', async () => {
          const app = getApp('');
          await request(app)
            .post('/user/login')
            .type('form')
            .send({email: 'noorg@123.com', password: 'password1234'})
            .expect(302)
            .expect('Location', '/success');
        });
  
        it('invalid user cant login', async () => {
          const app = getApp('');
          await request(app)
            .post('/user/login')
            .type('form')
            .send({email: 'invalid@123.com', password: 'password1234'})
            .expect(302)
            .expect('Location', '/failure');
        });
      });
    });
  
    describe('create user', () => {
      const validParams = {
        email: 'user@123.com',
        password: 'password1234',
        networkIDs: [],
        superUser: false,
        verificationType: 0,
        role: 0,
      };
  
      describe('as superuser', () => {
        const app = getApp('validorg', 'superuser@123.com');
  
        it('creates users successfully', async () => {
          const params = validParams;
          await request(app)
            .post('/user/async/')
            .send(params)
            .expect(201)
            .expect(stripDates)
            .expect({
              user: {
                isSuperUser: false,
                isReadOnlyUser: false,
                email: params.email,
                organization: 'validorg',
                networkIDs: params.networkIDs,
                role: 0,
                id: 5,
                tabs: [],
              },
            });
        });
  
        it('must supply email', async () => {
          const params = {
            ...validParams,
            email: '',
          };
          await request(app).post('/user/async/').send(params).expect(400);
        });
  
        it('must be valid email', async () => {
          const params = {
            ...validParams,
            email: 'abc',
          };
          await request(app).post('/user/async/').send(params).expect(400);
        });
      });
    });
  
    describe('list users', () => {
      it('lists users for organization', async () => {
        const app = getApp('validorg', 'superuser@123.com');
        await request(app)
          .get('/user/async/')
          .expect(200)
          .expect(stripDatesMany)
          .expect({
            users: [USERS_EXPECTED[0], USERS_EXPECTED[2]],
          });
      });
      it('list users (no organization)', async () => {
        const app = getApp('', 'superuser@123.com');
        await request(app)
          .get('/user/async/')
          .expect(200)
          .expect(stripDatesMany)
          .expect({
            users: USERS_EXPECTED,
          });
      });
    });
  
    describe('edit users', () => {
      const validUpdateParams = {
        networkIDs: [],
        password: 'mynewpassword',
        superUser: false,
        verificationType: 0,
        tabs: ['validtab'],
      };
      it('can update a user', async () => {
        const app = getApp('validorg', 'superuser@123.com');
        await request(app)
          .put('/user/async/1')
          .send(validUpdateParams)
          .expect(stripDates)
          .expect({
            user: {
              networkIDs: [],
              id: 1,
              email: 'valid@123.com',
              organization: 'validorg',
              role: 0,
              tabs: ['validtab'],
            },
          })
          .expect(200);
      });
  
      it('cannot edit another orgs user', async () => {
        const app = getApp('validorg', 'superuser@123.com');
        await request(app)
          .put('/user/async/2')
          .send(validUpdateParams)
          .expect(400)
          .expect({error: 'Error: User does not exist!'});
      });
    });
  
    describe('endpoints as normal user', () => {
      const app = getApp('validorg', 'valid@123.com');
      it('redirects restricted urls to login', async () => {
        await request(app).get('/user/async/').expect(302);
        await request(app).post('/user/async/').expect(302);
        await request(app).put('/user/async/1').expect(302);
        await request(app).delete('/user/async/1/').expect(302);
      });
    });
  });
  
  describe('magma api proxy tests', () => {
    const allNetworks = ['network1', 'network2'];
  
    beforeEach(() => {
      USERS.forEach(async user => await User.create(user));
      nock('https://' + API_HOST)
        .get('/magma/v1/networks')
        .reply(200, new Buffer(JSON.stringify(allNetworks), 'utf8'));
      nock('https://' + API_HOST)
        .get('/magma/v1/networks/network1')
        .reply(200);
      nock('https://' + API_HOST)
        .get('/magma/v1/networks/network2')
        .reply(200);
    });
  
    afterEach(async () => {
      await User.destroy({where: {}, truncate: true});
      nock.cleanAll();
    });
  
    describe('get all networks no organization', () => {
      it('as normal user, can only see own networks', async () => {
        const app = getApp('', 'valid@123.com');
        await request(app)
          .get('/nms/apicontroller/magma/v1/networks')
          .expect(200)
          .expect(res =>
            expect(JSON.parse(res.body.toString('utf8'))).toStrictEqual([
              'network1',
            ]),
          );
      });
      it('as super user, can see all networks', async () => {
        const app = getApp('', 'superuser@123.com');
        await request(app)
          .get('/nms/apicontroller/magma/v1/networks')
          .expect(200)
          .expect(res =>
            expect(JSON.parse(res.body.toString('utf8'))).toStrictEqual(
              allNetworks,
            ),
          );
      });
    });
  
    describe('get one network no organization', () => {
      it('as normal user, can only get own networks', async () => {
        const app = getApp('', 'valid@123.com');
        await request(app)
          .get('/nms/apicontroller/magma/v1/networks/network1')
          .expect(200);
        await request(app)
          .get('/nms/apicontroller/magma/v1/networks/network2')
          .expect(404);
      });
      it('as super user, can get all networks', async () => {
        const app = getApp('', 'superuser@123.com');
        await request(app)
          .get('/nms/apicontroller/magma/v1/networks/network1')
          .expect(200);
        await request(app)
          .get('/nms/apicontroller/magma/v1/networks/network2')
          .expect(200);
      });
    });
  });
  