1
1
import { logger } from 'firebase-functions/v2' ;
2
2
import { HttpsError , onCall } from 'firebase-functions/v2/https' ;
3
- import { onDocumentDeleted , onDocumentUpdated , onDocumentWritten } from 'firebase-functions/v2/firestore' ;
3
+ import { onDocumentDeleted , onDocumentUpdated , onDocumentWritten , DocumentSnapshot } from 'firebase-functions/v2/firestore' ;
4
4
import { FieldValue , UpdateData , WithFieldValue } from 'firebase-admin/firestore' ;
5
5
import { canPerform } from './utils/security-utils' ;
6
6
import { BATCH_MAX , bucket , firestoreService } from './config' ;
@@ -16,7 +16,16 @@ import {
16
16
Space ,
17
17
UserPermission ,
18
18
} from './models' ;
19
- import { extractContent , findAllContentsByParentSlug , findContentById , findContentsHistory , findSchemas , findSpaceById } from './services' ;
19
+ import {
20
+ extractContent ,
21
+ findAllContentsByParentSlug ,
22
+ findContentById ,
23
+ findContentsHistory ,
24
+ findDocumentsToPublishByStartFullSlug ,
25
+ findSchemas ,
26
+ findSpaceById ,
27
+ } from './services' ;
28
+ import { AuthData } from 'firebase-functions/lib/common/providers/https' ;
20
29
21
30
// Publish
22
31
const publish = onCall < PublishContentData > ( async request => {
@@ -30,50 +39,82 @@ const publish = onCall<PublishContentData>(async request => {
30
39
const schemasSnapshot = await findSchemas ( spaceId ) . get ( ) ;
31
40
if ( spaceSnapshot . exists && contentSnapshot . exists ) {
32
41
const space : Space = spaceSnapshot . data ( ) as Space ;
33
- const content : ContentDocument = contentSnapshot . data ( ) as ContentDocument ;
42
+ const content : Content = contentSnapshot . data ( ) as Content ;
34
43
const schemas = new Map ( schemasSnapshot . docs . map ( it => [ it . id , it . data ( ) as Schema ] ) ) ;
35
- for ( const locale of space . locales ) {
36
- const documentStorage : ContentDocumentStorage = {
37
- id : contentSnapshot . id ,
38
- name : content . name ,
39
- kind : content . kind ,
40
- locale : locale . id ,
41
- slug : content . slug ,
42
- fullSlug : content . fullSlug ,
43
- parentSlug : content . parentSlug ,
44
- createdAt : content . createdAt . toDate ( ) . toISOString ( ) ,
45
- updatedAt : content . updatedAt . toDate ( ) . toISOString ( ) ,
46
- publishedAt : new Date ( ) . toISOString ( ) ,
47
- } ;
48
- if ( content . data ) {
49
- if ( typeof content . data === 'string' ) {
50
- documentStorage . data = extractContent ( JSON . parse ( content . data ) , schemas , locale . id ) ;
51
- } else {
52
- documentStorage . data = extractContent ( content . data , schemas , locale . id ) ;
53
- }
44
+ if ( content . kind === ContentKind . DOCUMENT ) {
45
+ await publishDocument ( spaceId , space , contentId , content , contentSnapshot , schemas , auth ) ;
46
+ } else if ( content . kind === ContentKind . FOLDER ) {
47
+ const documentsSnapshot = await findDocumentsToPublishByStartFullSlug ( spaceId , `${ content . fullSlug } /` ) . get ( ) ;
48
+ for ( const documentSnapshot of documentsSnapshot . docs ) {
49
+ const document = documentSnapshot . data ( ) as ContentDocument ;
50
+ // SKIP if the page was already published, by comparing publishedAt and updatedAt
51
+ if ( document . publishedAt && document . publishedAt . seconds > document . updatedAt . seconds ) continue ;
52
+ await publishDocument ( spaceId , space , contentId , document , documentSnapshot , schemas , auth ) ;
54
53
}
55
- // Save generated JSON
56
- logger . info ( `[Content::contentPublish] Save file to spaces/${ spaceId } /contents/${ contentId } /${ locale . id } .json` ) ;
57
- await bucket . file ( `spaces/${ spaceId } /contents/${ contentId } /${ locale . id } .json` ) . save ( JSON . stringify ( documentStorage ) ) ;
58
54
}
59
55
// Save Cache
60
56
logger . info ( `[Content::contentPublish] Save file to spaces/${ spaceId } /contents/${ contentId } /cache.json` ) ;
61
57
await bucket . file ( `spaces/${ spaceId } /contents/${ contentId } /cache.json` ) . save ( '' ) ;
58
+ return ;
59
+ } else {
60
+ logger . info ( `[Content::contentPublish] Content ${ contentId } does not exist.` ) ;
61
+ throw new HttpsError ( 'not-found' , 'Content not found' ) ;
62
+ }
63
+ } ) ;
64
+
65
+ /**
66
+ * Publish Document
67
+ * @param {string } spaceId space id
68
+ * @param {Space } space
69
+ * @param {string } documentId
70
+ * @param {ContentDocument } document
71
+ * @param {DocumentSnapshot } documentSnapshot
72
+ * @param {Map<string, Schema> } schemas
73
+ * @param {AuthData } auth
74
+ */
75
+ async function publishDocument (
76
+ spaceId : string ,
77
+ space : Space ,
78
+ documentId : string ,
79
+ document : ContentDocument ,
80
+ documentSnapshot : DocumentSnapshot ,
81
+ schemas : Map < string , Schema > ,
82
+ auth ?: AuthData
83
+ ) {
84
+ for ( const locale of space . locales ) {
85
+ const documentStorage : ContentDocumentStorage = {
86
+ id : documentId ,
87
+ name : document . name ,
88
+ kind : document . kind ,
89
+ locale : locale . id ,
90
+ slug : document . slug ,
91
+ fullSlug : document . fullSlug ,
92
+ parentSlug : document . parentSlug ,
93
+ createdAt : document . createdAt . toDate ( ) . toISOString ( ) ,
94
+ updatedAt : document . updatedAt . toDate ( ) . toISOString ( ) ,
95
+ publishedAt : new Date ( ) . toISOString ( ) ,
96
+ } ;
97
+ if ( document . data ) {
98
+ if ( typeof document . data === 'string' ) {
99
+ documentStorage . data = extractContent ( JSON . parse ( document . data ) , schemas , locale . id ) ;
100
+ } else {
101
+ documentStorage . data = extractContent ( document . data , schemas , locale . id ) ;
102
+ }
103
+ }
104
+ // Save generated JSON
105
+ logger . info ( `[Content::contentPublish] Save file to spaces/${ spaceId } /contents/${ documentId } /${ locale . id } .json` ) ;
106
+ await bucket . file ( `spaces/${ spaceId } /contents/${ documentId } /${ locale . id } .json` ) . save ( JSON . stringify ( documentStorage ) ) ;
62
107
// Update publishedAt
63
- await contentSnapshot . ref . update ( { publishedAt : FieldValue . serverTimestamp ( ) } ) ;
108
+ await documentSnapshot . ref . update ( { publishedAt : FieldValue . serverTimestamp ( ) } ) ;
64
109
const addHistory : WithFieldValue < ContentHistory > = {
65
110
type : ContentHistoryType . PUBLISHED ,
66
111
name : auth ?. token [ 'name' ] || FieldValue . delete ( ) ,
67
112
email : auth ?. token . email || FieldValue . delete ( ) ,
68
113
createdAt : FieldValue . serverTimestamp ( ) ,
69
114
} ;
70
- await findContentsHistory ( spaceId , contentId ) . add ( addHistory ) ;
71
- return ;
72
- } else {
73
- logger . info ( `[Content::contentPublish] Content ${ contentId } does not exist.` ) ;
74
- throw new HttpsError ( 'not-found' , 'Content not found' ) ;
115
+ await findContentsHistory ( spaceId , documentId ) . add ( addHistory ) ;
75
116
}
76
- } ) ;
117
+ }
77
118
78
119
// Firestore events
79
120
const onContentUpdate = onDocumentUpdated ( 'spaces/{spaceId}/contents/{contentId}' , async event => {
0 commit comments