Compare commits

..

5 Commits

Author SHA1 Message Date
Ali BARIN
76296532cf Merge branch 'no-proxy' into custom-deployment 2024-05-13 09:16:12 +00:00
Ali BARIN
10290ce6e3 feat: add POST /api/v1/installation/users to seed user 2024-05-13 09:16:05 +00:00
Ali BARIN
a2df7c1e89 test(global-hooks): truncate config table 2024-05-13 09:16:05 +00:00
Ali BARIN
b89ba1e623 feat: add migration to mark userful instances installation completed 2024-05-13 09:16:05 +00:00
Ali BARIN
4d0481a3c6 feat: add DISABLE_SEED_USER to bypass yarn db:seed:user command 2024-05-13 09:16:05 +00:00
20 changed files with 30 additions and 173 deletions

View File

@@ -2,7 +2,6 @@ import appConfig from '../../src/config/app.js';
import logger from '../../src/helpers/logger.js';
import client from './client.js';
import User from '../../src/models/user.js';
import Config from '../../src/models/config.js';
import Role from '../../src/models/role.js';
import '../../src/config/orm.js';
import process from 'process';
@@ -46,8 +45,6 @@ export async function createUser(
if (userCount === 0) {
const user = await User.query().insertAndFetch(userParams);
logger.info(`User has been saved: ${user.email}`);
await Config.markInstallationCompleted();
} else {
logger.info('No need to seed a user.');
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.9 KiB

View File

@@ -1,44 +0,0 @@
import verifyCredentials from './verify-credentials.js';
import isStillVerified from './is-still-verified.js';
export default {
fields: [
{
key: 'screenName',
label: 'Screen Name',
type: 'string',
required: true,
readOnly: false,
value: null,
placeholder: null,
description:
'Screen name of your connection to be used on Automatisch UI.',
clickToCopy: false,
},
{
key: 'instanceUrl',
label: 'Instance URL',
type: 'string',
required: true,
readOnly: false,
value: null,
placeholder: null,
description: null,
clickToCopy: false,
},
{
key: 'apiKey',
label: 'API Key',
type: 'string',
required: true,
readOnly: false,
value: null,
placeholder: null,
description: 'Changedetection API key of your account.',
clickToCopy: false,
},
],
verifyCredentials,
isStillVerified,
};

View File

@@ -1,8 +0,0 @@
import verifyCredentials from './verify-credentials.js';
const isStillVerified = async ($) => {
await verifyCredentials($);
return true;
};
export default isStillVerified;

View File

@@ -1,10 +0,0 @@
const verifyCredentials = async ($) => {
await $.http.get('/v1/systeminfo');
await $.auth.set({
screenName: $.auth.data.screenName,
apiKey: $.auth.data.apiKey,
});
};
export default verifyCredentials;

View File

@@ -1,9 +0,0 @@
const addAuthHeader = ($, requestConfig) => {
if ($.auth.data?.apiKey) {
requestConfig.headers['x-api-key'] = $.auth.data.apiKey;
}
return requestConfig;
};
export default addAuthHeader;

View File

@@ -1,10 +0,0 @@
const setBaseUrl = ($, requestConfig) => {
const instanceUrl = $.auth.data.instanceUrl;
if (instanceUrl) {
requestConfig.baseURL = `${instanceUrl}/api`;
}
return requestConfig;
};
export default setBaseUrl;

View File

@@ -1,17 +0,0 @@
import defineApp from '../../helpers/define-app.js';
import addAuthHeader from './common/add-auth-header.js';
import auth from './auth/index.js';
import setBaseUrl from './common/set-base-url.js';
export default defineApp({
name: 'Changedetection',
key: 'changedetection',
iconUrl: '{BASE_URL}/apps/changedetection/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/changedetection/connection',
supportsConnections: true,
baseUrl: 'https://changedetection.io',
apiBaseUrl: '',
primaryColor: '3056d3',
beforeRequest: [setBaseUrl, addAuthHeader],
auth,
});

View File

@@ -1,10 +1,11 @@
import { describe, it, expect, beforeEach } from 'vitest';
import { vi, describe, it, expect, beforeEach } from 'vitest';
import request from 'supertest';
import app from '../../../../../app';
import createAuthTokenByUserId from '../../../../../helpers/create-auth-token-by-user-id';
import { createRole } from '../../../../../../test/factories/role';
import { createUser } from '../../../../../../test/factories/user';
import getUsersMock from '../../../../../../test/mocks/rest/api/v1/admin/users/get-users.js';
import * as license from '../../../../../helpers/license.ee.js';
describe('GET /api/v1/admin/users', () => {
let currentUser, currentUserRole, anotherUser, anotherUserRole, token;
@@ -31,6 +32,8 @@ describe('GET /api/v1/admin/users', () => {
});
it('should return users data', async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
const response = await request(app)
.get('/api/v1/admin/users')
.set('Authorization', token)

View File

@@ -1,9 +1,12 @@
import User from '../../../../../models/user.js';
import Config from '../../../../../models/config.js';
export default async (request, response) => {
const { email, password, fullName } = request.body;
await User.createAdmin({ email, password, fullName });
await User.createAdminUser({ email, password, fullName });
await Config.markInstallationCompleted();
response.status(204).end();
};

View File

@@ -4,7 +4,6 @@ import app from '../../../../../app.js';
import Config from '../../../../../models/config.js';
import User from '../../../../../models/user.js';
import { createRole } from '../../../../../../test/factories/role';
import { createUser } from '../../../../../../test/factories/user';
import { createInstallationCompletedConfig } from '../../../../../../test/factories/config';
describe('POST /api/v1/installation/users', () => {
@@ -18,7 +17,7 @@ describe('POST /api/v1/installation/users', () => {
});
describe('for incomplete installations', () => {
it('should respond with HTTP 204 with correct payload when no user', async () => {
it('should respond with HTTP 204 with correct payload', async () => {
expect(await Config.isInstallationCompleted()).toBe(false);
await request(app)
@@ -35,27 +34,6 @@ describe('POST /api/v1/installation/users', () => {
expect(user.roleId).toBe(adminRole.id);
expect(await Config.isInstallationCompleted()).toBe(true);
});
it('should respond with HTTP 403 with correct payload when one user exists at least', async () => {
expect(await Config.isInstallationCompleted()).toBe(false);
await createUser();
const usersCountBefore = await User.query().resultSize();
await request(app)
.post('/api/v1/installation/users')
.send({
email: 'user@automatisch.io',
password: 'password',
fullName: 'Initial admin'
})
.expect(403);
const usersCountAfter = await User.query().resultSize();
expect(usersCountBefore).toEqual(usersCountAfter);
});
});
describe('for completed installations', () => {

View File

@@ -1,16 +0,0 @@
import Config from '../models/config.js';
import User from '../models/user.js';
export async function allowInstallation(request, response, next) {
if (await Config.isInstallationCompleted()) {
return response.status(403).end();
}
const hasAnyUsers = await User.query().resultSize() > 0;
if (hasAnyUsers) {
return response.status(403).end();
}
next();
};

View File

@@ -0,0 +1,9 @@
import Config from '../models/config.js';
export async function authorizeInstallation(request, response, next) {
if (await Config.isInstallationCompleted()) {
return response.status(403).end();
} else {
next();
}
};

View File

@@ -10,7 +10,6 @@ import Base from './base.js';
import App from './app.js';
import AccessToken from './access-token.js';
import Connection from './connection.js';
import Config from './config.js';
import Execution from './execution.js';
import Flow from './flow.js';
import Identity from './identity.ee.js';
@@ -374,7 +373,7 @@ class User extends Base {
return apps;
}
static async createAdmin({ email, password, fullName }) {
static async createAdminUser({ email, password, fullName }) {
const adminRole = await Role.findAdmin();
const adminUser = await this.query().insert({
@@ -384,8 +383,6 @@ class User extends Base {
roleId: adminRole.id
});
await Config.markInstallationCompleted();
return adminUser;
}

View File

@@ -2,17 +2,25 @@ import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import { authenticateUser } from '../../../../helpers/authentication.js';
import { authorizeAdmin } from '../../../../helpers/authorization.js';
import { checkIsEnterprise } from '../../../../helpers/check-is-enterprise.js';
import getUsersAction from '../../../../controllers/api/v1/admin/users/get-users.ee.js';
import getUserAction from '../../../../controllers/api/v1/admin/users/get-user.ee.js';
const router = Router();
router.get('/', authenticateUser, authorizeAdmin, asyncHandler(getUsersAction));
router.get(
'/',
authenticateUser,
authorizeAdmin,
checkIsEnterprise,
asyncHandler(getUsersAction)
);
router.get(
'/:userId',
authenticateUser,
authorizeAdmin,
checkIsEnterprise,
asyncHandler(getUserAction)
);

View File

@@ -1,13 +1,13 @@
import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import { allowInstallation } from '../../../../helpers/allow-installation.js';
import { authorizeInstallation } from '../../../../helpers/authorize-installation.js';
import createUserAction from '../../../../controllers/api/v1/installation/users/create-user.js';
const router = Router();
router.post(
'/',
allowInstallation,
authorizeInstallation,
asyncHandler(createUserAction)
);

View File

@@ -41,14 +41,6 @@ export default defineConfig({
{ text: 'Connection', link: '/apps/carbone/connection' },
],
},
{
text: 'Changedetection',
collapsible: true,
collapsed: true,
items: [
{ text: 'Connection', link: '/apps/changedetection/connection' },
],
},
{
text: 'Datastore',
collapsible: true,

View File

@@ -1,14 +0,0 @@
# Changedetection
:::info
This page explains the steps you need to follow to set up the Changedetection
connection in Automatisch. If any of the steps are outdated, please let us know!
:::
1. Go to your Changedetection admin panel.
2. Click on the **Settings** button.
3. Click on the **API** tab.
4. Copy **API key** from the page to the `API Key` field on Automatisch.
5. Add your Instance URL in the **Instance URL** field on Automatisch.
6. Write any screen name to be displayed in Automatisch.
7. Now, you can start using the Changedetection connection with Automatisch.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.9 KiB