upstream: integrar 0.9.5 en 34 ficheros mas y portar los modulos nuevos

Segunda tanda. Resueltas por merge de tres vias 15 divergencias que no solapaban,
y aplicada la version de 0.9.5 en 19 vistas y modelos donde la rama solo arrastraba
codigo antiguo (firmas viejas de renderProductForm, renderJobForm, listTags sin
search, y el import sin renderSpreadEditWarning). Se preserva la eliminacion de
housing donde la rama lo habia descartado: modules_view, blockchain_view,
search_model y tags_model.

Modulos nuevos del dev portados: blog, data, gallery, mentions, polls, workflows,
comments, recurrence y media_gallery, mas contentPdf, pdfDocument y content_favorites.

main_views recupera renderEngagement, spreadsFor y renderSpreadEditWarning, que la
rama habia eliminado y que las vistas de 0.9.5 necesitan. Sin ellas polls_view
lanzaba TypeError al editar.

El overlay de i18n pasa de 15 a 41 claves (46 en castellano): incorpora las 9 que
upstream tenia en 0.9.1 y elimino en 0.9.5 mientras nuestro codigo las sigue usando
(menuBlogs, spreadHint, chatShareUrl, forumFilterHot, publishBlog...) y las 17 de
Karvan, que nunca existieron y tiraban de texto de reserva en ingles; ahora estan
traducidas al castellano.

Verificado con la app arrancada: declara 0.9.5, 0 claves i18n sin resolver (antes
26), 26 rutas responden 200/302, y la interfaz de la rama sale intacta: 10
categorias y 47 modulos en los hexagonos, topbar con Personal/Community y avatar,
7 accesos rapidos en la barra inferior y 0 etiquetas vacias (antes 1, la de Blogs).
This commit is contained in:
SITO 2026-08-18 22:03:41 +02:00
parent f964e61a1c
commit 82b6c3ae05
43 changed files with 3221 additions and 2416 deletions

View file

@ -130,9 +130,9 @@ module.exports = ({ cooler }) => {
return filterInactive(users);
}
if (filter === 'all' || filter === 'TOP KARMA' || filter === 'TOP ACTIVITY' || filter === 'TOP ECO') {
if (filter === 'all' || filter === 'TOP KARMA' || filter === 'TOP ACTIVITY' || filter === 'TOP INACTIVITY' || filter === 'TOP ECO') {
let users = await listAllBase(ssbClient);
if (filter !== 'TOP ACTIVITY') {
if (filter !== 'TOP ACTIVITY' && filter !== 'TOP INACTIVITY') {
users = filterInactive(users);
}
if (search) {
@ -170,6 +170,7 @@ module.exports = ({ cooler }) => {
}));
if (filter === 'TOP KARMA') return withMetrics.sort((a, b) => (b.karmaScore || 0) - (a.karmaScore || 0));
if (filter === 'TOP ACTIVITY') return withMetrics.sort((a, b) => (b.lastActivityTs || 0) - (a.lastActivityTs || 0));
if (filter === 'TOP INACTIVITY') return withMetrics.sort((a, b) => (a.lastActivityTs || 0) - (b.lastActivityTs || 0));
if (filter === 'TOP ECO') return withMetrics.sort((a, b) => (b.ecoScore || 0) - (a.ecoScore || 0));
return withMetrics;
}
@ -254,7 +255,7 @@ module.exports = ({ cooler }) => {
);
}
if (filter === 'CVs' || filter === 'MATCHSKILLS') {
if (filter === 'CVs') {
const records = await new Promise((res, rej) => {
pull(
ssbClient.createLogStream({ limit: logLimit, reverse: true}),
@ -295,54 +296,13 @@ module.exports = ({ cooler }) => {
return out;
}
if (filter === 'MATCHSKILLS') {
let base = await Promise.all(cvs.map(async c => {
const photo = await fetchUserImageUrl(c.author, 256);
const lastActivityTs = await getLastActivityTimestamp(c.author);
const { bucket, range } = bucketLastActivity(lastActivityTs);
const norm = this._normalizeCurriculum(c, photo);
const karmaScore = await getLastKarmaScore(c.author).catch(() => 0);
return { ...norm, lastActivityTs, lastActivityBucket: bucket, lastActivityRange: range, karmaScore };
}));
base = filterInactive(base);
const mecv = await this.getCVByUserId();
const userSkills = Array.from(new Set(
(mecv
? [
...(mecv.personalSkills || []),
...(mecv.oasisSkills || []),
...(mecv.educationalSkills || []),
...(mecv.professionalSkills || [])
]
: []).map(s => String(s || '').toLowerCase()).filter(Boolean)
));
if (!userSkills.length) return [];
const userSet = new Set(userSkills);
const matches = base.map(c => {
if (c.id === userId) return null;
const theirSkillsRaw = (c.skills || []).map(s => String(s || '').toLowerCase()).filter(Boolean);
const theirSet = new Set(theirSkillsRaw);
const common = Array.from(theirSet).filter(s => userSet.has(s));
if (!common.length) return null;
const unionSize = userSet.size + theirSet.size - common.length;
const matchScore = unionSize > 0 ? common.length / unionSize : 0;
const matchCoverage = userSet.size > 0 ? common.length / userSet.size : 0;
return { ...c, commonSkills: common, matchScore, matchCoverage };
}).filter(Boolean);
return matches.sort((a, b) =>
(b.matchScore - a.matchScore) ||
(b.commonSkills.length - a.commonSkills.length) ||
((b.karmaScore || 0) - (a.karmaScore || 0)) ||
((b.lastActivityTs || 0) - (a.lastActivityTs || 0))
);
}
}
return [];
},
_normalizeCurriculum(c, photoUrl) {
const photo = photoUrl || toImageUrl(c.photo, 256);
const photo = c.photo ? toImageUrl(c.photo, 256) : (photoUrl || toImageUrl(null, 256));
return {
id: c.author,
name: c.name,
@ -358,6 +318,8 @@ module.exports = ({ cooler }) => {
languages: typeof c.languages === 'string'
? c.languages.split(',').map(x => x.trim())
: Array.isArray(c.languages) ? c.languages : [],
status: c.status,
preferences: c.preferences,
createdAt: c.createdAt
};
},