meteor3: re-enable fixtures and sitemaps with async/Meteor-3 implementations
fixtures: drop @cleverbeagle/seeder (sync Mongo, unmaintained) for a small idempotent async seeder (same dev accounts). sitemaps: drop dead gadicohen:sitemaps for a WebApp.connectHandlers /sitemap.xml with the same static page list (the per-fire section was already disabled). Verified on dev boot: 6 users ensured, sitemap serving; REST smoke byte-identical.
This commit is contained in:
parent
66bab7a43b
commit
0ff9848cd4
8 changed files with 20493 additions and 15709 deletions
|
|
@ -49,7 +49,6 @@ aldeed:schema-deny
|
||||||
dburles:collection-helpers
|
dburles:collection-helpers
|
||||||
reywood:publish-composite
|
reywood:publish-composite
|
||||||
facts-base@1.0.2
|
facts-base@1.0.2
|
||||||
gadicohen:sitemaps
|
|
||||||
nspangler:autoreconnect
|
nspangler:autoreconnect
|
||||||
quave:synced-cron
|
quave:synced-cron
|
||||||
# lmachens:kadira
|
# lmachens:kadira
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,6 @@ flowkey:raven@1.1.0
|
||||||
fortawesome:fontawesome@4.7.0
|
fortawesome:fontawesome@4.7.0
|
||||||
fourseven:scss@5.0.0
|
fourseven:scss@5.0.0
|
||||||
gadicc:blaze-react-component@2.0.1
|
gadicc:blaze-react-component@2.0.1
|
||||||
gadicohen:sitemaps@0.0.17
|
|
||||||
geojson-utils@1.0.12
|
geojson-utils@1.0.12
|
||||||
github-oauth@1.4.2
|
github-oauth@1.4.2
|
||||||
google-oauth@1.4.5
|
google-oauth@1.4.5
|
||||||
|
|
|
||||||
10
UPGRADE.md
10
UPGRADE.md
|
|
@ -241,6 +241,16 @@ MONGO_CONTAINER=tcef-mongo7 MONGO_SHELL=mongosh MONGO_PORT=27019 ./smoke/smoke.s
|
||||||
async, `users.findOneAsync` for the username. `onCommentAdd` mail fan-out:
|
async, `users.findOneAsync` for the username. `onCommentAdd` mail fan-out:
|
||||||
`users.find().forEach` → `forEachAsync`. Still fire-and-forget from the
|
`users.find().forEach` → `forEachAsync`. Still fire-and-forget from the
|
||||||
insert. Comments UI staging verification pending (pre-existing note below).
|
insert. Comments UI staging verification pending (pre-existing note below).
|
||||||
|
- ✅ **fixtures.js re-enabled** — `@cleverbeagle/seeder` (sync Mongo, no Meteor
|
||||||
|
3 support) **removed from package.json** and replaced with a small in-repo
|
||||||
|
async seeder: idempotent, dev-only (staging opts in with `TCEF_SEED=1`);
|
||||||
|
same accounts as before (`admin@admin.com` / 5 test users / 5 Documents
|
||||||
|
each). Verified: `fixtures: 6 dev users ensured` on boot.
|
||||||
|
- ✅ **sitemaps.js re-enabled** — `gadicohen:sitemaps` (pre-0.9 API, dead on
|
||||||
|
Meteor 3) **removed from .meteor/packages**; `/sitemap.xml` is now a small
|
||||||
|
`WebApp.connectHandlers` handler serving the same static page list (the
|
||||||
|
per-fire section of the old handler was behind `firesMapEnabled = false`,
|
||||||
|
i.e. dead code, and was dropped). Verified serving on dev.
|
||||||
|
|
||||||
### Still TODO before the web (not just REST) is fully deployable on 3.x
|
### Still TODO before the web (not just REST) is fully deployable on 3.x
|
||||||
- **React 16 → 18** render root + verify ancient react-* libs.
|
- **React 16 → 18** render root + verify ancient react-* libs.
|
||||||
|
|
|
||||||
|
|
@ -1,54 +1,71 @@
|
||||||
import seeder from '@cleverbeagle/seeder';
|
/* eslint-disable no-await-in-loop */
|
||||||
import { Meteor } from 'meteor/meteor';
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { Accounts } from 'meteor/accounts-base';
|
||||||
import Documents from '../../api/Documents/Documents';
|
import Documents from '../../api/Documents/Documents';
|
||||||
|
|
||||||
const documentsSeed = userId => ({
|
/*
|
||||||
collection: Documents,
|
* Dev/staging fixtures. Replaces @cleverbeagle/seeder (sync Mongo, no Meteor 3
|
||||||
environments: ['development', 'staging'],
|
* support) with a small async seeder: idempotent (find-before-create), only
|
||||||
noLimit: true,
|
* runs outside production.
|
||||||
modelCount: 5,
|
*/
|
||||||
model(dataIndex) {
|
|
||||||
return {
|
|
||||||
owner: userId,
|
|
||||||
title: `Document #${dataIndex + 1}`,
|
|
||||||
body: `This is the body of document #${dataIndex + 1}`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
seeder(Meteor.users, {
|
const USERS = [
|
||||||
environments: ['development', 'staging'],
|
{
|
||||||
noLimit: true,
|
|
||||||
data: [{
|
|
||||||
email: 'admin@admin.com',
|
email: 'admin@admin.com',
|
||||||
password: 'password',
|
password: 'password',
|
||||||
profile: {
|
profile: { name: { first: 'Andy', last: 'Warhol' } },
|
||||||
name: {
|
roles: ['admin']
|
||||||
first: 'Andy',
|
|
||||||
last: 'Warhol',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
roles: ['admin'],
|
|
||||||
data(userId) {
|
|
||||||
return documentsSeed(userId);
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
modelCount: 5,
|
|
||||||
model(index, faker) {
|
|
||||||
const userCount = index + 1;
|
|
||||||
return {
|
|
||||||
email: `user+${userCount}@test.com`,
|
|
||||||
password: 'password',
|
|
||||||
profile: {
|
|
||||||
name: {
|
|
||||||
first: faker.name.firstName(),
|
|
||||||
last: faker.name.lastName(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
roles: ['user'],
|
|
||||||
data(userId) {
|
|
||||||
return documentsSeed(userId);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
...[
|
||||||
|
['Frida', 'Kahlo'],
|
||||||
|
['Joaquín', 'Sorolla'],
|
||||||
|
['Maruja', 'Mallo'],
|
||||||
|
['Remedios', 'Varo'],
|
||||||
|
['Pablo', 'Picasso']
|
||||||
|
].map(([first, last], i) => ({
|
||||||
|
email: `user+${i + 1}@test.com`,
|
||||||
|
password: 'password',
|
||||||
|
profile: { name: { first, last } },
|
||||||
|
roles: ['user']
|
||||||
|
}))
|
||||||
|
];
|
||||||
|
|
||||||
|
const DOCUMENTS_PER_USER = 5;
|
||||||
|
|
||||||
|
async function ensureUser({ email, password, profile, roles }) {
|
||||||
|
const existing = await Meteor.users.findOneAsync({ 'emails.address': email });
|
||||||
|
const userId = existing
|
||||||
|
? existing._id
|
||||||
|
: await Accounts.createUserAsync({ email, password, profile });
|
||||||
|
if (!existing && roles) {
|
||||||
|
await Meteor.users.updateAsync(userId, { $set: { roles } });
|
||||||
|
}
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensureDocuments(userId) {
|
||||||
|
const count = await Documents.find({ owner: userId }).countAsync();
|
||||||
|
if (count > 0) return;
|
||||||
|
for (let i = 0; i < DOCUMENTS_PER_USER; i += 1) {
|
||||||
|
await Documents.insertAsync({
|
||||||
|
owner: userId,
|
||||||
|
title: `Document #${i + 1}`,
|
||||||
|
body: `This is the body of document #${i + 1}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Meteor.startup(async () => {
|
||||||
|
// dev always; staging opts in with TCEF_SEED=1 (the old seeder's
|
||||||
|
// 'staging' environment had no reliable detection either).
|
||||||
|
if (!Meteor.isDevelopment && process.env.TCEF_SEED !== '1') return;
|
||||||
|
try {
|
||||||
|
for (const user of USERS) {
|
||||||
|
const userId = await ensureUser(user);
|
||||||
|
await ensureDocuments(userId);
|
||||||
|
}
|
||||||
|
console.log(`fixtures: ${USERS.length} dev users ensured`);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(`fixtures: seeding failed: ${e}`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,13 @@ import './catchExceptions';
|
||||||
import './i18n';
|
import './i18n';
|
||||||
import './accounts';
|
import './accounts';
|
||||||
import './api';
|
import './api';
|
||||||
// Meteor 3 debt: '@cleverbeagle/seeder' (dev/staging fixtures) uses sync Mongo
|
import './fixtures';
|
||||||
// (findOne) and has no Meteor 3 async support. Disabled — not needed for the
|
|
||||||
// REST smoke test. Re-implement dev fixtures with *Async if desired.
|
|
||||||
// import './fixtures';
|
|
||||||
import './email';
|
import './email';
|
||||||
import '/imports/api/Comments/server';
|
import '/imports/api/Comments/server';
|
||||||
import './IPGeocoder';
|
import './IPGeocoder';
|
||||||
import './migrations';
|
import './migrations';
|
||||||
import './facts';
|
import './facts';
|
||||||
// Meteor 3 debt: gadicohen:sitemaps@0.0.17 uses the pre-0.9 package API and no
|
import './sitemaps';
|
||||||
// longer exports the `sitemaps` global on Meteor 3. Disabled (SEO sitemap, not
|
|
||||||
// on the REST path). Replace with a maintained sitemap approach if needed.
|
|
||||||
// import './sitemaps';
|
|
||||||
import './subsUnion';
|
import './subsUnion';
|
||||||
import './prerender';
|
import './prerender';
|
||||||
import './feedback';
|
import './feedback';
|
||||||
|
|
|
||||||
|
|
@ -1,44 +1,37 @@
|
||||||
/* global sitemaps */
|
|
||||||
/* eslint-disable import/no-absolute-path */
|
/* eslint-disable import/no-absolute-path */
|
||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { WebApp } from 'meteor/webapp';
|
||||||
|
|
||||||
import Fires from '/imports/api/Fires/Fires';
|
/*
|
||||||
import Comments from '/imports/api/Comments/Comments';
|
* /sitemap.xml — own implementation replacing gadicohen:sitemaps (pre-0.9
|
||||||
|
* package API, dead on Meteor 3). Static pages only: the per-fire section of
|
||||||
|
* the old handler was behind `firesMapEnabled = false` (dead code) and was
|
||||||
|
* dropped; see git history if it's ever wanted back.
|
||||||
|
*/
|
||||||
|
|
||||||
const firesMapEnabled = false;
|
const PAGES = [
|
||||||
|
'/fires',
|
||||||
|
'/login',
|
||||||
|
'/signup',
|
||||||
|
'/recover-password',
|
||||||
|
'/credits',
|
||||||
|
'/terms',
|
||||||
|
'/license',
|
||||||
|
'/privacy',
|
||||||
|
'/about'
|
||||||
|
];
|
||||||
|
|
||||||
sitemaps.add('/sitemap.xml', () => {
|
function xmlEscape(s) {
|
||||||
const today = new Date();
|
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||||
|
}
|
||||||
|
|
||||||
const out = [];
|
WebApp.connectHandlers.use('/sitemap.xml', (req, res) => {
|
||||||
out.push({ page: '/fires', lastmod: today });
|
const lastmod = new Date().toISOString().slice(0, 10);
|
||||||
out.push({ page: '/login', lastmod: today });
|
const urls = PAGES.map((page) => {
|
||||||
out.push({ page: '/signup', lastmod: today });
|
const loc = xmlEscape(Meteor.absoluteUrl(page.replace(/^\//, '')));
|
||||||
out.push({ page: '/recover-password', lastmod: today });
|
return ` <url>\n <loc>${loc}</loc>\n <lastmod>${lastmod}</lastmod>\n </url>`;
|
||||||
out.push({ page: '/credits', lastmod: today });
|
}).join('\n');
|
||||||
out.push({ page: '/terms', lastmod: today });
|
const body = `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${urls}\n</urlset>\n`;
|
||||||
out.push({ page: '/license', lastmod: today });
|
res.writeHead(200, { 'Content-Type': 'application/xml; charset=utf-8' });
|
||||||
out.push({ page: '/privacy', lastmod: today });
|
res.end(body);
|
||||||
out.push({ page: '/about', lastmod: today });
|
|
||||||
|
|
||||||
// When user has public page
|
|
||||||
/* const users = Meteor.users.find().fetch();
|
|
||||||
_.each(users, function(user) {
|
|
||||||
out.push({
|
|
||||||
page: '/persona/' + user.username,
|
|
||||||
lastmod: user.updatedAt
|
|
||||||
});
|
|
||||||
}); */
|
|
||||||
|
|
||||||
if (firesMapEnabled) {
|
|
||||||
Fires.find({}, { limit: 100, sort: { createdAt: -1 } }).fetch().forEach((fire) => {
|
|
||||||
// Search the last comment of tha fire
|
|
||||||
const lastComment = Comments.findOne({ referenceId: `fire-${fire._id}` }, { sort: { createdAt: -1 } });
|
|
||||||
out.push({
|
|
||||||
page: `/fire/archive/${fire._id._str}`,
|
|
||||||
lastmod: lastComment ? lastComment.createdAt : fire.updatedAt
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
36001
package-lock.json
generated
36001
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -8,7 +8,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.29.7",
|
"@babel/runtime": "^7.29.7",
|
||||||
"@cleverbeagle/dates": "^0.5.1",
|
"@cleverbeagle/dates": "^0.5.1",
|
||||||
"@cleverbeagle/seeder": "^1.3.1",
|
|
||||||
"@turf/buffer": "^5.1.5",
|
"@turf/buffer": "^5.1.5",
|
||||||
"babel-runtime": "^6.26.0",
|
"babel-runtime": "^6.26.0",
|
||||||
"bcrypt": "^1.0.3",
|
"bcrypt": "^1.0.3",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue