Stiglo je novo izdanje. Osvježi stranu.
Pravo na uvid u kod. Otvoren protokol omogućava nezavisne operatere i interoperabilnost. Manifest
Izvor
4d7883a894b3
- server.js
- lib/auth.js
- lib/build.js
- lib/cards.js
- lib/db.js
- lib/gradovi.js
- lib/icons.js
- lib/imena.js
- lib/jezik.js
- lib/kartapodaci.js
- lib/lekcije.js
- lib/md.js
- lib/mehanika.js
- lib/mreza.js
- lib/pages.js
- lib/registar.js
- lib/routes.js
- lib/schema2.js
- lib/views.js
- seed/content.mjs
- seed/seed.mjs
- public/app.js
- public/style.css
1 import {personas,titles,bodies,replyParts} from './content.mjs';
2 import {indexPost,dinar} from '../lib/db.js';
3 import {EDITIONS} from '../lib/cards.js';
4 import {GRAD} from '../lib/gradovi.js';
5 import {token} from '../lib/auth.js';
6 export const START_DINAR=250;
7 export const CATEGORIES=[['oglasna-tabla','Oglasna tabla'],['prvi-koraci','Prvih šezdeset sekundi'],['yu-connect','YU Connect i .yu imena'],['registar','Registar i imena'],['pijaca','Pijaca MARKET.YU'],['dinar','Dinar i sličice'],['kultura','Kultura je naša infrastruktura'],['radionica','Radionica graditelja'],['uprava','Savjet i samouprava'],['mjesne-zajednice','Mjesne zajednice'],['kafana','Kafana']];
8 export function seed(db,{reg,mechanics:m,adminHash,now=Date.now()}){
9 const DAY=86400000;
10 CATEGORIES.forEach(([slug,name],i)=>db.run('INSERT INTO categories(slug,name,description,icon,position,admin_only) VALUES(?,?,?,?,?,?)',slug,name,name,'folder',i,i===0?1:0));
11 const add=(handle,display,city_id=null,is_seed=0,role='member')=>{let u=db.get('SELECT * FROM users WHERE handle=?',handle);if(u)return u;const no=db.get('SELECT COALESCE(MAX(member_no),0)+1 n FROM users').n;const id=Number(db.run("INSERT INTO users(handle,display,pass_hash,role,member_no,created_at,is_seed,city_id) VALUES(?,?,?,?,?,?,?,?)",handle,display,handle==='signal'?adminHash||'!':'!',role,no,now-20*DAY,is_seed,city_id).lastInsertRowid);dinar(db,id,250,'upis');return db.get('SELECT * FROM users WHERE id=?',id);};
12 const signal=add('signal','Signal',null,0,'admin');const treasury=add('blagajna','Blagajna',null,0,'system');
13 db.run('UPDATE users SET dinar=100000 WHERE id=?',treasury.id);db.run('INSERT INTO ledger(user_id,delta,reason,created_at) VALUES(?,?,?,?)',treasury.id,99750,'probno-izdavanje',now);
14 const users=personas.map(p=>{if(!GRAD[p.city_id])throw Error('Grad: '+p.city_id);const u=add(p.handle,p.display,p.city_id,1);db.run('UPDATE users SET bio=? WHERE id=?',p.bio,u.id);if(p.builder){db.run('UPDATE users SET abuse_contact=? WHERE id=?','Javna poruka na profilu; odgovaram u roku od 72 h.',u.id);db.run("INSERT INTO lesson_done VALUES(?,'pravila',?)",u.id,now);}return {...u,lang:p.lang};});
15 for(const c of db.all('SELECT * FROM user_cards')){if(EDITIONS.some(e=>e.slug===c.edition)&&!db.get('SELECT 1 FROM card_instances WHERE edition=? AND serial=?',c.edition,c.serial))m.mint(c.user_id,c.edition,'izdanje-1',c.serial,c.created_at);}
16 const all=[signal,...users,...db.all("SELECT * FROM users WHERE is_seed=0 AND handle NOT IN ('signal','blagajna')")];
17 for(const u of all){reg.create(u.id,u.handle,{system:true,trust:'provjereno'});db.run('INSERT INTO invites VALUES(?,?,?,0)',token(9),u.id,now);if(u.member_no<=100)m.mint(u.id,'osnivacka','nagrada');}
18 const systems=['hello','registar','registry','id','market','pijaca','isteklo','opozvano','sporno','proba-jedan','proba-dva','proba-tri'];
19 for(const name of systems){const status=name==='isteklo'?'izdato':['opozvano','sporno'].includes(name)?name:'izdato';reg.create(signal.id,name,{system:true,kind:'sistemsko',status,origin:'https://www.yugoslavia.forum/'+(name==='hello'?'s/hello':name==='market'?'pijaca':'registar'),trust:'sistemsko',net:name.startsWith('proba')?'proba':'glavna',at:name==='isteklo'?now-366*DAY:now});}
20 for(const r of db.all('SELECT name,owner_id FROM names').slice(0,31))reg.log('provjera',r.name,r.owner_id,{ishod:'ispravno'});
21 const cats=db.all('SELECT id FROM categories ORDER BY position').map(r=>r.id),bounds=[3,8,12,17,22,26,30,35,40,43,46];
22 for(let i=0;i<titles.length;i++){const cat= bounds.findIndex(n=>i<n),author=i<3?signal:users[(i-3)%users.length],lang=i===33?'mk':'sh',at=now-(18-i%15)*DAY;
23 const tid=Number(db.run('INSERT INTO threads(category_id,user_id,title,created_at,last_post_at,last_post_user,pinned,lang) VALUES(?,?,?,?,?,?,?,?)',cats[cat],author.id,titles[i],at,at,author.id,[0,3,4,26].includes(i)?1:0,lang).lastInsertRowid);
24 const pid=Number(db.run('INSERT INTO posts(thread_id,user_id,body,created_at,lang) VALUES(?,?,?,?,?)',tid,author.id,bodies[i],at,lang).lastInsertRowid);indexPost(db,pid,tid,titles[i],bodies[i]);
25 for(let j=0;j<5;j++){const u=users[(i+j*7)%users.length];let body=replyParts[j]+' '+GRAD[u.city_id].ime+'.';let plang='sh';if(u.lang==='sl'){body='Hvala za zapis. Pri nas v delavnici bomo poskusili in dodali svoje izkušnje. '+GRAD[u.city_id].ime+'.';plang='sl';}if(u.lang==='mk'){body='Благодарам за примерот. Ќе пробаме во работилницата и ќе ги споделиме резултатите.';plang='mk';}if(u.handle==='prishtina_js')body='Mirëdita, komšije! '+body;if(u.handle==='subotica_most')body='Jó napot! '+body;if(['nis_radio','retro_bgd','vienna_exp','berlin_rust','cacak_stolar'].includes(u.handle))body=body.replace('primjer','primer').replace('vidjeti','videti').replace('uporediti','uporediti');const rp=Number(db.run('INSERT INTO posts(thread_id,user_id,body,created_at,lang) VALUES(?,?,?,?,?)',tid,u.id,body,at+(j+1)*3600000,plang).lastInsertRowid);indexPost(db,rp,tid,titles[i],body);db.run('UPDATE threads SET reply_count=reply_count+1,last_post_at=?,last_post_user=? WHERE id=?',at+(j+1)*3600000,u.id,tid);}
26 }
27 db.run('INSERT INTO pages VALUES(?,?,?,?,1,?)','hello.yu',signal.id,'Dobro došli na YU mrežu','Ovo je javna stranica hello.yu. Pravo HTTPS porijeklo uvijek je vidljivo. [Prvih šezdeset sekundi](https://www.yugoslavia.forum/dobrodosli).',now);
28 for(let i=0;i<14;i++){const u=users[i],name=u.handle+'.yu';db.run('INSERT INTO projects(owner_id,title,kind,summary,city_id,name,url,lang,created_at) VALUES(?,?,?,?,?,?,?,?,?)',u.id,['Mala radionica','Škola komšijskog znanja','Zvučni arhiv','Otvorena slova'][i%4]+' · '+GRAD[u.city_id].ime,['zanat','studio','zadruga','program','kultura','škola'][i%6],'Dijelimo postupke, alate i iskustvo. Javite se kroz forum.',u.city_id,name,'https://www.yugoslavia.forum/u/'+u.handle,u.lang,now-4*DAY);if(i<9){db.run('INSERT INTO pages VALUES(?,?,?,?,1,?)',name,u.id,'Radionica · '+GRAD[u.city_id].ime,'# Zajednički rad\n\nMalo znanja svakog dana. Na ovoj stranici objavljujemo uputstva i otvorene pozive.',now);db.run('UPDATE names SET origin=? WHERE name=?','https://www.yugoslavia.forum/s/'+u.handle,name);reg.seal(name);}}
29 const goods=['Med iz Tuzle','Viola iz Mostara','Vino iz Maribora','Keramička zdjela','Drveni sto','Domaći ajvar','Otvoreni font','Zvučni zapis','Časovi programiranja','Platnena torba','Popravka tastature','Razmjena knjiga'];
30 for(let i=0;i<12;i++)db.run('INSERT INTO listings(seller_id,title,body,kind,price_eur_text,price_dinar,stock,status,created_at) VALUES(?,?,?,?,?,?,?,\'otvoreno\',?)',users[i].id,goods[i],'Probni oglas. Razgovaramo o izradi i uslovima, bez stvarnog plaćanja ili isporuke.','zanat',String(10+i*3)+' EUR',20+i*2,8,now-5*DAY);
31 for(let i=0;i<9;i++){const listing=db.get('SELECT * FROM listings WHERE id=?',i+1);const oid=Number(db.run("INSERT INTO orders(listing_id,buyer_id,seller_id,amount,status,created_at,updated_at) VALUES(?,?,?,?,'primljeno',?,?)",listing.id,users[i+14].id,listing.seller_id,listing.price_dinar,now-4*DAY,now-3*DAY).lastInsertRowid);dinar(db,users[i+14].id,-listing.price_dinar,'polog',String(oid));dinar(db,listing.seller_id,listing.price_dinar,'primljeno',String(oid));db.run('INSERT INTO ratings VALUES(?,?,?,?,?,?)',oid,users[i+14].id,listing.seller_id,4+i%2,'Jasno objašnjen postupak u probnoj narudžbi.',now-3*DAY);}
32 const disputed=m.order(users[20].id,1);m.orderAction(users[20].id,disputed,'spor');
33 const questions=['Pravna forma zajednice','Glas članova i stručnost','Prenosivost imena pri odlasku','Sistemsko otvaranje .yu','Pisma i vizuelno slična imena','Zaštićena institucionalna imena','Dodjela kratkih i kulturno važnih imena','Plaćanja i sporovi prije valute'];
34 for(let i=0;i<8;i++){const id=Number(db.run("INSERT INTO proposals(kind,title,body,options,author_id,thread_id,opens_at,closes_at,quorum,threshold,status) VALUES('rasprava',?,?,?,?,?,?,?,?,?,'otvoreno')",questions[i],'Javna rasprava; izbor ne mijenja pravila bez naknadnog prijedloga.',JSON.stringify(['za','protiv','uzdrzan']),signal.id,36+i%5,now-DAY,now+30*DAY,0,0).lastInsertRowid);for(let j=0;j<8;j++)db.run('INSERT INTO ballots VALUES(?,?,?,?)',id,users[(i+j)%users.length].id,['za','protiv','uzdrzan'][j%3],now-DAY);}
35 db.run("INSERT INTO proposals(kind,title,body,options,author_id,opens_at,closes_at,quorum,threshold,status,result) VALUES('prijedlog',?,?,?,?,?,?,10,0.5,'usvojeno',?)",'Javni izvještaji Savjeta','Izvještaj svakih sedam dana.',JSON.stringify(['za','protiv']),signal.id,now-15*DAY,now-10*DAY,JSON.stringify({n:24,yes:21,passed:true}));
36 db.run("INSERT INTO proposals(kind,title,body,options,author_id,opens_at,closes_at,quorum,threshold,status,result) VALUES('izbori',?,?,?,?,?,?,10,0.5,'usvojeno',?)",'Prvi Savjet','Mandati od 90 dana.',JSON.stringify(['za','protiv']),signal.id,now-15*DAY,now-10*DAY,JSON.stringify({n:32,yes:28,passed:true}));
37 const candidates=['tipograf_lj','prishtina_js','skopje_tape'];const election=Number(db.run("INSERT INTO proposals(kind,title,body,options,author_id,opens_at,closes_at,quorum,threshold,status) VALUES('izbori',?,?,?,?,?,?,10,0.5,'otvoreno')",'Dopunski izbori: jezičke zajednice','Jedan član, jedan glas; mandat 90 dana.',JSON.stringify(candidates),signal.id,now-DAY,now+30*DAY).lastInsertRowid);
38 candidates.forEach(h=>db.run('INSERT INTO candidates VALUES(?,?,?,?)',election,users.find(u=>u.handle===h).id,'jezičke zajednice','Predlažem više praktičnih primjera i ravnopravnost pisama.'));
39 for(const [i,seat] of ['opšte mjesto','trgovci','graditelji','sigurnost i privatnost','stvaraoci','opšte mjesto'].entries())db.run('INSERT INTO mandates(user_id,seat,starts_at,ends_at,proposal_id) VALUES(?,?,?,?,10)',users[i].id,seat,now-10*DAY,now+80*DAY);
40 db.run('INSERT INTO mandates(user_id,seat,starts_at,ends_at) VALUES(?,?,?,?)',signal.id,'osnivač',Date.UTC(2026,9,28),Date.UTC(2027,0,26));
41 for(let i=0;i<3;i++)db.run('INSERT INTO disputes(kind,ref,opener_id,respondent_id,statement,response,reviewer_id,decision,status,deadline_at,redact,created_at,decided_at) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)','ime','studio.yu',users[10].id,users[0].id,'Molim nezavisan pregled odluke.','Obrazloženje je dostavljeno.',i<2?users[1].id:null,i<2?['usvojena','odbijena'][i]:null,['usvojena','odbijena','u toku'][i],now+DAY,1,now-5*DAY,i<2?now-DAY:null);
42 for(const i of [18,19]){const u=users[i];db.run('INSERT INTO mirrors(owner_id,url,city_id,note,created_at,simulated) VALUES(?,?,?,?,?,1)',u.id,'https://ogledalo'+i+'.example.org',u.city_id,'SIMULACIJA: primjer nezavisnog ogledala.',now);}
43 for(const [i,u] of users.entries()){m.mint(u.id,EDITIONS[i%20].slug,'nagrada');m.mint(u.id,EDITIONS[(i+4)%20].slug,'kesica');}
44 for(let i=0;i<2;i++){const from=users[26+i*2],to=users[27+i*2],a=db.get("SELECT id FROM card_instances WHERE owner_id=? AND edition!='osnivacka' ORDER BY id LIMIT 1",from.id),b=db.get("SELECT id FROM card_instances WHERE owner_id=? AND edition!='osnivacka' ORDER BY id LIMIT 1",to.id);const trade=m.offer(from.id,to.id,[a.id],[b.id],0);m.accept(to.id,trade);}
45 db.run('INSERT INTO docs VALUES(?,?,?,?,?)','povelja','Povelja','Dobrovoljan ulazak i izlazak. Javan operater i pravila. Otvoren protokol i prenosivi podaci. Nezavisna žalba. Mandati ograničenog trajanja.',1,now);
46 reg.rotate();db.run('INSERT INTO docs VALUES(?,?,?,?,?)','vjezba','Vježba zamjene ključa','SIMULACIJA: stari ključ je potpisao objavu novog. Provjereni su raniji potpisi i slijed dnevnika.',1,now);
47 db.meta('seeded',now);
48 }
49