| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- const pull = require('../server/node_modules/pull-stream');
- const { getConfig } = require('../configs/config-manager.js');
- const logLimit = getConfig().ssbLogStream?.limit || 1000;
- const extractBlobId = str => {
- if (!str || typeof str !== 'string') return null;
- const match = str.match(/\(([^)]+\.sha256)\)/);
- return match ? match[1] : str.trim();
- };
- const parseCSV = str => str
- ? str.split(',').map(s => s.trim()).filter(Boolean)
- : [];
- module.exports = ({ cooler }) => {
- let ssb;
- const openSsb = async () => {
- if (!ssb) ssb = await cooler.open();
- return ssb;
- };
- return {
- type: 'curriculum',
- async createCV(data, photoBlobId) {
- const ssbClient = await openSsb();
- const userId = ssbClient.id;
- const content = {
- type: 'curriculum',
- author: userId,
- name: data.name,
- description: data.description,
- photo: extractBlobId(photoBlobId) || null,
- contact: userId,
- personalSkills: parseCSV(data.personalSkills),
- personalExperiences: data.personalExperiences || '',
- oasisExperiences: data.oasisExperiences || '',
- oasisSkills: parseCSV(data.oasisSkills),
- educationExperiences: data.educationExperiences || '',
- educationalSkills: parseCSV(data.educationalSkills),
- languages: data.languages || '',
- professionalExperiences: data.professionalExperiences || '',
- professionalSkills: parseCSV(data.professionalSkills),
- location: data.location || 'UNKNOWN',
- status: data.status || 'LOOKING FOR WORK',
- preferences: data.preferences || 'REMOTE WORKING',
- createdAt: new Date().toISOString()
- };
- return new Promise((resolve, reject) => {
- ssbClient.publish(content, (err, msg) => err ? reject(err) : resolve(msg));
- });
- },
- async updateCV(id, data, photoBlobId) {
- const ssbClient = await openSsb();
- const userId = ssbClient.id;
- const old = await new Promise((res, rej) =>
- ssbClient.get(id, (err, msg) =>
- err || !msg?.content
- ? rej(err || new Error('CV not found'))
- : res(msg)
- )
- );
- if (old.content.author !== userId) {
- throw new Error('Not the author');
- }
- const tombstone = {
- type: 'tombstone',
- target: id,
- deletedAt: new Date().toISOString()
- };
- await new Promise((res, rej) =>
- ssbClient.publish(tombstone, err => err ? rej(err) : res())
- );
- const content = {
- type: 'curriculum',
- author: userId,
- name: data.name,
- description: data.description,
- photo: extractBlobId(photoBlobId) || null,
- contact: userId,
- personalSkills: parseCSV(data.personalSkills),
- personalExperiences: data.personalExperiences || '',
- oasisExperiences: data.oasisExperiences || '',
- oasisSkills: parseCSV(data.oasisSkills),
- educationExperiences: data.educationExperiences || '',
- educationalSkills: parseCSV(data.educationalSkills),
- languages: data.languages || '',
- professionalExperiences: data.professionalExperiences || '',
- professionalSkills: parseCSV(data.professionalSkills),
- location: data.location || 'UNKNOWN',
- status: data.status || 'LOOKING FOR WORK',
- preferences: data.preferences || 'REMOTE WORKING',
- createdAt: old.content.createdAt,
- updatedAt: new Date().toISOString()
- };
- return new Promise((resolve, reject) => {
- ssbClient.publish(content, (err, msg) => err ? reject(err) : resolve(msg));
- });
- },
- async deleteCVById(id) {
- const ssbClient = await openSsb();
- const userId = ssbClient.id;
- const msg = await new Promise((res, rej) =>
- ssbClient.get(id, (err, msg) =>
- err || !msg?.content
- ? rej(new Error('CV not found'))
- : res(msg)
- )
- );
- if (msg.content.author !== userId) {
- throw new Error('Not the author');
- }
- const tombstone = {
- type: 'tombstone',
- target: id,
- deletedAt: new Date().toISOString()
- };
- return new Promise((resolve, reject) => {
- ssbClient.publish(tombstone, (err, result) => err ? reject(err) : resolve(result));
- });
- },
- async getCVByUserId(targetUserId) {
- const ssbClient = await openSsb();
- const userId = ssbClient.id;
- const authorId = targetUserId || userId;
- return new Promise((resolve, reject) => {
- pull(
- ssbClient.createLogStream({ limit: logLimit }),
- pull.collect((err, msgs) => {
- if (err) return reject(err);
- const tombstoned = new Set(
- msgs
- .filter(m => m.value?.content?.type === 'tombstone' && m.value.content.target)
- .map(m => m.value.content.target)
- );
- const cvMsgs = msgs
- .filter(m =>
- m.value?.content?.type === 'curriculum' &&
- m.value.content.author === authorId &&
- !tombstoned.has(m.key)
- )
- .sort((a, b) => b.value.timestamp - a.value.timestamp);
- if (!cvMsgs.length) {
- return resolve(null);
- }
- const latest = cvMsgs[0];
- resolve({ id: latest.key, ...latest.value.content });
- })
- );
- });
- }
- };
- };
|