1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
|
{
"docs": [
{
"location": "/",
"text": "Ponzu CMS + Server Framework Docs\n\n\n\n\nWhat is Ponzu?\n\n\n\n\nWatch the \nvideo introduction\n\n\n\n\nPonzu is a powerful and efficient open-source HTTP server framework and CMS. It \nprovides automatic, free, and secure HTTP/2 over TLS (certificates obtained via \n\nLet's Encrypt\n), a useful CMS and scaffolding to generate \ncontent editors, and a fast HTTP API on which to build modern applications.\n\n\nWant to jump in right away? Try the \nQuickstart\n\n\nTable of Contents\n\n\n\n\nCLI\n\n\nContent\n\n\nForm Fields\n\n\nHTTP API - Content\n\n\nHTTP API - File Metadata\n\n\nHTTP API - Search\n\n\nInterfaces - API\n\n\nInterfaces - Editor\n\n\nInterfaces - Item\n\n\nInterfaces - Search\n\n\nCreating Ponzu Addons\n\n\nUsing Ponzu Addons\n\n\nQuickstart\n\n\nBackups\n\n\nSystem Configuration\n\n\n\n\nNeed help? Get in touch\n\n\n\n\nChat: \n#ponzu on Slack\n\n\nReach out on Twitter: \n@ponzu_cms\n\n\nFile an \nissue\n\n\n\n\n\n\ncurrent version: \nv0.9.4\n @ ponzu:master",
"title": "Home"
},
{
"location": "/#ponzu-cms-server-framework-docs",
"text": "",
"title": "Ponzu CMS + Server Framework Docs"
},
{
"location": "/#what-is-ponzu",
"text": "Watch the video introduction Ponzu is a powerful and efficient open-source HTTP server framework and CMS. It \nprovides automatic, free, and secure HTTP/2 over TLS (certificates obtained via Let's Encrypt ), a useful CMS and scaffolding to generate \ncontent editors, and a fast HTTP API on which to build modern applications. Want to jump in right away? Try the Quickstart",
"title": "What is Ponzu?"
},
{
"location": "/#table-of-contents",
"text": "CLI Content Form Fields HTTP API - Content HTTP API - File Metadata HTTP API - Search Interfaces - API Interfaces - Editor Interfaces - Item Interfaces - Search Creating Ponzu Addons Using Ponzu Addons Quickstart Backups System Configuration",
"title": "Table of Contents"
},
{
"location": "/#need-help-get-in-touch",
"text": "Chat: #ponzu on Slack Reach out on Twitter: @ponzu_cms File an issue current version: v0.9.4 @ ponzu:master",
"title": "Need help? Get in touch"
},
{
"location": "/CLI/General-Usage/",
"text": "$ ponzu \n[\nflags\n]\n \ncommand\n \nparams\n\n\n\n\n\n\nCommands\n\n\nnew\n\n\nCreates a project directory of the name supplied as a parameter immediately\nfollowing the 'new' option in the $GOPATH/src directory. Note: 'new' depends on \nthe program 'git' and possibly a network connection. If there is no local \nrepository to clone from at the local machine's $GOPATH, 'new' will attempt to \nclone the 'github.com/haturatu/ponzu' package from over the network.\n\n\nExample:\n\n\n$ ponzu new github.com/nilslice/proj\n\n New ponzu project created at \n$GOPATH\n/src/github.com/nilslice/proj\n\n\n\n\n\n\n\ngenerate, gen, g\n\n\nGenerate boilerplate code for various Ponzu components, such as \ncontent\n.\n\n\nExample:\n\n\n generator struct fields and built-in types...\n \n|\n \n|\n\n v v \n$ ponzu gen content review title:\nstring\n body:\nstring\n:richtext rating:\nint\n\n ^ ^\n \n|\n \n|\n\n struct \ntype\n \n(\noptional\n)\n input view specifier\n\n\n\n\n\nThe command above will generate the file \ncontent/review.go\n with boilerplate\nmethods, as well as struct definition, and corresponding field tags like:\n\n\ntype\n \nReview\n \nstruct\n \n{\n\n \nitem\n.\nItem\n\n\n \nTitle\n \nstring\n \n`json:\ntitle\n`\n\n \nBody\n \nstring\n \n`json:\nbody\n`\n\n \nRating\n \nint\n \n`json:\nrating\n`\n\n \nTags\n \n[]\nstring\n \n`json:\ntags\n`\n\n\n}\n\n\n\n\n\n\nThe generate command will intelligently parse more sophisticated field names\nsuch as 'field_name' and convert it to 'FieldName' and vice versa, only where \nappropriate as per common Go idioms. Errors will be reported, but successful \ngenerate commands return nothing.\n\n\nInput View Specifiers\n \n(optional)\n\n\nThe CLI can optionally parse a third parameter on the fields provided to generate \nthe type of HTML view an editor field is presented within. If no third parameter\nis added, a plain text HTML input will be generated. In the example above, the \nargument shown as \nbody:string:richtext\n would show the Richtext input instead\nof a plain text HTML input (as shown in the screenshot). The following input\nview specifiers are implemented:\n\n\n\n\n\n\n\n\nCLI parameter\n\n\nGenerates\n\n\n\n\n\n\n\n\n\n\ncheckbox\n\n\neditor.Checkbox()\n\n\n\n\n\n\ncustom\n\n\ngenerates a pre-styled empty div to fill with HTML\n\n\n\n\n\n\nfile\n\n\neditor.File()\n\n\n\n\n\n\nhidden\n\n\neditor.Input()\n + uses type=hidden\n\n\n\n\n\n\ninput, text\n\n\neditor.Input()\n\n\n\n\n\n\nrichtext\n\n\neditor.Richtext()\n\n\n\n\n\n\nselect\n\n\neditor.Select()\n\n\n\n\n\n\ntextarea\n\n\neditor.Textarea()\n\n\n\n\n\n\ntags\n\n\neditor.Tags()\n\n\n\n\n\n\n\n\nGenerate Content References\n\n\nIt's also possible to generate all of the code needed to create references between\nyour content types. The syntax to do so is below, but refer to the \ndocumentation\n\nfor more details:\n\n\n$ ponzu gen c author name:string genre:string:select\n$ ponzu gen c book title:string author:@author,name,genre \n\n\n\n\n\nThe commands above will generate a \nBook\n Content type with a reference to an\n\nAuthor\n item, by also generating a \nreference.Select\n\nas the view for the \nauthor\n field.\n\n\n\n\nbuild\n\n\nFrom within your Ponzu project directory, running build will copy and move \nthe necessary files from your workspace into the vendored directory, and \nwill build/compile the project to then be run. \n\n\nOptional flags:\n- \n--gocmd\n sets the binary used when executing \ngo build\n within \nponzu\n build step\n\n\nExample:\n\n\n$ ponzu build\n\n(\nor\n)\n\n$ ponzu build --gocmd\n=\ngo1.8rc1 \n# useful for testing\n\n\n\n\n\n\nErrors will be reported, but successful build commands return nothing.\n\n\n\n\nrun\n\n\nStarts the HTTP server for the JSON API, Admin System, or both.\nThe segments, separated by a comma, describe which services to start, either \n'admin' (Admin System / CMS backend) or 'api' (JSON API), and, optionally, \nif the server should utilize TLS encryption - served over HTTPS, which is\nautomatically managed using Let's Encrypt (https://letsencrypt.org) \n\n\nOptional flags:\n\n\n\n\n--bind\n sets the address for ponzu to bind the HTTP(S) server\n\n\n--port\n sets the port on which the server listens for HTTP requests [defaults to 8080]\n\n\n--https-port\n sets the port on which the server listens for HTTPS requests [defaults to 443]\n\n\n--https\n enables auto HTTPS management via Let's Encrypt (port is always 443)\n\n\n--dev-https\n generates self-signed SSL certificates for development-only (port is 10443)\n\n\n--docs\n runs a local documentation server in case of no network connection\n\n\n--docs-port\n sets the port on which the docs server listens for HTTP requests [defaults to 1234]\n\n\n\n\nExample: \n\n\n$ ponzu run\n\n(\nor\n)\n\n$ ponzu run --bind\n=\n0\n.0.0.0\n\n(\nor\n)\n\n$ ponzu run --port\n=\n8080\n --https admin,api\n\n(\nor\n)\n \n$ ponzu run admin\n\n(\nor\n)\n\n$ ponzu run --port\n=\n8888\n api\n\n(\nor\n)\n\n$ ponzu run --dev-https\n\n\n\n\n\nDefaults to \n$ ponzu run --port=8080 admin,api\n (running Admin \n API on port 8080, without TLS)\n\n\nNote:\n \nAdmin and API cannot run on separate processes unless you use a copy of the\ndatabase, since the first process to open it receives a lock. If you intend\nto run the Admin and API on separate processes, you must call them with the\n'ponzu' command independently.\n\n\n\n\nupgrade\n\n\nWill backup your own custom project code (like content, addons, uploads, etc) so\nwe can safely re-clone Ponzu from the latest version you have or from the network \nif necessary. Before running \n$ ponzu upgrade\n, you should update the \nponzu\n\npackage by running \n$ go get -u github.com/haturatu/ponzu/...\n \n\n\nExample:\n\n\n$ ponzu upgrade\n\n\n\n\n\n\n\nadd, a\n\n\nDownloads an addon to GOPATH/src and copies it to the current Ponzu project's\n\n/addons\n directory.\n\n\nExample:\n\n\n$ ponzu add github.com/bosssauce/fbscheduler\n\n\n\n\n\nErrors will be reported, but successful add commands return nothing.\n\n\n\n\nversion, v\n\n\nPrints the version of Ponzu your project is using. Must be called from within a \nPonzu project directory. By passing the \n--cli\n flag, the \nversion\n command will \nprint the version of the Ponzu CLI you have installed.\n\n\nExample:\n\n\n$ ponzu version\nPonzu v0.8.2\n\n# (or)\n\n$ ponzu version --cli\nPonzu v0.9.2\n\n\n\n\n\n\n\nContributing\n\n\n\n\nCheckout branch ponzu-dev\n\n\nMake code changes\n\n\nTest changes to ponzu-dev branch\n\n\nmake a commit to ponzu-dev\n\n\nto manually test, you will need to use a new copy (ponzu new path/to/code), \nbut pass the \n--dev\n flag so that ponzu generates a new copy from the \nponzu-dev\n \nbranch, not master by default (i.e. \n$ponzu new --dev /path/to/code\n)\n\n\nbuild and run with \n$ ponzu build\n and \n$ ponzu run\n\n\n\n\n\n\nTo add back to master: \n\n\nfirst push to origin ponzu-dev\n\n\ncreate a pull request \n\n\nwill then be merged into master\n\n\n\n\n\n\n\n\nA typical contribution workflow might look like:\n\n\n# clone the repository and checkout ponzu-dev\n\n$ git clone https://github.com/haturatu/ponzu path/to/local/ponzu \n# (or your fork)\n\n$ git checkout ponzu-dev\n\n\n# install ponzu with go get or from your own local path\n\n$ go get github.com/haturatu/ponzu/...\n\n# or\n\n$ \ncd\n /path/to/local/ponzu \n$ go install ./...\n\n\n# edit files, add features, etc\n\n$ git add -A\n$ git commit -m \nedited files, added features, etc\n\n\n\n# now you need to test the feature.. make a new ponzu project, but pass --dev flag\n\n$ ponzu --dev new /path/to/new/project \n# will create $GOPATH/src/path/to/new/project\n\n\n\n# build \n run ponzu from the new project directory\n\n$ \ncd\n /path/to/new/project\n$ ponzu build \n ponzu run\n\n\n# push to your origin:ponzu-dev branch and create a PR at ponzu-cms/ponzu\n\n$ git push origin ponzu-dev\n\n# ... go to https://github.com/haturatu/ponzu and create a PR\n\n\n\n\n\n\nNote:\n if you intend to work on your own fork and contribute from it, you will\nneed to also pass \n--fork=path/to/your/fork\n (using OS-standard filepath structure),\nwhere \npath/to/your/fork\n \nmust\n be within \n$GOPATH/src\n, and you are working from a branch\ncalled \nponzu-dev\n. \n\n\nFor example: \n\n\n# ($GOPATH/src is implied in the fork path, do not add it yourself)\n\n$ ponzu new --dev --fork\n=\ngithub.com/nilslice/ponzu /path/to/new/project",
"title": "General Usage"
},
{
"location": "/CLI/General-Usage/#commands",
"text": "",
"title": "Commands"
},
{
"location": "/CLI/General-Usage/#new",
"text": "Creates a project directory of the name supplied as a parameter immediately\nfollowing the 'new' option in the $GOPATH/src directory. Note: 'new' depends on \nthe program 'git' and possibly a network connection. If there is no local \nrepository to clone from at the local machine's $GOPATH, 'new' will attempt to \nclone the 'github.com/haturatu/ponzu' package from over the network. Example: $ ponzu new github.com/nilslice/proj New ponzu project created at $GOPATH /src/github.com/nilslice/proj",
"title": "new"
},
{
"location": "/CLI/General-Usage/#generate-gen-g",
"text": "Generate boilerplate code for various Ponzu components, such as content . Example: generator struct fields and built-in types...\n | | \n v v \n$ ponzu gen content review title: string body: string :richtext rating: int \n ^ ^\n | | \n struct type ( optional ) input view specifier The command above will generate the file content/review.go with boilerplate\nmethods, as well as struct definition, and corresponding field tags like: type Review struct { \n item . Item \n\n Title string `json: title ` \n Body string `json: body ` \n Rating int `json: rating ` \n Tags [] string `json: tags ` } The generate command will intelligently parse more sophisticated field names\nsuch as 'field_name' and convert it to 'FieldName' and vice versa, only where \nappropriate as per common Go idioms. Errors will be reported, but successful \ngenerate commands return nothing. Input View Specifiers (optional) The CLI can optionally parse a third parameter on the fields provided to generate \nthe type of HTML view an editor field is presented within. If no third parameter\nis added, a plain text HTML input will be generated. In the example above, the \nargument shown as body:string:richtext would show the Richtext input instead\nof a plain text HTML input (as shown in the screenshot). The following input\nview specifiers are implemented: CLI parameter Generates checkbox editor.Checkbox() custom generates a pre-styled empty div to fill with HTML file editor.File() hidden editor.Input() + uses type=hidden input, text editor.Input() richtext editor.Richtext() select editor.Select() textarea editor.Textarea() tags editor.Tags() Generate Content References It's also possible to generate all of the code needed to create references between\nyour content types. The syntax to do so is below, but refer to the documentation \nfor more details: $ ponzu gen c author name:string genre:string:select\n$ ponzu gen c book title:string author:@author,name,genre The commands above will generate a Book Content type with a reference to an Author item, by also generating a reference.Select \nas the view for the author field.",
"title": "generate, gen, g"
},
{
"location": "/CLI/General-Usage/#build",
"text": "From within your Ponzu project directory, running build will copy and move \nthe necessary files from your workspace into the vendored directory, and \nwill build/compile the project to then be run. Optional flags:\n- --gocmd sets the binary used when executing go build within ponzu build step Example: $ ponzu build ( or ) \n$ ponzu build --gocmd = go1.8rc1 # useful for testing Errors will be reported, but successful build commands return nothing.",
"title": "build"
},
{
"location": "/CLI/General-Usage/#run",
"text": "Starts the HTTP server for the JSON API, Admin System, or both.\nThe segments, separated by a comma, describe which services to start, either \n'admin' (Admin System / CMS backend) or 'api' (JSON API), and, optionally, \nif the server should utilize TLS encryption - served over HTTPS, which is\nautomatically managed using Let's Encrypt (https://letsencrypt.org) Optional flags: --bind sets the address for ponzu to bind the HTTP(S) server --port sets the port on which the server listens for HTTP requests [defaults to 8080] --https-port sets the port on which the server listens for HTTPS requests [defaults to 443] --https enables auto HTTPS management via Let's Encrypt (port is always 443) --dev-https generates self-signed SSL certificates for development-only (port is 10443) --docs runs a local documentation server in case of no network connection --docs-port sets the port on which the docs server listens for HTTP requests [defaults to 1234] Example: $ ponzu run ( or ) \n$ ponzu run --bind = 0 .0.0.0 ( or ) \n$ ponzu run --port = 8080 --https admin,api ( or ) \n$ ponzu run admin ( or ) \n$ ponzu run --port = 8888 api ( or ) \n$ ponzu run --dev-https Defaults to $ ponzu run --port=8080 admin,api (running Admin API on port 8080, without TLS) Note: \nAdmin and API cannot run on separate processes unless you use a copy of the\ndatabase, since the first process to open it receives a lock. If you intend\nto run the Admin and API on separate processes, you must call them with the\n'ponzu' command independently.",
"title": "run"
},
{
"location": "/CLI/General-Usage/#upgrade",
"text": "Will backup your own custom project code (like content, addons, uploads, etc) so\nwe can safely re-clone Ponzu from the latest version you have or from the network \nif necessary. Before running $ ponzu upgrade , you should update the ponzu \npackage by running $ go get -u github.com/haturatu/ponzu/... Example: $ ponzu upgrade",
"title": "upgrade"
},
{
"location": "/CLI/General-Usage/#add-a",
"text": "Downloads an addon to GOPATH/src and copies it to the current Ponzu project's /addons directory. Example: $ ponzu add github.com/bosssauce/fbscheduler Errors will be reported, but successful add commands return nothing.",
"title": "add, a"
},
{
"location": "/CLI/General-Usage/#version-v",
"text": "Prints the version of Ponzu your project is using. Must be called from within a \nPonzu project directory. By passing the --cli flag, the version command will \nprint the version of the Ponzu CLI you have installed. Example: $ ponzu version\nPonzu v0.8.2 # (or) \n$ ponzu version --cli\nPonzu v0.9.2",
"title": "version, v"
},
{
"location": "/CLI/General-Usage/#contributing",
"text": "Checkout branch ponzu-dev Make code changes Test changes to ponzu-dev branch make a commit to ponzu-dev to manually test, you will need to use a new copy (ponzu new path/to/code), \nbut pass the --dev flag so that ponzu generates a new copy from the ponzu-dev \nbranch, not master by default (i.e. $ponzu new --dev /path/to/code ) build and run with $ ponzu build and $ ponzu run To add back to master: first push to origin ponzu-dev create a pull request will then be merged into master A typical contribution workflow might look like: # clone the repository and checkout ponzu-dev \n$ git clone https://github.com/haturatu/ponzu path/to/local/ponzu # (or your fork) \n$ git checkout ponzu-dev # install ponzu with go get or from your own local path \n$ go get github.com/haturatu/ponzu/... # or \n$ cd /path/to/local/ponzu \n$ go install ./... # edit files, add features, etc \n$ git add -A\n$ git commit -m edited files, added features, etc # now you need to test the feature.. make a new ponzu project, but pass --dev flag \n$ ponzu --dev new /path/to/new/project # will create $GOPATH/src/path/to/new/project # build run ponzu from the new project directory \n$ cd /path/to/new/project\n$ ponzu build ponzu run # push to your origin:ponzu-dev branch and create a PR at ponzu-cms/ponzu \n$ git push origin ponzu-dev # ... go to https://github.com/haturatu/ponzu and create a PR Note: if you intend to work on your own fork and contribute from it, you will\nneed to also pass --fork=path/to/your/fork (using OS-standard filepath structure),\nwhere path/to/your/fork must be within $GOPATH/src , and you are working from a branch\ncalled ponzu-dev . For example: # ($GOPATH/src is implied in the fork path, do not add it yourself) \n$ ponzu new --dev --fork = github.com/nilslice/ponzu /path/to/new/project",
"title": "Contributing"
},
{
"location": "/CLI/Generating-References/",
"text": "In Ponzu, users make connections between Content types using references. In order \nto use the CLI to generate these references, a slightly different syntax is required. \nIn all cases, the Content type you wish to reference does not need to exist prior\nto the \"parent\" type referencing it at generate-time, but in the following examples,\nthe referenced \"child\" type will be shown before the parent type for clarity.\n\n\nSyntax\n\n\n@\n\n\nThe \n@\n symbol is used to declare that the following name is a reference. The \nCLI will take care to parse the name and treat it as a Content type to which the \ncurrent type refers.\n\n\n[]\n\n\nThe \n[]\n, which if used, is always in front of the \n@\n symbol. It signifies \nthat the reference type is a slice or a collection of references. When \n[]\n\nis used, the CLI will automatically generate a \nreference.SelectRepeater()\n view \nfor you.\n\n\n,arg1,arg2,argN\n\n\nImmediately following the reference name (after the @ symbol), users may optionally\npass arguments to specify how the reference is displayed in the parent type's\neditor. References are included in the parent types editor as a dropdown menu, with\neach possible reference as an option. These arguments define what goes inside the\n\noption\n/option\n text node, as would be seen by an Admin.\n\n\nThe arguments must be valid JSON struct tag names from the reference type's fields. \nNotice in the example below, the \ntitle\n and \nprice\n are formatted exactly as they \nwere in the generate command for the \nproduct\n type.\n\n\n\n\n\n\nExample\n\n\n$ ponzu gen content product title:string price:int description:string:textarea\n$ ponzu gen content catalog year:int products:\n[]@product\n,title,price\n\n\n\n\n\nThe commands above output the following. For demonstration, we will omit the full\ncode generated for the \nProduct\n, since the reference is in the \nCatalog\n type.\n\n\n// content/product.go\n\n\npackage\n \ncontent\n\n\n...\n\n\n\ntype\n \nProduct\n \nstruct\n \n{\n\n \nitem\n.\nItem\n\n\n \nTitle\n \nstring\n \n`json:\ntitle\n`\n\n \nPrice\n \nint\n \n`json:\nprice\n`\n\n \nDescription\n \nstring\n \n`json:\ndescription\n`\n\n\n}\n\n\n\n...\n\n\n\n\n\n\npackage\n \ncontent\n\n\n\nimport\n \n(\n\n \nfmt\n\n\n \ngithub.com/bosssauce/reference\n\n\n \ngithub.com/haturatu/ponzu/management/editor\n\n \ngithub.com/haturatu/ponzu/system/item\n\n\n)\n\n\n\ntype\n \nCatalog\n \nstruct\n \n{\n\n \nitem\n.\nItem\n\n\n \nYear\n \nint\n \n`json:\nyear\n`\n\n \n// all references are stored as []string or string types\n\n \nProducts\n \n[]\nstring\n \n`json:\nproducts\n`\n \n\n}\n\n\n\nfunc\n \n(\nc\n \n*\nCatalog\n)\n \nMarshalEditor\n()\n \n([]\nbyte\n,\n \nerror\n)\n \n{\n\n \nview\n,\n \nerr\n \n:=\n \neditor\n.\nForm\n(\nc\n,\n\n \neditor\n.\nField\n{\n\n \nView\n:\n \neditor\n.\nInput\n(\nYear\n,\n \nc\n,\n \nmap\n[\nstring\n]\nstring\n{\n\n \nlabel\n:\n \nYear\n,\n\n \ntype\n:\n \ntext\n,\n\n \nplaceholder\n:\n \nEnter the Year here\n,\n\n \n}),\n\n \n},\n\n \neditor\n.\nField\n{\n\n \n// reference.SelectRepeater since []@product was used\n\n \nView\n:\n \nreference\n.\nSelectRepeater\n(\nProducts\n,\n \nc\n,\n \nmap\n[\nstring\n]\nstring\n{\n\n \nlabel\n:\n \nProducts\n,\n\n \n},\n\n \nProduct\n,\n \n// generated from @product\n\n \n`{{ .title }} {{ .price }} `\n,\n \n// generated from ,title,price args\n\n \n),\n\n \n},\n\n \n)\n\n\n \nif\n \nerr\n \n!=\n \nnil\n \n{\n\n \nreturn\n \nnil\n,\n \nfmt\n.\nErrorf\n(\nFailed to render Catalog editor view: %s\n,\n \nerr\n.\nError\n())\n\n \n}\n\n\n \nreturn\n \nview\n,\n \nnil\n\n\n}\n\n\n\nfunc\n \ninit\n()\n \n{\n\n \nitem\n.\nTypes\n[\nCatalog\n]\n \n=\n \nfunc\n()\n \ninterface\n{}\n \n{\n \nreturn\n \nnew\n(\nCatalog\n)\n \n}\n\n\n}\n\n\n\n\n\n\nNote:\n\nIf the reference should be only a single item, rather than a slice (or collection)\nof items, omit the \n[]\n, changing the command to:\n\n\n$ ponzu gen content catalog year:int product:@product,title,price",
"title": "Generating References"
},
{
"location": "/CLI/Generating-References/#syntax",
"text": "",
"title": "Syntax"
},
{
"location": "/CLI/Generating-References/#_1",
"text": "The @ symbol is used to declare that the following name is a reference. The \nCLI will take care to parse the name and treat it as a Content type to which the \ncurrent type refers.",
"title": "@"
},
{
"location": "/CLI/Generating-References/#_2",
"text": "The [] , which if used, is always in front of the @ symbol. It signifies \nthat the reference type is a slice or a collection of references. When [] \nis used, the CLI will automatically generate a reference.SelectRepeater() view \nfor you.",
"title": "[]"
},
{
"location": "/CLI/Generating-References/#arg1arg2argn",
"text": "Immediately following the reference name (after the @ symbol), users may optionally\npass arguments to specify how the reference is displayed in the parent type's\neditor. References are included in the parent types editor as a dropdown menu, with\neach possible reference as an option. These arguments define what goes inside the option /option text node, as would be seen by an Admin. The arguments must be valid JSON struct tag names from the reference type's fields. \nNotice in the example below, the title and price are formatted exactly as they \nwere in the generate command for the product type.",
"title": ",arg1,arg2,argN"
},
{
"location": "/CLI/Generating-References/#example",
"text": "$ ponzu gen content product title:string price:int description:string:textarea\n$ ponzu gen content catalog year:int products: []@product ,title,price The commands above output the following. For demonstration, we will omit the full\ncode generated for the Product , since the reference is in the Catalog type. // content/product.go package content ... type Product struct { \n item . Item \n\n Title string `json: title ` \n Price int `json: price ` \n Description string `json: description ` } ... package content import ( \n fmt \n\n github.com/bosssauce/reference \n\n github.com/haturatu/ponzu/management/editor \n github.com/haturatu/ponzu/system/item ) type Catalog struct { \n item . Item \n\n Year int `json: year ` \n // all references are stored as []string or string types \n Products [] string `json: products ` } func ( c * Catalog ) MarshalEditor () ([] byte , error ) { \n view , err := editor . Form ( c , \n editor . Field { \n View : editor . Input ( Year , c , map [ string ] string { \n label : Year , \n type : text , \n placeholder : Enter the Year here , \n }), \n }, \n editor . Field { \n // reference.SelectRepeater since []@product was used \n View : reference . SelectRepeater ( Products , c , map [ string ] string { \n label : Products , \n }, \n Product , // generated from @product \n `{{ .title }} {{ .price }} ` , // generated from ,title,price args \n ), \n }, \n ) \n\n if err != nil { \n return nil , fmt . Errorf ( Failed to render Catalog editor view: %s , err . Error ()) \n } \n\n return view , nil } func init () { \n item . Types [ Catalog ] = func () interface {} { return new ( Catalog ) } } Note: \nIf the reference should be only a single item, rather than a slice (or collection)\nof items, omit the [] , changing the command to: $ ponzu gen content catalog year:int product:@product,title,price",
"title": "Example"
},
{
"location": "/Content/An-Overview/",
"text": "Nearly everything you work on in Ponzu is inside content files on the content types you create. These types must all reside in the \ncontent\n package and are the fundamental core of your CMS. In order for Content types to be rendered and managed by the CMS, they must implement the \neditor.Editable\n interface, and add their own \ninterface{}\n container to the global \nitem.Types\n map. \n\n\nSound like a lot? Don't worry, all of this can be done for you by using the code-generating command line tools that come with Ponzu.\n\n\nIt is rare to hand-write a new Content type, and should be generated instead!\n\n\nGenerating Content types\n\n\nTo generate content types and boilerplate code, use the Ponzu CLI \ngenerate\n command as such:\n\n\n$ ponzu generate content post title:string body:string:richtext author:string\n\n\n\n\n\nThe command above will create a file at \ncontent/post.go\n and will generate the following code:\n\n\npackage\n \ncontent\n\n\n\nimport\n \n(\n\n \nfmt\n\n\n \ngithub.com/haturatu/ponzu/management/editor\n\n \ngithub.com/haturatu/ponzu/system/item\n\n\n)\n\n\n\ntype\n \nPost\n \nstruct\n \n{\n\n \nitem\n.\nItem\n\n\n \nTitle\n \nstring\n \n`json:\ntitle\n`\n\n \nBody\n \nstring\n \n`json:\nbody\n`\n\n \nAuthor\n \nstring\n \n`json:\nauthor\n`\n\n\n}\n\n\n\n// MarshalEditor writes a buffer of html to edit a Post within the CMS\n\n\n// and implements editor.Editable\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nMarshalEditor\n()\n \n([]\nbyte\n,\n \nerror\n)\n \n{\n\n \nview\n,\n \nerr\n \n:=\n \neditor\n.\nForm\n(\np\n,\n\n \n// Take note that the first argument to these Input-like functions\n\n \n// is the string version of each Post field, and must follow\n\n \n// this pattern for auto-decoding and auto-encoding reasons:\n\n \neditor\n.\nField\n{\n\n \nView\n:\n \neditor\n.\nInput\n(\nTitle\n,\n \np\n,\n \nmap\n[\nstring\n]\nstring\n{\n\n \nlabel\n:\n \nTitle\n,\n\n \ntype\n:\n \ntext\n,\n\n \nplaceholder\n:\n \nEnter the Title here\n,\n\n \n}),\n\n \n},\n\n \neditor\n.\nField\n{\n\n \nView\n:\n \neditor\n.\nRichtext\n(\nBody\n,\n \np\n,\n \nmap\n[\nstring\n]\nstring\n{\n\n \nlabel\n:\n \nBody\n,\n\n \nplaceholder\n:\n \nEnter the Body here\n,\n\n \n}),\n\n \n},\n\n \neditor\n.\nField\n{\n\n \nView\n:\n \neditor\n.\nInput\n(\nAuthor\n,\n \np\n,\n \nmap\n[\nstring\n]\nstring\n{\n\n \nlabel\n:\n \nAuthor\n,\n\n \ntype\n:\n \ntext\n,\n\n \nplaceholder\n:\n \nEnter the Author here\n,\n\n \n}),\n\n \n},\n\n \n)\n\n\n \nif\n \nerr\n \n!=\n \nnil\n \n{\n\n \nreturn\n \nnil\n,\n \nfmt\n.\nErrorf\n(\nFailed to render Post editor view: %s\n,\n \nerr\n.\nError\n())\n\n \n}\n\n\n \nreturn\n \nview\n,\n \nnil\n\n\n}\n\n\n\nfunc\n \ninit\n()\n \n{\n\n \nitem\n.\nTypes\n[\nPost\n]\n \n=\n \nfunc\n()\n \ninterface\n{}\n \n{\n \nreturn\n \nnew\n(\nPost\n)\n \n}\n\n\n}\n\n\n\n\n\n\nThe code above is the baseline amount required to manage content for the \nPost\n type from within the CMS. See \nExtending Content\n for information about how to add more functionality to your Content types. \n\n\nAll content managed by the CMS and exposed via the API is considered an \"item\", and thus should embed the \nitem.Item\n type. There are many benefits to this, such as becoming automatically sortable by time, and being given default methods that are useful inside and out of the CMS. All content types that are created by the \ngenerate\n command via Ponzu CLI will embed Item. \n\n\nRelated packages\n\n\nThe \nitem\n package has a number of useful interfaces, which make it simple to add functionality to all content types and other types that embed Item. \n\n\nThe \neditor\n package has the Editable interface, which allows types to create an editor for their fields within the CMS. Additionally, there is a helper function \neditor.Form\n which simplifies defining the editor's input layout and input types using \neditor.Input\n and various other functions to make HTML input elements like Select, Checkbox, Richtext, Textarea and more.\n\n\nThe \napi\n package has interfaces including \napi.Createable\n and \napi.Mergeable\n which make it trivial to accept and approve or reject content submitted from 3rd parties (POST from HTML forms, mobile clients, etc).",
"title": "An Overview"
},
{
"location": "/Content/An-Overview/#generating-content-types",
"text": "To generate content types and boilerplate code, use the Ponzu CLI generate command as such: $ ponzu generate content post title:string body:string:richtext author:string The command above will create a file at content/post.go and will generate the following code: package content import ( \n fmt \n\n github.com/haturatu/ponzu/management/editor \n github.com/haturatu/ponzu/system/item ) type Post struct { \n item . Item \n\n Title string `json: title ` \n Body string `json: body ` \n Author string `json: author ` } // MarshalEditor writes a buffer of html to edit a Post within the CMS // and implements editor.Editable func ( p * Post ) MarshalEditor () ([] byte , error ) { \n view , err := editor . Form ( p , \n // Take note that the first argument to these Input-like functions \n // is the string version of each Post field, and must follow \n // this pattern for auto-decoding and auto-encoding reasons: \n editor . Field { \n View : editor . Input ( Title , p , map [ string ] string { \n label : Title , \n type : text , \n placeholder : Enter the Title here , \n }), \n }, \n editor . Field { \n View : editor . Richtext ( Body , p , map [ string ] string { \n label : Body , \n placeholder : Enter the Body here , \n }), \n }, \n editor . Field { \n View : editor . Input ( Author , p , map [ string ] string { \n label : Author , \n type : text , \n placeholder : Enter the Author here , \n }), \n }, \n ) \n\n if err != nil { \n return nil , fmt . Errorf ( Failed to render Post editor view: %s , err . Error ()) \n } \n\n return view , nil } func init () { \n item . Types [ Post ] = func () interface {} { return new ( Post ) } } The code above is the baseline amount required to manage content for the Post type from within the CMS. See Extending Content for information about how to add more functionality to your Content types. All content managed by the CMS and exposed via the API is considered an \"item\", and thus should embed the item.Item type. There are many benefits to this, such as becoming automatically sortable by time, and being given default methods that are useful inside and out of the CMS. All content types that are created by the generate command via Ponzu CLI will embed Item.",
"title": "Generating Content types"
},
{
"location": "/Content/An-Overview/#related-packages",
"text": "The item package has a number of useful interfaces, which make it simple to add functionality to all content types and other types that embed Item. The editor package has the Editable interface, which allows types to create an editor for their fields within the CMS. Additionally, there is a helper function editor.Form which simplifies defining the editor's input layout and input types using editor.Input and various other functions to make HTML input elements like Select, Checkbox, Richtext, Textarea and more. The api package has interfaces including api.Createable and api.Mergeable which make it trivial to accept and approve or reject content submitted from 3rd parties (POST from HTML forms, mobile clients, etc).",
"title": "Related packages"
},
{
"location": "/Content/Extending-Content/",
"text": "Extending your Content types with more features and functionality within the system\nis done by implementing the various built-in interfaces provided by Ponzu. To learn \nmore about interfaces, see \nA Tour of Go - Interfaces\n.\n\n\nIt is also common to add more advanced functionality to Content types using Addons. Refer to the \nAddon documentation\n for more information about how to use and create Ponzu Addons.\n\n\nItem Interfaces\n\n\nAll Content types which embed an \nitem.Item\n will implicitly \nimplement\n its many\ninterfaces. In Ponzu, the following interfaces are exported from the \nsystem/item\n\npackage and have a default implementation which can be overridden to change your\ncontent types' functionality within the system.\n\n\n\n\nitem.Pushable\n\n\nitem.Hideable\n\n\nitem.Omittable\n\n\nitem.Hookable\n\n\nitem.Identifiable\n\n\nitem.Sortable\n\n\nitem.Sluggable\n\n\n\n\nAPI Interfaces\n\n\nTo enable 3rd-party clients to interact with your Content types, you can extend your types with the API interfaces:\n\n\n\n\napi.Createable\n\n\napi.Updateable\n\n\napi.Deleteable\n\n\napi.Trustable\n\n\n\n\nEditor Interfaces\n\n\nTo manage how content is edited and handled in the CMS, use the following Editor interfaces:\n\n\n\n\neditor.Editable\n\n\neditor.Mergeable\n\n\n\n\nSearch Interfaces\n\n\nTo enable and customize full-text search on your content types, use the following interfaces:\n\n\n\n\nsearch.Searchable",
"title": "Extending Content"
},
{
"location": "/Content/Extending-Content/#item-interfaces",
"text": "All Content types which embed an item.Item will implicitly implement its many\ninterfaces. In Ponzu, the following interfaces are exported from the system/item \npackage and have a default implementation which can be overridden to change your\ncontent types' functionality within the system. item.Pushable item.Hideable item.Omittable item.Hookable item.Identifiable item.Sortable item.Sluggable",
"title": "Item Interfaces"
},
{
"location": "/Content/Extending-Content/#api-interfaces",
"text": "To enable 3rd-party clients to interact with your Content types, you can extend your types with the API interfaces: api.Createable api.Updateable api.Deleteable api.Trustable",
"title": "API Interfaces"
},
{
"location": "/Content/Extending-Content/#editor-interfaces",
"text": "To manage how content is edited and handled in the CMS, use the following Editor interfaces: editor.Editable editor.Mergeable",
"title": "Editor Interfaces"
},
{
"location": "/Content/Extending-Content/#search-interfaces",
"text": "To enable and customize full-text search on your content types, use the following interfaces: search.Searchable",
"title": "Search Interfaces"
},
{
"location": "/Form-Fields/HTML-Inputs/",
"text": "Ponzu provides a number of helpful HTML Inputs to create forms which CMS admins\nuse to manage content. The input functions are typically used inside a Content\ntype's \nMarshalEditor()\n func from within an \neditor.Form()\n - for example:\n\n\n// MarshalEditor writes a buffer of html to edit a Post within the CMS\n\n\n// and implements editor.Editable\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nMarshalEditor\n()\n \n([]\nbyte\n,\n \nerror\n)\n \n{\n\n \nview\n,\n \nerr\n \n:=\n \neditor\n.\nForm\n(\np\n,\n\n \neditor\n.\nField\n{\n \n// \n- editor.Fields contain input-like funcs\n\n \nView\n:\n \neditor\n.\nInput\n(\nTitle\n,\n \np\n,\n \nmap\n[\nstring\n]\nstring\n{\n \n// \n- makes a text input\n\n \nlabel\n:\n \nTitle\n,\n\n \ntype\n:\n \ntext\n,\n\n \nplaceholder\n:\n \nEnter the Title here\n,\n\n \n}),\n\n \n},\n\n \neditor\n.\nField\n{\n\n \nView\n:\n \neditor\n.\nRichtext\n(\nBody\n,\n \np\n,\n \nmap\n[\nstring\n]\nstring\n{\n \n// \n- makes a WYSIWIG editor\n\n \nlabel\n:\n \nBody\n,\n\n \nplaceholder\n:\n \nEnter the Body here\n,\n\n \n}),\n\n \n},\n\n \neditor\n.\nField\n{\n\n \nView\n:\n \neditor\n.\nInput\n(\nAuthor\n,\n \np\n,\n \nmap\n[\nstring\n]\nstring\n{\n\n \nlabel\n:\n \nAuthor\n,\n\n \ntype\n:\n \ntext\n,\n\n \nplaceholder\n:\n \nEnter the Author here\n,\n\n \n}),\n\n \n},\n\n \n)\n\n\n \nif\n \nerr\n \n!=\n \nnil\n \n{\n\n \nreturn\n \nnil\n,\n \nfmt\n.\nErrorf\n(\nFailed to render Post editor view: %s\n,\n \nerr\n.\nError\n())\n\n \n}\n\n\n \nreturn\n \nview\n,\n \nnil\n\n\n}\n\n\n\n\n\n\n\n\nField Input Functions\n\n\nThere are many of these input-like HTML view funcs exported from Ponzu's\n\nmanagement/editor\n package. Below is a list of the built-in options:\n\n\neditor.Input\n\n\nThe \neditor.Input\n function produces a standard text input.\n\n\nScreenshot\n\n\n\n\nFunction Signature\n\n\nInput\n(\nfieldName\n \nstring\n,\n \np\n \ninterface\n{},\n \nattrs\n,\n \noptions\n \nmap\n[\nstring\n]\nstring\n)\n \n[]\nbyte\n\n\n\n\n\n\nExample\n\n\n...\n\n\neditor\n.\nField\n{\n\n \nView\n:\n \neditor\n.\nInput\n(\nTitle\n,\n \ns\n,\n \nmap\n[\nstring\n]\nstring\n{\n\n \nlabel\n:\n \nTitle\n,\n\n \ntype\n:\n \ntext\n,\n\n \nplaceholder\n:\n \nEnter the Title here\n,\n\n \n}),\n\n\n},\n\n\n...\n\n\n\n\n\n\n\n\neditor.InputRepeater\n\n\nThe \neditor.InputRepeater\n function applies a controller UI to the \neditor.Input\n \nview so any arbitrary number of inputs can be added for your field.\n\n\n\n\nUsing Repeaters\n\n\nWhen using the \neditor.InputRepeater\n make sure it's corresponding field is a \nslice \n[]T\n\ntype. You will experience errors if it is not.\n\n\n\n\nScreenshot\n\n\n\n\nFunction Signature\n\n\nInputRepeater\n(\nfieldName\n \nstring\n,\n \np\n \ninterface\n{},\n \nattrs\n,\n \noptions\n \nmap\n[\nstring\n]\nstring\n)\n \n[]\nbyte\n\n\n\n\n\n\nExample\n\n\n...\n\n\neditor\n.\nField\n{\n\n \nView\n:\n \neditor\n.\nInputRepeater\n(\nTitle\n,\n \ns\n,\n \nmap\n[\nstring\n]\nstring\n{\n\n \nlabel\n:\n \nTitles\n,\n\n \ntype\n:\n \ntext\n,\n\n \nplaceholder\n:\n \nEnter the Title here\n,\n\n \n}),\n\n\n},\n\n\n...\n\n\n\n\n\n\n\n\neditor.Checkbox\n\n\nThe \neditor.Checkbox\n function returns any number of checkboxes in a collection,\ndefined by the value:name map of options.\n\n\nScreenshot\n\n\n\n\nFunction Signature\n\n\nCheckbox\n(\nfieldName\n \nstring\n,\n \np\n \ninterface\n{},\n \nattrs\n,\n \noptions\n \nmap\n[\nstring\n]\nstring\n)\n \n[]\nbyte\n\n\n\n\n\n\nExample\n\n\n...\n\n\neditor\n.\nField\n{\n\n \nView\n:\n \neditor\n.\nCheckbox\n(\nOptions\n,\n \ns\n,\n \nmap\n[\nstring\n]\nstring\n{\n\n \nlabel\n:\n \nOptions\n,\n\n \n},\n \nmap\n[\nstring\n]\nstring\n{\n\n \n// \nvalue\n: \nDisplay Name\n,\n\n \n1\n:\n \nFirst\n,\n\n \n2\n:\n \nSecond\n,\n\n \n3\n:\n \nThird\n,\n\n \n}),\n\n\n},\n\n\n...\n\n\n\n\n\n\n\n\neditor.Richtext\n\n\nThe \neditor.Richetext\n function displays an HTML5 rich text / WYSYWIG editor which\nsupports text formatting and styling, images, quotes, arbitrary HTML, and more. \n\n\nThe rich text editor is a modified version of \nSummernote\n \nusing a theme called \nMaterialNote\n\n\nScreenshot\n\n\n\n\nFunction Signature\n\n\nRichtext\n(\nfieldName\n \nstring\n,\n \np\n \ninterface\n{},\n \nattrs\n \nmap\n[\nstring\n]\nstring\n)\n \n[]\nbyte\n\n\n\n\n\n\nExample\n\n\n...\n\n\neditor\n.\nField\n{\n\n \nView\n:\n \neditor\n.\nRichtext\n(\nOpinion\n,\n \ns\n,\n \nmap\n[\nstring\n]\nstring\n{\n\n \nlabel\n:\n \nRich Text Editor\n,\n\n \nplaceholder\n:\n \nEnter the Opinion here\n,\n\n \n}),\n\n\n},\n\n\n...\n\n\n\n\n\n\n\n\neditor.Tags\n\n\nThe \neditor.Tags\n function returns a container input element for lists of arbitrary\nbits of information.\n\n\nScreenshot\n\n\n\n\nFunction Signature\n\n\nTags\n(\nfieldName\n \nstring\n,\n \np\n \ninterface\n{},\n \nattrs\n \nmap\n[\nstring\n]\nstring\n)\n \n[]\nbyte\n\n\n\n\n\n\nExample\n\n\n...\n\n\neditor\n.\nField\n{\n\n \nView\n:\n \neditor\n.\nTags\n(\nCategory\n,\n \ns\n,\n \nmap\n[\nstring\n]\nstring\n{\n\n \nlabel\n:\n \nTags\n,\n\n \nplaceholder\n:\n \n+Category\n,\n\n \n}),\n\n\n},\n\n\n...\n\n\n\n\n\n\n\n\neditor.File\n\n\nThe \neditor.File\n function returns an HTML file upload element, which saves files\ninto the \n/uploads\n directory, and can be viewed from the \"Uploads\" section in the\nAdmin dashboard. See also the \nFile Metadata API\n.\n\n\n\n\nField Type\n\n\nWhen using the \neditor.File\n function, its corresponding field type must be\na \nstring\n, as files will be stored as URL paths in the database. \n\n\n\n\nScreenshot\n\n\n\n\nFunction Signature\n\n\nFile\n(\nfieldName\n \nstring\n,\n \np\n \ninterface\n{},\n \nattrs\n \nmap\n[\nstring\n]\nstring\n)\n \n[]\nbyte\n\n\n\n\n\n\nExample\n\n\n...\n\n\neditor\n.\nField\n{\n\n \nView\n:\n \neditor\n.\nFile\n(\nPhoto\n,\n \ns\n,\n \nmap\n[\nstring\n]\nstring\n{\n\n \nlabel\n:\n \nFile Upload\n,\n\n \nplaceholder\n:\n \nUpload the Photo here\n,\n\n \n}),\n\n\n},\n\n\n...\n\n\n\n\n\n\n\n\neditor.FileRepeater\n\n\nThe \neditor.FileRepeater\n function applies a controller UI to the \neditor.File\n \nview so any arbitrary number of uploads can be added for your field.\n\n\n\n\nUsing Repeaters\n\n\nWhen using the \neditor.FileRepeater\n make sure it's corresponding field is a \nslice \n[]string\n\ntype. You will experience errors if it is not.\n\n\n\n\nScreenshot\n\n\n\n\nFunction Signature\n\n\nFileRepeater\n(\nfieldName\n \nstring\n,\n \np\n \ninterface\n{},\n \nattrs\n \nmap\n[\nstring\n]\nstring\n)\n \n[]\nbyte\n\n\n\n\n\n\nExample\n\n\n...\n\n\neditor\n.\nField\n{\n\n \nView\n:\n \neditor\n.\nFileRepeater\n(\nPhoto\n,\n \ns\n,\n \nmap\n[\nstring\n]\nstring\n{\n\n \nlabel\n:\n \nFile Upload Repeater\n,\n\n \nplaceholder\n:\n \nUpload the Photo here\n,\n\n \n}),\n\n\n},\n\n\n...\n\n\n\n\n\n\n\n\neditor.Select\n\n\nThe \neditor.Select\n function returns a single HTML select input with options\nas defined in the \noptions map[string]string\n parameter of the function call.\n\n\nScreenshot\n\n\n\n\nFunction Signature\n\n\nfunc\n \nSelect\n(\nfieldName\n \nstring\n,\n \np\n \ninterface\n{},\n \nattrs\n,\n \noptions\n \nmap\n[\nstring\n]\nstring\n)\n \n[]\nbyte\n\n\n\n\n\n\nExample\n\n\n...\n\n\neditor\n.\nField\n{\n\n \nView\n:\n \neditor\n.\nSelect\n(\nRating\n,\n \ns\n,\n \nmap\n[\nstring\n]\nstring\n{\n\n \nlabel\n:\n \nSelect Dropdown\n,\n\n \n},\n \nmap\n[\nstring\n]\nstring\n{\n\n \n// \nvalue\n: \nDisplay Name\n,\n\n \nG\n:\n \nG\n,\n\n \nPG\n:\n \nPG\n,\n\n \nPG-13\n:\n \nPG-13\n,\n\n \nR\n:\n \nR\n,\n\n \n}),\n\n\n},\n\n\n...\n\n\n\n\n\n\n\n\neditor.SelectRepeater\n\n\nThe \neditor.SelectRepeater\n function applies a controller UI to the \neditor.Select\n \nview so any arbitrary number of dropdowns can be added for your field.\n\n\nScreenshot\n\n\n\n\nFunction Signature\n\n\nfunc\n \nSelectRepeater\n(\nfieldName\n \nstring\n,\n \np\n \ninterface\n{},\n \nattrs\n,\n \noptions\n \nmap\n[\nstring\n]\nstring\n)\n \n[]\nbyte\n\n\n\n\n\n\nExample\n\n\n...\n\n\neditor\n.\nField\n{\n\n \nView\n:\n \neditor\n.\nSelectRepeater\n(\nRating\n,\n \ns\n,\n \nmap\n[\nstring\n]\nstring\n{\n\n \nlabel\n:\n \nSelect Dropdown Repeater\n,\n\n \n},\n \nmap\n[\nstring\n]\nstring\n{\n\n \n// \nvalue\n: \nDisplay Name\n,\n\n \nG\n:\n \nG\n,\n\n \nPG\n:\n \nPG\n,\n\n \nPG-13\n:\n \nPG-13\n,\n\n \nR\n:\n \nR\n,\n\n \n}),\n\n\n},\n\n\n...\n\n\n\n\n\n\n\n\neditor.Textarea\n\n\nThe \neditor.Textarea\n function returns an HTML textarea input to add unstyled text\nblocks. Newlines in the textarea are preserved.\n\n\nScreenshot\n\n\n\n\nFunction Signature\n\n\nTextarea\n(\nfieldName\n \nstring\n,\n \np\n \ninterface\n{},\n \nattrs\n \nmap\n[\nstring\n]\nstring\n)\n \n[]\nbyte\n\n\n\n\n\n\nExample\n\n\n...\n\n\neditor\n.\nField\n{\n\n \nView\n:\n \neditor\n.\nTextarea\n(\nReadme\n,\n \ns\n,\n \nmap\n[\nstring\n]\nstring\n{\n\n \nlabel\n:\n \nTextarea\n,\n\n \nplaceholder\n:\n \nEnter the Readme here\n,\n\n \n}),\n\n\n},\n\n\n...\n\n\n\n\n\n\n\n\nData References\n\n\nIt is common to want to keep a reference from one Content type to another. To do\nthis in Ponzu, use the \nbosssauce/reference\n \npackage. It comes pre-installed with Ponzu as an \n\"Addon\"\n.\n\n\nreference.Select\n\n\nScreenshot\n\n\n\n\nFunction Signature\n\n\nfunc\n \nSelect\n(\nfieldName\n \nstring\n,\n \np\n \ninterface\n{},\n \nattrs\n \nmap\n[\nstring\n]\nstring\n,\n \ncontentType\n,\n \ntmplString\n \nstring\n)\n \n[]\nbyte\n\n\n\n\n\n\nExample\n\n\n...\n\n\neditor\n.\nField\n{\n\n \nView\n:\n \nreference\n.\nSelect\n(\nDirectedBy\n,\n \ns\n,\n \nmap\n[\nstring\n]\nstring\n{\n\n \nlabel\n:\n \nSelect Dropdown\n,\n\n \n},\n \nDirector\n,\n \n`{{.last-name}}, {{.first_name}}`\n),\n\n\n},\n\n\n...\n\n\n\n\n\n\n\n\nreference.SelectRepeater\n\n\nScreenshot\n\n\n\n\nFunction Signature\n\n\nfunc\n \nSelectRepeater\n(\nfieldName\n \nstring\n,\n \np\n \ninterface\n{},\n \nattrs\n \nmap\n[\nstring\n]\nstring\n,\n \ncontentType\n,\n \ntmplString\n \nstring\n)\n \n[]\nbyte\n\n\n\n\n\n\nExample\n\n\n...\n\n\neditor\n.\nField\n{\n\n \nView\n:\n \nreference\n.\nSelectRepeater\n(\nPlacesFilmed\n,\n \ns\n,\n \nmap\n[\nstring\n]\nstring\n{\n\n \nlabel\n:\n \nSelect Dropdown Repeater\n,\n\n \n},\n \nLocation\n,\n \n`{{.name}}, {{.region}}`\n),\n\n\n},\n\n\n...",
"title": "HTML Inputs"
},
{
"location": "/Form-Fields/HTML-Inputs/#field-input-functions",
"text": "There are many of these input-like HTML view funcs exported from Ponzu's management/editor package. Below is a list of the built-in options:",
"title": "Field Input Functions"
},
{
"location": "/Form-Fields/HTML-Inputs/#editorinput",
"text": "The editor.Input function produces a standard text input.",
"title": "editor.Input"
},
{
"location": "/Form-Fields/HTML-Inputs/#screenshot",
"text": "",
"title": "Screenshot"
},
{
"location": "/Form-Fields/HTML-Inputs/#function-signature",
"text": "Input ( fieldName string , p interface {}, attrs , options map [ string ] string ) [] byte",
"title": "Function Signature"
},
{
"location": "/Form-Fields/HTML-Inputs/#example",
"text": "... editor . Field { \n View : editor . Input ( Title , s , map [ string ] string { \n label : Title , \n type : text , \n placeholder : Enter the Title here , \n }), }, ...",
"title": "Example"
},
{
"location": "/Form-Fields/HTML-Inputs/#editorinputrepeater",
"text": "The editor.InputRepeater function applies a controller UI to the editor.Input \nview so any arbitrary number of inputs can be added for your field. Using Repeaters When using the editor.InputRepeater make sure it's corresponding field is a slice []T \ntype. You will experience errors if it is not.",
"title": "editor.InputRepeater"
},
{
"location": "/Form-Fields/HTML-Inputs/#screenshot_1",
"text": "",
"title": "Screenshot"
},
{
"location": "/Form-Fields/HTML-Inputs/#function-signature_1",
"text": "InputRepeater ( fieldName string , p interface {}, attrs , options map [ string ] string ) [] byte",
"title": "Function Signature"
},
{
"location": "/Form-Fields/HTML-Inputs/#example_1",
"text": "... editor . Field { \n View : editor . InputRepeater ( Title , s , map [ string ] string { \n label : Titles , \n type : text , \n placeholder : Enter the Title here , \n }), }, ...",
"title": "Example"
},
{
"location": "/Form-Fields/HTML-Inputs/#editorcheckbox",
"text": "The editor.Checkbox function returns any number of checkboxes in a collection,\ndefined by the value:name map of options.",
"title": "editor.Checkbox"
},
{
"location": "/Form-Fields/HTML-Inputs/#screenshot_2",
"text": "",
"title": "Screenshot"
},
{
"location": "/Form-Fields/HTML-Inputs/#function-signature_2",
"text": "Checkbox ( fieldName string , p interface {}, attrs , options map [ string ] string ) [] byte",
"title": "Function Signature"
},
{
"location": "/Form-Fields/HTML-Inputs/#example_2",
"text": "... editor . Field { \n View : editor . Checkbox ( Options , s , map [ string ] string { \n label : Options , \n }, map [ string ] string { \n // value : Display Name , \n 1 : First , \n 2 : Second , \n 3 : Third , \n }), }, ...",
"title": "Example"
},
{
"location": "/Form-Fields/HTML-Inputs/#editorrichtext",
"text": "The editor.Richetext function displays an HTML5 rich text / WYSYWIG editor which\nsupports text formatting and styling, images, quotes, arbitrary HTML, and more. The rich text editor is a modified version of Summernote \nusing a theme called MaterialNote",
"title": "editor.Richtext"
},
{
"location": "/Form-Fields/HTML-Inputs/#screenshot_3",
"text": "",
"title": "Screenshot"
},
{
"location": "/Form-Fields/HTML-Inputs/#function-signature_3",
"text": "Richtext ( fieldName string , p interface {}, attrs map [ string ] string ) [] byte",
"title": "Function Signature"
},
{
"location": "/Form-Fields/HTML-Inputs/#example_3",
"text": "... editor . Field { \n View : editor . Richtext ( Opinion , s , map [ string ] string { \n label : Rich Text Editor , \n placeholder : Enter the Opinion here , \n }), }, ...",
"title": "Example"
},
{
"location": "/Form-Fields/HTML-Inputs/#editortags",
"text": "The editor.Tags function returns a container input element for lists of arbitrary\nbits of information.",
"title": "editor.Tags"
},
{
"location": "/Form-Fields/HTML-Inputs/#screenshot_4",
"text": "",
"title": "Screenshot"
},
{
"location": "/Form-Fields/HTML-Inputs/#function-signature_4",
"text": "Tags ( fieldName string , p interface {}, attrs map [ string ] string ) [] byte",
"title": "Function Signature"
},
{
"location": "/Form-Fields/HTML-Inputs/#example_4",
"text": "... editor . Field { \n View : editor . Tags ( Category , s , map [ string ] string { \n label : Tags , \n placeholder : +Category , \n }), }, ...",
"title": "Example"
},
{
"location": "/Form-Fields/HTML-Inputs/#editorfile",
"text": "The editor.File function returns an HTML file upload element, which saves files\ninto the /uploads directory, and can be viewed from the \"Uploads\" section in the\nAdmin dashboard. See also the File Metadata API . Field Type When using the editor.File function, its corresponding field type must be\na string , as files will be stored as URL paths in the database.",
"title": "editor.File"
},
{
"location": "/Form-Fields/HTML-Inputs/#screenshot_5",
"text": "",
"title": "Screenshot"
},
{
"location": "/Form-Fields/HTML-Inputs/#function-signature_5",
"text": "File ( fieldName string , p interface {}, attrs map [ string ] string ) [] byte",
"title": "Function Signature"
},
{
"location": "/Form-Fields/HTML-Inputs/#example_5",
"text": "... editor . Field { \n View : editor . File ( Photo , s , map [ string ] string { \n label : File Upload , \n placeholder : Upload the Photo here , \n }), }, ...",
"title": "Example"
},
{
"location": "/Form-Fields/HTML-Inputs/#editorfilerepeater",
"text": "The editor.FileRepeater function applies a controller UI to the editor.File \nview so any arbitrary number of uploads can be added for your field. Using Repeaters When using the editor.FileRepeater make sure it's corresponding field is a slice []string \ntype. You will experience errors if it is not.",
"title": "editor.FileRepeater"
},
{
"location": "/Form-Fields/HTML-Inputs/#screenshot_6",
"text": "",
"title": "Screenshot"
},
{
"location": "/Form-Fields/HTML-Inputs/#function-signature_6",
"text": "FileRepeater ( fieldName string , p interface {}, attrs map [ string ] string ) [] byte",
"title": "Function Signature"
},
{
"location": "/Form-Fields/HTML-Inputs/#example_6",
"text": "... editor . Field { \n View : editor . FileRepeater ( Photo , s , map [ string ] string { \n label : File Upload Repeater , \n placeholder : Upload the Photo here , \n }), }, ...",
"title": "Example"
},
{
"location": "/Form-Fields/HTML-Inputs/#editorselect",
"text": "The editor.Select function returns a single HTML select input with options\nas defined in the options map[string]string parameter of the function call.",
"title": "editor.Select"
},
{
"location": "/Form-Fields/HTML-Inputs/#screenshot_7",
"text": "",
"title": "Screenshot"
},
{
"location": "/Form-Fields/HTML-Inputs/#function-signature_7",
"text": "func Select ( fieldName string , p interface {}, attrs , options map [ string ] string ) [] byte",
"title": "Function Signature"
},
{
"location": "/Form-Fields/HTML-Inputs/#example_7",
"text": "... editor . Field { \n View : editor . Select ( Rating , s , map [ string ] string { \n label : Select Dropdown , \n }, map [ string ] string { \n // value : Display Name , \n G : G , \n PG : PG , \n PG-13 : PG-13 , \n R : R , \n }), }, ...",
"title": "Example"
},
{
"location": "/Form-Fields/HTML-Inputs/#editorselectrepeater",
"text": "The editor.SelectRepeater function applies a controller UI to the editor.Select \nview so any arbitrary number of dropdowns can be added for your field.",
"title": "editor.SelectRepeater"
},
{
"location": "/Form-Fields/HTML-Inputs/#screenshot_8",
"text": "",
"title": "Screenshot"
},
{
"location": "/Form-Fields/HTML-Inputs/#function-signature_8",
"text": "func SelectRepeater ( fieldName string , p interface {}, attrs , options map [ string ] string ) [] byte",
"title": "Function Signature"
},
{
"location": "/Form-Fields/HTML-Inputs/#example_8",
"text": "... editor . Field { \n View : editor . SelectRepeater ( Rating , s , map [ string ] string { \n label : Select Dropdown Repeater , \n }, map [ string ] string { \n // value : Display Name , \n G : G , \n PG : PG , \n PG-13 : PG-13 , \n R : R , \n }), }, ...",
"title": "Example"
},
{
"location": "/Form-Fields/HTML-Inputs/#editortextarea",
"text": "The editor.Textarea function returns an HTML textarea input to add unstyled text\nblocks. Newlines in the textarea are preserved.",
"title": "editor.Textarea"
},
{
"location": "/Form-Fields/HTML-Inputs/#screenshot_9",
"text": "",
"title": "Screenshot"
},
{
"location": "/Form-Fields/HTML-Inputs/#function-signature_9",
"text": "Textarea ( fieldName string , p interface {}, attrs map [ string ] string ) [] byte",
"title": "Function Signature"
},
{
"location": "/Form-Fields/HTML-Inputs/#example_9",
"text": "... editor . Field { \n View : editor . Textarea ( Readme , s , map [ string ] string { \n label : Textarea , \n placeholder : Enter the Readme here , \n }), }, ...",
"title": "Example"
},
{
"location": "/Form-Fields/HTML-Inputs/#data-references",
"text": "It is common to want to keep a reference from one Content type to another. To do\nthis in Ponzu, use the bosssauce/reference \npackage. It comes pre-installed with Ponzu as an \"Addon\" .",
"title": "Data References"
},
{
"location": "/Form-Fields/HTML-Inputs/#referenceselect",
"text": "",
"title": "reference.Select"
},
{
"location": "/Form-Fields/HTML-Inputs/#screenshot_10",
"text": "",
"title": "Screenshot"
},
{
"location": "/Form-Fields/HTML-Inputs/#function-signature_10",
"text": "func Select ( fieldName string , p interface {}, attrs map [ string ] string , contentType , tmplString string ) [] byte",
"title": "Function Signature"
},
{
"location": "/Form-Fields/HTML-Inputs/#example_10",
"text": "... editor . Field { \n View : reference . Select ( DirectedBy , s , map [ string ] string { \n label : Select Dropdown , \n }, Director , `{{.last-name}}, {{.first_name}}` ), }, ...",
"title": "Example"
},
{
"location": "/Form-Fields/HTML-Inputs/#referenceselectrepeater",
"text": "",
"title": "reference.SelectRepeater"
},
{
"location": "/Form-Fields/HTML-Inputs/#screenshot_11",
"text": "",
"title": "Screenshot"
},
{
"location": "/Form-Fields/HTML-Inputs/#function-signature_11",
"text": "func SelectRepeater ( fieldName string , p interface {}, attrs map [ string ] string , contentType , tmplString string ) [] byte",
"title": "Function Signature"
},
{
"location": "/Form-Fields/HTML-Inputs/#example_11",
"text": "... editor . Field { \n View : reference . SelectRepeater ( PlacesFilmed , s , map [ string ] string { \n label : Select Dropdown Repeater , \n }, Location , `{{.name}}, {{.region}}` ), }, ...",
"title": "Example"
},
{
"location": "/HTTP-APIs/Content/",
"text": "Ponzu provides a read \n write HTTP API to access and interact with content on a\nsystem. By default, write access (including create, update and delete) and search \nare disabled. See the section on Ponzu's \nAPI Interfaces\n to learn\nmore about how to enable these endpoints.\n\n\n\n\nEndpoints\n\n\nGet Content by Type\n\n\nGET\n \n/api/content?type=\nType\nid=\nID\n\n\nSample Response\n\n\n{\n\n \ndata\n:\n \n[\n\n \n{\n\n \nuuid\n:\n \n024a5797-e064-4ee0-abe3-415cb6d3ed18\n,\n\n \nid\n:\n \n6\n,\n\n \nslug\n:\n \nitem-id-024a5797-e064-4ee0-abe3-415cb6d3ed18\n \n// customizable\n\n \ntimestamp\n:\n \n1493926453826\n,\n \n// milliseconds since Unix epoch\n\n \nupdated\n:\n \n1493926453826\n,\n\n \n// your content data...,\n\n \n}\n\n \n]\n\n\n}\n\n\n\n\n\n\n\n\nGet Contents by Type\n\n\nGET\n \n/api/contents?type=\nType\n\n\n\n\noptional params:\n\n\norder\n (string: ASC / DESC, default: DESC)\n\n\ncount\n (int: -1 - N, default: 10, -1 returns all)\n\n\noffset\n (int: 0 - N, default: 0)\n\n\n\n\n\n\n\n\nSample Response\n\n\n{\n\n \ndata\n:\n \n[\n\n \n{\n\n \nuuid\n:\n \n024a5797-e064-4ee0-abe3-415cb6d3ed18\n,\n\n \nid\n:\n \n6\n,\n\n \nslug\n:\n \nitem-id-024a5797-e064-4ee0-abe3-415cb6d3ed18\n,\n \n// customizable\n\n \ntimestamp\n:\n \n1493926453826\n,\n \n// milliseconds since Unix epoch\n\n \nupdated\n:\n \n1493926453826\n,\n\n \n// your content data...,\n\n \n},\n\n \n{\n\n \nuuid\n:\n \n5a9177c7-634d-4fb1-88a6-ef6c45de797c\n,\n\n \nid\n:\n \n7\n,\n\n \nslug\n:\n \nitem-id-5a9177c7-634d-4fb1-88a6-ef6c45de797c\n,\n \n// customizable\n\n \ntimestamp\n:\n \n1493926453826\n,\n \n// milliseconds since Unix epoch\n\n \nupdated\n:\n \n1493926453826\n,\n\n \n// your content data...,\n\n \n},\n\n \n// more objects...\n\n \n]\n\n\n}\n\n\n\n\n\n\n\n\nGet Content by Slug\n\n\nGET\n \n/api/content?slug=\nSlug\n\n\nSample Response\n\n\n{\n\n \ndata\n:\n \n[\n\n \n{\n\n \nuuid\n:\n \n024a5797-e064-4ee0-abe3-415cb6d3ed18\n,\n\n \nid\n:\n \n6\n,\n\n \nslug\n:\n \nitem-id-024a5797-e064-4ee0-abe3-415cb6d3ed18\n,\n \n// customizable\n\n \ntimestamp\n:\n \n1493926453826\n,\n \n// milliseconds since Unix epoch\n\n \nupdated\n:\n \n1493926453826\n,\n\n \n// your content data...,\n\n \n}\n\n \n]\n\n\n}\n\n\n\n\n\n\n\n\nNew Content\n\n\nPOST\n \n/api/content/create?type=\nType\n\n\n\n\nRequest Data Encoding\n\n\nRequest must be \nmultipart/form-data\n encoded. If not, a \n400 Bad Request\n \nResponse will be returned.\n\n\n\n\nSample Response\n\n\n{\n\n \ndata\n:\n \n[\n\n \n{\n\n \nid\n:\n \n6\n,\n \n// will be omitted if status is pending\n\n \ntype\n:\n \nReview\n,\n\n \nstatus\n:\n \npublic\n\n \n}\n\n \n]\n\n\n}\n\n\n\n\n\n\n\n\nUpdate Content\n\n\nPOST\n \n/api/content/update?type=\nType\nid=\nid\n\n\n\n\nRequest Data Encoding\n\n\nRequest must be \nmultipart/form-data\n encoded. If not, a \n400 Bad Request\n \nResponse will be returned.\n\n\n\n\nSample Response\n\n\n{\n\n \ndata\n:\n \n[\n\n \n{\n\n \nid\n:\n \n6\n,\n\n \ntype\n:\n \nReview\n,\n\n \nstatus\n:\n \npublic\n\n \n}\n\n \n]\n\n\n}\n\n\n\n\n\n\n\n\nDelete Content\n\n\nPOST\n \n/api/content/delete?type=\nType\nid=\nid\n\n\n\n\nRequest Data Encoding\n\n\nRequest must be \nmultipart/form-data\n encoded. If not, a \n400 Bad Request\n \nResponse will be returned.\n\n\n\n\nSample Response\n\n\n{\n\n \ndata\n:\n \n[\n\n \n{\n\n \nid\n:\n \n6\n,\n\n \ntype\n:\n \nReview\n,\n\n \nstatus\n:\n \ndeleted\n\n \n}\n\n \n]\n\n\n}\n\n\n\n\n\n\n\n\nAdditional Information\n\n\nAll API endpoints are CORS-enabled (can be disabled in configuration at run-time) and API requests are recorded by your system to generate graphs of total requests and unique client requests within the Admin dashboard.\n\n\nResponse Headers\n\n\nThe following headers are common across all Ponzu API responses. Some of them can be modified\nin the \nsystem configuration\n while your system is running.\n\n\nHTTP/1.1\n\n\nHTTP/1.1 200 OK\nAccess-Control-Allow-Headers: Accept, Authorization, Content-Type\nAccess-Control-Allow-Origin: *\nCache-Control: max-age=2592000, public\nContent-Encoding: gzip\nContent-Type: application/json\nEtag: MTQ5Mzk0NTYzNQ==\nVary: Accept-Encoding\nDate: Fri, 05 May 2017 01:15:49 GMT\nContent-Length: 199\n\n\n\n\n\nHTTP/2\n\n\naccess-control-allow-headers: Accept, Authorization, Content-Type\naccess-control-allow-origin: *\ncache-control: max-age=2592000, public\ncontent-encoding: gzip\ncontent-length: 199\ncontent-type: application/json\ndate: Fri, 05 May 2017 01:38:11 GMT\netag: MTQ5Mzk0ODI4MA==\nstatus: 200\nvary: Accept-Encoding\n\n\n\n\n\nHelpful links\n\n\nTypewriter\n\nGenerate \n sync front-end data structures from Ponzu content types. (\nPonzu example\n)",
"title": "Content"
},
{
"location": "/HTTP-APIs/Content/#endpoints",
"text": "",
"title": "Endpoints"
},
{
"location": "/HTTP-APIs/Content/#get-content-by-type",
"text": "GET /api/content?type= Type id= ID",
"title": "Get Content by Type"
},
{
"location": "/HTTP-APIs/Content/#sample-response",
"text": "{ \n data : [ \n { \n uuid : 024a5797-e064-4ee0-abe3-415cb6d3ed18 , \n id : 6 , \n slug : item-id-024a5797-e064-4ee0-abe3-415cb6d3ed18 // customizable \n timestamp : 1493926453826 , // milliseconds since Unix epoch \n updated : 1493926453826 , \n // your content data..., \n } \n ] }",
"title": "Sample Response"
},
{
"location": "/HTTP-APIs/Content/#get-contents-by-type",
"text": "GET /api/contents?type= Type optional params: order (string: ASC / DESC, default: DESC) count (int: -1 - N, default: 10, -1 returns all) offset (int: 0 - N, default: 0)",
"title": "Get Contents by Type"
},
{
"location": "/HTTP-APIs/Content/#sample-response_1",
"text": "{ \n data : [ \n { \n uuid : 024a5797-e064-4ee0-abe3-415cb6d3ed18 , \n id : 6 , \n slug : item-id-024a5797-e064-4ee0-abe3-415cb6d3ed18 , // customizable \n timestamp : 1493926453826 , // milliseconds since Unix epoch \n updated : 1493926453826 , \n // your content data..., \n }, \n { \n uuid : 5a9177c7-634d-4fb1-88a6-ef6c45de797c , \n id : 7 , \n slug : item-id-5a9177c7-634d-4fb1-88a6-ef6c45de797c , // customizable \n timestamp : 1493926453826 , // milliseconds since Unix epoch \n updated : 1493926453826 , \n // your content data..., \n }, \n // more objects... \n ] }",
"title": "Sample Response"
},
{
"location": "/HTTP-APIs/Content/#get-content-by-slug",
"text": "GET /api/content?slug= Slug",
"title": "Get Content by Slug"
},
{
"location": "/HTTP-APIs/Content/#sample-response_2",
"text": "{ \n data : [ \n { \n uuid : 024a5797-e064-4ee0-abe3-415cb6d3ed18 , \n id : 6 , \n slug : item-id-024a5797-e064-4ee0-abe3-415cb6d3ed18 , // customizable \n timestamp : 1493926453826 , // milliseconds since Unix epoch \n updated : 1493926453826 , \n // your content data..., \n } \n ] }",
"title": "Sample Response"
},
{
"location": "/HTTP-APIs/Content/#new-content",
"text": "POST /api/content/create?type= Type Request Data Encoding Request must be multipart/form-data encoded. If not, a 400 Bad Request \nResponse will be returned.",
"title": "New Content"
},
{
"location": "/HTTP-APIs/Content/#sample-response_3",
"text": "{ \n data : [ \n { \n id : 6 , // will be omitted if status is pending \n type : Review , \n status : public \n } \n ] }",
"title": "Sample Response"
},
{
"location": "/HTTP-APIs/Content/#update-content",
"text": "POST /api/content/update?type= Type id= id Request Data Encoding Request must be multipart/form-data encoded. If not, a 400 Bad Request \nResponse will be returned.",
"title": "Update Content"
},
{
"location": "/HTTP-APIs/Content/#sample-response_4",
"text": "{ \n data : [ \n { \n id : 6 , \n type : Review , \n status : public \n } \n ] }",
"title": "Sample Response"
},
{
"location": "/HTTP-APIs/Content/#delete-content",
"text": "POST /api/content/delete?type= Type id= id Request Data Encoding Request must be multipart/form-data encoded. If not, a 400 Bad Request \nResponse will be returned.",
"title": "Delete Content"
},
{
"location": "/HTTP-APIs/Content/#sample-response_5",
"text": "{ \n data : [ \n { \n id : 6 , \n type : Review , \n status : deleted \n } \n ] }",
"title": "Sample Response"
},
{
"location": "/HTTP-APIs/Content/#additional-information",
"text": "All API endpoints are CORS-enabled (can be disabled in configuration at run-time) and API requests are recorded by your system to generate graphs of total requests and unique client requests within the Admin dashboard.",
"title": "Additional Information"
},
{
"location": "/HTTP-APIs/Content/#response-headers",
"text": "The following headers are common across all Ponzu API responses. Some of them can be modified\nin the system configuration while your system is running.",
"title": "Response Headers"
},
{
"location": "/HTTP-APIs/Content/#http11",
"text": "HTTP/1.1 200 OK\nAccess-Control-Allow-Headers: Accept, Authorization, Content-Type\nAccess-Control-Allow-Origin: *\nCache-Control: max-age=2592000, public\nContent-Encoding: gzip\nContent-Type: application/json\nEtag: MTQ5Mzk0NTYzNQ==\nVary: Accept-Encoding\nDate: Fri, 05 May 2017 01:15:49 GMT\nContent-Length: 199",
"title": "HTTP/1.1"
},
{
"location": "/HTTP-APIs/Content/#http2",
"text": "access-control-allow-headers: Accept, Authorization, Content-Type\naccess-control-allow-origin: *\ncache-control: max-age=2592000, public\ncontent-encoding: gzip\ncontent-length: 199\ncontent-type: application/json\ndate: Fri, 05 May 2017 01:38:11 GMT\netag: MTQ5Mzk0ODI4MA==\nstatus: 200\nvary: Accept-Encoding",
"title": "HTTP/2"
},
{
"location": "/HTTP-APIs/Content/#helpful-links",
"text": "Typewriter \nGenerate sync front-end data structures from Ponzu content types. ( Ponzu example )",
"title": "Helpful links"
},
{
"location": "/HTTP-APIs/File-Metadata/",
"text": "Ponzu provides a read-only HTTP API to get metadata about the files that have been uploaded to your system. As a security and bandwidth abuse precaution, the API is only queryable by \"slug\" which is the normalized filename of the uploaded file. \n\n\n\n\nEndpoints\n\n\nGet File by Slug (single item)\n\n\nGET\n \n/api/uploads?slug=\nSlug\n\n\nSample Response\n\n\n{\n\n \ndata\n:\n \n[\n\n \n{\n\n \nuuid\n:\n \n024a5797-e064-4ee0-abe3-415cb6d3ed18\n,\n\n \nid\n:\n \n6\n,\n\n \nslug\n:\n \nfilename.jpg\n,\n\n \ntimestamp\n:\n \n1493926453826\n,\n \n// milliseconds since Unix epoch\n\n \nupdated\n:\n \n1493926453826\n,\n\n \nname\n:\n \nfilename.jpg\n,\n\n \npath\n:\n \n/api/uploads/2017/05/filename.jpg\n,\n\n \ncontent_length\n:\n \n357557\n,\n\n \ncontent_type\n:\n \nimage/jpeg\n,\n\n \n}\n\n \n]\n\n\n}",
"title": "File Metadata"
},
{
"location": "/HTTP-APIs/File-Metadata/#endpoints",
"text": "",
"title": "Endpoints"
},
{
"location": "/HTTP-APIs/File-Metadata/#get-file-by-slug-single-item",
"text": "GET /api/uploads?slug= Slug",
"title": "Get File by Slug (single item)"
},
{
"location": "/HTTP-APIs/File-Metadata/#sample-response",
"text": "{ \n data : [ \n { \n uuid : 024a5797-e064-4ee0-abe3-415cb6d3ed18 , \n id : 6 , \n slug : filename.jpg , \n timestamp : 1493926453826 , // milliseconds since Unix epoch \n updated : 1493926453826 , \n name : filename.jpg , \n path : /api/uploads/2017/05/filename.jpg , \n content_length : 357557 , \n content_type : image/jpeg , \n } \n ] }",
"title": "Sample Response"
},
{
"location": "/HTTP-APIs/Search/",
"text": "Ponzu provides a read-only HTTP API to search the contents of your system's database. \nFull-text search is made possible by the use of \nBleve\n, \nwhich handles the indexing and querying. \n\n\n\n\nEndpoints\n\n\nSearch Content\n\n\nGET\n \n/api/search?type=\nType\nq=\nQuery String\n\n\n\n\nSearch must be enabled individually for each Content type\n\n\n\n\nSearch is not on by default to protect your data in case it shouldn't be indexed and published via the API.\n\n\nSearchMapping()\n is implemented with default mapping (ideal for 99% of use cases). \n\n\nTo enable search, add a \nIndexContent() bool\n method to your content type and return \ntrue\n (default implementation returns false).\n\n\n\n\n\n\n\n\n\n\nType\n must implement \ndb.Searchable\n\n\n\n\n\n\nSearch is currently limited to single \nType\n per request\n\n\n\n\n\n\nQuery String\n documentation here: \nBleve Docs - Query String\n\n\n\n\n\n\nSearch results are formatted exactly the same as standard Content API calls, so you don't need to change your client data model \n\n\n\n\n\n\nSearch handler will respect other interface implementations on your content, including: \n\n\n\n\nitem.Hideable\n\n\nitem.Omittable\n \n\n\nitem.Pushable\n \n(Note: only the first search result will be pushed)\n\n\n\n\n\n\n\n\nSample Response\n\n\n{\n\n \ndata\n:\n \n[\n\n \n{\n\n \nuuid\n:\n \n024a5797-e064-4ee0-abe3-415cb6d3ed18\n,\n\n \nid\n:\n \n6\n,\n\n \nslug\n:\n \nitem-id-024a5797-e064-4ee0-abe3-415cb6d3ed18\n,\n \n// customizable\n\n \ntimestamp\n:\n \n1493926453826\n,\n \n// milliseconds since Unix epoch\n\n \nupdated\n:\n \n1493926453826\n,\n\n \n// your content data...,\n\n \n}\n\n \n]\n\n\n}",
"title": "Search"
},
{
"location": "/HTTP-APIs/Search/#endpoints",
"text": "",
"title": "Endpoints"
},
{
"location": "/HTTP-APIs/Search/#search-content",
"text": "GET /api/search?type= Type q= Query String Search must be enabled individually for each Content type Search is not on by default to protect your data in case it shouldn't be indexed and published via the API. SearchMapping() is implemented with default mapping (ideal for 99% of use cases). To enable search, add a IndexContent() bool method to your content type and return true (default implementation returns false). Type must implement db.Searchable Search is currently limited to single Type per request Query String documentation here: Bleve Docs - Query String Search results are formatted exactly the same as standard Content API calls, so you don't need to change your client data model Search handler will respect other interface implementations on your content, including: item.Hideable item.Omittable item.Pushable (Note: only the first search result will be pushed)",
"title": "Search Content"
},
{
"location": "/HTTP-APIs/Search/#sample-response",
"text": "{ \n data : [ \n { \n uuid : 024a5797-e064-4ee0-abe3-415cb6d3ed18 , \n id : 6 , \n slug : item-id-024a5797-e064-4ee0-abe3-415cb6d3ed18 , // customizable \n timestamp : 1493926453826 , // milliseconds since Unix epoch \n updated : 1493926453826 , \n // your content data..., \n } \n ] }",
"title": "Sample Response"
},
{
"location": "/Interfaces/API/",
"text": "Ponzu provides a set of interfaces from the \nsystem/api\n package which enable \nricher interaction with your system from external clients. If you need to allow \n3rd-party apps to manage content, use the following interfaces.\n\n\nThe API interfaces adhere to a common function signature, expecting an \n\nhttp.ResponseWriter\n and \n*http.Request\n as arguments and returning an \nerror\n.\nThis provides Ponzu developers with full control over the request/response \nlife-cycle.\n\n\n\n\nInterfaces\n\n\napi.Createable\n\n\nExternalable enables 3rd-party clients (outside the CMS) to send content via a \n\nmultipart/form-data\n encoded \nPOST\n request to a specific endpoint: \n\n/api/content/create?type=\nType\n. When \napi.Createable\n is implemented, content \nwill be saved from the request in a \"Pending\" section which will is visible only \nwithin the CMS.\n\n\nTo work with \"Pending\" data, implement the \neditor.Mergeable\n\ninterface, which will add \"Approve\" and \"Reject\" buttons to your Content types'\neditor -- or implement \napi.Trustable\n to bypass \nthe \"Pending\" section altogether and become \"Public\" immediately. \n\n\nMethod Set\n\n\ntype\n \nCreateable\n \ninterface\n \n{\n\n \nCreate\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n\n}\n\n\n\n\n\n\nImplementation\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nCreate\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\n\n\napi.Updateable\n\n\nUpdateable enables 3rd-party clients (outside the CMS) to update existing content \nvia a \nmultipart/form-data\n encoded \nPOST\n request to a specific endpoint: \n\n/api/content/update?type=\nType\nid=\nid\n. Request validation should be employed \notherwise any client could change data in your database.\n\n\nMethod Set\n\n\ntype\n \nUpdateable\n \ninterface\n \n{\n\n \nUpdate\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n\n}\n\n\n\n\n\n\nImplementation\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nUpdate\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\n\n\napi.Deleteable\n\n\nUpdateable enables 3rd-party clients (outside the CMS) to delete existing content \nvia a \nmultipart/form-data\n encoded \nPOST\n request to a specific endpoint: \n\n/api/content/delete?type=\nType\nid=\nid\n. Request validation should be employed \notherwise any client could delete data from your database.\n\n\nMethod Set\n\n\ntype\n \nDeleteable\n \ninterface\n \n{\n\n \nDelete\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n\n}\n\n\n\n\n\n\nImplementation\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nDelete\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\n\n\napi.Trustable\n\n\nTrustable provides a way for submitted content (via \napi.Createable\n) to bypass \nthe \neditor.Mergeable\n step in which CMS end-users must manually click the \n\"Approve\" button in order for content to be put in the \"Public\" section and access \nvia the content API endpoints. \napi.Trustable\n has a single method: \nAutoApprove\n \nwhich will automatically approve content, bypassing the \"Pending\" section \naltogether.\n\n\ntype\n \nTrustable\n \ninterface\n \n{\n\n \nAutoApprove\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n\n}\n\n\n\n\n\n\nImplementation\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nAutoApprove\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}",
"title": "API"
},
{
"location": "/Interfaces/API/#interfaces",
"text": "",
"title": "Interfaces"
},
{
"location": "/Interfaces/API/#apicreateable",
"text": "Externalable enables 3rd-party clients (outside the CMS) to send content via a multipart/form-data encoded POST request to a specific endpoint: /api/content/create?type= Type . When api.Createable is implemented, content \nwill be saved from the request in a \"Pending\" section which will is visible only \nwithin the CMS. To work with \"Pending\" data, implement the editor.Mergeable \ninterface, which will add \"Approve\" and \"Reject\" buttons to your Content types'\neditor -- or implement api.Trustable to bypass \nthe \"Pending\" section altogether and become \"Public\" immediately.",
"title": "api.Createable"
},
{
"location": "/Interfaces/API/#method-set",
"text": "type Createable interface { \n Create ( http . ResponseWriter , * http . Request ) error }",
"title": "Method Set"
},
{
"location": "/Interfaces/API/#implementation",
"text": "func ( p * Post ) Create ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "Implementation"
},
{
"location": "/Interfaces/API/#apiupdateable",
"text": "Updateable enables 3rd-party clients (outside the CMS) to update existing content \nvia a multipart/form-data encoded POST request to a specific endpoint: /api/content/update?type= Type id= id . Request validation should be employed \notherwise any client could change data in your database.",
"title": "api.Updateable"
},
{
"location": "/Interfaces/API/#method-set_1",
"text": "type Updateable interface { \n Update ( http . ResponseWriter , * http . Request ) error }",
"title": "Method Set"
},
{
"location": "/Interfaces/API/#implementation_1",
"text": "func ( p * Post ) Update ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "Implementation"
},
{
"location": "/Interfaces/API/#apideleteable",
"text": "Updateable enables 3rd-party clients (outside the CMS) to delete existing content \nvia a multipart/form-data encoded POST request to a specific endpoint: /api/content/delete?type= Type id= id . Request validation should be employed \notherwise any client could delete data from your database.",
"title": "api.Deleteable"
},
{
"location": "/Interfaces/API/#method-set_2",
"text": "type Deleteable interface { \n Delete ( http . ResponseWriter , * http . Request ) error }",
"title": "Method Set"
},
{
"location": "/Interfaces/API/#implementation_2",
"text": "func ( p * Post ) Delete ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "Implementation"
},
{
"location": "/Interfaces/API/#apitrustable",
"text": "Trustable provides a way for submitted content (via api.Createable ) to bypass \nthe editor.Mergeable step in which CMS end-users must manually click the \n\"Approve\" button in order for content to be put in the \"Public\" section and access \nvia the content API endpoints. api.Trustable has a single method: AutoApprove \nwhich will automatically approve content, bypassing the \"Pending\" section \naltogether. type Trustable interface { \n AutoApprove ( http . ResponseWriter , * http . Request ) error }",
"title": "api.Trustable"
},
{
"location": "/Interfaces/API/#implementation_3",
"text": "func ( p * Post ) AutoApprove ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "Implementation"
},
{
"location": "/Interfaces/Editor/",
"text": "Ponzu provides a set of interfaces from the \nmanagement/editor\n package which \nextend the system's functionality and determine how content editors are rendered \nwithin the CMS.\n\n\n\n\nInterfaces\n\n\neditor.Editable\n\n\nEditable determines what \n[]bytes\n are rendered inside the editor page. Use \nEdtiable on anything inside your CMS that you want to provide configuration, editable \nfields, or any HTML/markup to display to an end-user.\n\n\n\n\nImplementing \neditor.Editable\n\n\nMost of the time, Ponzu developers generate the majority of this code using \nthe Ponzu CLI \ngenerate\n command\n.\n\n\n\n\nMethod Set\n\n\ntype\n \nEditable\n \ninterface\n \n{\n\n \nMarshalEditor\n()\n \n([]\nbyte\n,\n \nerror\n)\n\n\n}\n\n\n\n\n\n\nImplementation\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nMarshalEditor\n()\n \n([]\nbyte\n,\n \nerror\n)\n \n{\n\n \n// The editor.Form func sets up a structured UI with default styles and form\n\n \n// elements based on the fields provided. Most often, Ponzu developers will\n\n \n// have the `$ ponzu generate` command generate the MarshalEditor func and \n\n \n// its internal form fields\n\n \nview\n,\n \nerr\n \n:=\n \neditor\n.\nForm\n(\np\n,\n\n \neditor\n.\nField\n{\n\n \nView\n:\n \neditor\n.\nInput\n(\nName\n,\n \np\n,\n \nmap\n[\nstring\n]\nstring\n{\n\n \nlabel\n:\n \nName\n,\n\n \ntype\n:\n \ntext\n,\n\n \nplaceholder\n:\n \nEnter the Name here\n,\n\n \n}),\n\n \n},\n\n \n)\n\n\n}\n\n\n\n\n\n\n\n\nMarshalEditor() \n View Rendering\n\n\nAlthough it is common to use the \neditor.Form\n and \neditor.Fields\n to structure your content editor inside \nMarshalEditor()\n, the method signature defines that its return value needs only to be \n[]byte, error\n. Keep in mind that you can return a \n[]byte\n of any raw HTML or other markup to be rendered in the editor view.\n\n\n\n\n\n\neditor.Mergeable\n\n\nMergable enables a CMS end-user to merge the \"Pending\" content from an outside source into the \"Public\" section, and thus making it visible via the public content API. It also allows the end-user to reject content. \"Approve\" and \"Reject\" buttons will be visible on the edit page for content submitted.\n\n\nMethod Set\n\n\ntype\n \nMergeable\n \ninterface\n \n{\n\n \nApprove\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n\n}\n\n\n\n\n\n\nExample\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nApprove\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}",
"title": "Editor"
},
{
"location": "/Interfaces/Editor/#interfaces",
"text": "",
"title": "Interfaces"
},
{
"location": "/Interfaces/Editor/#editoreditable",
"text": "Editable determines what []bytes are rendered inside the editor page. Use \nEdtiable on anything inside your CMS that you want to provide configuration, editable \nfields, or any HTML/markup to display to an end-user. Implementing editor.Editable Most of the time, Ponzu developers generate the majority of this code using \nthe Ponzu CLI generate command .",
"title": "editor.Editable"
},
{
"location": "/Interfaces/Editor/#method-set",
"text": "type Editable interface { \n MarshalEditor () ([] byte , error ) }",
"title": "Method Set"
},
{
"location": "/Interfaces/Editor/#implementation",
"text": "func ( p * Post ) MarshalEditor () ([] byte , error ) { \n // The editor.Form func sets up a structured UI with default styles and form \n // elements based on the fields provided. Most often, Ponzu developers will \n // have the `$ ponzu generate` command generate the MarshalEditor func and \n // its internal form fields \n view , err := editor . Form ( p , \n editor . Field { \n View : editor . Input ( Name , p , map [ string ] string { \n label : Name , \n type : text , \n placeholder : Enter the Name here , \n }), \n }, \n ) } MarshalEditor() View Rendering Although it is common to use the editor.Form and editor.Fields to structure your content editor inside MarshalEditor() , the method signature defines that its return value needs only to be []byte, error . Keep in mind that you can return a []byte of any raw HTML or other markup to be rendered in the editor view.",
"title": "Implementation"
},
{
"location": "/Interfaces/Editor/#editormergeable",
"text": "Mergable enables a CMS end-user to merge the \"Pending\" content from an outside source into the \"Public\" section, and thus making it visible via the public content API. It also allows the end-user to reject content. \"Approve\" and \"Reject\" buttons will be visible on the edit page for content submitted.",
"title": "editor.Mergeable"
},
{
"location": "/Interfaces/Editor/#method-set_1",
"text": "type Mergeable interface { \n Approve ( http . ResponseWriter , * http . Request ) error }",
"title": "Method Set"
},
{
"location": "/Interfaces/Editor/#example",
"text": "func ( p * Post ) Approve ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "Example"
},
{
"location": "/Interfaces/Format/",
"text": "Ponzu provides a set of interfaces from the \nmanagement/format\n package which \ndetermine how content data should be converted and formatted for exporting via\nthe Admin interface.\n\n\n\n\nInterfaces\n\n\nformat.CSVFormattable\n\n\nCSVFormattable controls if an \"Export\" button is added to the contents view for \na Content type in the CMS to export the data to CSV. If it is implemented, a\nbutton will be present beneath the \"New\" button per Content type. \n\n\nMethod Set\n\n\ntype\n \nCSVFormattable\n \ninterface\n \n{\n\n \nFormatCSV\n()\n \n[]\nstring\n\n\n}\n\n\n\n\n\n\nImplementation\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nFormatCSV\n()\n \n[]\nstring\n \n{\n\n \n// []string contains the JSON struct tags generated for your Content type \n\n \n// implementing the interface\n\n \nreturn\n \n[]\nstring\n{\n\n \nid\n,\n\n \ntimestamp\n,\n\n \nslug\n,\n\n \ntitle\n,\n\n \nphotos\n,\n\n \nbody\n,\n\n \nwritten_by\n,\n\n \n}\n\n\n}\n\n\n\n\n\n\n\n\nFormatCSV() []string\n\n\nJust like other Ponzu content extension interfaces, like \nPush()\n, you will \nreturn the JSON struct tags for the fields you want exported to the CSV file. \nThese will also be the \"header\" row in the CSV file to give titles to the file\ncolumns. Keep in mind that all of item.Item's fields are available here as well.",
"title": "Format"
},
{
"location": "/Interfaces/Format/#interfaces",
"text": "",
"title": "Interfaces"
},
{
"location": "/Interfaces/Format/#formatcsvformattable",
"text": "CSVFormattable controls if an \"Export\" button is added to the contents view for \na Content type in the CMS to export the data to CSV. If it is implemented, a\nbutton will be present beneath the \"New\" button per Content type.",
"title": "format.CSVFormattable"
},
{
"location": "/Interfaces/Format/#method-set",
"text": "type CSVFormattable interface { \n FormatCSV () [] string }",
"title": "Method Set"
},
{
"location": "/Interfaces/Format/#implementation",
"text": "func ( p * Post ) FormatCSV () [] string { \n // []string contains the JSON struct tags generated for your Content type \n // implementing the interface \n return [] string { \n id , \n timestamp , \n slug , \n title , \n photos , \n body , \n written_by , \n } } FormatCSV() []string Just like other Ponzu content extension interfaces, like Push() , you will \nreturn the JSON struct tags for the fields you want exported to the CSV file. \nThese will also be the \"header\" row in the CSV file to give titles to the file\ncolumns. Keep in mind that all of item.Item's fields are available here as well.",
"title": "Implementation"
},
{
"location": "/Interfaces/Item/",
"text": "Ponzu provides a set of interfaces from the \nsystem/item\n package which extend \nthe functionality of the content in your system and how it interacts with other \ncomponents inside and outside of Ponzu. \n\n\n\n\nInterfaces\n\n\nitem.Pushable\n\n\nPushable, if \nHTTP/2 Server Push\n \nis supported by the client, can tell a handler which resources it would like to \nhave \"pushed\" preemptively to the client. This saves follow-on roundtrip requests \nfor other items which are referenced by the Pushable item. The \nPush\n method, the \nonly method in Pushable, must return a \n[]string\n containing the \njson\n field tags \nof the referenced items within the type.\n\n\nMethod Set\n\n\ntype\n \nPushable\n \ninterface\n \n{\n\n \n// the values contained in []string fields returned by Push must be URL paths\n\n \nPush\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \n([]\nstring\n,\n \nerror\n)\n\n\n}\n\n\n\n\n\n\nImplementation\n\n\nThe \nPush\n method returns a \n[]string\n containing the \njson\n tag field names for\nwhich you want to have pushed to a supported client and an error value. The values \nfor the field names \nmust\n be URL paths, and cannot be from another origin.\n\n\ntype\n \nPost\n \nstruct\n \n{\n\n \nitem\n.\nItem\n\n\n \nHeaderPhoto\n \nstring\n \n`json:\nheader_photo\n`\n\n \nAuthor\n \nstring\n \n`json:\nauthor\n`\n \n// reference `/api/content/?type=Author\nid=2`\n\n \n// ...\n\n\n}\n\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nPush\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \n([]\nstring\n,\n \nerror\n)\n \n{\n\n \nreturn\n \n[]\nstring\n{\n\n \nheader_photo\n,\n\n \nauthor\n,\n\n \n},\n \nnil\n\n\n}\n\n\n\n\n\n\n\n\nitem.Hideable\n\n\nHideable tells an API handler that data of this type shouldn\u2019t be exposed outside \nthe system. Hideable types cannot be used as references (relations in Content types).\nThe \nHide\n method, the only method in Hideable, takes an \nhttp.ResponseWriter, *http.Request\n \nand returns an \nerror\n. A special error in the \nitems\n package, \nErrAllowHiddenItem\n \ncan be returned as the error from Hide to instruct handlers to show hidden \ncontent in specific cases.\n\n\nMethod Set\n\n\ntype\n \nHideable\n \ninterface\n \n{\n\n \nHide\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n\n}\n\n\n\n\n\n\nImplementation\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nHide\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\n\n\nitem.Omittable\n\n\nOmittable tells a content API handler to keep certain fields from being exposed \nthrough the JSON response. It's single method, \nOmit\n takes no arguments and \nreturns a \n[]string\n which must be made up of the JSON struct tags for the type \ncontaining fields to be omitted and an error value.\n\n\nMethod Set\n\n\ntype\n \nOmittable\n \ninterface\n \n{\n\n \nOmit\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \n([]\nstring\n,\n \nerror\n)\n\n\n}\n\n\n\n\n\n\nImplementation\n\n\ntype\n \nPost\n \nstruct\n \n{\n\n \nitem\n.\nItem\n\n\n \nHeaderPhoto\n \nstring\n \n`json:\nheader_photo\n`\n\n \nAuthor\n \nstring\n \n`json:\nauthor\n`\n\n \n// ...\n\n\n}\n\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nOmit\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \n([]\nstring\n,\n \nerror\n)\n \n{\n\n \nreturn\n \n[]\nstring\n{\n\n \nheader_photo\n,\n\n \nauthor\n,\n\n \n},\n \nnil\n\n\n}\n\n\n\n\n\n\n\n\nitem.Hookable\n\n\nHookable provides lifecycle hooks into the http handlers which manage Save, Delete,\nApprove, and Reject routines. All methods in its set take an \n\nhttp.ResponseWriter, *http.Request\n and return an \nerror\n.\n\n\nMethod Set\n\n\ntype\n \nHookable\n \ninterface\n \n{\n\n \nBeforeAPICreate\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n \nAfterAPICreate\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n\n \nBeforeAPIUpdate\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n \nAfterAPIUpdate\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n\n \nBeforeAPIDelete\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n \nAfterAPIDelete\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n\n \nBeforeAdminCreate\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n \nAfterAdminCreate\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n\n \nBeforeAdminUpdate\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n \nAfterAdminUpdate\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n\n \nBeforeAdminDelete\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n \nAfterAdminDelete\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n\n \nBeforeSave\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n \nAfterSave\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n\n \nBeforeDelete\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n \nAfterDelete\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n\n \nBeforeApprove\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n \nAfterApprove\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n\n \nBeforeReject\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n \nAfterReject\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n\n \n// Enable/Disable used exclusively for addons\n\n \nBeforeEnable\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n \nAfterEnable\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n\n \nBeforeDisable\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n \nAfterDisable\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n\n\n}\n\n\n\n\n\n\nImplementations\n\n\nBeforeAPICreate\n\n\nBeforeAPICreate is called before an item is created via a 3rd-party client. If a \nnon-nil \nerror\n value is returned, the item will not be created/saved.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nBeforeAPICreate\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nAfterAPICreate\n\n\nAfterAPICreate is called after an item has been created via a 3rd-party client.\nAt this point, the item has been saved to the database. If a non-nil \nerror\n is\nreturned, it will respond to the client with an empty response, so be sure to \nuse the \nhttp.ResponseWriter\n from within your hook appropriately.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nAfterAPICreate\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nBeforeApprove\n\n\nBeforeApprove is called before an item is merged as \"Public\" from its prior \nstatus as \"Pending\". If a non-nil \nerror\n value is returned, the item will not be\nappproved, and an error message is displayed to the Admin. \n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nBeforeApprove\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nAfterApprove\n\n\nAfterApprove is called after an item has been merged as \"Public\" from its prior\nstatus as \"Pending\". If a non-nil \nerror\n is returned, an error message is \ndisplayed to the Admin, however the item will already be irreversibly merged.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nAfterApprove\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nBeforeReject\n\n\nBeforeReject is called before an item is rejected and deleted by default. To reject\nan item, but not delete it, return a non-nil \nerror\n from this hook - doing so \nwill allow the hook to do what you want it to do prior to the return, but the item\nwill remain in the \"Pending\" section.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nBeforeReject\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nAfterReject\n\n\nAfterReject is called after an item is rejected and has been deleted.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nAfterReject\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nBeforeSave\n\n\nBeforeSave is called before any CMS Admin or 3rd-party client triggers a save to \nthe database. This could be done by clicking the 'Save' button on a Content editor, \nor by a API call to Create or Update the Content item. By returning a non-nil \n\nerror\n value, the item will not be saved.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nBeforeSave\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nAfterSave\n\n\nAfterSave is called after any CMS Admin or 3rd-party client triggers a save to \nthe database. This could be done by clicking the 'Save' button on a Content editor, \nor by a API call to Create or Update the Content item.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nAfterSave\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nBeforeDelete\n\n\nBeforeDelete is called before any CMS Admin or 3rd-party client triggers a delete to \nthe database. This could be done by clicking the 'Delete' button on a Content editor, \nor by a API call to Delete the Content item. By returning a non-nil \nerror\n value,\nthe item will not be deleted.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nBeforeDelete\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nAfterDelete\n\n\nAfterSave is called after any CMS Admin or 3rd-party client triggers a delete to \nthe database. This could be done by clicking the 'Delete' button on a Content editor, \nor by a API call to Delete the Content item.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nAfterDelete\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nBeforeAPIDelete\n\n\nBeforeDelete is only called before a 3rd-party client triggers a delete to the \ndatabase. By returning a non-nil \nerror\n value, the item will not be deleted.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nBeforeAPIDelete\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nAfterAPIDelete\n\n\nAfterAPIDelete is only called after a 3rd-party client triggers a delete to the \ndatabase.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nAfterAPIDelete\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nBeforeAPIUpdate\n\n\nBeforeAPIUpdate is only called before a 3rd-party client triggers an update to \nthe database. By returning a non-nil \nerror\n value, the item will not be updated.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nBeforeAPIUpdate\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nAfterAPIUpdate\n\n\nAfterAPIUpdate is only called after a 3rd-party client triggers an update to \nthe database.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nAfterAPIUpdate\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nBeforeAdminCreate\n\n\nBeforeAdminCreate is only called before a CMS Admin creates a new Content item.\nIt is not called for subsequent saves to the item once it has been created and \nassigned an ID. By returning a non-nil \nerror\n value, the item will not be created.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nBeforeAdminCreate\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nAfterAdminCreate\n\n\nAfterAdminCreate is only called after a CMS Admin creates a new Content item.\nIt is not called for subsequent saves to the item once it has been created and \nassigned an ID.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nAfterAdminCreate\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nBeforeAdminUpdate\n\n\nBeforeAdminUpdate is only called before a CMS Admin updates a Content item. By \nreturning a non-nil \nerror\n, the item will not be updated.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nBeforeAdminUpdate\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nAfterAdminUpdate\n\n\nAfterAdminUpdate is only called after a CMS Admin updates a Content item.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nAfterAdminUpdate\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nBeforeAdminDelete\n\n\nBeforeAdminDelete is only called before a CMS Admin deletes a Content item. By\nreturning a non-nil \nerror\n value, the item will not be deleted.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nBeforeAdminDelete\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nAfterAdminDelete\n\n\nAfterAdminDelete is only called after a CMS Admin deletes a Content item.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nAfterAdminDelete\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nBeforeEnable\n\n\nBeforeEnable is only applicable to Addon items, and is called before the addon\nchanges status to \"Enabled\". By returning a non-nil \nerror\n value, the addon\nwill not become enabled.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nBeforeEnable\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nAfterEnable\n\n\nAfterEnable is only applicable to Addon items, and is called after the addon \nchanges status to \"Enabled\".\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nAfterEnable\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nBeforeDisable\n\n\nBeforeDisable is only applicable to Addon items, and is called before the addon\nchanges status to \"Disabled\". By returning a non-nil \nerror\n value, the addon\nwill not become disabled.\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nBeforeDisable\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nAfterDisable\n\n\nAfterDisable is only applicable to Addon items, and is called after the addon \nchanges status to \"Disabled\".\n\n\nfunc\n \n(\np\n \n*\nPost\n)\n \nAfterDisable\n(\nhttp\n.\nResponseWriter\n,\n \n*\nhttp\n.\nRequest\n)\n \nerror\n \n{\n\n \nreturn\n \nnil\n\n\n}\n\n\n\n\n\n\nHookable is implemented by Item by default as no-ops which are expected to be overridden. \n\n\n\n\nNote\n\n\nreturning an error from any of these \nHookable\n methods will end the request, \ncausing it to halt immediately after the hook. For example, returning an \nerror\n \nfrom \nBeforeDelete\n will result in the content being kept in the database. \nThe same logic applies to all of these interface methods that return an error \n- \nthe error defines the behavior\n.\n\n\n\n\n\n\nitem.Identifiable\n\n\nIdentifiable enables a struct to have its ID set/get. Typically this is done to set an ID to -1 indicating it is new for DB inserts, since by default a newly initialized struct would have an ID of 0, the int zero-value, and BoltDB's starting key per bucket is 0, thus overwriting the first record.\nMost notable, Identifiable\u2019s \nString\n method is used to set a meaningful display name for an Item. \nString\n is called by default in the Admin dashboard to show the Items of certain types, and in the default creation of an Item\u2019s slug.\nIdentifiable is implemented by Item by default.\n\n\nMethod Set\n\n\ntype\n \nIdentifiable\n \ninterface\n \n{\n\n \nItemID\n()\n \nint\n\n \nSetItemID\n(\nint\n)\n\n \nUniqueID\n()\n \nuuid\n.\nUUID\n\n \nString\n()\n \nstring\n\n\n}\n\n\n\n\n\n\nImplementation\n\n\nitem.Identifiable\n has a default implementation in the \nsystem/item\n package. \nIt is not advised to override these methods, with the exception of \nString()\n, \nwhich is commonly used to set the display name of Content items when listed in \nthe CMS, and to customize slugs.\n\n\nfunc\n \n(\ni\n \nItem\n)\n \nItemID\n()\n \nint\n \n{\n\n \nreturn\n \ni\n.\nID\n\n\n}\n\n\n\nfunc\n \n(\ni\n \n*\nItem\n)\n \nSetItemID\n(\nid\n \nint\n)\n \n{\n\n \ni\n.\nID\n \n=\n \nid\n\n\n}\n\n\n\nfunc\n \n(\ni\n \nItem\n)\n \nUniqueID\n()\n \nuuid\n.\nUUID\n \n{\n\n \nreturn\n \ni\n.\nUUID\n\n\n}\n\n\n\nfunc\n \n(\ni\n \nItem\n)\n \nString\n()\n \nstring\n \n{\n\n \nreturn\n \nfmt\n.\nSprintf\n(\nItem ID: %s\n,\n \ni\n.\nUniqueID\n())\n\n\n}\n\n\n\n\n\n\n\n\nitem.Sluggable\n\n\nSluggable makes a struct locatable by URL with it's own path. As an Item implementing Sluggable, slugs may overlap. If this is an issue, make your content struct (or one which embeds Item) implement Sluggable and it will override the slug created by Item's \nSetSlug\n method with your own.\nIt is not recommended to override \nSetSlug\n, but rather the \nString\n method on your content struct, which will have a similar, more predictable effect.\nSluggable is implemented by Item by default.\n\n\nMethod Set\n\n\ntype\n \nSluggable\n \ninterface\n \n{\n\n \nSetSlug\n(\nstring\n)\n\n \nItemSlug\n()\n \nstring\n\n\n}\n\n\n\n\n\n\nImplementation\n\n\nitem.Sluggable\n has a default implementation in the \nsystem/item\n package. It is\npossible to override these methods on your own Content types, but beware, behavior\nis undefined. It is tempting to override the \nSetSlug()\n method to customize your\nContent item slug, but try first to override the \nString()\n method found in the\n\nitem.Identifiable\n interface instead. If you don't get the desired results, try\n\nSetSlug()\n.\n\n\nfunc\n \n(\ni\n \n*\nItem\n)\n \nSetSlug\n(\nslug\n \nstring\n)\n \n{\n\n \ni\n.\nSlug\n \n=\n \nslug\n\n\n}\n\n\n\nfunc\n \n(\ni\n \n*\nItem\n)\n \nItemSlug\n()\n \nstring\n \n{\n\n \nreturn\n \ni\n.\nSlug\n\n\n}\n\n\n\n\n\n\n\n\nitem.Sortable\n\n\nSortable enables items to be sorted by time, as per the sort.Interface interface. Sortable is implemented by Item by default.\n\n\nMethod Set\n\n\ntype\n \nSortable\n \ninterface\n \n{\n\n \nTime\n()\n \nint64\n\n \nTouch\n()\n \nint64\n\n\n}\n\n\n\n\n\n\nImplementation\n\n\nitem.Sortable\n has a default implementation in the \nsystem/item\n package. It is\npossible to override these methods on your own Content type, but beware, behavior \nis undefined.\n\n\nfunc\n \n(\ni\n \nItem\n)\n \nTime\n()\n \nint64\n \n{\n\n \nreturn\n \ni\n.\nTimestamp\n\n\n}\n\n\n\nfunc\n \n(\ni\n \nItem\n)\n \nTouch\n()\n \nint64\n \n{\n\n \nreturn\n \ni\n.\nUpdated\n\n\n}",
"title": "Item"
},
{
"location": "/Interfaces/Item/#interfaces",
"text": "",
"title": "Interfaces"
},
{
"location": "/Interfaces/Item/#itempushable",
"text": "Pushable, if HTTP/2 Server Push \nis supported by the client, can tell a handler which resources it would like to \nhave \"pushed\" preemptively to the client. This saves follow-on roundtrip requests \nfor other items which are referenced by the Pushable item. The Push method, the \nonly method in Pushable, must return a []string containing the json field tags \nof the referenced items within the type.",
"title": "item.Pushable"
},
{
"location": "/Interfaces/Item/#method-set",
"text": "type Pushable interface { \n // the values contained in []string fields returned by Push must be URL paths \n Push ( http . ResponseWriter , * http . Request ) ([] string , error ) }",
"title": "Method Set"
},
{
"location": "/Interfaces/Item/#implementation",
"text": "The Push method returns a []string containing the json tag field names for\nwhich you want to have pushed to a supported client and an error value. The values \nfor the field names must be URL paths, and cannot be from another origin. type Post struct { \n item . Item \n\n HeaderPhoto string `json: header_photo ` \n Author string `json: author ` // reference `/api/content/?type=Author id=2` \n // ... } func ( p * Post ) Push ( res http . ResponseWriter , req * http . Request ) ([] string , error ) { \n return [] string { \n header_photo , \n author , \n }, nil }",
"title": "Implementation"
},
{
"location": "/Interfaces/Item/#itemhideable",
"text": "Hideable tells an API handler that data of this type shouldn\u2019t be exposed outside \nthe system. Hideable types cannot be used as references (relations in Content types).\nThe Hide method, the only method in Hideable, takes an http.ResponseWriter, *http.Request \nand returns an error . A special error in the items package, ErrAllowHiddenItem \ncan be returned as the error from Hide to instruct handlers to show hidden \ncontent in specific cases.",
"title": "item.Hideable"
},
{
"location": "/Interfaces/Item/#method-set_1",
"text": "type Hideable interface { \n Hide ( http . ResponseWriter , * http . Request ) error }",
"title": "Method Set"
},
{
"location": "/Interfaces/Item/#implementation_1",
"text": "func ( p * Post ) Hide ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "Implementation"
},
{
"location": "/Interfaces/Item/#itemomittable",
"text": "Omittable tells a content API handler to keep certain fields from being exposed \nthrough the JSON response. It's single method, Omit takes no arguments and \nreturns a []string which must be made up of the JSON struct tags for the type \ncontaining fields to be omitted and an error value.",
"title": "item.Omittable"
},
{
"location": "/Interfaces/Item/#method-set_2",
"text": "type Omittable interface { \n Omit ( http . ResponseWriter , * http . Request ) ([] string , error ) }",
"title": "Method Set"
},
{
"location": "/Interfaces/Item/#implementation_2",
"text": "type Post struct { \n item . Item \n\n HeaderPhoto string `json: header_photo ` \n Author string `json: author ` \n // ... } func ( p * Post ) Omit ( res http . ResponseWriter , req * http . Request ) ([] string , error ) { \n return [] string { \n header_photo , \n author , \n }, nil }",
"title": "Implementation"
},
{
"location": "/Interfaces/Item/#itemhookable",
"text": "Hookable provides lifecycle hooks into the http handlers which manage Save, Delete,\nApprove, and Reject routines. All methods in its set take an http.ResponseWriter, *http.Request and return an error .",
"title": "item.Hookable"
},
{
"location": "/Interfaces/Item/#method-set_3",
"text": "type Hookable interface { \n BeforeAPICreate ( http . ResponseWriter , * http . Request ) error \n AfterAPICreate ( http . ResponseWriter , * http . Request ) error \n\n BeforeAPIUpdate ( http . ResponseWriter , * http . Request ) error \n AfterAPIUpdate ( http . ResponseWriter , * http . Request ) error \n\n BeforeAPIDelete ( http . ResponseWriter , * http . Request ) error \n AfterAPIDelete ( http . ResponseWriter , * http . Request ) error \n\n BeforeAdminCreate ( http . ResponseWriter , * http . Request ) error \n AfterAdminCreate ( http . ResponseWriter , * http . Request ) error \n\n BeforeAdminUpdate ( http . ResponseWriter , * http . Request ) error \n AfterAdminUpdate ( http . ResponseWriter , * http . Request ) error \n\n BeforeAdminDelete ( http . ResponseWriter , * http . Request ) error \n AfterAdminDelete ( http . ResponseWriter , * http . Request ) error \n\n BeforeSave ( http . ResponseWriter , * http . Request ) error \n AfterSave ( http . ResponseWriter , * http . Request ) error \n\n BeforeDelete ( http . ResponseWriter , * http . Request ) error \n AfterDelete ( http . ResponseWriter , * http . Request ) error \n\n BeforeApprove ( http . ResponseWriter , * http . Request ) error \n AfterApprove ( http . ResponseWriter , * http . Request ) error \n\n BeforeReject ( http . ResponseWriter , * http . Request ) error \n AfterReject ( http . ResponseWriter , * http . Request ) error \n\n // Enable/Disable used exclusively for addons \n BeforeEnable ( http . ResponseWriter , * http . Request ) error \n AfterEnable ( http . ResponseWriter , * http . Request ) error \n\n BeforeDisable ( http . ResponseWriter , * http . Request ) error \n AfterDisable ( http . ResponseWriter , * http . Request ) error }",
"title": "Method Set"
},
{
"location": "/Interfaces/Item/#implementations",
"text": "",
"title": "Implementations"
},
{
"location": "/Interfaces/Item/#beforeapicreate",
"text": "BeforeAPICreate is called before an item is created via a 3rd-party client. If a \nnon-nil error value is returned, the item will not be created/saved. func ( p * Post ) BeforeAPICreate ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "BeforeAPICreate"
},
{
"location": "/Interfaces/Item/#afterapicreate",
"text": "AfterAPICreate is called after an item has been created via a 3rd-party client.\nAt this point, the item has been saved to the database. If a non-nil error is\nreturned, it will respond to the client with an empty response, so be sure to \nuse the http.ResponseWriter from within your hook appropriately. func ( p * Post ) AfterAPICreate ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "AfterAPICreate"
},
{
"location": "/Interfaces/Item/#beforeapprove",
"text": "BeforeApprove is called before an item is merged as \"Public\" from its prior \nstatus as \"Pending\". If a non-nil error value is returned, the item will not be\nappproved, and an error message is displayed to the Admin. func ( p * Post ) BeforeApprove ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "BeforeApprove"
},
{
"location": "/Interfaces/Item/#afterapprove",
"text": "AfterApprove is called after an item has been merged as \"Public\" from its prior\nstatus as \"Pending\". If a non-nil error is returned, an error message is \ndisplayed to the Admin, however the item will already be irreversibly merged. func ( p * Post ) AfterApprove ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "AfterApprove"
},
{
"location": "/Interfaces/Item/#beforereject",
"text": "BeforeReject is called before an item is rejected and deleted by default. To reject\nan item, but not delete it, return a non-nil error from this hook - doing so \nwill allow the hook to do what you want it to do prior to the return, but the item\nwill remain in the \"Pending\" section. func ( p * Post ) BeforeReject ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "BeforeReject"
},
{
"location": "/Interfaces/Item/#afterreject",
"text": "AfterReject is called after an item is rejected and has been deleted. func ( p * Post ) AfterReject ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "AfterReject"
},
{
"location": "/Interfaces/Item/#beforesave",
"text": "BeforeSave is called before any CMS Admin or 3rd-party client triggers a save to \nthe database. This could be done by clicking the 'Save' button on a Content editor, \nor by a API call to Create or Update the Content item. By returning a non-nil error value, the item will not be saved. func ( p * Post ) BeforeSave ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "BeforeSave"
},
{
"location": "/Interfaces/Item/#aftersave",
"text": "AfterSave is called after any CMS Admin or 3rd-party client triggers a save to \nthe database. This could be done by clicking the 'Save' button on a Content editor, \nor by a API call to Create or Update the Content item. func ( p * Post ) AfterSave ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "AfterSave"
},
{
"location": "/Interfaces/Item/#beforedelete",
"text": "BeforeDelete is called before any CMS Admin or 3rd-party client triggers a delete to \nthe database. This could be done by clicking the 'Delete' button on a Content editor, \nor by a API call to Delete the Content item. By returning a non-nil error value,\nthe item will not be deleted. func ( p * Post ) BeforeDelete ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "BeforeDelete"
},
{
"location": "/Interfaces/Item/#afterdelete",
"text": "AfterSave is called after any CMS Admin or 3rd-party client triggers a delete to \nthe database. This could be done by clicking the 'Delete' button on a Content editor, \nor by a API call to Delete the Content item. func ( p * Post ) AfterDelete ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "AfterDelete"
},
{
"location": "/Interfaces/Item/#beforeapidelete",
"text": "BeforeDelete is only called before a 3rd-party client triggers a delete to the \ndatabase. By returning a non-nil error value, the item will not be deleted. func ( p * Post ) BeforeAPIDelete ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "BeforeAPIDelete"
},
{
"location": "/Interfaces/Item/#afterapidelete",
"text": "AfterAPIDelete is only called after a 3rd-party client triggers a delete to the \ndatabase. func ( p * Post ) AfterAPIDelete ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "AfterAPIDelete"
},
{
"location": "/Interfaces/Item/#beforeapiupdate",
"text": "BeforeAPIUpdate is only called before a 3rd-party client triggers an update to \nthe database. By returning a non-nil error value, the item will not be updated. func ( p * Post ) BeforeAPIUpdate ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "BeforeAPIUpdate"
},
{
"location": "/Interfaces/Item/#afterapiupdate",
"text": "AfterAPIUpdate is only called after a 3rd-party client triggers an update to \nthe database. func ( p * Post ) AfterAPIUpdate ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "AfterAPIUpdate"
},
{
"location": "/Interfaces/Item/#beforeadmincreate",
"text": "BeforeAdminCreate is only called before a CMS Admin creates a new Content item.\nIt is not called for subsequent saves to the item once it has been created and \nassigned an ID. By returning a non-nil error value, the item will not be created. func ( p * Post ) BeforeAdminCreate ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "BeforeAdminCreate"
},
{
"location": "/Interfaces/Item/#afteradmincreate",
"text": "AfterAdminCreate is only called after a CMS Admin creates a new Content item.\nIt is not called for subsequent saves to the item once it has been created and \nassigned an ID. func ( p * Post ) AfterAdminCreate ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "AfterAdminCreate"
},
{
"location": "/Interfaces/Item/#beforeadminupdate",
"text": "BeforeAdminUpdate is only called before a CMS Admin updates a Content item. By \nreturning a non-nil error , the item will not be updated. func ( p * Post ) BeforeAdminUpdate ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "BeforeAdminUpdate"
},
{
"location": "/Interfaces/Item/#afteradminupdate",
"text": "AfterAdminUpdate is only called after a CMS Admin updates a Content item. func ( p * Post ) AfterAdminUpdate ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "AfterAdminUpdate"
},
{
"location": "/Interfaces/Item/#beforeadmindelete",
"text": "BeforeAdminDelete is only called before a CMS Admin deletes a Content item. By\nreturning a non-nil error value, the item will not be deleted. func ( p * Post ) BeforeAdminDelete ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "BeforeAdminDelete"
},
{
"location": "/Interfaces/Item/#afteradmindelete",
"text": "AfterAdminDelete is only called after a CMS Admin deletes a Content item. func ( p * Post ) AfterAdminDelete ( res http . ResponseWriter , req * http . Request ) error { \n return nil }",
"title": "AfterAdminDelete"
},
{
"location": "/Interfaces/Item/#beforeenable",
"text": "BeforeEnable is only applicable to Addon items, and is called before the addon\nchanges status to \"Enabled\". By returning a non-nil error value, the addon\nwill not become enabled. func ( p * Post ) BeforeEnable ( http . ResponseWriter , * http . Request ) error { \n return nil }",
"title": "BeforeEnable"
},
{
"location": "/Interfaces/Item/#afterenable",
"text": "AfterEnable is only applicable to Addon items, and is called after the addon \nchanges status to \"Enabled\". func ( p * Post ) AfterEnable ( http . ResponseWriter , * http . Request ) error { \n return nil }",
"title": "AfterEnable"
},
{
"location": "/Interfaces/Item/#beforedisable",
"text": "BeforeDisable is only applicable to Addon items, and is called before the addon\nchanges status to \"Disabled\". By returning a non-nil error value, the addon\nwill not become disabled. func ( p * Post ) BeforeDisable ( http . ResponseWriter , * http . Request ) error { \n return nil }",
"title": "BeforeDisable"
},
{
"location": "/Interfaces/Item/#afterdisable",
"text": "AfterDisable is only applicable to Addon items, and is called after the addon \nchanges status to \"Disabled\". func ( p * Post ) AfterDisable ( http . ResponseWriter , * http . Request ) error { \n return nil } Hookable is implemented by Item by default as no-ops which are expected to be overridden. Note returning an error from any of these Hookable methods will end the request, \ncausing it to halt immediately after the hook. For example, returning an error \nfrom BeforeDelete will result in the content being kept in the database. \nThe same logic applies to all of these interface methods that return an error \n- the error defines the behavior .",
"title": "AfterDisable"
},
{
"location": "/Interfaces/Item/#itemidentifiable",
"text": "Identifiable enables a struct to have its ID set/get. Typically this is done to set an ID to -1 indicating it is new for DB inserts, since by default a newly initialized struct would have an ID of 0, the int zero-value, and BoltDB's starting key per bucket is 0, thus overwriting the first record.\nMost notable, Identifiable\u2019s String method is used to set a meaningful display name for an Item. String is called by default in the Admin dashboard to show the Items of certain types, and in the default creation of an Item\u2019s slug.\nIdentifiable is implemented by Item by default.",
"title": "item.Identifiable"
},
{
"location": "/Interfaces/Item/#method-set_4",
"text": "type Identifiable interface { \n ItemID () int \n SetItemID ( int ) \n UniqueID () uuid . UUID \n String () string }",
"title": "Method Set"
},
{
"location": "/Interfaces/Item/#implementation_3",
"text": "item.Identifiable has a default implementation in the system/item package. \nIt is not advised to override these methods, with the exception of String() , \nwhich is commonly used to set the display name of Content items when listed in \nthe CMS, and to customize slugs. func ( i Item ) ItemID () int { \n return i . ID } func ( i * Item ) SetItemID ( id int ) { \n i . ID = id } func ( i Item ) UniqueID () uuid . UUID { \n return i . UUID } func ( i Item ) String () string { \n return fmt . Sprintf ( Item ID: %s , i . UniqueID ()) }",
"title": "Implementation"
},
{
"location": "/Interfaces/Item/#itemsluggable",
"text": "Sluggable makes a struct locatable by URL with it's own path. As an Item implementing Sluggable, slugs may overlap. If this is an issue, make your content struct (or one which embeds Item) implement Sluggable and it will override the slug created by Item's SetSlug method with your own.\nIt is not recommended to override SetSlug , but rather the String method on your content struct, which will have a similar, more predictable effect.\nSluggable is implemented by Item by default.",
"title": "item.Sluggable"
},
{
"location": "/Interfaces/Item/#method-set_5",
"text": "type Sluggable interface { \n SetSlug ( string ) \n ItemSlug () string }",
"title": "Method Set"
},
{
"location": "/Interfaces/Item/#implementation_4",
"text": "item.Sluggable has a default implementation in the system/item package. It is\npossible to override these methods on your own Content types, but beware, behavior\nis undefined. It is tempting to override the SetSlug() method to customize your\nContent item slug, but try first to override the String() method found in the item.Identifiable interface instead. If you don't get the desired results, try SetSlug() . func ( i * Item ) SetSlug ( slug string ) { \n i . Slug = slug } func ( i * Item ) ItemSlug () string { \n return i . Slug }",
"title": "Implementation"
},
{
"location": "/Interfaces/Item/#itemsortable",
"text": "Sortable enables items to be sorted by time, as per the sort.Interface interface. Sortable is implemented by Item by default.",
"title": "item.Sortable"
},
{
"location": "/Interfaces/Item/#method-set_6",
"text": "type Sortable interface { \n Time () int64 \n Touch () int64 }",
"title": "Method Set"
},
{
"location": "/Interfaces/Item/#implementation_5",
"text": "item.Sortable has a default implementation in the system/item package. It is\npossible to override these methods on your own Content type, but beware, behavior \nis undefined. func ( i Item ) Time () int64 { \n return i . Timestamp } func ( i Item ) Touch () int64 { \n return i . Updated }",
"title": "Implementation"
},
{
"location": "/Interfaces/Search/",
"text": "Ponzu provides a set of interfaces from the \nsystem/search\n package to enable and customize full-text search access to content in your system. \nSearch is not enabled by default\n, and must be enabled per Content type individually.\n\n\nInterfaces\n\n\nsearch.Searchable\n\n\nSearchable determines how content is indexed and whether the system should index the content when it is created and updated or be removed from the index when content is deleted.\n\n\n\n\nSearch is \ndisabled\n for all Content items by default. Each Content item that should be indexed and searchable must implement the \nsearch.Searchable\n interface.\n\n\n\n\nMethod Set\n\n\ntype\n \nSearchable\n \ninterface\n \n{\n\n \nSearchMapping\n()\n \n(\n*\nmapping\n.\nIndexMappingImpl\n,\n \nerror\n)\n\n \nIndexContent\n()\n \nbool\n\n\n}\n\n\n\n\n\n\nBy default, Ponzu sets up the \nBleve's\n \"default mapping\", which is typically what you want for most content-based systems. This can be overridden by implementing your own \nSearchMapping() (*mapping.IndexMappingImpl, error)\n method on your Content type. \n\n\nThis way, all you need to do to get full-text search is to add the \nIndexContent() bool\n method to each Content type you want search enabled. Return \ntrue\n from this method to enable search. \n\n\nExample\n\n\n// ...\n\n\n\ntype\n \nSong\n \nstruct\n \n{\n\n \nitem\n.\nItem\n\n\n \nName\n \nstring\n \n`json:\nname\n`\n\n \n// ...\n\n\n}\n\n\n\nfunc\n \n(\ns\n \n*\nSong\n)\n \nIndexContent\n()\n \nbool\n \n{\n\n \nreturn\n \ntrue\n\n\n}\n\n\n\n\n\n\n\n\nIndexing Existing Content\n\n\nIf you previously had search disabled and had already added content to your system, you will need to re-index old content items in your CMS. Otherwise, they will not show up in search queries.. This requires you to manually open each item and click 'Save'. This could be scripted and Ponzu \nmight\n ship with a re-indexing function at some point in the fututre.",
"title": "Search"
},
{
"location": "/Interfaces/Search/#interfaces",
"text": "",
"title": "Interfaces"
},
{
"location": "/Interfaces/Search/#searchsearchable",
"text": "Searchable determines how content is indexed and whether the system should index the content when it is created and updated or be removed from the index when content is deleted. Search is disabled for all Content items by default. Each Content item that should be indexed and searchable must implement the search.Searchable interface.",
"title": "search.Searchable"
},
{
"location": "/Interfaces/Search/#method-set",
"text": "type Searchable interface { \n SearchMapping () ( * mapping . IndexMappingImpl , error ) \n IndexContent () bool } By default, Ponzu sets up the Bleve's \"default mapping\", which is typically what you want for most content-based systems. This can be overridden by implementing your own SearchMapping() (*mapping.IndexMappingImpl, error) method on your Content type. This way, all you need to do to get full-text search is to add the IndexContent() bool method to each Content type you want search enabled. Return true from this method to enable search.",
"title": "Method Set"
},
{
"location": "/Interfaces/Search/#example",
"text": "// ... type Song struct { \n item . Item \n\n Name string `json: name ` \n // ... } func ( s * Song ) IndexContent () bool { \n return true } Indexing Existing Content If you previously had search disabled and had already added content to your system, you will need to re-index old content items in your CMS. Otherwise, they will not show up in search queries.. This requires you to manually open each item and click 'Save'. This could be scripted and Ponzu might ship with a re-indexing function at some point in the fututre.",
"title": "Example"
},
{
"location": "/Ponzu-Addons/Creating-Addons/",
"text": "Coming soon\n\n\nFor a reference to creating your own addons, see:\n\nhttps://github.com/bosssauce/fbscheduler",
"title": "Creating Addons"
},
{
"location": "/Ponzu-Addons/Creating-Addons/#coming-soon",
"text": "For a reference to creating your own addons, see: https://github.com/bosssauce/fbscheduler",
"title": "Coming soon"
},
{
"location": "/Ponzu-Addons/Using-Addons/",
"text": "Coming soon\n\n\nFor a reference to creating your own addons, see:\n\nhttps://github.com/bosssauce/fbscheduler",
"title": "Using Addons"
},
{
"location": "/Ponzu-Addons/Using-Addons/#coming-soon",
"text": "For a reference to creating your own addons, see: https://github.com/bosssauce/fbscheduler",
"title": "Coming soon"
},
{
"location": "/Quickstart/Overview/",
"text": "Quickstart Steps\n\n\n1) Install \nGo 1.8+\n\n\n2) Install Ponzu CLI:\n\n\n$ go get github.com/haturatu/ponzu/\u2026\n\n\n\n\n\n3) Create a new project (path is created in your GOPATH):\n\n\n$ ponzu new github.com/nilslice/reviews\n\n\n\n\n\n4) Enter your new project directory:\n\n\n$ \ncd\n \n$GOPATH\n/src/github.com/nilslice/reviews\n\n\n\n\n\n5) Generate content type file and boilerplate code (creates \ncontent/review.go\n):\n\n\n$ ponzu generate content review title:\nstring\n author:\nstring\n rating:\nfloat64\n body:\nstring\n:richtext website_url:\nstring\n items:\n[]string\n photo:string:file\n`\n\n\n\n\n\n\n6) Build your project:\n\n\n$ ponzu build\n\n\n\n\n\n7) Run your project with defaults:\n\n\n$ ponzu run\n\n\n\n\n\n8) Open browser to \nhttp://localhost:8080/admin\n\n\nNotes\n\n\n\n\nOne-time initialization to set configuration\n\n\nAll fields can be changed in Configuration afterward",
"title": "Overview"
},
{
"location": "/Quickstart/Overview/#quickstart-steps",
"text": "1) Install Go 1.8+ 2) Install Ponzu CLI: $ go get github.com/haturatu/ponzu/\u2026 3) Create a new project (path is created in your GOPATH): $ ponzu new github.com/nilslice/reviews 4) Enter your new project directory: $ cd $GOPATH /src/github.com/nilslice/reviews 5) Generate content type file and boilerplate code (creates content/review.go ): $ ponzu generate content review title: string author: string rating: float64 body: string :richtext website_url: string items: []string photo:string:file ` 6) Build your project: $ ponzu build 7) Run your project with defaults: $ ponzu run 8) Open browser to http://localhost:8080/admin",
"title": "Quickstart Steps"
},
{
"location": "/Quickstart/Overview/#notes",
"text": "One-time initialization to set configuration All fields can be changed in Configuration afterward",
"title": "Notes"
},
{
"location": "/References/Overview/",
"text": "References in Ponzu allow you to create relationships between your Content types.\nPonzu uses an embedded database, rather than a more traditional relational database \nwith SQL support. This may seem unnatural since there is no native concept of\n\"foreign keys\" or \"joins\" like you may be used to. Instead, Ponzu wires up your\ndata using references, which are simply URL paths, like \n/api/content?type=Post\nid=1\n\n\nA foreign key as a URL path?! Am I crazy? No! For the purpose Ponzu serves, \nthis structure works quite well, especially given its creation was specifically \ntuned for HTTP/2 features such as \"Request/Response Multiplexing\" and \"Server Push.\" \n\n\nThere is a deeper dive into the HTTP/2 concepts \nbelow\n, but first we'll walk through\na quick tutorial on Ponzu's references. \n\n\nTo generate references from the CLI, please \nread through the documentation\n. \nThe example below assumes you understand the syntax. \n\n\n\n\nCreate Your Content Types\n\n\nHere we are creating two Content types, \nAuthor\n and \nBook\n. A \nBook\n will keep\na reference to an \nAuthor\n in the sense that an author wrote the book.\n\n\n$ ponzu gen c author name:string photo:string:file bio:string:textarea\n$ ponzu gen c book title:string author:@author,name pages:int year:int\n\n\n\n\n\nThe structs generated for each look like:\n\n\ncontent/author.go\n\n\ntype\n \nAuthor\n \nstruct\n \n{\n\n \nitem\n.\nItem\n\n\n \nName\n \nstring\n \n`json:\nname\n`\n\n \nPhoto\n \nstring\n \n`json:\nphoto\n`\n\n \nBio\n \nstring\n \n`json:\nbio\n`\n\n\n}\n\n\n\n\n\n\ncontent/book.go\n\n\ntype\n \nBook\n \nstruct\n \n{\n\n \nitem\n.\nItem\n\n\n \nTitle\n \nstring\n \n`json:\ntitle\n`\n\n \nAuthor\n \nstring\n \n`json:\nauthor\n`\n\n \nPages\n \nint\n \n`json:\npages\n`\n\n \nYear\n \nint\n \n`json:\nyear\n`\n\n\n}\n\n\n\n\n\n\nNotice how the \nAuthor\n field within the \nBook\n struct is a \nstring\n type, not\nan \nAuthor\n type. This is because the \nAuthor\n is stored as a \nstring\n in our\ndatabase, as a reference to the \nAuthor\n, instead of embedding the \nAuthor\n data \ninside the \nBook\n. \n\n\nSome example JSON data for the two structs looks like:\n\n\nGET\n \n/api/content?type=Author\nid=1\n (\nAuthor\n)\n\n\n{\n\n \ndata\n:\n \n[\n\n \n{\n\n \nuuid\n:\n \n024a5797-e064-4ee0-abe3-415cb6d3ed18\n,\n\n \nid\n:\n \n1\n,\n\n \nslug\n:\n \nitem-id-024a5797-e064-4ee0-abe3-415cb6d3ed18\n,\n\n \ntimestamp\n:\n \n1493926453826\n,\n\n \nupdated\n:\n \n1493926453826\n,\n\n \nname\n:\n \nShel Silverstein\n,\n\n \nphoto\n:\n \n/api/uploads/2017/05/shel-silverstein.jpg\n,\n\n \nbio\n:\n \nSheldon Allan Silverstein was an American poet...\n\n \n}\n\n \n]\n\n\n}\n\n\n\n\n\n\nGET\n \n/api/content?type=Book\nid=1\n (\nBook\n)\n\n\n{\n\n \ndata\n:\n \n[\n\n \n{\n\n \nuuid\n:\n \n024a5797-e064-4ee0-abe3-415cb6d3ed18\n,\n\n \nid\n:\n \n1\n,\n\n \nslug\n:\n \nitem-id-024a5797-e064-4ee0-abe3-415cb6d3ed18\n,\n\n \ntimestamp\n:\n \n1493926453826\n,\n\n \nupdated\n:\n \n1493926453826\n,\n\n \ntitle\n:\n \nThe Giving Tree\n,\n\n \nauthor\n:\n \n/api/content?type=Author\nid=1\n,\n\n \npages\n:\n \n57\n,\n\n \nyear\n:\n \n1964\n\n \n}\n\n \n]\n\n\n}\n\n\n\n\n\n\nAs you can see, the \nAuthor\n is a reference as the \nauthor\n field in the JSON\nresponse for a \nBook\n. When you're building your client, you need to make a second\nrequest for the \nAuthor\n, to the URL path found in the \nauthor\n field of the \nBook\n\nresponse. \n\n\nFor example, in pseudo-code: \n\n\n# Request 1: \n\n\n$book\n \n=\n GET /api/content?type\n=\nBook\nid\n=\n1\n\n\n\n# Request 2: \n\n\n$author\n \n=\n GET \n$book\n.author \n# where author = /api/content?type=Author\nid=1\n\n\n\n\n\n\nUntil recently, this would be considered bad practice and would be costly to do\nover HTTP. However, with the wide availability of HTTP/2 clients, including all\nmodern web browsers, mobile devices, and HTTP/2 libraries in practically every \nprogramming language, this pattern is fast and scalable. \n\n\n\n\nDesigned For HTTP/2\n\n\nAt this point, you've likely noticed that you're still making two independent \nHTTP requests to your Ponzu server. Further, if there are multiple references or more\nthan one item, you'll be making many requests -- \nhow can that be efficient?\n \n\n\nThere are two main concepts at play: Request/Response Multiplexing and Server Push.\n\n\nRequest/Response Multiplexing\n\n\nWith HTTP/2, a client and server (peers) transfer data over a single TCP connection, \nand can send data back and forth at the same time. No longer does a request need\nto wait to be sent until after an expected response is read. This means that HTTP \nrequests can be sent much faster and at the \nsame time\n on a single connection. \nWhere previously, a client would open up several TCP connections, the re-use of a \nsingle connection reduces CPU overhead and makes the server more efficient.\n\n\nThis feature is automatically provided to you when using HTTP/2 - the only \nrequirement is that you connect via HTTPS and have active TLS certificates, which \nyou can get for free by running Ponzu with the \n--https\n flag and configuring it \nwith a properly set, active domain name of your own. \n\n\nServer Push\n\n\nAnother impactful feature of HTTP/2 is \"Server Push\": the ability to preemptively\nsend a response from the server to a client without waiting for a request. This\nis where Ponzu's reference design really shows it's power. Let's revisit the\nexample from above:\n\n\n# Request 1: \n\n\n$book\n \n=\n GET /api/content?type\n=\nBook\nid\n=\n1\n\n\n\n# Request 2: \n\n\n$author\n \n=\n GET \n$book\n.author \n# where author = /api/content?type=Author\nid=1\n\n\n\n\n\n\nInstead of waiting for the server to respond with the data for \n$book.author\n, \nthe response data is already in the client's cache before we even make the request!\nNow there is no round-trip made to the server and back, and the client reads the \npushed response from cache in fractions of a millisecond. \n\n\nBut, how does the server know which response to push and when? You'll need to \nspecify which fields of the type you've requested should be pushed. This is done\nby implementing the \nitem.Pushable\n interface\n. \nSee the example below which demonstrates a complete implementation on the \nBook\n\nstruct, which has a reference to an \nAuthor\n.\n\n\nExample\n\n\ncontent/book.go\n\n\n...\n\n\ntype\n \nBook\n \nstruct\n \n{\n\n \nitem\n.\nItem\n\n\n \nTitle\n \nstring\n \n`json:\ntitle\n`\n\n \nAuthor\n \nstring\n \n`json:\nauthor\n`\n\n \nPages\n \nint\n \n`json:\npages\n`\n\n \nYear\n \nint\n \n`json:\nyear\n`\n\n\n}\n\n\n\n\nfunc\n \n(\nb\n \n*\nBook\n)\n \nPush\n(\nres\n \nhttp\n.\nResponseWriter\n,\n \nreq\n \n*\nhttp\n.\nRequest\n)\n \n([]\nstring\n,\n \nerror\n)\n \n{\n\n \nreturn\n \n[]\nstring\n{\n\n \n// the json struct tag is used to tell the server which\n\n \n// field(s) it should push - only URL paths originating\n\n \n// from your server can be pushed!\n\n \nauthor\n,\n \n \n},\n \nnil\n\n\n}\n\n\n...\n\n\n\n\n\n\nNow, whenever a single \nBook\n is requested, the server will preemptively push the\n\nAuthor\n referenced by the book. The response for the \nAuthor\n will \nalready be\non the client\n and will remain there until a request for the referenced \nAuthor\n \nhas been made.\n\n\n\n\nWhat else can I Push?\n\n\nOnly fields that are URL paths originating from your server can be pushed. \nThis means that you could also implement \nitem.Pushable\n on the \nAuthor\n\ntype, and return \n[]string{\"photo\"}, nil\n to push the Author's image!\n\n\n\n\n\n\nOther Considerations\n\n\nHTTP/2 Server Push is a powerful feature, but it can be abused just like anything\nelse. To try and help mitigate potential issues, Ponzu has put some \"stop-gaps\"\nin place. Server Push is only activated on \nsingle item\n API responses, so you\nshouldn't expect to see references or files pushed from the \n/api/contents\n endpoint.\nAn exception to this is the \n/api/search\n endpoint, which only the \nfirst\n \nresult is pushed (if applicable) no matter how many items are in the response. \n\n\nYou should take advantage of HTTP/2 in Ponzu and get the most out of the system. \nWith the automatic HTTPS feature, there is no reason not to and you gain the \nadditional benefit of encrypting your traffic - which your users will appreciate!",
"title": "Overview"
},
{
"location": "/References/Overview/#create-your-content-types",
"text": "Here we are creating two Content types, Author and Book . A Book will keep\na reference to an Author in the sense that an author wrote the book. $ ponzu gen c author name:string photo:string:file bio:string:textarea\n$ ponzu gen c book title:string author:@author,name pages:int year:int The structs generated for each look like: content/author.go type Author struct { \n item . Item \n\n Name string `json: name ` \n Photo string `json: photo ` \n Bio string `json: bio ` } content/book.go type Book struct { \n item . Item \n\n Title string `json: title ` \n Author string `json: author ` \n Pages int `json: pages ` \n Year int `json: year ` } Notice how the Author field within the Book struct is a string type, not\nan Author type. This is because the Author is stored as a string in our\ndatabase, as a reference to the Author , instead of embedding the Author data \ninside the Book . Some example JSON data for the two structs looks like: GET /api/content?type=Author id=1 ( Author ) { \n data : [ \n { \n uuid : 024a5797-e064-4ee0-abe3-415cb6d3ed18 , \n id : 1 , \n slug : item-id-024a5797-e064-4ee0-abe3-415cb6d3ed18 , \n timestamp : 1493926453826 , \n updated : 1493926453826 , \n name : Shel Silverstein , \n photo : /api/uploads/2017/05/shel-silverstein.jpg , \n bio : Sheldon Allan Silverstein was an American poet... \n } \n ] } GET /api/content?type=Book id=1 ( Book ) { \n data : [ \n { \n uuid : 024a5797-e064-4ee0-abe3-415cb6d3ed18 , \n id : 1 , \n slug : item-id-024a5797-e064-4ee0-abe3-415cb6d3ed18 , \n timestamp : 1493926453826 , \n updated : 1493926453826 , \n title : The Giving Tree , \n author : /api/content?type=Author id=1 , \n pages : 57 , \n year : 1964 \n } \n ] } As you can see, the Author is a reference as the author field in the JSON\nresponse for a Book . When you're building your client, you need to make a second\nrequest for the Author , to the URL path found in the author field of the Book \nresponse. For example, in pseudo-code: # Request 1: $book = GET /api/content?type = Book id = 1 # Request 2: $author = GET $book .author # where author = /api/content?type=Author id=1 Until recently, this would be considered bad practice and would be costly to do\nover HTTP. However, with the wide availability of HTTP/2 clients, including all\nmodern web browsers, mobile devices, and HTTP/2 libraries in practically every \nprogramming language, this pattern is fast and scalable.",
"title": "Create Your Content Types"
},
{
"location": "/References/Overview/#designed-for-http2",
"text": "At this point, you've likely noticed that you're still making two independent \nHTTP requests to your Ponzu server. Further, if there are multiple references or more\nthan one item, you'll be making many requests -- how can that be efficient? There are two main concepts at play: Request/Response Multiplexing and Server Push.",
"title": "Designed For HTTP/2"
},
{
"location": "/References/Overview/#requestresponse-multiplexing",
"text": "With HTTP/2, a client and server (peers) transfer data over a single TCP connection, \nand can send data back and forth at the same time. No longer does a request need\nto wait to be sent until after an expected response is read. This means that HTTP \nrequests can be sent much faster and at the same time on a single connection. \nWhere previously, a client would open up several TCP connections, the re-use of a \nsingle connection reduces CPU overhead and makes the server more efficient. This feature is automatically provided to you when using HTTP/2 - the only \nrequirement is that you connect via HTTPS and have active TLS certificates, which \nyou can get for free by running Ponzu with the --https flag and configuring it \nwith a properly set, active domain name of your own.",
"title": "Request/Response Multiplexing"
},
{
"location": "/References/Overview/#server-push",
"text": "Another impactful feature of HTTP/2 is \"Server Push\": the ability to preemptively\nsend a response from the server to a client without waiting for a request. This\nis where Ponzu's reference design really shows it's power. Let's revisit the\nexample from above: # Request 1: $book = GET /api/content?type = Book id = 1 # Request 2: $author = GET $book .author # where author = /api/content?type=Author id=1 Instead of waiting for the server to respond with the data for $book.author , \nthe response data is already in the client's cache before we even make the request!\nNow there is no round-trip made to the server and back, and the client reads the \npushed response from cache in fractions of a millisecond. But, how does the server know which response to push and when? You'll need to \nspecify which fields of the type you've requested should be pushed. This is done\nby implementing the item.Pushable interface . \nSee the example below which demonstrates a complete implementation on the Book \nstruct, which has a reference to an Author .",
"title": "Server Push"
},
{
"location": "/References/Overview/#example",
"text": "content/book.go ... type Book struct { \n item . Item \n\n Title string `json: title ` \n Author string `json: author ` \n Pages int `json: pages ` \n Year int `json: year ` } func ( b * Book ) Push ( res http . ResponseWriter , req * http . Request ) ([] string , error ) { \n return [] string { \n // the json struct tag is used to tell the server which \n // field(s) it should push - only URL paths originating \n // from your server can be pushed! \n author , \n }, nil } ... Now, whenever a single Book is requested, the server will preemptively push the Author referenced by the book. The response for the Author will already be\non the client and will remain there until a request for the referenced Author \nhas been made. What else can I Push? Only fields that are URL paths originating from your server can be pushed. \nThis means that you could also implement item.Pushable on the Author \ntype, and return []string{\"photo\"}, nil to push the Author's image!",
"title": "Example"
},
{
"location": "/References/Overview/#other-considerations",
"text": "HTTP/2 Server Push is a powerful feature, but it can be abused just like anything\nelse. To try and help mitigate potential issues, Ponzu has put some \"stop-gaps\"\nin place. Server Push is only activated on single item API responses, so you\nshouldn't expect to see references or files pushed from the /api/contents endpoint.\nAn exception to this is the /api/search endpoint, which only the first \nresult is pushed (if applicable) no matter how many items are in the response. You should take advantage of HTTP/2 in Ponzu and get the most out of the system. \nWith the automatic HTTPS feature, there is no reason not to and you gain the \nadditional benefit of encrypting your traffic - which your users will appreciate!",
"title": "Other Considerations"
},
{
"location": "/Running-Backups/Backups/",
"text": "Both the databases \nsystem.db\n \n \nanalytics.db\n, and the \n/uploads\n directory can be backed up over HTTP using \nwget\n, \ncurl\n, etc. All of which are located at the \n/admin/backup\n route and require HTTP Basic Auth. In order to enable backups, you must add a user/password pair inside the CMS Configuration at \n/admin/configure\n near the bottom of the page.\n\n\nAll backups are made using a \nGET\n request to the \n/admin/backup\n path with a query parameter of \n?source={system,analytics,uploads}\n (only one source can be included in the URL).\n\n\nHere are some full backup scripts to use or modify to fit your needs:\n\nhttps://github.com/haturatu/backup-scripts\n\n\nSystem \n Analytics\n\n\nThe \nsystem.db\n \n \nanalytics.db\n data files are sent uncompressed in their original form as they exist on your server. No temporary copy is stored on the origin server, and it is possible that the backup could fail so checking for successful backups is recommended. See https://github.com/boltdb/bolt#database-backups for more information about how BoltDB handles HTTP backups.\n\n\nAn example backup request for the \nsystem.db\n data file would look like:\n\n\n$ curl --user user:pass \nhttps://example.com/admin/backup?source=system\n \n system.db.bak\n\n\n\n\n\nUploads\n\n\nThe \nuploads\n directory is gzip compressed and archived as a tar file, stored in the temporary directory (typically \n/tmp\n on Linux) on your origin server with a timestamp in the file name. It is removed after the HTTP response for the backup has been written.\n\n\nAn example backup request for the \n/uploads\n directory would look like:\n\n\n$ curl --user user:pass \nhttps://example.com/admin/backup?source=uploads\n \n uploads.tar.gz\n\n# unarchive the tarball with gzip \n\n$ tar xzf uploads.tar.gz\n\n\n\n\n\nSearch Indexes\n\n\nThe \nsearch\n directory, which is created to store the various search indexes for your content types (only if they implement \nsearch.Searchable\n), is backed up in the same fashion as \nUploads\n. \n\n\nAn example backup request for the \n/search\n directory would look like:\n\n\n$ curl --user user:pass \nhttps://example.com/admin/backup?source=search\n \n search.tar.gz\n\n# unarchive the tarball with gzip \n\n$ tar xzf search.tar.gz",
"title": "Backups"
},
{
"location": "/Running-Backups/Backups/#system-analytics",
"text": "The system.db analytics.db data files are sent uncompressed in their original form as they exist on your server. No temporary copy is stored on the origin server, and it is possible that the backup could fail so checking for successful backups is recommended. See https://github.com/boltdb/bolt#database-backups for more information about how BoltDB handles HTTP backups. An example backup request for the system.db data file would look like: $ curl --user user:pass https://example.com/admin/backup?source=system system.db.bak",
"title": "System & Analytics"
},
{
"location": "/Running-Backups/Backups/#uploads",
"text": "The uploads directory is gzip compressed and archived as a tar file, stored in the temporary directory (typically /tmp on Linux) on your origin server with a timestamp in the file name. It is removed after the HTTP response for the backup has been written. An example backup request for the /uploads directory would look like: $ curl --user user:pass https://example.com/admin/backup?source=uploads uploads.tar.gz # unarchive the tarball with gzip \n$ tar xzf uploads.tar.gz",
"title": "Uploads"
},
{
"location": "/Running-Backups/Backups/#search-indexes",
"text": "The search directory, which is created to store the various search indexes for your content types (only if they implement search.Searchable ), is backed up in the same fashion as Uploads . An example backup request for the /search directory would look like: $ curl --user user:pass https://example.com/admin/backup?source=search search.tar.gz # unarchive the tarball with gzip \n$ tar xzf search.tar.gz",
"title": "Search Indexes"
},
{
"location": "/System-Configuration/Settings/",
"text": "Ponzu has several options which can be configured at run-time. To view these\nconfiguration settings, visit the \n/admin/configure\n page of your Ponzu CMS.\n\n\n\n\nSite Name\n\n\nThe Site Name setting changes the displayed name on your admin dashboard. This is\nvisible publicly on the \n/admin/login\n page.\n\n\n\n\nDomain Name\n\n\nInternally, Ponzu needs to know where its canonical HTTP access origin is, and\nrequires you to add the qualified domain name you are using. In development, use \n\nlocalhost\n or some other name mapped to the loopback address (\n127.0.0.1\n).\n\n\nOnce you have deployed your Ponzu server to a remote host and pointed a public \ndomain at it, you need to change the Domain Name setting to match. This is \nespecially important when fetching TLS (SSL) certificates from \nLet's Encrypt\n\n- since the process requires an active, verifiable domain. To set up your server\nwith TLS over HTTPS connections, follow these steps:\n\n\n\n\nSet your Domain Name in the system configuration\n\n\nSet the Administrator Email to register with Let's Encrypt\n\n\nStop your Ponzu server\n\n\nRun your Ponzu server with the \n--https\n flag e.g. \n$ ponzu run --https\n\n\nVisit your CMS admin with \nhttps://\n prepended to your URL\n\n\n\n\n\n\nVerifying HTTPS / TLS Connections\n\n\nIf successful, your APIs and CMS will be accessible via HTTPS, and you will\nsee a green indicator near the URL bar of most browsers. This also enables \nyour server to use the HTTP/2 protocol.\n\n\n\n\nDevelopment Environment\n\n\nYou can test HTTPS \n HTTP/2 connections in your development environment on \nlocalhost\n,\nby running Ponzu with the \n--devhttps\n flag e.g. \n$ ponzu --devhttps run\n \n\n\nIf you're greeted with a warning from the browser saying the connection is not\nsecure, follow the steps outlined in the CLI message, or here:\n\n\nIf your browser rejects HTTPS requests, try allowing insecure connections on localhost.\non Chrome, visit chrome://flags/#allow-insecure-localhost\n\n\n\n\n\n\n\nAdministrator Email\n\n\nThe Administrator Email is the contact email for the person who is the main admin\nof your Ponzu CMS. This can be changed at any point, but once a Let's Encrypt\ncertificate has been fetched using an Administrator Email, it will remain the \ncontact until a new certificate is requested. \n\n\n\n\nClient Secret\n\n\nThe Client Secret is a secure value used by the server to sign tokens and authenticate requests.\n\nDo not share this\n value with any untrusted party.\n\n\n\n\nSecurity and the Client Secret\n\n\nHTTP requests with a valid token, signed with the Client Secret, can take any\naction an Admin can within the CMS. Be cautious of this when sharing account\nlogins or details with anyone.\n\n\n\n\n\n\nEtag Header\n\n\nThe Etag Header value is automatically created when content is changed and serves\nas a caching validation mechanism.\n\n\n\n\nCORS\n\n\nCORS, or \"Cross-Origin Resource Sharing\" is a security setting which defines how\nresources (or URLs) can be accessed from outside clients / domains. By default, \nPonzu HTTP APIs can be accessed from any origin, meaning a script from an unknown\nwebsite could fetch data. \n\n\nBy disabling CORS, you limit API requests to only the Domain Name you set.\n\n\n\n\nGZIP\n\n\nGZIP is a popular codec which when applied to most HTTP responses, decreases data\ntransmission size and response times. The GZIP setting on Ponzu has a minor \nside-effect of using more CPU, so you can disable it if you notice your system \nis CPU-constrained. However, traffic levels would need to be extremely demanding\nfor this to be noticeable.\n\n\n\n\nHTTP Cache\n\n\nThe HTTP Cache configuration allows a system to disable the default HTTP cache,\nwhich saves the server from repeating API queries and sending responses -- it's\ngenerally advised to keep this enabled unless you have \nfrequently\n changing data.\n\n\nThe \nMax-Age\n value setting overrides the default 2592000-second (30 day) cache\n\nmax-age\n duration set in API response headers. The \n0\n value is an alias to \n\n2592000\n, so check the \nDisable HTTP Cache\n box if you don't want any caching.\n\n\n\n\nInvalidate Cache\n\n\nIf this box is checked and then the configuration is saved, the server will \nre-generate an Etag to send in responses. By doing so, the cache becomes invalidated\nand reset so new content or assets will be included in previously cached responses.\n\n\nThe cache is invalidated when content changes, so this is typically not a widely \nused setting.\n\n\n\n\nDatabase Backup Credentials\n\n\nIn order to enable HTTP backups of the components that make up your system, you\nwill need to add an HTTP Basic Auth user and password pair. When used to \n\nrun backups\n, the \nuser:password\n pair tells your server\nthat the backup request is made from a trusted party. \n\n\n\n\nBackup Access with Credentials\n\n\nThis \nuser:password\n pair should not be shared outside of your organization as \nit allows full database downloads and archives of your system's uploads.",
"title": "Settings"
},
{
"location": "/System-Configuration/Settings/#site-name",
"text": "The Site Name setting changes the displayed name on your admin dashboard. This is\nvisible publicly on the /admin/login page.",
"title": "Site Name"
},
{
"location": "/System-Configuration/Settings/#domain-name",
"text": "Internally, Ponzu needs to know where its canonical HTTP access origin is, and\nrequires you to add the qualified domain name you are using. In development, use localhost or some other name mapped to the loopback address ( 127.0.0.1 ). Once you have deployed your Ponzu server to a remote host and pointed a public \ndomain at it, you need to change the Domain Name setting to match. This is \nespecially important when fetching TLS (SSL) certificates from Let's Encrypt \n- since the process requires an active, verifiable domain. To set up your server\nwith TLS over HTTPS connections, follow these steps: Set your Domain Name in the system configuration Set the Administrator Email to register with Let's Encrypt Stop your Ponzu server Run your Ponzu server with the --https flag e.g. $ ponzu run --https Visit your CMS admin with https:// prepended to your URL Verifying HTTPS / TLS Connections If successful, your APIs and CMS will be accessible via HTTPS, and you will\nsee a green indicator near the URL bar of most browsers. This also enables \nyour server to use the HTTP/2 protocol.",
"title": "Domain Name"
},
{
"location": "/System-Configuration/Settings/#development-environment",
"text": "You can test HTTPS HTTP/2 connections in your development environment on localhost ,\nby running Ponzu with the --devhttps flag e.g. $ ponzu --devhttps run If you're greeted with a warning from the browser saying the connection is not\nsecure, follow the steps outlined in the CLI message, or here: If your browser rejects HTTPS requests, try allowing insecure connections on localhost.\non Chrome, visit chrome://flags/#allow-insecure-localhost",
"title": "Development Environment"
},
{
"location": "/System-Configuration/Settings/#administrator-email",
"text": "The Administrator Email is the contact email for the person who is the main admin\nof your Ponzu CMS. This can be changed at any point, but once a Let's Encrypt\ncertificate has been fetched using an Administrator Email, it will remain the \ncontact until a new certificate is requested.",
"title": "Administrator Email"
},
{
"location": "/System-Configuration/Settings/#client-secret",
"text": "The Client Secret is a secure value used by the server to sign tokens and authenticate requests. Do not share this value with any untrusted party. Security and the Client Secret HTTP requests with a valid token, signed with the Client Secret, can take any\naction an Admin can within the CMS. Be cautious of this when sharing account\nlogins or details with anyone.",
"title": "Client Secret"
},
{
"location": "/System-Configuration/Settings/#etag-header",
"text": "The Etag Header value is automatically created when content is changed and serves\nas a caching validation mechanism.",
"title": "Etag Header"
},
{
"location": "/System-Configuration/Settings/#cors",
"text": "CORS, or \"Cross-Origin Resource Sharing\" is a security setting which defines how\nresources (or URLs) can be accessed from outside clients / domains. By default, \nPonzu HTTP APIs can be accessed from any origin, meaning a script from an unknown\nwebsite could fetch data. By disabling CORS, you limit API requests to only the Domain Name you set.",
"title": "CORS"
},
{
"location": "/System-Configuration/Settings/#gzip",
"text": "GZIP is a popular codec which when applied to most HTTP responses, decreases data\ntransmission size and response times. The GZIP setting on Ponzu has a minor \nside-effect of using more CPU, so you can disable it if you notice your system \nis CPU-constrained. However, traffic levels would need to be extremely demanding\nfor this to be noticeable.",
"title": "GZIP"
},
{
"location": "/System-Configuration/Settings/#http-cache",
"text": "The HTTP Cache configuration allows a system to disable the default HTTP cache,\nwhich saves the server from repeating API queries and sending responses -- it's\ngenerally advised to keep this enabled unless you have frequently changing data. The Max-Age value setting overrides the default 2592000-second (30 day) cache max-age duration set in API response headers. The 0 value is an alias to 2592000 , so check the Disable HTTP Cache box if you don't want any caching.",
"title": "HTTP Cache"
},
{
"location": "/System-Configuration/Settings/#invalidate-cache",
"text": "If this box is checked and then the configuration is saved, the server will \nre-generate an Etag to send in responses. By doing so, the cache becomes invalidated\nand reset so new content or assets will be included in previously cached responses. The cache is invalidated when content changes, so this is typically not a widely \nused setting.",
"title": "Invalidate Cache"
},
{
"location": "/System-Configuration/Settings/#database-backup-credentials",
"text": "In order to enable HTTP backups of the components that make up your system, you\nwill need to add an HTTP Basic Auth user and password pair. When used to run backups , the user:password pair tells your server\nthat the backup request is made from a trusted party. Backup Access with Credentials This user:password pair should not be shared outside of your organization as \nit allows full database downloads and archives of your system's uploads.",
"title": "Database Backup Credentials"
},
{
"location": "/System-Deployment/Docker/",
"text": "Ponzu Docker build\n\n\nPonzu is distributed as a \ndocker image\n, \nwhich aids in ponzu deployment. The Dockerfile in this directory is used by Ponzu \nto generate the docker image which contains the ponzu executable.\n\n\nIf you are deploying your own Ponzu project, you can write a new Dockerfile that\nis based from the \nponzu/ponzu\n image of your choice. For example:\n\n\nFROM\n ponzu/ponzu:latest\n\n\n\n# your project set up ...\n\n\n# ...\n\n\n# ...\n\n\n\n\n\n\nThe following are convenient commands during development of Ponzu core:\n\n\nBuild the docker image. Run from the root of the project.\n\n\n# from the root of ponzu:\n\ndocker build -t ponzu-dev\n\n\n\n\n\nStart the image, share the local directory and pseudo terminal (tty) into for debugging:\n\n\ndocker run -v \n$(\npwd\n)\n:/go/src/github.com/haturatu/ponzu -it ponzu-dev\n\npwd\n \n# will output the go src directory for ponzu\n\nponzu version \n# will output the ponzu version\n\n\n# make an edit on your local and rebuild\n\ngo install ./...\n\n\n\n\n\nSpecial thanks to \n@krismeister\n for contributing this!",
"title": "Docker"
},
{
"location": "/System-Deployment/Docker/#ponzu-docker-build",
"text": "Ponzu is distributed as a docker image , \nwhich aids in ponzu deployment. The Dockerfile in this directory is used by Ponzu \nto generate the docker image which contains the ponzu executable. If you are deploying your own Ponzu project, you can write a new Dockerfile that\nis based from the ponzu/ponzu image of your choice. For example: FROM ponzu/ponzu:latest # your project set up ... # ... # ...",
"title": "Ponzu Docker build"
},
{
"location": "/System-Deployment/Docker/#the-following-are-convenient-commands-during-development-of-ponzu-core",
"text": "",
"title": "The following are convenient commands during development of Ponzu core:"
},
{
"location": "/System-Deployment/Docker/#build-the-docker-image-run-from-the-root-of-the-project",
"text": "# from the root of ponzu: \ndocker build -t ponzu-dev",
"title": "Build the docker image. Run from the root of the project."
},
{
"location": "/System-Deployment/Docker/#start-the-image-share-the-local-directory-and-pseudo-terminal-tty-into-for-debugging",
"text": "docker run -v $( pwd ) :/go/src/github.com/haturatu/ponzu -it ponzu-dev pwd # will output the go src directory for ponzu \nponzu version # will output the ponzu version # make an edit on your local and rebuild \ngo install ./... Special thanks to @krismeister for contributing this!",
"title": "Start the image, share the local directory and pseudo terminal (tty) into for debugging:"
},
{
"location": "/System-Deployment/SysV-Style/",
"text": "For reference, here is an example init script to run Ponzu servers. You must \ndefine the \nPROJECT_DIR\n \n \nRUNAS\n variables by replacing \nPROJECT DIRECTORY\n\n\n \nUSER\n in the script below:\n\n\n#!/bin/sh\n\n\n### BEGIN INIT INFO\n\n\n# Provides: ponzu-server\n\n\n# Required-Start: $local_fs $network $named $time $syslog\n\n\n# Required-Stop: $local_fs $network $named $time $syslog\n\n\n# Default-Start: 2 3 4 5\n\n\n# Default-Stop: 0 1 6\n\n\n# Description: Ponzu API \n Admin server\n\n\n### END INIT INFO\n\n\n\nPROJECT_DIR\n=\nPROJECT DIRECTORY\n\n\nSCRIPT\n=\ncd $PROJECT_DIR \n ponzu run --port=80\n \n# add --https here to get TLS/HTTPS\n\n\nRUNAS\n=\nUSER\n\n\n\nPIDFILE\n=\n/var/run/ponzu-server.pid\n\nLOGFILE\n=\n/var/log/ponzu-server.log\n\nstart\n()\n \n{\n\n \nif\n \n[\n -f /var/run/\n$PIDNAME\n \n]\n \n \nkill\n -0 \n$(\ncat /var/run/\n$PIDNAME\n)\n;\n \nthen\n\n \necho\n \nService already running\n \n2\n\n \nreturn\n \n1\n\n \nfi\n\n \necho\n \nStarting service\u2026\n \n2\n\n \nlocal\n \nCMD\n=\n$SCRIPT\n \n \\\n$LOGFILE\n\\\n \n echo \\$!\n\n su -c \n$CMD\n \n$RUNAS\n \n \n$PIDFILE\n\n \necho\n \nService started\n \n2\n\n\n}\n\n\nstop\n()\n \n{\n\n \nif\n \n[\n ! -f \n$PIDFILE\n \n]\n \n||\n ! \nkill\n -0 \n$(\ncat \n$PIDFILE\n)\n;\n \nthen\n\n \necho\n \nService not running\n \n2\n\n \nreturn\n \n1\n\n \nfi\n\n \necho\n \nStopping service\u2026\n \n2\n\n \nkill\n -15 \n$(\ncat \n$PIDFILE\n)\n \n rm -f \n$PIDFILE\n\n \necho\n \nService stopped\n \n2\n\n\n}\n\n\nuninstall\n()\n \n{\n\n \necho\n -n \nAre you really sure you want to uninstall this service? That cannot be undone. [yes|No] \n\n \nlocal\n SURE\n \nread\n SURE\n \nif\n \n[\n \n$SURE\n \n=\n \nyes\n \n]\n;\n \nthen\n\n stop\n rm -f \n$PIDFILE\n\n \necho\n \nNotice: log file is not be removed: \n$LOGFILE\n \n2\n\n update-rc.d -f \nNAME\n remove\n rm -fv \n$0\n\n \nfi\n\n\n}\n\n\n\ncase\n \n$1\n in\n start\n)\n\n start\n \n;;\n\n stop\n)\n\n stop\n \n;;\n\n uninstall\n)\n\n uninstall\n \n;;\n\n restart\n)\n\n stop\n start\n \n;;\n\n *\n)\n\n \necho\n \nUsage: \n$0\n {start|stop|restart|uninstall}\n\n\nesac",
"title": "SysV Style"
}
]
}
|