test backend lingdocs auth
This commit is contained in:
parent
1dcf1bf266
commit
41f401aa45
|
@ -29,5 +29,5 @@ jobs:
|
||||||
cd ..
|
cd ..
|
||||||
cd functions
|
cd functions
|
||||||
npm install
|
npm install
|
||||||
- name: deploy functions
|
- name: deploy functions and hosting routes
|
||||||
run: firebase deploy -f --token ${FIREBASE_TOKEN}
|
run: firebase deploy -f --token ${FIREBASE_TOKEN}
|
60
README.md
60
README.md
|
@ -138,6 +138,66 @@ pm2 start ecosystem.config.js
|
||||||
pm2 save
|
pm2 save
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Put behind a NGINX reverse proxy with this config (encryption by LetsEncrypt)
|
||||||
|
|
||||||
|
```
|
||||||
|
server {
|
||||||
|
server_name account.lingdocs.com;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://localhost:4000;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
proxy_set_header Access-Control-Allow-Origin *;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 500 /500.json;
|
||||||
|
location /500.json {
|
||||||
|
return 500 '{"ok":false,"error":"500 Internal Server Error"}';
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 502 /502.json;
|
||||||
|
location /502.json {
|
||||||
|
return 502 '{"ok":false,"error":"502 Bad Gateway"}';
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 503 /503.json;
|
||||||
|
location /503.json {
|
||||||
|
return 503 '{"ok":false,"error":"503 Service Temporarily Unavailable"}';
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 504 /504.json;
|
||||||
|
location /504.json {
|
||||||
|
return 504 '{"ok":false,"error":"504 Gateway Timeout"}';
|
||||||
|
}
|
||||||
|
|
||||||
|
listen [::]:443 ssl ipv6only=on; # managed by Certbot
|
||||||
|
listen 443 ssl; # managed by Certbot
|
||||||
|
ssl_certificate /etc/letsencrypt/live/account.lingdocs.com/fullchain.pem; # managed by Certbot
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/account.lingdocs.com/privkey.pem; # managed by Certbot
|
||||||
|
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||||
|
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||||
|
|
||||||
|
}
|
||||||
|
server {
|
||||||
|
if ($host = account.lingdocs.com) {
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
} # managed by Certbot
|
||||||
|
|
||||||
|
|
||||||
|
server_name account.lingdocs.com;
|
||||||
|
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
return 404; # managed by Certbot
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
#### CouchDB
|
#### CouchDB
|
||||||
|
|
||||||
When a user upgrades their account level to `student` or `editor`:
|
When a user upgrades their account level to `student` or `editor`:
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
# auth.lingdocs.com
|
|
||||||
|
|
||||||
Auth service for LingDocs (in progress, not usable yet)
|
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
"public": "public",
|
"public": "public",
|
||||||
"rewrites": [
|
"rewrites": [
|
||||||
{
|
{
|
||||||
"source": "/authory",
|
"source": "/testme",
|
||||||
"function": "authory"
|
"function": "testme"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -410,6 +410,16 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.55.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.55.tgz",
|
||||||
"integrity": "sha512-koZJ89uLZufDvToeWO5BrC4CR4OUfHnUz2qoPs/daQH6qq3IN62QFxCTZ+bKaCE0xaoCAJYE4AXre8AbghCrhg=="
|
"integrity": "sha512-koZJ89uLZufDvToeWO5BrC4CR4OUfHnUz2qoPs/daQH6qq3IN62QFxCTZ+bKaCE0xaoCAJYE4AXre8AbghCrhg=="
|
||||||
},
|
},
|
||||||
|
"@types/node-fetch": {
|
||||||
|
"version": "2.5.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.12.tgz",
|
||||||
|
"integrity": "sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"form-data": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/prop-types": {
|
"@types/prop-types": {
|
||||||
"version": "15.7.3",
|
"version": "15.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
|
||||||
|
@ -540,6 +550,12 @@
|
||||||
"retry": "0.12.0"
|
"retry": "0.12.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"asynckit": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
|
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"axios": {
|
"axios": {
|
||||||
"version": "0.21.1",
|
"version": "0.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
|
||||||
|
@ -648,6 +664,15 @@
|
||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"combined-stream": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"delayed-stream": "~1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"compressible": {
|
"compressible": {
|
||||||
"version": "2.0.18",
|
"version": "2.0.18",
|
||||||
"resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
|
"resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
|
||||||
|
@ -731,6 +756,12 @@
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"delayed-stream": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"depd": {
|
"depd": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
||||||
|
@ -980,6 +1011,17 @@
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz",
|
||||||
"integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA=="
|
"integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA=="
|
||||||
},
|
},
|
||||||
|
"form-data": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"forwarded": {
|
"forwarded": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
|
||||||
|
|
|
@ -22,12 +22,14 @@
|
||||||
"firebase-functions": "^3.11.0",
|
"firebase-functions": "^3.11.0",
|
||||||
"google-spreadsheet": "^3.1.15",
|
"google-spreadsheet": "^3.1.15",
|
||||||
"nano": "^9.0.3",
|
"nano": "^9.0.3",
|
||||||
|
"node-fetch": "^2.6.1",
|
||||||
"react": "^17.0.1",
|
"react": "^17.0.1",
|
||||||
"react-bootstrap": "^1.5.1",
|
"react-bootstrap": "^1.5.1",
|
||||||
"react-dom": "^17.0.1"
|
"react-dom": "^17.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^26.0.20",
|
"@types/jest": "^26.0.20",
|
||||||
|
"@types/node-fetch": "^2.5.12",
|
||||||
"firebase-functions-test": "^0.2.0",
|
"firebase-functions-test": "^0.2.0",
|
||||||
"typescript": "^3.8.0"
|
"typescript": "^3.8.0"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,75 +1,26 @@
|
||||||
import * as functions from "firebase-functions";
|
import * as functions from "firebase-functions";
|
||||||
import publish from "./publish";
|
import fetch from "node-fetch";
|
||||||
import {
|
|
||||||
receiveSubmissions,
|
|
||||||
} from "./submissions";
|
|
||||||
import generatePassword from "./generate-password";
|
|
||||||
import * as BT from "../../website/src/lib/backend-types"
|
|
||||||
import cors from "cors";
|
import cors from "cors";
|
||||||
import * as admin from "firebase-admin";
|
// import publish from "./publish";
|
||||||
import { getUserDbName } from "./lib/userDbName";
|
// import * as BT from "../../website/src/lib/backend-types"
|
||||||
|
|
||||||
const nano = require("nano")(functions.config().couchdb.couchdb_url);
|
export const testme = functions
|
||||||
const usersDb = nano.db.use("_users");
|
// .runWith({
|
||||||
|
// timeoutSeconds: 200,
|
||||||
admin.initializeApp();
|
// memory: "2GB"
|
||||||
|
// })
|
||||||
const validateFirebaseIdToken = async (req: any, res: any, next: any) => {
|
|
||||||
if ((!req.headers.authorization || !req.headers.authorization.startsWith('Bearer ')) &&
|
|
||||||
!(req.cookies && req.cookies.__session)) {
|
|
||||||
res.status(403).send({ message: "Unauthorized" });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let idToken;
|
|
||||||
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
|
|
||||||
// Read the ID Token from the Authorization header.
|
|
||||||
idToken = req.headers.authorization.split('Bearer ')[1];
|
|
||||||
} else if(req.cookies) {
|
|
||||||
// Read the ID Token from cookie.
|
|
||||||
idToken = req.cookies.__session;
|
|
||||||
} else {
|
|
||||||
// No cookie
|
|
||||||
res.status(403).send({ message: "Unauthorized" });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const decodedIdToken = await admin.auth().verifyIdToken(idToken);
|
|
||||||
req.user = decodedIdToken;
|
|
||||||
next();
|
|
||||||
return;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error while verifying Firebase ID token:', error);
|
|
||||||
res.status(403).send({ message: "Unauthorized" });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const isEditor = async (req: any) => {
|
|
||||||
const uid = req.user.uid as string;
|
|
||||||
const couchDbUser = await getCouchDbUser(uid);
|
|
||||||
return !!couchDbUser && couchDbUser.level === "editor";
|
|
||||||
}
|
|
||||||
|
|
||||||
export const publishDictionary = functions
|
|
||||||
.region("europe-west1")
|
|
||||||
.runWith({
|
|
||||||
timeoutSeconds: 200,
|
|
||||||
memory: "2GB"
|
|
||||||
})
|
|
||||||
.https.onRequest((req, res) => {
|
.https.onRequest((req, res) => {
|
||||||
return cors({ origin: true })(req, res, () => {
|
return cors({ credentials: true, origin: /\.lingdocs\.com$/ })(req, res, () => {
|
||||||
validateFirebaseIdToken(req, res, async () => {
|
const { headers: { cookie }} = req;
|
||||||
try {
|
if (!cookie) {
|
||||||
const response = await publish();
|
return res.status(401).send({ ok: false, error: "unauthorized" });
|
||||||
return res.send(response);
|
|
||||||
} catch (error) {
|
|
||||||
return res.status(500).send({
|
|
||||||
error: error.toString(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
fetch("https://account.lingdocs.com/api/user", {
|
||||||
|
headers: { cookie },
|
||||||
|
}).then(r => r.json()).then(r => {
|
||||||
|
res.send({ ok: true, r });
|
||||||
|
}).catch((error) => res.send({ ok: false, error }));
|
||||||
|
return;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -82,151 +33,30 @@ export const submissions = functions
|
||||||
memory: "1GB"
|
memory: "1GB"
|
||||||
})
|
})
|
||||||
.https.onRequest((req, res) => {
|
.https.onRequest((req, res) => {
|
||||||
return cors({ origin: true })(req, res, () => {
|
res.send({ ok: false, error: "function under maintenance" });
|
||||||
validateFirebaseIdToken(req, res, async () => {
|
// return cors({ origin: true })(req, res, () => {
|
||||||
if (!Array.isArray(req.body)) {
|
// validateFirebaseIdToken(req, res, async () => {
|
||||||
res.status(400).send({
|
// if (!Array.isArray(req.body)) {
|
||||||
ok: false,
|
// res.status(400).send({
|
||||||
error: "invalid submission",
|
// ok: false,
|
||||||
});
|
// error: "invalid submission",
|
||||||
return;
|
|
||||||
}
|
|
||||||
const suggestions = req.body as BT.SubmissionsRequest;
|
|
||||||
// @ts-ignore
|
|
||||||
const uid = req.user.uid as string;
|
|
||||||
const editor = await isEditor(req);
|
|
||||||
try {
|
|
||||||
const response = await receiveSubmissions(suggestions, editor);
|
|
||||||
// TODO: WARN IF ANY OF THE EDITS DIDN'T HAPPEN
|
|
||||||
res.send(response);
|
|
||||||
return;
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
return res.status(500).send({
|
|
||||||
error: error.toString(),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}).catch(console.error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
export const getUserInfo = functions.region("europe-west1").https.onRequest((req, res) => {
|
|
||||||
return cors({ origin: true })(req, res, () => {
|
|
||||||
validateFirebaseIdToken(req, res, async () => {
|
|
||||||
try {
|
|
||||||
// @ts-ignore
|
|
||||||
const uid = req.user.uid as string;
|
|
||||||
const user = await getCouchDbUser(uid);
|
|
||||||
if (!user) {
|
|
||||||
const noneFound: BT.GetUserInfoResponse = {
|
|
||||||
ok: true,
|
|
||||||
message: "no couchdb user found",
|
|
||||||
};
|
|
||||||
res.send(noneFound);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const userFound: BT.GetUserInfoResponse = { ok: true, user };
|
|
||||||
res.send(userFound);
|
|
||||||
return;
|
|
||||||
} catch(error) {
|
|
||||||
console.error(error);
|
|
||||||
res.status(500).send({
|
|
||||||
ok: false,
|
|
||||||
error: error.message,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).catch(console.error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// export const cleanUpUser = functions
|
|
||||||
// .region("europe-west1")
|
|
||||||
// .auth.user().onDelete(async (user) => {
|
|
||||||
// const couchDbUser = await getCouchDbUser(user.uid);
|
|
||||||
// if (!couchDbUser) return;
|
|
||||||
// await usersDb.destroy(
|
|
||||||
// `org.couchdb.user:${user.uid}`,
|
|
||||||
// couchDbUser._rev,
|
|
||||||
// );
|
|
||||||
// try {
|
|
||||||
// await nano.db.destroy(getUserDbName(user.uid));
|
|
||||||
// } catch (e) {
|
|
||||||
// console.log("errored destroying", e);
|
|
||||||
// };
|
|
||||||
// });
|
// });
|
||||||
|
// return;
|
||||||
export const upgradeUser = functions.region("europe-west1").https.onRequest((req, res) => {
|
// }
|
||||||
return cors({ origin: true })(req, res, () => {
|
// const suggestions = req.body as BT.SubmissionsRequest;
|
||||||
validateFirebaseIdToken(req, res, async () => {
|
// // @ts-ignore
|
||||||
const password = (req.body.password || "") as string;
|
// const uid = req.user.uid as string;
|
||||||
const studentPassword = functions.config().upgrades.student_password as string;
|
// const editor = await isEditor(req);
|
||||||
if (password.toLowerCase() !== studentPassword.toLowerCase()) {
|
// try {
|
||||||
const wrongPass: BT.UpgradeUserResponse = {
|
// const response = await receiveSubmissions(suggestions, editor);
|
||||||
ok: false,
|
// // TODO: WARN IF ANY OF THE EDITS DIDN'T HAPPEN
|
||||||
error: "incorrect password",
|
// res.send(response);
|
||||||
};
|
// return;
|
||||||
res.send(wrongPass);
|
// } catch (error) {
|
||||||
return;
|
// console.error(error);
|
||||||
}
|
// return res.status(500).send({
|
||||||
// @ts-ignore
|
// error: error.toString(),
|
||||||
const uid = req.user.uid;
|
// });
|
||||||
const couchDbUser = await getCouchDbUser(uid);
|
// };
|
||||||
if (couchDbUser) {
|
// }).catch(console.error);
|
||||||
const alreadyUpgraded: BT.UpgradeUserResponse = {
|
|
||||||
ok: true,
|
|
||||||
message: "user already upgraded",
|
|
||||||
};
|
|
||||||
res.send(alreadyUpgraded);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const user = await admin.auth().getUser(uid);
|
|
||||||
const userdbPassword = generatePassword();
|
|
||||||
const newCouchDbUser: BT.CouchDbUser = {
|
|
||||||
_id: `org.couchdb.user:${user.uid}`,
|
|
||||||
type: "user",
|
|
||||||
name: user.uid,
|
|
||||||
email: user.email || "",
|
|
||||||
providerData: user.providerData,
|
|
||||||
displayName: user.displayName || "",
|
|
||||||
roles: [],
|
|
||||||
password: userdbPassword,
|
|
||||||
level: "student",
|
|
||||||
userdbPassword,
|
|
||||||
};
|
|
||||||
await usersDb.insert(newCouchDbUser);
|
|
||||||
// create wordlist database for user
|
|
||||||
const userDbName = getUserDbName(user.uid);
|
|
||||||
await nano.db.create(userDbName);
|
|
||||||
const securityInfo = {
|
|
||||||
admins: {
|
|
||||||
names: [user.uid],
|
|
||||||
roles: ["_admin"]
|
|
||||||
},
|
|
||||||
members: {
|
|
||||||
names: [user.uid],
|
|
||||||
roles: ["_admin"],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const userDb = nano.db.use(userDbName);
|
|
||||||
await userDb.insert(securityInfo, "_security");
|
|
||||||
// TODO: SET THE USERDBPASSWORD TO BE userdbPassword;
|
|
||||||
const upgraded: BT.UpgradeUserResponse = {
|
|
||||||
ok: true,
|
|
||||||
message: "user upgraded to student",
|
|
||||||
};
|
|
||||||
res.send(upgraded);
|
|
||||||
}).catch(console.error);
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
async function getCouchDbUser(uid: string): Promise<undefined | BT.CouchDbUser> {
|
|
||||||
const user = await usersDb.find({
|
|
||||||
selector: {
|
|
||||||
name: uid,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!user.docs.length) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return user.docs[0] as BT.CouchDbUser;
|
|
||||||
}
|
|
|
@ -16,7 +16,7 @@ import {
|
||||||
// } from "./word-list-maker";
|
// } from "./word-list-maker";
|
||||||
import {
|
import {
|
||||||
PublishDictionaryResponse,
|
PublishDictionaryResponse,
|
||||||
} from "../../website/src/lib/backend-types";
|
} from "../../website/src/lib/functions-types";
|
||||||
import { Storage } from "@google-cloud/storage";
|
import { Storage } from "@google-cloud/storage";
|
||||||
const storage = new Storage({
|
const storage = new Storage({
|
||||||
projectId: "lingdocs",
|
projectId: "lingdocs",
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {
|
||||||
dictionaryEntryBooleanFields,
|
dictionaryEntryBooleanFields,
|
||||||
dictionaryEntryNumberFields,
|
dictionaryEntryNumberFields,
|
||||||
} from "@lingdocs/pashto-inflector";
|
} from "@lingdocs/pashto-inflector";
|
||||||
import * as BT from "../../website/src/lib/backend-types";
|
import * as FT from "../../website/src/lib/functions-types";
|
||||||
import * as functions from "firebase-functions";
|
import * as functions from "firebase-functions";
|
||||||
|
|
||||||
const fieldsForEdit = [
|
const fieldsForEdit = [
|
||||||
|
@ -17,7 +17,7 @@ const fieldsForEdit = [
|
||||||
const nano = require("nano")(functions.config().couchdb.couchdb_url);
|
const nano = require("nano")(functions.config().couchdb.couchdb_url);
|
||||||
const reviewTasksDb = nano.db.use("review-tasks");
|
const reviewTasksDb = nano.db.use("review-tasks");
|
||||||
|
|
||||||
export async function receiveSubmissions(e: BT.SubmissionsRequest, editor: boolean): Promise<BT.SubmissionsResponse> {
|
export async function receiveSubmissions(e: FT.SubmissionsRequest, editor: boolean): Promise<FT.SubmissionsResponse> {
|
||||||
const { edits, reviewTasks } = sortSubmissions(e);
|
const { edits, reviewTasks } = sortSubmissions(e);
|
||||||
|
|
||||||
// TODO: BETTER PROMISE MULTI-TASKING
|
// TODO: BETTER PROMISE MULTI-TASKING
|
||||||
|
@ -111,11 +111,11 @@ export async function receiveSubmissions(e: BT.SubmissionsRequest, editor: boole
|
||||||
}
|
}
|
||||||
|
|
||||||
type SortedSubmissions = {
|
type SortedSubmissions = {
|
||||||
edits: BT.Edit[],
|
edits: FT.Edit[],
|
||||||
reviewTasks: BT.ReviewTask[],
|
reviewTasks: FT.ReviewTask[],
|
||||||
};
|
};
|
||||||
|
|
||||||
export function sortSubmissions(submissions: BT.Submission[]): SortedSubmissions {
|
export function sortSubmissions(submissions: FT.Submission[]): SortedSubmissions {
|
||||||
const base: SortedSubmissions = {
|
const base: SortedSubmissions = {
|
||||||
edits: [],
|
edits: [],
|
||||||
reviewTasks: [],
|
reviewTasks: [],
|
||||||
|
@ -131,12 +131,12 @@ export function sortSubmissions(submissions: BT.Submission[]): SortedSubmissions
|
||||||
}
|
}
|
||||||
|
|
||||||
type SortedEdits = {
|
type SortedEdits = {
|
||||||
entryEdits: BT.EntryEdit[],
|
entryEdits: FT.EntryEdit[],
|
||||||
newEntries: BT.NewEntry[],
|
newEntries: FT.NewEntry[],
|
||||||
entryDeletions: BT.EntryDeletion[],
|
entryDeletions: FT.EntryDeletion[],
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sortEdits(edits: BT.Edit[]): SortedEdits {
|
export function sortEdits(edits: FT.Edit[]): SortedEdits {
|
||||||
const base: SortedEdits = {
|
const base: SortedEdits = {
|
||||||
entryEdits: [],
|
entryEdits: [],
|
||||||
newEntries: [],
|
newEntries: [],
|
||||||
|
|
|
@ -31,6 +31,11 @@ const Account = ({ user, loadUser }: { user: AT.LingdocsUser | undefined, loadUs
|
||||||
setUpgradeError("");
|
setUpgradeError("");
|
||||||
setWaiting(false);
|
setWaiting(false);
|
||||||
window.addEventListener("message", handleIncomingMessage);
|
window.addEventListener("message", handleIncomingMessage);
|
||||||
|
console.log("send test func");
|
||||||
|
fetch("https://functions.lingdocs.com/testme", { credentials: "include" }).then((res) => res.text()).then((res) => {
|
||||||
|
console.log("test func here");
|
||||||
|
console.log(res);
|
||||||
|
});
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener("message", handleIncomingMessage);
|
window.removeEventListener("message", handleIncomingMessage);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue