@@ -17,9 +17,12 @@ use rfd_data::{
1717use rfd_github:: { GitHubError , GitHubNewRfdNumber , GitHubRfdRepo } ;
1818use rfd_model:: {
1919 schema_ext:: { ContentFormat , Visibility } ,
20- storage:: { JobFilter , JobStore , RfdFilter , RfdMetaStore , RfdPdfsStore , RfdStorage , RfdStore } ,
21- CommitSha , FileSha , Job , NewJob , Rfd , RfdId , RfdMeta , RfdPdf , RfdPdfs , RfdRevision ,
22- RfdRevisionId ,
20+ storage:: {
21+ JobFilter , JobStore , RfdFilter , RfdMetaStore , RfdPdfsStore , RfdRevisionFilter ,
22+ RfdRevisionMetaStore , RfdRevisionStore , RfdStorage , RfdStore ,
23+ } ,
24+ CommitSha , FileSha , Job , NewJob , NewRfdRevision , Rfd , RfdId , RfdMeta , RfdPdf , RfdPdfs ,
25+ RfdRevision , RfdRevisionId ,
2326} ;
2427use rsa:: {
2528 pkcs1:: { DecodeRsaPrivateKey , EncodeRsaPrivateKey } ,
@@ -94,6 +97,25 @@ pub enum UpdateRfdContentError {
9497 Storage ( #[ from] StoreError ) ,
9598}
9699
100+ #[ derive( Debug , Clone , Deserialize , Serialize , JsonSchema ) ]
101+ pub struct RfdRevisionMeta {
102+ pub id : TypedUuid < RfdRevisionId > ,
103+ pub commit_sha : CommitSha ,
104+ pub committed_at : DateTime < Utc > ,
105+ pub major_change : bool ,
106+ }
107+
108+ impl From < RfdRevision > for RfdRevisionMeta {
109+ fn from ( value : RfdRevision ) -> Self {
110+ Self {
111+ id : value. id ,
112+ commit_sha : value. commit ,
113+ committed_at : value. committed_at ,
114+ major_change : value. major_change ,
115+ }
116+ }
117+ }
118+
97119#[ partial( RfdWithoutContent ) ]
98120#[ partial( RfdWithPdf ) ]
99121#[ derive( Debug , Clone , Deserialize , Serialize , JsonSchema ) ]
@@ -267,6 +289,11 @@ impl From<TypedUuid<RfdRevisionId>> for RfdRevisionIdentifier {
267289 }
268290}
269291
292+ #[ derive( Debug , Clone ) ]
293+ pub enum RfdRevisionMetadataChange {
294+ MajorChange ( bool ) ,
295+ }
296+
270297impl RfdContext {
271298 pub async fn new (
272299 public_url : String ,
@@ -459,6 +486,32 @@ impl RfdContext {
459486 Ok ( rfd_list)
460487 }
461488
489+ #[ instrument( skip( self , caller) ) ]
490+ pub async fn list_revisions (
491+ & self ,
492+ caller : & Caller < RfdPermission > ,
493+ rfd_number : i32 ,
494+ pagination : & ListPagination ,
495+ ) -> ResourceResult < Vec < RfdRevisionMeta > , StoreError > {
496+ let rfd = self . get_rfd ( caller, rfd_number, None ) . await ?;
497+
498+ let filter = RfdRevisionFilter :: default ( ) . rfd ( Some ( vec ! [ rfd. id] ) ) ;
499+ if caller. can ( & RfdPermission :: GetRfdsAll )
500+ || caller. can ( & RfdPermission :: GetRfd ( rfd_number) )
501+ || rfd. visibility == Visibility :: Public
502+ {
503+ Ok (
504+ RfdRevisionStore :: list ( & * self . storage , vec ! [ filter] , pagination)
505+ . await ?
506+ . into_iter ( )
507+ . map ( |rev| rev. into ( ) )
508+ . collect ( ) ,
509+ )
510+ } else {
511+ resource_not_found ( )
512+ }
513+ }
514+
462515 #[ instrument( skip( self , caller) ) ]
463516 async fn get_rfd (
464517 & self ,
@@ -820,6 +873,43 @@ impl RfdContext {
820873 }
821874 }
822875
876+ #[ instrument( skip( self , caller) ) ]
877+ pub async fn update_rfd_revision_metadata (
878+ & self ,
879+ caller : & Caller < RfdPermission > ,
880+ rfd_number : i32 ,
881+ id : TypedUuid < RfdRevisionId > ,
882+ changes : & [ RfdRevisionMetadataChange ] ,
883+ ) -> ResourceResult < RfdRevision , StoreError > {
884+ if !caller. can ( & RfdPermission :: UpdateRfdsAll )
885+ && !caller. can ( & RfdPermission :: UpdateRfd ( rfd_number) )
886+ {
887+ return resource_not_found ( ) ;
888+ }
889+
890+ let rfd = self . get_rfd ( caller, rfd_number, None ) . await ?;
891+ let Some ( revision) = RfdRevisionStore :: get ( & * self . storage , & id, false ) . await ? else {
892+ return resource_not_found ( ) ;
893+ } ;
894+
895+ // Someone is trying to access a revision from a different RFD than the one they claim to
896+ // request, probably to bypass access control.
897+ if revision. rfd_id != rfd. id {
898+ return resource_not_found ( ) ;
899+ }
900+
901+ let mut to_update = NewRfdRevision :: from ( revision) ;
902+ for change in changes {
903+ match change {
904+ RfdRevisionMetadataChange :: MajorChange ( major_change) => {
905+ to_update. major_change = * major_change;
906+ }
907+ }
908+ }
909+
910+ Ok ( RfdRevisionStore :: upsert ( & * self . storage , to_update) . await ?)
911+ }
912+
823913 // Job Operations
824914 pub async fn list_jobs (
825915 & self ,
0 commit comments