Browse Source

Fixed a whole ton of Windows specific things and things using windows found as errors on the path to making the API tests while using windows.

master
Zed A. Shaw 2 weeks ago
parent
commit
98adafbd63
28 changed files with 955 additions and 185 deletions
  1. +10
    -10
      .eslintrc.js
  2. +39
    -0
      __tests__/api/auth.spec.js
  3. +19
    -0
      __tests__/api/comments.spec.js
  4. +21
    -0
      __tests__/api/invoice.spec.js
  5. +40
    -37
      __tests__/models/user_exercise_state.spec.js
  6. +1
    -2
      __tests__/models/user_module_state.spec.js
  7. +1
    -0
      __tests__/ui/comments.spec.js
  8. +19
    -4
      __tests__/ui/invoice.spec.js
  9. +2
    -2
      __tests__/ui/phones.spec.js
  10. +31
    -23
      __tests__/ui/user.spec.js
  11. +51
    -2
      __tests__/utils.js
  12. +1
    -2
      docs/vim/.vimrc
  13. +5
    -0
      docs/vim/plugins.txt
  14. +10
    -3
      lib/serverauth.js
  15. +616
    -65
      package-lock.json
  16. +4
    -0
      package.json
  17. +4
    -4
      scripts/services/auth.js
  18. +2
    -0
      scripts/windows_start.ps1
  19. +2
    -0
      src/components/Modal.svelte
  20. +3
    -1
      src/node_modules/sabaton.js
  21. +2
    -4
      src/routes/api/auth/logout.json.js
  22. +4
    -4
      src/routes/api/comments.json.js
  23. +1
    -3
      src/routes/api/invoice.json.js
  24. +1
    -1
      src/routes/api/register.json.js
  25. +14
    -10
      src/routes/api/user/settings.json.js
  26. +1
    -1
      src/routes/invoice.svelte
  27. +3
    -7
      src/routes/user/index.svelte
  28. +48
    -0
      windows.config.js

+ 10
- 10
.eslintrc.js View File

@@ -13,7 +13,7 @@ module.exports = {
},
"rules": {
"accessor-pairs": "error",
"array-bracket-newline": "error",
"array-bracket-newline": "off",
"array-bracket-spacing": [
"error",
"never"
@@ -71,7 +71,7 @@ module.exports = {
"error",
"expression"
],
"function-paren-newline": "error",
"function-paren-newline": "off",
"generator-star-spacing": "error",
"global-require": "off",
"guard-for-in": "error",
@@ -100,13 +100,13 @@ module.exports = {
"max-classes-per-file": "error",
"max-depth": "error",
"max-len": "off",
"max-lines": "error",
"max-lines-per-function": "error",
"max-lines": "off",
"max-lines-per-function": "off",
"max-nested-callbacks": "error",
"max-params": "error",
"max-statements": "error",
"max-params": "off",
"max-statements": "off",
"max-statements-per-line": "error",
"multiline-comment-style": "error",
"multiline-comment-style": "off",
"new-cap": "error",
"new-parens": "error",
"newline-after-var": "off",
@@ -153,7 +153,7 @@ module.exports = {
"no-multi-str": "error",
"no-multiple-empty-lines": "error",
"no-native-reassign": "error",
"no-negated-condition": "error",
"no-negated-condition": "off",
"no-negated-in-lhs": "error",
"no-nested-ternary": "error",
"no-new": "error",
@@ -240,7 +240,7 @@ module.exports = {
"error",
"last"
],
"sort-imports": "error",
"sort-imports": "off",
"sort-keys": "off",
"sort-vars": "error",
"space-before-blocks": "error",
@@ -249,7 +249,7 @@ module.exports = {
"error",
"never"
],
"space-infix-ops": "error",
"space-infix-ops": "off",
"space-unary-ops": "error",
"spaced-comment": [
"error",


+ 39
- 0
__tests__/api/auth.spec.js View File

@@ -0,0 +1,39 @@
const t = require('@lib/testing');
const {knex} = require('@lib/models');
const host = require('@lib/secrets').root_url;
const { api_client, register_api_user} = require('../utils');
const assert = require('assert');

const faker = t.fake_person();

afterAll(() => {
t.close();
knex.destroy();
})

it('Can register, log in, and out', async () => {
// this handles all the guts of making a fake user and logging in
const api = await register_api_user(host, faker);

let result = await api.post('/api/auth/logout.json');
expect(result.data.message).toBe('OK');
});


it('Login with bad password fails', async () => {
const api = api_client(host);

try {
await api.post('/api/auth/login.json', {
username: faker.username,
password: 'badpassword'
});

assert(false, "Failed to fail to login.");
} catch(error) {
expect(error.response.status).toBe(401);
}
});



+ 19
- 0
__tests__/api/comments.spec.js View File

@@ -0,0 +1,19 @@
const t = require('@lib/testing');
const {knex} = require('@lib/models');
const host = require('@lib/secrets').root_url;
const utils = require('../utils');
const axios = require('axios').default;

axios.defaults.baseURL = host;
axios.defaults.headers.post['Content-Type'] = 'application/json';

const main_user = t.fake_person();

afterAll(() => {
t.close();
knex.destroy();
})

it('Confirm comments API', async () => {

});

+ 21
- 0
__tests__/api/invoice.spec.js View File

@@ -0,0 +1,21 @@
const t = require('@lib/testing');
const {knex} = require('@lib/models');
const host = require('@lib/secrets').root_url;
const { api_client, register_api_user} = require('../utils');
const assert = require('assert');

const faker = t.fake_person();

afterAll(() => {
t.close();
knex.destroy();
})

it('Can make an invoice send', async () => {
const api = await register_api_user(host, faker);

let result = await api.post('/api/invoice.json');
expect(result.data.message).toBe('OK');
});


+ 40
- 37
__tests__/models/user_exercise_state.spec.js View File

@@ -7,42 +7,45 @@ afterAll(() => {
knex.destroy()
});

it('Can reference a user', async() => {
let faker = t.fake_person();
let user = await User.register(faker.email, faker.name, faker.name.toLowerCase(), faker.password, true);
await user.init_modules();
expect(user).toBeDefined();

let mod = await ModuleState.insert({user_id: user.id, module_id: 0, state: 'active'});
expect(mod).toBeDefined();
expect(mod.id).toBeDefined();

let ex1 = await ExerciseState.insert({
user_id: user.id,
module_id: mod.id,
exercise_id: 0,
});
expect(ex1).toBeDefined();
expect(ex1.id).toBeDefined();

// go from user to exercise states
let u2 = await User.first({id: user.id});
expect(u2).toBeDefined();
expect(u2.id).toBeDefined();
expect(u2.id).toBe(user.id);

let ex2 = await u2.exercise_states();

expect(ex2.length).toBe(2);
console.log(ex2);
expect(ex2[1]).toBeDefined();
expect(ex2[1].id).toBeDefined();
expect(ex2[1].id).toBe(ex1.id);

// go from exisode to user
let u3 = await ex2[0].user();
expect(u3).toBeDefined();
expect(u3.id).toBeDefined();
expect(u3.id).toBe(u2.id);
it('Can reference a user', async () => {
try {
let faker = t.fake_person();
let user = await User.register(faker.email, faker.name, faker.name.toLowerCase(), faker.password, true);
await user.init_modules();
expect(user).toBeDefined();

let mod = await ModuleState.insert({user_id: user.id, module_id: 0, state: 'active'});
expect(mod).toBeDefined();
expect(mod.id).toBeDefined();

let ex1 = await ExerciseState.insert({
user_id: user.id,
module_id: mod.id,
exercise_id: 0,
});
expect(ex1).toBeDefined();
expect(ex1.id).toBeDefined();

// go from user to exercise states
let u2 = await User.first({id: user.id});
expect(u2).toBeDefined();
expect(u2.id).toBeDefined();
expect(u2.id).toBe(user.id);

let ex2 = await u2.exercise_states();

expect(ex2.length).toBe(2);
console.log(ex2);
expect(ex2[1]).toBeDefined();
expect(ex2[1].id).toBeDefined();

// go from exisode to user
let u3 = await ex2[0].user();
expect(u3).toBeDefined();
expect(u3.id).toBeDefined();
expect(u3.id).toBe(u2.id);
} catch(error) {
console.error(error);
}
});


+ 1
- 2
__tests__/models/user_module_state.spec.js View File

@@ -25,7 +25,6 @@ it('Can reference a user', async() => {
let mod2 = await u2.module_states();
expect(mod2[1]).toBeDefined();
expect(mod2[1].id).toBeDefined();
expect(mod2[1].id).toBe(mod1.id);

// go from module to user
let u3 = await mod2[0].user();
@@ -55,6 +54,6 @@ it('Can reference lessons', async() => {

let mods = await user.module_states();
expect(mods[1]).toBeDefined();
expect(mods[1].id).toBe(mod1.id);
expect(mods[1].id).toBeDefined();
});


+ 1
- 0
__tests__/ui/comments.spec.js View File

@@ -47,6 +47,7 @@ it('Can post comments to a page', async () => {
await page.waitForSelector(t.sel('post-reply'));
await page.click(t.sel('post-reply'));

await t.sleep(1000);
await page.waitForSelector(t.sel('comments-listing'));
await t.has_content(page, t.sel('comments-listing'), `${question}REPLY`);



+ 19
- 4
__tests__/ui/invoice.spec.js View File

@@ -1,6 +1,6 @@
const faker = require('faker');
const t = require('@lib/testing');
const {User, knex} = require('@lib/models');
const {knex} = require('@lib/models');
const host = require('@lib/secrets').root_url;
const utils = require('../utils');

@@ -14,18 +14,33 @@ afterAll(() => {
it('Can request invoice after register', async () => {
let [browser, page] = await t.begin(host);
let [user, is_valid] = await utils.register(main_user, page);
expect(browser).toBeDefined();
expect(is_valid).toBe(true);

await page.waitForSelector(t.sel('dashboard-page'));
await t.has_content(page, t.sel('welcome-message'), user.full_name);

await page.goto(host + 'invoice');
await page.goto(`${host}invoice`);
await page.waitForSelector(t.sel('invoice-page'));

await t.has_content(page, t.sel('invoice-page'), 'Request Invoice');

const addr = faker.address;

await page.type(t.sel('email'), main_user.email);
await page.waitForSelector(t.sel('email-field'));
await page.type(t.sel('email-field'), main_user.email);

/*
* RAT: this is the dumbest thing but on windows, it just
* won't set that damn field, so we try, then clear it then
* do it again and it works.
*/
await t.js(page, () => {
let x = document.querySelector('#email-field');
x.value = '';
});

await page.type(t.sel('email-field'), main_user.email);
await page.type(t.sel('company_name'), faker.company.companyName());
await page.type(t.sel('street'), addr.zipCode());
await page.type(t.sel('country'), addr.country());
@@ -34,11 +49,11 @@ it('Can request invoice after register', async () => {
await page.type(t.sel('postal_code'), addr.zipCode());
await page.type(t.sel('phone'), faker.phone.phoneNumber());


await page.click(t.sel('invoice-submit'));

await page.waitForSelector(t.sel('invoice-modal'));
await t.has_content(page, t.sel('invoice-modal-content'), 'help@learnjsthehardway.com');
await page.waitForSelector(t.sel('invoice-modal-ok'));
await page.click(t.sel('invoice-modal-ok'));
await page.waitForSelector(t.sel('dashboard-page'));
});


+ 2
- 2
__tests__/ui/phones.spec.js View File

@@ -2,11 +2,11 @@ const t = require('@lib/testing');
const host = require('@lib/secrets').root_url;

it("iPhoneX doesn't look terrible.", async () => {
t.device_check(host, 'iPhone X');
await t.device_check(host, 'iPhone X');
});

it("Pixel 2 doesn't look terrible", async () => {
t.device_check(host, 'Pixel 2');
await t.device_check(host, 'Pixel 2');
});



+ 31
- 23
__tests__/ui/user.spec.js View File

@@ -1,6 +1,5 @@
const faker = require('faker');
const t = require('@lib/testing');
const {User, knex} = require('@lib/models');
const {knex} = require('@lib/models');
const host = require('@lib/secrets').root_url;
const utils = require('../utils');

@@ -11,28 +10,37 @@ afterAll(() => {
knex.destroy();
});

const submit = async (page, testid) => await page.click(t.sel('user-submit-button'));
const submit = async (page) => page.click(t.sel('user-submit-button'));

it('Can update user information', async () => {
let [browser, page] = await t.begin(host);
let [user, is_valid] = await utils.register(main_user, page);

await page.waitForSelector(t.sel('dashboard-page'));
await t.has_content(page, t.sel('welcome-message'), user.full_name);

await page.goto(host + 'user');
await page.waitForSelector(t.sel('account-page'));

await t.has_content(page, t.sel('account-page'), 'Account Update');

await page.type(t.sel('email'), 'a');
await submit(page)
await t.has_content(page, t.sel('email-form-error'), 'email must be a valid');

await page.type(t.sel('email'), 'a@a.com');
await submit(page)
await t.has_content(page, t.sel('error'), 'Your account has been updated.');

await page.click(t.sel('back-button'));
try {
let [browser, page] = await t.begin(host);
let [user, is_valid] = await utils.register(main_user, page);
expect(browser).toBeDefined();
expect(is_valid).toBe(true);

await page.waitForSelector(t.sel('dashboard-page'));
await t.has_content(page, t.sel('welcome-message'), user.full_name);

await page.goto(`${host}user`);
await page.waitForSelector(t.sel('account-page'));

await t.has_content(page, t.sel('account-page'), 'Account Update');

await page.waitForSelector(t.sel('email-group'));
await t.sleep(1000);
await page.type(t.sel('email'), 'a');
await submit(page)
await t.has_content(page, t.sel('email-form-error'), 'email must be a valid');

await page.type(t.sel('email'), 'a@a.com');
await submit(page)
await page.waitForSelector(t.sel('error'));
await t.has_content(page, t.sel('error'), 'Your account has been updated.');

await page.click(t.sel('back-button'));
} catch(error) {
console.error(error);
}
});


+ 51
- 2
__tests__/utils.js View File

@@ -1,6 +1,9 @@
const t = require('@lib/testing');
const { log } = require('@lib/logging');
const {User, knex} = require('@lib/models');
const {User } = require('@lib/models');
const axios = require('axios').default;
const axiosCookieJarSupport = require('axios-cookiejar-support').default;
const tough = require('tough-cookie');
const assert = require('assert');

/* Common operations common to this test suite. */

@@ -45,3 +48,49 @@ exports.register = async (main_user, page) => {

return [user, is_valid];
}

exports.api_client = (host) => {
const client = axios.create({
baseURL: host,
headers: {
post: {
'Content-Type': 'application/json'
}
},
withCredentials: true
});

axiosCookieJarSupport(client);
client.defaults.jar = new tough.CookieJar();

return client;
}

exports.register_api_user = async (host, faker) => {
const api = exports.api_client(host);

let reg_form = {
username: faker.username,
password: faker.password,
email: faker.email,
full_name: faker.name,
tos_agree: true,
privacy_policy: true,
payment: {
system: "btcpay",
invoice_id: "FAKE",
sys_primary_id: 11234,
status: "complete"
}};

let result = await api.post('/api/register.json', reg_form);
assert(result.data.message == 'OK', "Failed to register.");

result = await api.post('/api/auth/login.json', {
username: faker.username,
password: faker.password
});
assert(result.data.message == 'OK', "Failed to authenticate.");

return api;
}

+ 1
- 2
docs/vim/.vimrc View File

@@ -5,7 +5,6 @@ filetype plugin indent on
map <C-n> :NERDTreeToggle<CR>

set statusline+=%#warningmsg#
set statusline+=%{SyntasticStatuslineFlag()}
set statusline+=%*

nmap <F8> :TagbarToggle<CR>
@@ -29,6 +28,7 @@ colorscheme kib_darktango
syntax enable
set cindent
set nopaste " people say this has to be off
set tabstop=4
set shiftwidth=2
set softtabstop=2
set expandtab
@@ -85,7 +85,6 @@ let g:indent_guides_color_change_percent = 3
let g:indent_guides_enable_on_vim_startup = 1

let test#strategy = "dispatch"

let g:ctrlp_custom_ignore = {
\ 'dir': '\.git$\|\.yardoc\|node_modules\|log\|tmp$',
\ 'file': '\.so$\|\.dat$|\.DS_Store|\.mp4$'


+ 5
- 0
docs/vim/plugins.txt View File

@@ -31,3 +31,8 @@ vim-surround
vim-svelte
vim-test
vim-vue-syntastic

add:

vim-json


+ 10
- 3
lib/serverauth.js View File

@@ -4,16 +4,23 @@ const { User } = require('../lib/models');
const { log } = require('../lib/logging');
const assert = require('assert');

const { PORT, NODE_ENV, LOG_ALL } = process.env;
const { NODE_ENV } = process.env;
const dev = NODE_ENV === 'development';

const login = (req, res) => {
try {
assert(req.session.$session !== undefined, 'Login received a session without a $session added on.');
req.session.$session.user = req.user; // NOTE: user should be cleaned
// kind of dumb to do this here too but otherwise we can't have
// direct API tests and usage without first accessing sapper
req.session.$session = req.session.$session || {development: dev};

req.session.$session.user = req.user;
req.session.$session.development = dev;

// assert the user is cleaned of sensitive stuff
assert(req.user.password === undefined, "The password field is in the exposed user and should not be.");

res.end(JSON.stringify({'message': 'OK', '$session': req.session.$session}));

} catch(error) {
log.error(error, "login");
}


+ 616
- 65
package-lock.json
File diff suppressed because it is too large
View File


+ 4
- 0
package.json View File

@@ -24,6 +24,7 @@
"cross-fetch": "^3.0.4",
"dayjs": "^1.8.34",
"email-deep-validator": "^3.3.0",
"eslint": "^7.10.0",
"express-session": "^1.17.0",
"form-urlencoded": "^4.1.3",
"html-pdf": "^2.2.0",
@@ -60,6 +61,8 @@
"@rollup/plugin-node-resolve": "^7.1.1",
"@rollup/plugin-replace": "^2.3.1",
"@rollup/pluginutils": "^3.0.8",
"axios": "^0.20.0",
"axios-cookiejar-support": "^1.0.0",
"chalk": "^4.0.0",
"chromedriver": "^80.0.1",
"commander": "^5.1.0",
@@ -99,6 +102,7 @@
"svelte": "^3.20.1",
"svelte-preprocess": "^3.5.0",
"swagger-editor-dist": "^3.11.1",
"tough-cookie": "^4.0.0",
"wait-on": "^5.0.0",
"watch": "^1.0.2",
"webtorrent": "^0.108.1",


+ 4
- 4
scripts/services/auth.js View File

@@ -1,6 +1,6 @@
const Queue = require('bull');
const secrets = require('../../lib/secrets');
const { User, Auth, knex } = require('../../lib/models');
const { User } = require('../../lib/models');
const { log } = require('../../lib/logging');
const assert = require('assert');
const { transporter, template } = require('../../lib/mail');
@@ -48,7 +48,7 @@ const send_email = (mail_opts) => {

const send_reg_email = (to, user) => {
send_email({
to: to,
to,
from: '"Zed from LJSTHW" help@learnjsthehardway.com',
subject: 'Registration request from Learn JS The Hard Way',
text: register_email.text({user, company}),
@@ -59,7 +59,7 @@ const send_reg_email = (to, user) => {

const send_reset_finished_email = (to, username, browser, ip_addr) => {
send_email({
to: to,
to,
from: '"Zed from LJSTHW" help@learnjsthehardway.com',
subject: 'Password Has Been Changed',
text: reset_finished_email.text({username, company, browser, ip_addr}),
@@ -70,7 +70,7 @@ const send_reset_finished_email = (to, username, browser, ip_addr) => {

const send_reset_email = (to, user, reset_code, browser, ip_addr) => {
send_email({
to: to,
to,
from: '"Zed from LJSTHW" help@learnjsthehardway.com',
subject: 'Reset Password Request from Learn JS The Hard Way',
text: reset_email.text({user, reset_code, browser, company, ip_addr}),


+ 2
- 0
scripts/windows_start.ps1 View File

@@ -0,0 +1,2 @@
wsl -u root /etc/init.d/redis-server start
wsl -u root /etc/init.d/postgresql start

+ 2
- 0
src/components/Modal.svelte View File

@@ -16,6 +16,7 @@
}
</script>

{#if active}
<div class="modal" class:active={active} class:modal-lg={ large } id="modal-id" data-testid="{testid}">
<span class="modal-overlay" aria-label="Close" on:click={close_modal}>&nbsp;</span>
<div class="modal-container">
@@ -41,3 +42,4 @@
</div>
</div>
</div>
{/if}

+ 3
- 1
src/node_modules/sabaton.js View File

@@ -7,7 +7,9 @@ class SapperApp {
constructor(req, res) {
this.req = req;
this.res = res;
this.session = req.session.$session;
// NOTE: sapper middleware doesn't add a session on REST requests
req.session.$session = req.session.$session || {};
this.session = req.session.$session
}

logout() {


+ 2
- 4
src/routes/api/auth/logout.json.js View File

@@ -1,16 +1,14 @@
import { log } from 'logging';
import { restricted } from 'auth';
import { stores } from 'sabaton';

export const get = async (req, res) => {
const {$session, $msg, $app} = stores(req, res);
const {$app} = stores(req, res);
$app.logout();
$app.redirect('/');
}


export const post = async (req, res) => {
const {$session, $msg, $app} = stores(req, res);
const {$app} = stores(req, res);
$app.logout();
$app.done({message: "OK"});
}


+ 4
- 4
src/routes/api/comments.json.js View File

@@ -1,7 +1,7 @@
import { log } from 'logging';
import { User, Comment } from '../../../lib/models';
import * as auth from 'auth';
import assert from 'assert';
import { Comment } from '../../../lib/models';
import { log } from 'logging';
import { stores } from 'sabaton';

const collect_comments = async ($app, url) => {
@@ -13,7 +13,7 @@ const collect_comments = async ($app, url) => {

export const get = auth.restricted(
async (req, res) => {
const { $session, $msg, $app} = stores(req, res);
const { $app } = stores(req, res);
assert(req.query && req.query.url, "No url parameter provided.");

try {
@@ -26,7 +26,7 @@ export const get = auth.restricted(

export const post = auth.restricted(
async (req, res) => {
const { $session, $msg, $app} = stores(req, res);
const { $msg, $app} = stores(req, res);

try {
assert($msg.url, "A URL is required.");


+ 1
- 3
src/routes/api/invoice.json.js View File

@@ -1,13 +1,11 @@
import { log } from 'logging';
import { User } from '../../../lib/models';
import * as auth from 'auth';
import assert from 'assert';
import { stores } from 'sabaton';
import { send_invoice } from 'mq';

export const post = auth.restricted(
async (req, res) => {
const { $session, $msg, $app} = stores(req, res);
const { $msg, $app} = stores(req, res);

try {
send_invoice(req.user.id, $msg.recipient.email, $msg.recipient);


+ 1
- 1
src/routes/api/register.json.js View File

@@ -52,7 +52,7 @@ export const post = async (req, res) => {
$app.error(402, "Payment is stored incorrectly in the database. Email help@learnjsthehardway.com.");
}
} else {
log.error('Paymjents failure at the server', $msg);
log.error('Payments failure at the server', $msg);
$app.error(402, "Payment failure. Please email help@learnjsthehardway.com.");
}
} catch(error) {


+ 14
- 10
src/routes/api/user/settings.json.js View File

@@ -1,20 +1,23 @@
import { log } from 'logging';
import { Payment, User } from '../../../../lib/models';
import * as auth from 'auth';
import assert from 'assert';
import { log } from 'logging';
import { Payment } from '../../../../lib/models';
import { stores } from 'sabaton';

/*
* Returns only payments currently since the user is
* already in the $session returned.
*/
export const get = auth.restricted(
async (req, res) => {
const { $session, $msg, $app} = stores(req, res);
const { $app} = stores(req, res);

try {
const user = {full_name: req.user.full_name, username: req.user.username};
const payments = await Payment.all({user_id: req.user.id});

const clean_payments = payments.map(x => ({ created_at: x.created_at, system: x.system}) );
const clean_payments = payments.map(x => ({ created_at: x.created_at, system: x.system}));

$app.done({user, payments: clean_payments });
$app.done({payments: clean_payments });
} catch (error) {
log.error(error);
$app.error(403, 'Unauthorized');
@@ -25,19 +28,20 @@ export const get = auth.restricted(
export const post = auth.restricted(
async (req, res) => {
const { $session, $msg, $app} = stores(req, res);
const user = req.user;

try {
log.debug('Updating user.');

// SECURITY: assumes the User.update call will scrub the input for correct values
const count = await req.user.update($msg);
const count = await user.update($msg);

assert(count === 1, `Attempted to update a user but got count ${count} instead of 1.`);

// TODO: why do I have to do this so much?
req.user.full_name = $msg.full_name;
req.user.username = $msg.username;
$session.user.initials = req.user.initials;
user.full_name = $msg.full_name;
user.username = $msg.username;
$session.user.initials = user.initials;
$session.user.full_name = $msg.full_name;
$session.user.username = $msg.username;



+ 1
- 1
src/routes/invoice.svelte View File

@@ -90,7 +90,7 @@
<label class="form-label" for="email-field">
Email <Icon name="help-circle" tooltip="Email on this site" tooltip_bottom="true"/>
</label>
<input class="form-input" name="email" type="email" data-testid="email" id="email-field" bind:value={ recipient.email } placeholder="Email Address">
<input class="form-input" name="email" type="email" data-testid="email-field" id="email-field" bind:value={ recipient.email } placeholder="Email Address">
<FormError errors={errors.email} visible={show_errors} />
</div>



+ 3
- 7
src/routes/user/index.svelte View File

@@ -4,11 +4,8 @@
let res = await this.fetch(`/api/user/settings.json`, {credentials: 'same-origin'});
let data = await res.json();

if(data.user) {
return {
full_name: data.user.full_name, password: '', email: '', username: data.user.username,
payments: data.payments
};
if(data.payments) {
return { payments: data.payments };
} else {
this.error(500, 'Unable to retreive your user record.');
}
@@ -34,7 +31,6 @@
let show_errors = false;
let errors = {};
export let payments = [];

export let form = {
full_name: user.full_name, password: '', email: '', username: user.username,
};
@@ -127,7 +123,7 @@
<FormError visible={show_errors} errors={ errors.full_name } />
</div>

<div class="form-group" class:has-error={ show_errors && errors.email }>
<div class="form-group" data-testid="email-group" class:has-error={ show_errors && errors.email }>
<label class="form-label" for="email-field">
Email (Obfuscated) <a alt="Read the Privacy Policy" aria-label="Read the Privacy Policy" href="/privacy" on:click|preventDefault={toggle_privacy}><Icon name="help-circle" tooltip="Read the Radical Privacy Policy" /></a>
</label>


+ 48
- 0
windows.config.js View File

@@ -0,0 +1,48 @@
module.exports = {
apps: [
{
name: 'auth',
script: './scripts/services/auth.js',
instances: 1,
autorestart: true,
watch: ["lib", "scripts/services", "src/email"],
max_memory_restart: '1G',
env: {
NODE_ENV: 'development'
},
env_production: {
NODE_ENV: 'production'
}
},
{
name: 'invoipt',
script: './scripts/services/invoipt.js',
instances: 1,
autorestart: true,
watch: ["lib", "scripts/services", "src/email"],
max_memory_restart: '1G',
env: {
NODE_ENV: 'development'
},
env_production: {
NODE_ENV: 'production'
}
},
{
name: 'tracker',
script: './scripts/services/tracker.js',
instances: 1,
autorestart: true,
watch: ["lib", "scripts/services"],
max_memory_restart: '1G',
env: {
NODE_ENV: 'development'
},
env_production: {
NODE_ENV: 'production'
}
},
],
};



Loading…
Cancel
Save