mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-01-27 13:53:09 +00:00
Compare commits
15 Commits
crawlGoogl
...
delete-rou
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bbff081ed | ||
|
|
c3281038bd | ||
|
|
cc7e2ebc40 | ||
|
|
22be3916b3 | ||
|
|
49831f4a17 | ||
|
|
19d6ef23a5 | ||
|
|
3da6822017 | ||
|
|
cd676d2509 | ||
|
|
7c100e608d | ||
|
|
a1b8a85583 | ||
|
|
d253023134 | ||
|
|
abee6b98c0 | ||
|
|
e0d4eafe17 | ||
|
|
2d3ebfd6bf | ||
|
|
2d2f1dc84c |
@@ -266,7 +266,7 @@ const EditPage = createClass({
|
|||||||
brew.text = brew.text.normalize('NFC');
|
brew.text = brew.text.normalize('NFC');
|
||||||
this.savedBrew.text = this.savedBrew.text.normalize('NFC');
|
this.savedBrew.text = this.savedBrew.text.normalize('NFC');
|
||||||
brew.pageCount = ((brew.renderer=='legacy' ? brew.text.match(/\\page/g) : brew.text.match(/^\\page$/gm)) || []).length + 1;
|
brew.pageCount = ((brew.renderer=='legacy' ? brew.text.match(/\\page/g) : brew.text.match(/^\\page$/gm)) || []).length + 1;
|
||||||
brew.patches = stringifyPatches(makePatches(encodeURI(this.savedBrew.text), encodeURI(brew.text)));
|
brew.patches = stringifyPatches(makePatches(this.savedBrew.text, brew.text));
|
||||||
brew.hash = await md5(this.savedBrew.text);
|
brew.hash = await md5(this.savedBrew.text);
|
||||||
//brew.text = undefined; - Temporary parallel path
|
//brew.text = undefined; - Temporary parallel path
|
||||||
brew.textBin = undefined;
|
brew.textBin = undefined;
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ fs.emptyDirSync('./build');
|
|||||||
livereload('./build'); // Install the Chrome extension LiveReload to automatically refresh the browser
|
livereload('./build'); // Install the Chrome extension LiveReload to automatically refresh the browser
|
||||||
watchFile('./server.js', { // Restart server when change detected to this file or any nested directory from here
|
watchFile('./server.js', { // Restart server when change detected to this file or any nested directory from here
|
||||||
ignore : ['./build', './client', './themes'], // Ignore folders that are not running server code / avoids unneeded restarts
|
ignore : ['./build', './client', './themes'], // Ignore folders that are not running server code / avoids unneeded restarts
|
||||||
ext : 'js' // Extensions to watch (only .js/.json by default)
|
ext : 'js json' // Extensions to watch (only .js/.json by default)
|
||||||
//watch : ['./server', './themes'], // Watch additional folders if needed
|
//watch : ['./server', './themes'], // Watch additional folders if needed
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
133
server/app.js
133
server/app.js
@@ -36,7 +36,6 @@ import bodyParser from 'body-parser';
|
|||||||
import cookieParser from 'cookie-parser';
|
import cookieParser from 'cookie-parser';
|
||||||
import forceSSL from './forcessl.mw.js';
|
import forceSSL from './forcessl.mw.js';
|
||||||
|
|
||||||
|
|
||||||
const sanitizeBrew = (brew, accessType)=>{
|
const sanitizeBrew = (brew, accessType)=>{
|
||||||
brew._id = undefined;
|
brew._id = undefined;
|
||||||
brew.__v = undefined;
|
brew.__v = undefined;
|
||||||
@@ -147,109 +146,6 @@ app.get('/', (req, res, next)=>{
|
|||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/analyze', async (req, res, next) => {
|
|
||||||
const accounts = JSON.parse(fs.readFileSync('accounts.json', 'utf8'));
|
|
||||||
|
|
||||||
let totalBrewsStubbed = accounts.reduce((sum, account) => {
|
|
||||||
if (account.brewsStubbed) {
|
|
||||||
return sum + account.brewsStubbed;
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
let totalAccountsProcessed = accounts.filter(account => account.fullyProcessed).length;
|
|
||||||
let totalAccountsWithInvalidCredentials = accounts.filter(account => account.invalidCredentials).length;
|
|
||||||
|
|
||||||
console.log(`Total Brews Stubbed: ${totalBrewsStubbed}`);
|
|
||||||
console.log(`Total Accounts Processed: ${totalAccountsProcessed}`);
|
|
||||||
console.log(`Total Accounts with Invalid Credentials: ${totalAccountsWithInvalidCredentials}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/destroy', async (req, res, next) => {
|
|
||||||
const accounts = JSON.parse(fs.readFileSync('accounts.json', 'utf8'));
|
|
||||||
let updated = false;
|
|
||||||
|
|
||||||
function sleep(ms) {
|
|
||||||
return new Promise(resolve => setTimeout(resolve, ms));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 40000; i < accounts.length; i++) {
|
|
||||||
if (accounts[i].fullyProcessed || accounts[i].invalidCredentials) continue;
|
|
||||||
|
|
||||||
const originalAccount = { ...accounts[i] };
|
|
||||||
const account = accounts[i];
|
|
||||||
|
|
||||||
console.log(`Processing account: ${account.username}`);
|
|
||||||
|
|
||||||
let googleBrews;
|
|
||||||
let auth;
|
|
||||||
try {
|
|
||||||
auth = await GoogleActions.authCheck(account, res);
|
|
||||||
googleBrews = await GoogleActions.listGoogleBrews(auth);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(`Auth error for ${account.username}`);
|
|
||||||
accounts[i] = { ...originalAccount, invalidCredentials: true };
|
|
||||||
updated = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!auth) {
|
|
||||||
accounts[i] = { ...originalAccount, missingAuth: true };
|
|
||||||
updated = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Google Brews:', googleBrews.length);
|
|
||||||
if (googleBrews.length === 0) {
|
|
||||||
accounts[i] = { ...originalAccount, fullyProcessed: true, brewsStubbed: 0 };
|
|
||||||
updated = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fields = ['googleId', 'title', 'editId', 'shareId'];
|
|
||||||
let brews = await HomebrewModel.getByUser(account.username, true, fields).catch(err => console.error(err));
|
|
||||||
const stubbedEditIds = new Set(brews.map(b => b.editId));
|
|
||||||
googleBrews = googleBrews.filter(b => !stubbedEditIds.has(b.editId));
|
|
||||||
console.log('Unstubbed Google Brews:', googleBrews.length);
|
|
||||||
|
|
||||||
const results = await Promise.all(
|
|
||||||
googleBrews.map(async (brew) => {
|
|
||||||
let brewFromServer = await GoogleActions.getGoogleBrew(auth, brew.googleId, brew.editId, 'edit');
|
|
||||||
splitTextStyleAndMetadata(brewFromServer);
|
|
||||||
brewFromServer.authors = [account.username];
|
|
||||||
api.excludeStubProps(brewFromServer);
|
|
||||||
console.log(`Trying to Stub: ${brewFromServer.title} (${brewFromServer.shareId})`);
|
|
||||||
let saved = await new HomebrewModel(brewFromServer).save().catch(err => console.error(err));
|
|
||||||
if (saved) {
|
|
||||||
console.log(`Saved Stub: ${saved.title} (${saved.shareId})`);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const stubCount = results.filter(Boolean).length;
|
|
||||||
console.log('Brews stubbed:', stubCount);
|
|
||||||
|
|
||||||
accounts[i] = {
|
|
||||||
...originalAccount,
|
|
||||||
brewsStubbed: stubCount,
|
|
||||||
fullyProcessed: stubCount === googleBrews.length
|
|
||||||
};
|
|
||||||
|
|
||||||
updated = true;
|
|
||||||
|
|
||||||
sleep(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updated) {
|
|
||||||
fs.writeFileSync('accounts.json', JSON.stringify(accounts, null, 2), 'utf8');
|
|
||||||
console.log('accounts.json updated');
|
|
||||||
}
|
|
||||||
|
|
||||||
res.send('One account processed');
|
|
||||||
});
|
|
||||||
|
|
||||||
//Home page Legacy
|
//Home page Legacy
|
||||||
app.get('/legacy', (req, res, next)=>{
|
app.get('/legacy', (req, res, next)=>{
|
||||||
req.brew = {
|
req.brew = {
|
||||||
@@ -476,6 +372,34 @@ app.put('/api/user/rename', async (req, res)=>{
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//Delete brews based on author
|
||||||
|
app.delete('/api/user/delete', async (req, res)=>{
|
||||||
|
const { username } = req.body;
|
||||||
|
|
||||||
|
const ownAccount = req.account && (req.account.username == username);
|
||||||
|
if(!ownAccount) return res.status(403).json({ error: 'Must be logged in to delete your account' });
|
||||||
|
|
||||||
|
try {
|
||||||
|
const brews = await HomebrewModel.getByUser(username, true, ['_id', 'googleId', 'editId', 'authors']);
|
||||||
|
|
||||||
|
const deletePromises = brews.map((brew)=>{
|
||||||
|
req.brew = brew;
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
api.deleteBrew(req, res, (err)=>err ? reject(err) : resolve());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(deletePromises);
|
||||||
|
|
||||||
|
return res.json({ success: true, message: `All brews for ${username} have been deleted.` });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deleting brews:', error);
|
||||||
|
if(!res.headersSent) {
|
||||||
|
return res.status(500).json({ error: 'Failed to delete the brews.' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
//Edit Page
|
//Edit Page
|
||||||
app.get('/edit/:id', asyncHandler(getBrew('edit')), asyncHandler(async(req, res, next)=>{
|
app.get('/edit/:id', asyncHandler(getBrew('edit')), asyncHandler(async(req, res, next)=>{
|
||||||
req.brew = req.brew.toObject ? req.brew.toObject() : req.brew;
|
req.brew = req.brew.toObject ? req.brew.toObject() : req.brew;
|
||||||
@@ -486,7 +410,6 @@ app.get('/edit/:id', asyncHandler(getBrew('edit')), asyncHandler(async(req, res,
|
|||||||
title : req.brew.title || 'Untitled Brew',
|
title : req.brew.title || 'Untitled Brew',
|
||||||
description : req.brew.description || 'No description.',
|
description : req.brew.description || 'No description.',
|
||||||
image : req.brew.thumbnail || defaultMetaTags.image,
|
image : req.brew.thumbnail || defaultMetaTags.image,
|
||||||
locale : req.brew.lang,
|
|
||||||
type : 'article'
|
type : 'article'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,7 @@
|
|||||||
import Mongoose from 'mongoose';
|
import Mongoose from 'mongoose';
|
||||||
|
|
||||||
const getMongoDBURL = (config)=>{
|
const getMongoDBURL = (config)=>{
|
||||||
console.log('mongodb uri', config.get('MONGODB_URI'));
|
return config.get('mongodb_uri') ||
|
||||||
return config.get('MONGODB_URI') ||
|
|
||||||
config.get('mongolab_uri') ||
|
config.get('mongolab_uri') ||
|
||||||
'mongodb://127.0.0.1/homebrewery'; // changed from mongodb://localhost/homebrewery to accommodate versions 16+ of node.
|
'mongodb://127.0.0.1/homebrewery'; // changed from mongodb://localhost/homebrewery to accommodate versions 16+ of node.
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -52,13 +52,13 @@ const api = {
|
|||||||
// ID Validation Checks
|
// ID Validation Checks
|
||||||
// Homebrewery ID
|
// Homebrewery ID
|
||||||
// Typically 12 characters, but the DB shows a range of 7 to 14 characters
|
// Typically 12 characters, but the DB shows a range of 7 to 14 characters
|
||||||
if(!id.match(/^[a-zA-Z0-9-_]{7,14}$/)){
|
if(!id.match(/^[A-Za-z0-9_-]{7,14}$/)){
|
||||||
throw { name: 'ID Error', message: 'Invalid ID', status: 404, HBErrorCode: '11', brewId: id };
|
throw { name: 'ID Error', message: 'Invalid ID', status: 404, HBErrorCode: '11', brewId: id };
|
||||||
}
|
}
|
||||||
// Google ID
|
// Google ID
|
||||||
// Typically 33 characters, old format is 44 - always starts with a 1
|
// Typically 33 characters, old format is 44 - always starts with a 1
|
||||||
// Managed by Google, may change outside of our control, so any length between 33 and 44 is acceptable
|
// Managed by Google, may change outside of our control, so any length between 33 and 44 is acceptable
|
||||||
if(googleId && !googleId.match(/^1(?:[a-zA-Z0-9-_]{32,43})$/)){
|
if(googleId && !googleId.match(/^1(?:[A-Za-z0-9+\/]{32,43})$/)){
|
||||||
throw { name: 'Google ID Error', message: 'Invalid ID', status: 404, HBErrorCode: '12', brewId: id };
|
throw { name: 'Google ID Error', message: 'Invalid ID', status: 404, HBErrorCode: '12', brewId: id };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,14 +375,14 @@ const api = {
|
|||||||
try {
|
try {
|
||||||
const patches = parsePatch(brewFromClient.patches);
|
const patches = parsePatch(brewFromClient.patches);
|
||||||
// Patch to a throwaway variable while parallelizing - we're more concerned with error/no error.
|
// Patch to a throwaway variable while parallelizing - we're more concerned with error/no error.
|
||||||
const patchedResult = decodeURI(applyPatches(patches, encodeURI(brewFromServer.text))[0]);
|
const patchedResult = applyPatches(patches, brewFromServer.text, { allowExceedingIndices: true })[0];
|
||||||
if(patchedResult != brewFromClient.text)
|
if(patchedResult != brewFromClient.text)
|
||||||
throw("Patches did not apply cleanly, text mismatch detected");
|
throw("Patches did not apply cleanly, text mismatch detected");
|
||||||
// brew.text = applyPatches(patches, brewFromServer.text)[0];
|
// brew.text = applyPatches(patches, brewFromServer.text)[0];
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
//debugTextMismatch(brewFromClient.text, brewFromServer.text, `edit/${brewFromClient.editId}`);
|
//debugTextMismatch(brewFromClient.text, brewFromServer.text, `edit/${brewFromClient.editId}`);
|
||||||
console.error('Failed to apply patches:', {
|
console.error('Failed to apply patches:', {
|
||||||
//patches : brewFromClient.patches,
|
patches : brewFromClient.patches,
|
||||||
brewId : brewFromClient.editId || 'unknown',
|
brewId : brewFromClient.editId || 'unknown',
|
||||||
error : err
|
error : err
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user