- commit
- f13ddd4
- parent
- 36b9540
- author
- Eric Bower
- date
- 2023-11-12 18:33:07 +0000 UTC
feat(pastes): set custom expiration and set paste to unlisted (#52)
5 files changed,
+82,
-45
+7,
-0
1@@ -55,6 +55,7 @@ type PostPageData struct {
2 Contents template.HTML
3 PublishAtISO string
4 PublishAt string
5+ ExpiresAt string
6 }
7
8 type TransparencyPageData struct {
9@@ -185,6 +186,10 @@ func postHandler(w http.ResponseWriter, r *http.Request) {
10 if err != nil {
11 logger.Error(err)
12 }
13+ expiresAt := "never"
14+ if post.ExpiresAt != nil {
15+ expiresAt = post.ExpiresAt.Format("02 Jan, 2006")
16+ }
17
18 data = PostPageData{
19 Site: *cfg.GetSiteData(),
20@@ -199,6 +204,7 @@ func postHandler(w http.ResponseWriter, r *http.Request) {
21 Username: username,
22 BlogName: blogName,
23 Contents: template.HTML(parsedText),
24+ ExpiresAt: expiresAt,
25 }
26 } else {
27 logger.Infof("post not found %s/%s", username, slug)
28@@ -213,6 +219,7 @@ func postHandler(w http.ResponseWriter, r *http.Request) {
29 Username: username,
30 BlogName: blogName,
31 Contents: "oops! we can't seem to find this post.",
32+ ExpiresAt: "",
33 }
34 }
35
+31,
-2
1@@ -109,8 +109,8 @@ scp ./delete.txt {{.Site.Domain}}:/</pre>
2
3 <section id="pipe">
4 <h2 class="text-xl">
5- <a href="#pipe" rel="nofollow noopener">#</a>
6- Can I pipe my paste?
7+ <a href="#pipe" rel="nofollow noopener">#</a>
8+ Can I pipe my paste?
9 </h2>
10 <p>
11 Yes!
12@@ -120,6 +120,35 @@ scp ./delete.txt {{.Site.Domain}}:/</pre>
13 <pre># if the tty warning annoys you
14 echo "foobar" | ssh -T pastes.sh</pre>
15 </section>
16+
17+ <section id="expires">
18+ <h2 class="text-xl">
19+ <a href="#expires" rel="nofollow noopener">#</a>
20+ Can I set the expiration date to a paste?
21+ </h2>
22+ <p>
23+ Yes. The default expiration date for a paste is 90 days.
24+ We do allow the user to set the paste to never expire.
25+ We also allow custom <a href="https://pkg.go.dev/time#ParseDuration">duration</a>
26+ or <a href="https://pkg.go.dev/github.com/araddon/dateparse#ParseStrict">timestamp</a>.
27+ </p>
28+ <pre>echo "foobar" | ssh pastes.sh FILENAME expires=false</pre>
29+ <pre>echo "foobar" | ssh pastes.sh FILENAME expires=2023-12-12</pre>
30+ <pre>echo "foobar" | ssh pastes.sh FILENAME expires=1h</pre>
31+ </section>
32+
33+ <section id="unlisted">
34+ <h2 class="text-xl">
35+ <a href="#unlisted" rel="nofollow noopener">#</a>
36+ Can I hide pastes from my landing page?
37+ </h2>
38+ <p>
39+ Yes. Unlisted in this context means it does not show up on
40+ your user landing page where we show all of your pastes.
41+ In this case, yes, you can "hide" it using a pipe command.
42+ </p>
43+ <pre>echo "foobar" | ssh pastes.sh FILENAME hidden=true</pre>
44+ </section>
45 </main>
46 {{template "marketing-footer" .}}
47 {{end}}
+4,
-2
1@@ -85,7 +85,9 @@ echo "foobar" | ssh -T pastes.sh</pre>
2 <section>
3 <h2 class="text-lg font-bold">Features</h2>
4 <ul>
5- <li>Pastes last 90 days</li>
6+ <li>Pastes last <strong>90 days</strong> by default</li>
7+ <li><a href="/help#expires">Ability to set custom expiration</a></li>
8+ <li><a href="/help#unlisted">Ability to "hide" pastes</a></li>
9 <li>Bring your own editor</li>
10 <li>Terminal workflow with no installation</li>
11 <li>Public-key based authentication</li>
12@@ -106,7 +108,7 @@ echo "foobar" | ssh -T pastes.sh</pre>
13 <section>
14 <h2 class="text-lg font-bold">Roadmap</h2>
15 <ol>
16- <li>Ability to customize expiration</li>
17+ <li>Mobile support?</li>
18 </ol>
19 </section>
20 </main>
+1,
-0
1@@ -33,6 +33,7 @@
2 <span> | </span>
3 <a href="{{.RawURL}}">raw</a>
4 </p>
5+ <p class="font-bold m-0">expires: {{.ExpiresAt}}</p>
6 </header>
7 <main>
8 <article>
+39,
-41
1@@ -43,57 +43,55 @@ func (p *FileHooks) FileMeta(s ssh.Session, data *filehandlers.PostMetaData) err
2 data.ExpiresAt = &expiresAt
3 }
4
5- if p.Db.HasFeatureForUser(data.User.ID, "pastes-advanced") {
6- var hidden bool
7- var expiresFound bool
8- var expires *time.Time
9+ var hidden bool
10+ var expiresFound bool
11+ var expires *time.Time
12
13- cmd := s.Command()
14+ cmd := s.Command()
15
16- for _, arg := range cmd {
17- if strings.Contains(arg, "=") {
18- splitArg := strings.Split(arg, "=")
19- if len(splitArg) != 2 {
20+ for _, arg := range cmd {
21+ if strings.Contains(arg, "=") {
22+ splitArg := strings.Split(arg, "=")
23+ if len(splitArg) != 2 {
24+ continue
25+ }
26+
27+ switch splitArg[0] {
28+ case "hidden":
29+ val, err := strconv.ParseBool(splitArg[1])
30+ if err != nil {
31+ continue
32+ }
33+
34+ hidden = val
35+ case "expires":
36+ val, err := strconv.ParseBool(splitArg[1])
37+ if err == nil {
38+ expiresFound = !val
39 continue
40 }
41
42- switch splitArg[0] {
43- case "hidden":
44- val, err := strconv.ParseBool(splitArg[1])
45- if err != nil {
46- continue
47- }
48-
49- hidden = val
50- case "expires":
51- val, err := strconv.ParseBool(splitArg[1])
52- if err == nil {
53- expiresFound = !val
54- continue
55- }
56-
57- duration, err := time.ParseDuration(splitArg[1])
58- if err == nil {
59- expiresFound = true
60- expireTime := time.Now().Add(duration)
61- expires = &expireTime
62- continue
63- }
64-
65- expireTime, err := dateparse.ParseStrict(splitArg[1])
66- if err == nil {
67- expiresFound = true
68- expires = &expireTime
69- }
70+ duration, err := time.ParseDuration(splitArg[1])
71+ if err == nil {
72+ expiresFound = true
73+ expireTime := time.Now().Add(duration)
74+ expires = &expireTime
75+ continue
76+ }
77+
78+ expireTime, err := dateparse.ParseStrict(splitArg[1])
79+ if err == nil {
80+ expiresFound = true
81+ expires = &expireTime
82 }
83 }
84 }
85+ }
86
87- data.Hidden = hidden
88+ data.Hidden = hidden
89
90- if expiresFound {
91- data.ExpiresAt = expires
92- }
93+ if expiresFound {
94+ data.ExpiresAt = expires
95 }
96
97 return nil