Fix family publishing, concurrent edits and session consistency

This commit is contained in:
Codex
2026-10-03 20:27:11 +08:00
parent 80f8bd72af
commit 56a24c80e2
12 changed files with 210 additions and 38 deletions
+52 -1
View File
@@ -146,7 +146,7 @@ class WebTests(unittest.TestCase):
for path in ['/api/users','/api/audit','/media/live/cam_'+'a'*16+'_hd/index.m3u8',
'/api/recordings?camera='+'a'*16]:
self.assertEqual(request(path),403)
for path in ['/api/storage','/api/users','/api/family/person']:
for path in ['/api/storage','/api/users','/api/family/person','/api/family/event']:
self.assertEqual(request(path,{}),403)
self.assertEqual(request('/api/family'),200)
app.ACCOUNTS.save(dict(member,disabled=True),self.admin)
@@ -275,6 +275,57 @@ class WebTests(unittest.TestCase):
event=app.FAMILY.event(dict(good,sourceUrl='https://example.org/report'),None)
self.assertEqual(event['sourceUrl'],'https://example.org/report')
def test_event_accepts_full_chinese_body_and_multiline_summary(self):
payload={'title':'中文长文','eventDate':'2026-10-03','body':'家'*12000,'summary':'第一段\n第二段',
'status':'published','revision':app.setting('familyRevision',0)}
self.assertGreater(len(json.dumps(payload).encode()),16384)
code,_,body=self.request('/api/family/event',data=payload)
self.assertEqual(code,200)
saved=json.loads(body)['item']
self.assertEqual(saved['body'],payload['body'])
self.assertEqual(saved['summary'],payload['summary'])
for changes in [{'body':'家'*12001},{'summary':'家'*401},{'summary':'bad\x00text'}]:
invalid=dict(payload,**changes,revision=app.setting('familyRevision',0))
self.assertEqual(self.request('/api/family/event',data=invalid)[0],400)
def test_event_keeps_publication_history_and_omitted_status(self):
def save(data):return app.FAMILY.save('event',dict(data,revision=app.setting('familyRevision',0)),self.admin)['item']
event=save({'title':'记事','eventDate':'2026-10-03','body':'正文','status':'published'})
published=event['publishedAt'];created=event['createdAt']
edited=dict(event,title='更新标题');edited.pop('status');edited.pop('publishedAt')
event=save(edited)
self.assertEqual(event['status'],'published');self.assertEqual(event['publishedAt'],published)
event=save(dict(event,status='draft'))
self.assertEqual(event['publishedAt'],published)
reader={'role':'member','familyAccess':'read'}
self.assertNotIn(event['id'],[e['id'] for e in app.FAMILY.snapshot(reader)['events']])
event=save(dict(event,status='published'))
self.assertEqual(event['publishedAt'],published);self.assertEqual(event['createdAt'],created)
def test_biological_birth_order_checked_on_link_and_person_changes(self):
def save(kind,data):return app.FAMILY.save(kind,dict(data,revision=app.setting('familyRevision',0)),self.admin)['item']
parent=save('person',{'name':'Parent','birthDate':'1980-01-01'})
child=save('person',{'name':'Child','birthDate':'2000-01-01'})
relation=save('link',{'fromId':parent['id'],'toId':child['id'],'kind':'parent','lineage':'biological'})
for person,date in [(parent,'2000-01-01'),(parent,'2001-01-01'),(child,'1979-01-01')]:
revision=app.setting('familyRevision',0)
with self.assertRaises(app.Problem):save('person',dict(person,birthDate=date))
self.assertEqual(app.setting('familyRevision',0),revision)
self.assertEqual(app.get_object('people',person['id'])['birthDate'],person['birthDate'])
save('link',dict(relation,active=False))
save('person',dict(parent,birthDate='2001-01-01'))
with self.assertRaises(app.Problem):save('link',dict(relation,active=True))
save('link',dict(relation,active=True,lineage='adoptive'))
def test_request_body_limit_is_bounded_and_invalid_length_is_400(self):
from email.message import Message
from types import SimpleNamespace
for length in ['invalid','-1','0','131073']:
headers=Message();headers['Content-Type']='application/json';headers['Content-Length']=length
fake=SimpleNamespace(headers=headers,rfile=io.BytesIO(b'{}'))
with self.assertRaises(app.Problem) as caught:app.Handler.body(fake,131072)
self.assertEqual(caught.exception.status,400)
def test_event_endpoint_and_static_modules(self):
self.assertEqual(self.request('/api/family/event',False,{'title':'Denied'})[0],401)
payload={'title':'API event','eventDate':'2026-01-01','body':'Test only','status':'published','revision':app.setting('familyRevision',0)}