Files
NodeBB/src/database/postgres/main.js
Barış Soner Uşaklı 04998908ba Fixes for "validate email" & "send validation email" in ACP (#11677)
* confirmObj changes

dont expire confirm:<code>, add a expires field instead
dont expire confirm:byUid:<uid>

on admin manage users display the users email status
	1. verified
	2. verify email sent (pending)
	3. verify email sent (expired)
	4. no email entered

fix validate email in acp to use
	email in user:<uid> if they have one
	if not check if its in confirm:<code>
	if its not in above cant validate throw error

fix send validate email to use
	email in user:<uid> if they have one
	if not check if its in confirm:<code>
	if its not in above too cant validate throw error

* add back socket.io tests

* test: fix confirm tests

no longer using pexpire
return correct time left on token

* chore: update openapi

* fix: delete call

* test: mget test fixes

* test: fix tests
2023-06-05 12:12:48 -04:00

270 lines
5.8 KiB
JavaScript

'use strict';
module.exports = function (module) {
const helpers = require('./helpers');
module.flushdb = async function () {
await module.pool.query(`DROP SCHEMA "public" CASCADE`);
await module.pool.query(`CREATE SCHEMA "public"`);
};
module.emptydb = async function () {
await module.pool.query(`DELETE FROM "legacy_object"`);
};
module.exists = async function (key) {
if (!key) {
return;
}
// Redis/Mongo consider empty zsets as non-existent, match that behaviour
const type = await module.type(key);
if (type === 'zset') {
if (Array.isArray(key)) {
const members = await Promise.all(key.map(key => module.getSortedSetRange(key, 0, 0)));
return members.map(member => member.length > 0);
}
const members = await module.getSortedSetRange(key, 0, 0);
return members.length > 0;
}
if (Array.isArray(key)) {
const res = await module.pool.query({
name: 'existsArray',
text: `
SELECT o."_key" k
FROM "legacy_object_live" o
WHERE o."_key" = ANY($1::TEXT[])`,
values: [key],
});
return key.map(k => res.rows.some(r => r.k === k));
}
const res = await module.pool.query({
name: 'exists',
text: `
SELECT EXISTS(SELECT *
FROM "legacy_object_live"
WHERE "_key" = $1::TEXT
LIMIT 1) e`,
values: [key],
});
return res.rows[0].e;
};
module.scan = async function (params) {
let { match } = params;
if (match.startsWith('*')) {
match = `%${match.substring(1)}`;
}
if (match.endsWith('*')) {
match = `${match.substring(0, match.length - 1)}%`;
}
const res = await module.pool.query({
text: `
SELECT o."_key"
FROM "legacy_object_live" o
WHERE o."_key" LIKE '${match}'`,
});
return res.rows.map(r => r._key);
};
module.delete = async function (key) {
if (!key) {
return;
}
await module.pool.query({
name: 'delete',
text: `
DELETE FROM "legacy_object"
WHERE "_key" = $1::TEXT`,
values: [key],
});
};
module.deleteAll = async function (keys) {
if (!Array.isArray(keys) || !keys.length) {
return;
}
await module.pool.query({
name: 'deleteAll',
text: `
DELETE FROM "legacy_object"
WHERE "_key" = ANY($1::TEXT[])`,
values: [keys],
});
};
module.get = async function (key) {
if (!key) {
return;
}
const res = await module.pool.query({
name: 'get',
text: `
SELECT s."data" t
FROM "legacy_object_live" o
INNER JOIN "legacy_string" s
ON o."_key" = s."_key"
AND o."type" = s."type"
WHERE o."_key" = $1::TEXT
LIMIT 1`,
values: [key],
});
return res.rows.length ? res.rows[0].t : null;
};
module.mget = async function (keys) {
if (!keys || !Array.isArray(keys) || !keys.length) {
return [];
}
const res = await module.pool.query({
name: 'mget',
text: `
SELECT s."data", s."_key"
FROM "legacy_object_live" o
INNER JOIN "legacy_string" s
ON o."_key" = s."_key"
AND o."type" = s."type"
WHERE o."_key" = ANY($1::TEXT[])
LIMIT 1`,
values: [keys],
});
const map = {};
res.rows.forEach((d) => {
map[d._key] = d.data;
});
return keys.map(k => (map.hasOwnProperty(k) ? map[k] : null));
};
module.set = async function (key, value) {
if (!key) {
return;
}
await module.transaction(async (client) => {
await helpers.ensureLegacyObjectType(client, key, 'string');
await client.query({
name: 'set',
text: `
INSERT INTO "legacy_string" ("_key", "data")
VALUES ($1::TEXT, $2::TEXT)
ON CONFLICT ("_key")
DO UPDATE SET "data" = $2::TEXT`,
values: [key, value],
});
});
};
module.increment = async function (key) {
if (!key) {
return;
}
return await module.transaction(async (client) => {
await helpers.ensureLegacyObjectType(client, key, 'string');
const res = await client.query({
name: 'increment',
text: `
INSERT INTO "legacy_string" ("_key", "data")
VALUES ($1::TEXT, '1')
ON CONFLICT ("_key")
DO UPDATE SET "data" = ("legacy_string"."data"::NUMERIC + 1)::TEXT
RETURNING "data" d`,
values: [key],
});
return parseFloat(res.rows[0].d);
});
};
module.rename = async function (oldKey, newKey) {
await module.transaction(async (client) => {
await client.query({
name: 'deleteRename',
text: `
DELETE FROM "legacy_object"
WHERE "_key" = $1::TEXT`,
values: [newKey],
});
await client.query({
name: 'rename',
text: `
UPDATE "legacy_object"
SET "_key" = $2::TEXT
WHERE "_key" = $1::TEXT`,
values: [oldKey, newKey],
});
});
};
module.type = async function (key) {
const res = await module.pool.query({
name: 'type',
text: `
SELECT "type"::TEXT t
FROM "legacy_object_live"
WHERE "_key" = $1::TEXT
LIMIT 1`,
values: [key],
});
return res.rows.length ? res.rows[0].t : null;
};
async function doExpire(key, date) {
await module.pool.query({
name: 'expire',
text: `
UPDATE "legacy_object"
SET "expireAt" = $2::TIMESTAMPTZ
WHERE "_key" = $1::TEXT`,
values: [key, date],
});
}
module.expire = async function (key, seconds) {
await doExpire(key, new Date(((Date.now() / 1000) + seconds) * 1000));
};
module.expireAt = async function (key, timestamp) {
await doExpire(key, new Date(timestamp * 1000));
};
module.pexpire = async function (key, ms) {
await doExpire(key, new Date(Date.now() + parseInt(ms, 10)));
};
module.pexpireAt = async function (key, timestamp) {
await doExpire(key, new Date(timestamp));
};
async function getExpire(key) {
const res = await module.pool.query({
name: 'ttl',
text: `
SELECT "expireAt"::TEXT
FROM "legacy_object"
WHERE "_key" = $1::TEXT
LIMIT 1`,
values: [key],
});
return res.rows.length ? new Date(res.rows[0].expireAt).getTime() : null;
}
module.ttl = async function (key) {
return Math.round((await getExpire(key) - Date.now()) / 1000);
};
module.pttl = async function (key) {
return await getExpire(key) - Date.now();
};
};