Compare commits

..

49 Commits

Author SHA1 Message Date
bel cbba8fa7e4 meta header fixes high res devices 2024-01-21 13:57:22 -07:00
bel 072e4b279d embed water.css 2024-01-21 13:57:09 -07:00
Bel LaPointe 0a700f19c8 set /raw/ to cache 2024-01-09 15:04:51 -07:00
Bel LaPointe 5b645b1898 to gitea 2024-01-09 14:45:36 -07:00
Bel LaPointe a4d39d38dc gogs.inhome 2023-04-10 11:14:06 -06:00
Bel LaPointe 6a82a7d90c wip 2023-04-10 11:09:40 -06:00
bel b495652eb9 up go mod 2022-06-26 21:56:50 -06:00
bel 706b78257a submod 2022-06-26 21:27:04 -06:00
bel c1c5a9c021 firefox doesnt like big font anymore 2022-06-21 17:27:48 -06:00
Bel LaPointe 7f86e146a1 go mod 2021-09-17 08:23:07 -06:00
Bel LaPointe 46e79c0571 do not wrap button with anchor for edit and del 2021-09-03 19:23:45 -06:00
Bel LaPointe f931053650 search file names first 2021-07-29 07:14:33 -06:00
Bel LaPointe f2175e41a9 fix tests, 2021-07-29 07:08:49 -06:00
bel 2d16bf0ad5 ensure file size mb at least 1, fix shebang 2021-07-15 19:18:47 -06:00
Bel LaPointe 69ac5f1cbf gitignore vendor 2021-04-08 12:21:04 -05:00
Bel LaPointe 125455fcb6 trim right 2021-04-08 12:10:45 -05:00
Bel LaPointe 1b8f7f86f4 out of bounds 2021-03-29 07:59:29 -05:00
Bel LaPointe 6ea5f2c675 expandtab 2021-03-19 21:18:05 -05:00
Bel LaPointe 3b91c6782d vim editor 2021-03-16 15:55:46 -05:00
Bel LaPointe 5a16beb676 symlinks ok 2021-02-25 22:27:10 -06:00
Bel LaPointe 817fc57dd1 dont search attachments or git 2021-02-25 22:23:13 -06:00
Bel LaPointe 095ba7820d jsut in case 2021-02-25 22:17:32 -06:00
Bel LaPointe 96cce88aed no more todo 2021-02-25 22:10:18 -06:00
Bel LaPointe baf739658e create pre-commit file to skip big files 2021-02-25 22:09:50 -06:00
Bel LaPointe 0c6d3a6c6a script 2021-02-25 21:53:48 -06:00
Bel LaPointe e8ea8d8abf try 2021-02-25 20:56:07 -06:00
Bel LaPointe 79009305a1 mm 2021-02-25 20:46:50 -06:00
Bel LaPointe 03f5742a91 grrr 2021-02-25 20:46:19 -06:00
Bel LaPointe 4ad68109d2 gr 2021-02-25 20:34:53 -06:00
Bel LaPointe 61f97f2f0a big 2021-02-25 20:34:08 -06:00
Bel LaPointe 31ebc8ffbc big 2021-02-25 20:33:45 -06:00
Bel LaPointe 567c74bb57 big file 2021-02-25 20:33:30 -06:00
Bel LaPointe c4161c9db6 big file 2021-02-25 20:32:54 -06:00
Bel LaPointe fd67e7033b making a big file 2021-02-25 20:19:44 -06:00
Bel LaPointe cbd287e20e no log 2021-02-25 19:28:58 -06:00
Bel LaPointe 479caef353 create raw endpoint, link to it for attachments 2021-02-25 19:28:44 -06:00
Bel LaPointe 8fefc60f6b impl attach 2021-02-25 17:00:22 -06:00
Bel LaPointe 014076dd06 todo 2021-02-25 16:43:57 -06:00
Bel LaPointe d408229ba9 UI to attach 2021-02-25 16:43:32 -06:00
Bel LaPointe 47d6c37819 stupid scroll 2021-02-25 16:22:40 -06:00
Bel LaPointe 1eb8fa7223 rm dead 2021-02-25 15:45:23 -06:00
Bel LaPointe f9c28b3c45 exporterer 2020-09-28 10:06:17 -06:00
Bel LaPointe a26d34c2b3 export req less 2020-09-28 10:05:11 -06:00
Bel LaPointe 4d076ede3d export markdown 2020-09-28 09:48:34 -06:00
Bel LaPointe f60d0618e6 notes on ro dont have comments 2020-09-28 09:39:42 -06:00
Bel LaPointe b975a7c103 Explore other html renders but find nothing 2020-09-27 11:35:55 -06:00
Bel LaPointe 0e9150b8f6 Explicit extensions 2020-09-27 11:05:07 -06:00
Bel LaPointe 4fdbee6df5 Whoopsies fixed it 2020-08-07 13:46:39 -06:00
Bel LaPointe e6a126ea0b Remove dbeug logs 2020-08-07 13:08:42 -06:00
65 changed files with 1016 additions and 482 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
vendor
gollum
public
**.sw*

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
#! /usr/local/bin/python3
#! /usr/gitea.inhome.blapointe.com/local/bin/python3
def main(args) :
print("args", args)

251
config/water.css.txt Normal file
View File

@ -0,0 +1,251 @@
body{
font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;line-height:1.4;max-width:800px;margin:20px auto;padding:0 10px;word-wrap:break-word;color:#dbdbdb;background:#421531;text-rendering:optimizeLegibility
}.button,button,input,textarea{
transition:background-color .1s linear,border-color .1s linear,color .1s linear,box-shadow .1s linear,transform .1s ease
}h1{
font-size:2.2em;margin-top:0
}h1,h2,h3,h4,h5,h6{
margin-bottom:12px
}h1,h2,h3,h4,h5,h6,strong{
color:#fff
}b,h1,h2,h3,h4,h5,h6,strong,th{
font-weight:600
}q:after,q:before{
content:none
}blockquote,q{
border-left:4px solid #adb4a0;margin:1.5em 0;padding:.5em 1em;font-style:italic
}blockquote>footer{
font-style:normal;border:0
}address,blockquote cite{
font-style:normal
}a[href^=mailto\:]:before{
content:"📧 "
}a[href^=tel\:]:before{
content:"📞 "
}a[href^=sms\:]:before{
content:"💬 "
}mark{
background-color:#8fae83;border-radius:2px;padding:0 2px;color:#000
}.button,button,input[type=button],input[type=checkbox],input[type=radio],input[type=range],input[type=submit],select{
cursor:pointer
}input:not([type=checkbox]):not([type=radio]),select{
display:block
}.button,button,input,select,textarea{
color:#fff;background-color:#300330;font-family:inherit;font-size:inherit;margin-right:6px;margin-bottom:6px;padding:10px;border:none;border-radius:6px;outline:none
}.button,button,input,select,textarea{
-webkit-appearance:none
}textarea{
margin-right:0;width:100%;box-sizing:border-box;resize:vertical
}select{
background:#300330 url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='63' width='117' fill='%23efefef'%3E%3Cpath d='M115 2c-1-2-4-2-5 0L59 53 7 2a4 4 0 0 0-5 5l54 54 2 2 3-2 54-54c2-1 2-4 0-5z'/%3E%3C/svg%3E") calc(100% - 12px) 50%/12px no-repeat;padding-right:35px
}select::-ms-expand{
display:none
}select[multiple]{
padding-right:10px;background-image:none;overflow-y:auto
}.button,button,input[type=button],input[type=submit]{
padding-right:30px;padding-left:30px
}.button:hover,button:hover,input[type=button]:hover,input[type=submit]:hover{
background:#55354c
}.button:focus,button:focus,input:focus,select:focus,textarea:focus{
box-shadow:0 0 0 2px #adb4a0
}input[type=checkbox],input[type=radio]{
position:relative;width:14px;height:14px;display:inline-block;vertical-align:middle;margin:0 2px 0 0
}input[type=radio]{
border-radius:50%
}input[type=checkbox]:checked,input[type=radio]:checked{
background:#55354c
}input[type=checkbox]:checked:before,input[type=radio]:checked:before{
content:"•";display:block;position:absolute;left:50%;top:50%;transform:translateX(-50%) translateY(-50%)
}input[type=checkbox]:checked:before{
content:"✔";transform:translateY(-50%) translateY(.5px) translateX(-6px)
}.button:active,button:active,input[type=button]:active,input[type=checkbox]:active,input[type=radio]:active,input[type=range]:active,input[type=submit]:active{
transform:translateY(2px)
}.button:disabled,button:disabled,input:disabled,select:disabled,textarea:disabled{
cursor:not-allowed;opacity:.5
}::-webkit-input-placeholder{
color:#a9a9a9
}:-ms-input-placeholder{
color:#a9a9a9
}::-ms-input-placeholder{
color:#a9a9a9
}::placeholder{
color:#a9a9a9
}fieldset{
border:1px solid #adb4a0;border-radius:6px;margin:0 0 6px;padding:10px
}legend{
font-size:.9em;font-weight:600
}input[type=range]{
margin:10px 0;padding:10px 0;background:transparent
}input[type=range]:focus{
outline:none
}input[type=range]::-webkit-slider-runnable-track{
width:100%;height:9.5px;transition:.2s;background:#300330;border-radius:3px
}input[type=range]::-webkit-slider-thumb{
box-shadow:0 1px 1px #000,0 0 1px #0d0d0d;height:20px;width:20px;border-radius:50%;background:#dbdbdb;-webkit-appearance:none;margin-top:-7px
}input[type=range]:focus::-webkit-slider-runnable-track{
background:#300330
}input[type=range]::-moz-range-track{
width:100%;height:9.5px;transition:.2s;background:#300330;border-radius:3px
}input[type=range]::-moz-range-thumb{
box-shadow:1px 1px 1px #000,0 0 1px #0d0d0d;height:20px;width:20px;border-radius:50%;background:#dbdbdb
}input[type=range]::-ms-track{
width:100%;height:9.5px;background:transparent;border-color:transparent;border-width:16px 0;color:transparent
}input[type=range]::-ms-fill-lower,input[type=range]::-ms-fill-upper{
background:#300330;border:.2px solid #010101;border-radius:3px;box-shadow:1px 1px 1px #000,0 0 1px #0d0d0d
}input[type=range]::-ms-thumb{
box-shadow:1px 1px 1px #000,0 0 1px #0d0d0d;border:1px solid #000;height:20px;width:20px;border-radius:50%;background:#dbdbdb
}input[type=range]:focus::-ms-fill-lower,input[type=range]:focus::-ms-fill-upper{
background:#300330
}a{
text-decoration:none;color:#7fc090
}a:hover{
text-decoration:underline
}code,samp,time{
background:#300330;color:#dcff7f;padding:2.5px 5px;border-radius:6px;font-size:1em
}pre>code{
padding:10px;display:block;overflow-x:auto
}var{
color:#8a9e84;font-style:normal;font-family:monospace
}kbd{
background:#300330;border:1px solid #dbdbdb;border-radius:2px;color:#dbdbdb;padding:2px 4px
}img{
max-width:100%;height:auto
}hr{
border:none;border-top:1px solid #dbdbdb
}table{
border-collapse:collapse;margin-bottom:10px;width:100%
}td,th{
padding:6px;text-align:left
}thead{
border-bottom:1px solid #dbdbdb
}tfoot{
border-top:1px solid #dbdbdb
}tbody tr:nth-child(2n){
background-color:#3e0a2b
}::-webkit-scrollbar{
height:10px;width:10px
}::-webkit-scrollbar-track{
background:#300330;border-radius:6px
}::-webkit-scrollbar-thumb{
background:#55354c;border-radius:6px
}::-webkit-scrollbar-thumb:hover{
background:#6e4562
}::-moz-selection{
background-color:#200220
}::selection{
background-color:#200220
}details{
display:flex;flex-direction:column;align-items:flex-start;background-color:#3e0a2b;padding:10px 10px 0;margin:1em 0;border-radius:6px;overflow:hidden
}details[open]{
padding:10px
}details>:last-child{
margin-bottom:0
}details[open] summary{
margin-bottom:10px
}summary{
display:list-item;background-color:#300330;padding:10px;margin:-10px -10px 0
}details>:not(summary){
margin-top:0
}summary::-webkit-details-marker{
color:#dbdbdb
}footer{
border-top:1px solid #300330;padding-top:10px;font-size:.8em;color:#787878
}
button, input, select, textarea {
background-color: #300330;
}
thead, tr:nth-child(2n) {
background-color:#3e0a2b;
background-color:#300330 !important;
}
nav {
display: block;
background: #300330;
padding: .5pt;
border-radius: 6px;
}
nav li li li li {
display: none;
}
img {
max-height: 400px;
}
body {
/*font-size: 125%;*/
background: #3b242b;
margin-top: 0;
margin-bottom: 0;
height: calc(100vh - 1em);
overflow: auto;
display: flex;
flex-direction: column;
}
body > .form {
flex-grow: 2;
}
body > .form > form {
height: 100%;
display: flex;
flex-direction: column;
}
body > .form > form > textarea ,
body > .form > form > div {
flex-grow: 2;
}
rendered > h2:nth-child(2) {
margin: 0;
position: fixed;
padding: .25em;
width: 100%;
background: #3b242b;
top: 0;
}
h1, h2, h3, h4, h5, h6, h7, h8 {
position: relative;
}
.comment {
display: none;
margin: 0;
padding: 0;
flex-direction: column;
justify-content: center;
position: absolute;
right: 100%;
padding-right: 1em;
width: 10em;
top: 0;
text-align: right;
font-size: 12pt;
}
body > h2:first-of-type {
margin: 0;
margin-bottom: .5em;
padding: .3em 0 .3em 0;
background-color: #3b242b;
z-index: 999;
position: -webkit-sticky;
position: sticky;
top: 0;
}
h1:hover > .comment,
h2:hover > .comment,
h3:hover > .comment,
h4:hover > .comment,
h5:hover > .comment,
h6:hover > .comment,
h7:hover > .comment,
h8:hover > .comment,
.comment:focus,
.comment:focus-within {
display: inline-flex;
}
.attachments > details > form {
display: flex;
flex-direction: row;
width: 100%;
}
.attachments > details > form > input:first-of-type {
flex-grow: 2;
}

View File

@ -1,7 +1,7 @@
package filetree
import (
"local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/config"
"os"
"testing"
)

View File

@ -1,7 +1,7 @@
package filetree
import (
"local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/config"
"os"
"testing"
)

View File

@ -2,7 +2,7 @@ package filetree
import (
"fmt"
"local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/config"
"os"
"path"
"strings"

View File

@ -1,7 +1,7 @@
package filetree
import (
"local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/config"
"testing"
)

15
go.mod Normal file
View File

@ -0,0 +1,15 @@
module gitea.inhome.blapointe.com/local/notes-server
go 1.16
require (
gitea.inhome.blapointe.com/local/args v0.0.0-20240109214601-658deda479a4
gitea.inhome.blapointe.com/local/gziphttp v0.0.0-20240109214739-0d639b0a9eb9
gitea.inhome.blapointe.com/local/oauth2 v0.0.0-20240109220403-8897142866f1
gitea.inhome.blapointe.com/local/router v0.0.0-20231109150317-e6b81bf7c23c
github.com/fairlyblank/md2min v0.0.0-20171213131418-39cd6e9904ac
github.com/gomarkdown/markdown v0.0.0-20220607163217-45f7c050e2d1
github.com/russross/blackfriday v1.6.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0
github.com/yuin/goldmark v1.3.4-0.20210326114109-75d8cce5b78c
)

216
go.sum Normal file
View File

@ -0,0 +1,216 @@
bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
cloud.google.com/go v0.33.1/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
gitea.inhome.blapointe.com/local/args v0.0.0-20240109214601-658deda479a4 h1:4qBHjKAiEwRV1A1tN1JK6PsLV1+UwESXKrjGqfCCdNk=
gitea.inhome.blapointe.com/local/args v0.0.0-20240109214601-658deda479a4/go.mod h1:SqCOE3bE3wvrztVIQGHuyxHKfDjRKU9EWhBdkmkiwyc=
gitea.inhome.blapointe.com/local/gziphttp v0.0.0-20240109214739-0d639b0a9eb9 h1:Vq4jPYz6pCDMx7rxySw7SbKH3FHBywt1oS1TpXx4noM=
gitea.inhome.blapointe.com/local/gziphttp v0.0.0-20240109214739-0d639b0a9eb9/go.mod h1:YSOO/quInfKxfgqHH8exd71292hkLgqu2BO5oz6EATE=
gitea.inhome.blapointe.com/local/logb v0.0.0-20231109150430-1221d87a6dbc/go.mod h1:KwilawX4UgD4HxSJAVFEzkuckrnHeQrd49KwUX6GpYU=
gitea.inhome.blapointe.com/local/oauth2 v0.0.0-20240109220403-8897142866f1 h1:GO2/M+5a5i4FqiOnG6hq73nITDv2Rf8oTF973RsYQgo=
gitea.inhome.blapointe.com/local/oauth2 v0.0.0-20240109220403-8897142866f1/go.mod h1:XvS1/YJqCL+HoLo76dSLTjRYR+4Hfg4srhEVhMK3L8E=
gitea.inhome.blapointe.com/local/router v0.0.0-20231109150317-e6b81bf7c23c h1:+9kTZ3+ziuvmo+mC/xh/wVogFIAT1LeMzJMfSk0onsE=
gitea.inhome.blapointe.com/local/router v0.0.0-20231109150317-e6b81bf7c23c/go.mod h1:xYz/cn236KTBSWNQ9bqCyBmy8aQ7VL95pDDJmeupmN4=
gitea.inhome.blapointe.com/local/storage v0.0.0-20231109151605-736d446d407d/go.mod h1:TRK5z/XTT6jws++Q21Y8DQot+5vZGTNeHf+RjuY8aQk=
github.com/Azure/azure-pipeline-go v0.1.8/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg=
github.com/Azure/azure-storage-blob-go v0.0.0-20181023070848-cf01652132cc/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Unknwon/goconfig v0.0.0-20181105214110-56bd8ab18619/go.mod h1:wngxua9XCNjvHjDiTiV26DaKDT+0c63QR6H5hjVUUxw=
github.com/a8m/tree v0.0.0-20180321023834-3cf936ce15d6/go.mod h1:FSdwKX97koS5efgm8WevNf7XS3PqtyFkKDDXrz778cg=
github.com/abbot/go-http-auth v0.4.0/go.mod h1:Cz6ARTIzApMJDzh5bRMSUou6UMSp0IEXg9km/ci7TJM=
github.com/anacrolix/dms v0.0.0-20180117034613-8af4925bffb5/go.mod h1:DGqLjaZ3ziKKNRt+U5Q9PLWJ52Q/4rxfaaH/b3QYKaE=
github.com/aws/aws-sdk-go v1.15.81/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM=
github.com/billziss-gh/cgofuse v1.1.0/go.mod h1:LJjoaUojlVjgo5GQoEJTcJNqZJeRU0nCR84CyxKt2YM=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/coreos/bbolt v0.0.0-20180318001526-af9db2027c98/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/cpuguy83/go-md2man v1.0.8/go.mod h1:N6JayAiVKtlHSnuTCeuLSQVs75hb8q+dYQLjr7cDsKY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/djherbis/times v1.1.0/go.mod h1:CGMZlo255K5r4Yw0b9RRfFQpM2y7uOmxg4jm9HsaVf8=
github.com/dropbox/dropbox-sdk-go-unofficial v5.4.0+incompatible/go.mod h1:lr+LhMM3F6Y3lW1T9j2U5l7QeuWm87N9+PPXo3yH4qY=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/fairlyblank/md2min v0.0.0-20171213131418-39cd6e9904ac h1:MufpS7OgWOVDMM5dTYwJ3bHDlAc0/dPKUTpTLcFyi50=
github.com/fairlyblank/md2min v0.0.0-20171213131418-39cd6e9904ac/go.mod h1:QAobgT+CwT/SRphqV6Jrz5jt3wkW9Q72QNquEvh6dLk=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs=
github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=
github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=
github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=
github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=
github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=
github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
github.com/goftp/file-driver v0.0.0-20180502053751-5d604a0fc0c9/go.mod h1:GpOj6zuVBG3Inr9qjEnuVTgBlk2lZ1S9DcoFiXWyKss=
github.com/goftp/server v0.0.0-20190111142836-88de73f463af/go.mod h1:k/SS6VWkxY7dHPhoMQ8IdRu8L4lQtmGbhyXGg+vCnXE=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomarkdown/markdown v0.0.0-20220607163217-45f7c050e2d1 h1:wAupuFkZ/yq219/mSbqDtMfUZQY0gTYEtoz3/LKtppU=
github.com/gomarkdown/markdown v0.0.0-20220607163217-45f7c050e2d1/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jlaffaye/ftp v0.0.0-20181101112434-47f21d10f0ee/go.mod h1:lli8NYPQOFy3O++YmYbqVgOcQ1JPCwdOy+5zSjKJ9qY=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
github.com/minio/minio-go/v6 v6.0.57/go.mod h1:5+R/nM9Pwrh0vqF+HbYYDQ84wdUFPyXHkrdT4AIkifM=
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/ncw/go-acd v0.0.0-20171120105400-887eb06ab6a2/go.mod h1:MLIrzg7gp/kzVBxRE1olT7CWYMCklcUWU+ekoxOD9x0=
github.com/ncw/rclone v1.46.0/go.mod h1:+uFY4HNpat/yXXIEin5ETWXxIwEplC+eDe/vT8vlk1w=
github.com/ncw/swift v1.0.44/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/nsf/termbox-go v0.0.0-20181027232701-60ab7e3d12ed/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
github.com/okzk/sdnotify v0.0.0-20180710141335-d9becc38acbd/go.mod h1:4soZNh0zW0LtYGdQ416i0jO0EIqMGcbtaspRS4BDvRQ=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pengsrc/go-shared v0.2.0/go.mod h1:jVblp62SafmidSkvWrXyxAme3gaTfEtWwRPGz5cpvHg=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.8.3/go.mod h1:NxmoDg/QLVWluQDUYG7XBZTLUpKeFa8e3aMf1BfjyHk=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rfjakob/eme v0.0.0-20171028163933-2222dbd4ba46/go.mod h1:U2bmx0hDj8EyDdcxmD5t3XHDnBFnyNNc22n1R4008eM=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sevlyar/go-daemon v0.1.4/go.mod h1:6dJpPatBT9eUwM5VCw9Bt6CdX9Tk6UWvhW3MebLDRKE=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/t3rm1n4l/go-mega v0.0.0-20190205172012-55a226cf41da/go.mod h1:XWL4vDyd3JKmJx+hZWUVgCNmmhZ2dTBcaNDcxH465s0=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yuin/goldmark v1.3.4-0.20210326114109-75d8cce5b78c h1:cPcogYxzMuZfHQkeQtauv6Pq/cwtO4TPhAnWeq0v5q8=
github.com/yuin/goldmark v1.3.4-0.20210326114109-75d8cce5b78c/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yunify/qingstor-sdk-go v2.2.15+incompatible/go.mod h1:w6wqLDQ5bBTzxGJ55581UrSwLrsTAsdo9N6yX/8d9RY=
go.mongodb.org/mongo-driver v1.7.2/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/oauth2 v0.0.0-20181120190819-8f65e3013eba/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20181120235003-faade3cbb06a/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,9 +1,10 @@
package main
import (
"local/notes-server/config"
"local/notes-server/server"
"local/notes-server/versions"
"gitea.inhome.blapointe.com/local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/notes/editor"
"gitea.inhome.blapointe.com/local/notes-server/server"
"gitea.inhome.blapointe.com/local/notes-server/versions"
"log"
"net/http"
"os"
@ -12,6 +13,7 @@ import (
)
func main() {
log.Println(len(editor.CodeMirrorCSS))
server := server.New()
if err := server.Routes(); err != nil {
panic(err)

View File

@ -3,8 +3,8 @@ package main
import (
"fmt"
"io/ioutil"
"local/notes-server/config"
"local/notes-server/server"
"gitea.inhome.blapointe.com/local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/server"
"log"
"net/http"
"net/http/httptest"

View File

@ -7,7 +7,7 @@ import (
"fmt"
"io"
"io/ioutil"
"local/notes-server/filetree"
"gitea.inhome.blapointe.com/local/notes-server/filetree"
"os"
"path"
"strings"
@ -34,6 +34,9 @@ func (n *Notes) Comment(urlPath string, lineno int, comment string) error {
writer := io.Writer(f2)
for i := 0; i < lineno+1; i++ {
line, _, err := reader.ReadLine()
if err == io.EOF {
break
}
if err != nil {
return err
}
@ -46,14 +49,13 @@ func (n *Notes) Comment(urlPath string, lineno int, comment string) error {
return err
}
}
formatted := "\n"
formatted += fmt.Sprintf("> *%s*\n", comment)
formatted := fmt.Sprintf("> *%s*\n\n", comment)
_, err = io.Copy(writer, strings.NewReader(formatted))
if err != nil {
return err
}
_, err = io.Copy(writer, reader)
if err != nil {
if err != nil && err != io.EOF {
return err
}
f2.Close()

View File

@ -3,7 +3,7 @@ package notes
import (
"bytes"
"io/ioutil"
"local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/config"
"os"
"path"
"strings"
@ -42,7 +42,7 @@ func TestComment(t *testing.T) {
t.Error(err)
}
if err := n.Comment(fpath, 10000, "big line no"); err == nil {
if err := n.Comment(fpath, 10000, "big line no"); err != nil {
t.Error(err)
}

View File

@ -2,7 +2,7 @@ package notes
import (
"errors"
"local/notes-server/filetree"
"gitea.inhome.blapointe.com/local/notes-server/filetree"
"path"
)

View File

@ -1,7 +1,7 @@
package notes
import (
"local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/config"
"testing"
)

View File

@ -1,11 +1,16 @@
package notes
import (
"local/notes-server/filetree"
"fmt"
"gitea.inhome.blapointe.com/local/notes-server/filetree"
"os"
)
func (n *Notes) Delete(urlPath string) error {
p := filetree.NewPathFromURL(urlPath)
return os.Remove(p.Local)
err := os.Remove(p.Local)
if err != nil {
err = fmt.Errorf("failed to delete %q => %q: %v", urlPath, p.Local, err)
}
return err
}

View File

@ -2,8 +2,9 @@ package notes
import (
"io/ioutil"
"local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/config"
"os"
"path"
"testing"
)
@ -11,33 +12,43 @@ func TestDelete(t *testing.T) {
config.Root = "/tmp"
ioutil.WriteFile("/tmp/a", []byte("hi"), os.ModePerm)
n := &Notes{}
if err := n.Delete("/notes/a"); err != nil {
t.Error(err)
}
if _, err := os.Stat("/tmp/a"); err == nil {
t.Error(err)
}
d, err := ioutil.TempDir(os.TempDir(), "trydel*")
if err != nil {
t.Fatal(err)
}
for i := 0; i < 3; i++ {
f, err := ioutil.TempFile(d, "file*")
t.Run("delete 404", func(t *testing.T) {
if err := n.Delete("/notes/a"); err != nil {
t.Error(err)
}
if _, err := os.Stat("/tmp/a"); err == nil {
t.Error(err)
}
})
t.Run("delete w. content", func(t *testing.T) {
d, err := ioutil.TempDir(os.TempDir(), "trydel*")
if err != nil {
t.Fatal(err)
}
f.Close()
}
if err := n.Delete(d); err == nil {
t.Error(err)
}
config.Root = path.Dir(d)
for i := 0; i < 3; i++ {
f, err := ioutil.TempFile(d, "file*")
if err != nil {
t.Fatal(err)
}
f.Close()
}
if err := n.Delete("/abc/" + path.Base(d)); err == nil {
t.Error(err)
}
})
e, err := ioutil.TempDir(os.TempDir(), "trydel*")
if err != nil {
t.Fatal(err)
}
if err := n.Delete(e); err != nil {
t.Error(err)
}
t.Run("delete empty dir", func(t *testing.T) {
d2p := os.TempDir()
d2, err := ioutil.TempDir(d2p, "trydel*")
config.Root = path.Dir(d2p)
if err != nil {
t.Fatal(err)
}
if err := n.Delete("/abc/" + path.Base(d2)); err != nil {
t.Errorf("failed to del empty dir %s in %s: %v", d2, d2p, err)
}
})
}

View File

@ -3,7 +3,7 @@ package notes
import (
"errors"
"io/ioutil"
"local/notes-server/filetree"
"gitea.inhome.blapointe.com/local/notes-server/filetree"
)
func (n *Notes) Dir(urlPath string) (string, string, error) {

View File

@ -1,7 +1,7 @@
package notes
import (
"local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/config"
"testing"
)

View File

@ -4,7 +4,8 @@ import (
"errors"
"fmt"
"io/ioutil"
"local/notes-server/filetree"
"gitea.inhome.blapointe.com/local/notes-server/filetree"
"gitea.inhome.blapointe.com/local/notes-server/notes/editor"
"strings"
)
@ -26,11 +27,49 @@ func editFile(p filetree.Path) string {
}
b, _ := ioutil.ReadFile(p.Local)
return fmt.Sprintf(`
<form action="/submit/%s" method="post" style="width:100%%; height: 90%%">
<table style="width:100%%; height: 90%%">
<textarea name="content" style="width:100%%; min-height:90%%; cursor:crosshair;">%s</textarea>
</table>
<button type="submit">Submit</button>
</form>
`, href, b)
<div class="form">
<form action="/submit/%s" method="post">
<textarea id="mytext" name="content" style="cursor:crosshair;">%s</textarea>
<button type="submit">Submit</button>
</form>
</div>
<!--
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.59.4/codemirror.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.59.4/codemirror.min.css
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.59.4/keymap/vim.min.js
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.59.4/theme/dracula.min.css
-->
<script>%s</script>
<style>%s</style>
<script>%s</script>
<style>%s</style>
<script>
if( ! /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
CodeMirror.fromTextArea(document.getElementById("mytext"), {
lineNumbers: true,
mode: "md",
theme: "dracula",
keyMap: "vim",
smartIndent: true,
indentUnit: 3,
tabSize: 3,
indentWithTabs: false,
lineWrapping: true,
autofocus: true,
dragDrop: false,
spellcheck: true,
autocorrect: false,
autocapitalize: false,
extraKeys: {
Tab: (cm) => {
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
cm.replaceSelection(spaces);
},
},
})
} else {
console.log(navigator.userAgent)
}
</script>
`, href, b, editor.CodeMirrorJS, editor.CodeMirrorCSS, editor.CodeMirrorVIM, editor.CodeMirrorTheme)
}

View File

@ -1,7 +1,7 @@
package notes
import (
"local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/config"
"strings"
"testing"
)

1
notes/editor/codemirror.min.css vendored Normal file

File diff suppressed because one or more lines are too long

1
notes/editor/codemirror.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1
notes/editor/dracula.min.css vendored Normal file
View File

@ -0,0 +1 @@
.cm-s-dracula .CodeMirror-gutters,.cm-s-dracula.CodeMirror{background-color:#282a36!important;color:#f8f8f2!important;border:none}.cm-s-dracula .CodeMirror-gutters{color:#282a36}.cm-s-dracula .CodeMirror-cursor{border-left:solid thin #f8f8f0}.cm-s-dracula .CodeMirror-linenumber{color:#6d8a88}.cm-s-dracula .CodeMirror-selected{background:rgba(255,255,255,.1)}.cm-s-dracula .CodeMirror-line::selection,.cm-s-dracula .CodeMirror-line>span::selection,.cm-s-dracula .CodeMirror-line>span>span::selection{background:rgba(255,255,255,.1)}.cm-s-dracula .CodeMirror-line::-moz-selection,.cm-s-dracula .CodeMirror-line>span::-moz-selection,.cm-s-dracula .CodeMirror-line>span>span::-moz-selection{background:rgba(255,255,255,.1)}.cm-s-dracula span.cm-comment{color:#6272a4}.cm-s-dracula span.cm-string,.cm-s-dracula span.cm-string-2{color:#f1fa8c}.cm-s-dracula span.cm-number{color:#bd93f9}.cm-s-dracula span.cm-variable{color:#50fa7b}.cm-s-dracula span.cm-variable-2{color:#fff}.cm-s-dracula span.cm-def{color:#50fa7b}.cm-s-dracula span.cm-operator{color:#ff79c6}.cm-s-dracula span.cm-keyword{color:#ff79c6}.cm-s-dracula span.cm-atom{color:#bd93f9}.cm-s-dracula span.cm-meta{color:#f8f8f2}.cm-s-dracula span.cm-tag{color:#ff79c6}.cm-s-dracula span.cm-attribute{color:#50fa7b}.cm-s-dracula span.cm-qualifier{color:#50fa7b}.cm-s-dracula span.cm-property{color:#66d9ef}.cm-s-dracula span.cm-builtin{color:#50fa7b}.cm-s-dracula span.cm-type,.cm-s-dracula span.cm-variable-3{color:#ffb86c}.cm-s-dracula .CodeMirror-activeline-background{background:rgba(255,255,255,.1)}.cm-s-dracula .CodeMirror-matchingbracket{text-decoration:underline;color:#fff!important}

17
notes/editor/embed.go Normal file
View File

@ -0,0 +1,17 @@
package editor
import _ "embed"
var (
//go:embed codemirror.min.js
CodeMirrorJS string
//go:embed codemirror.min.css
CodeMirrorCSS string
//go:embed vim.min.js
CodeMirrorVIM string
//go:embed dracula.min.css
CodeMirrorTheme string
)

1
notes/editor/vim.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -7,16 +7,17 @@ import (
"fmt"
"io"
"io/ioutil"
"local/notes-server/filetree"
"log"
"gitea.inhome.blapointe.com/local/notes-server/filetree"
"gitea.inhome.blapointe.com/local/notes-server/notes/md"
"path"
"regexp"
"strings"
"github.com/gomarkdown/markdown"
"github.com/fairlyblank/md2min"
"github.com/gomarkdown/markdown/ast"
"github.com/gomarkdown/markdown/html"
"github.com/gomarkdown/markdown/parser"
blackfriday "github.com/russross/blackfriday/v2"
"github.com/yuin/goldmark"
)
func (n *Notes) File(urlPath string) (string, error) {
@ -25,13 +26,37 @@ func (n *Notes) File(urlPath string) (string, error) {
return "", errors.New("path is dir")
}
b, _ := ioutil.ReadFile(p.Local)
renderer := html.NewRenderer(html.RendererOptions{
Flags: html.CommonFlags | html.TOC,
RenderNodeHook: n.commentFormer(urlPath, b),
return n.gomarkdown(urlPath, b)
return n.blackfriday(urlPath, b)
return n.goldmark(urlPath, b)
return n.md2min(urlPath, b)
}
func (n *Notes) blackfriday(urlPath string, b []byte) (string, error) {
renderer := blackfriday.NewHTMLRenderer(blackfriday.HTMLRendererParameters{
Flags: blackfriday.TOC | blackfriday.Smartypants | blackfriday.SmartypantsFractions | blackfriday.SmartypantsDashes | blackfriday.SmartypantsQuotesNBSP | blackfriday.CompletePage,
})
parser := parser.NewWithExtensions(parser.CommonExtensions | parser.HeadingIDs | parser.AutoHeadingIDs | parser.Titleblock)
content := markdown.ToHTML(b, parser, renderer)
return string(content) + "\n", nil
return string(blackfriday.Run(
b,
blackfriday.WithRenderer(renderer),
)), nil
}
func (n *Notes) goldmark(urlPath string, b []byte) (string, error) {
buff := bytes.NewBuffer(nil)
err := goldmark.Convert(b, buff)
return string(buff.Bytes()), err
}
func (n *Notes) md2min(urlPath string, b []byte) (string, error) {
mdc := md2min.New("h1")
buff := bytes.NewBuffer(nil)
err := mdc.Parse(b, buff)
return string(buff.Bytes()), err
}
func (n *Notes) gomarkdown(urlPath string, b []byte) (string, error) {
return md.Gomarkdown(b, n.commentFormer(urlPath, b))
}
func (n *Notes) commentFormer(urlPath string, md []byte) html.RenderNodeFunc {
@ -42,18 +67,21 @@ func (n *Notes) commentFormer(urlPath string, md []byte) html.RenderNodeFunc {
nextHeader := func() {
cur++
for cur < len(lines) {
if bytes.Contains(lines[cur], []byte("```")) {
cur++
for cur < len(lines) && !bytes.Contains(lines[cur], []byte("```")) {
for _, opener_closer := range [][]string{{"```", "```"}, {`<summary>`, `</summary>`}} {
if cur < len(lines) && bytes.Contains(lines[cur], []byte(opener_closer[0])) {
cur++
for cur < len(lines) && !bytes.Contains(lines[cur], []byte(opener_closer[1])) {
cur++
}
cur++
}
cur++
}
if cur >= len(lines) {
break
}
line := lines[cur]
if ok, err := regexp.Match(`^\s*#+\s*[^\s]+\s*$`, line); err != nil {
ok, err := regexp.Match(`^\s*#+\s*.+$`, line)
if err != nil {
panic(err)
} else if ok {
return
@ -62,8 +90,7 @@ func (n *Notes) commentFormer(urlPath string, md []byte) html.RenderNodeFunc {
}
}
return func(w io.Writer, node ast.Node, entering bool) (ast.WalkStatus, bool) {
if heading, ok := node.(*ast.Heading); ok && !entering {
log.Printf("%+v", heading)
if heading, ok := node.(*ast.Heading); !n.RO && ok && !entering {
nextHeader()
fmt.Fprintf(w, `
<form method="POST" action=%q class="comment">

View File

@ -3,7 +3,7 @@ package notes
import (
"fmt"
"io/ioutil"
"local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/config"
"os"
"path"
"strings"

35
notes/md/file.go Executable file
View File

@ -0,0 +1,35 @@
package md
import (
"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/html"
"github.com/gomarkdown/markdown/parser"
)
func Gomarkdown(b []byte, renderHook html.RenderNodeFunc) (string, error) {
renderer := html.NewRenderer(html.RendererOptions{
Flags: html.CommonFlags | html.TOC,
RenderNodeHook: renderHook,
})
ext := parser.NoExtensions
for _, extension := range []parser.Extensions{
parser.NoIntraEmphasis,
parser.Tables,
parser.FencedCode,
parser.Autolink,
parser.Strikethrough,
parser.SpaceHeadings,
parser.HeadingIDs,
parser.BackslashLineBreak,
parser.DefinitionLists,
parser.MathJax,
parser.Titleblock,
parser.AutoHeadingIDs,
parser.Includes,
} {
ext |= extension
}
parser := parser.NewWithExtensions(ext)
content := markdown.ToHTML(b, parser, renderer)
return string(content) + "\n", nil
}

View File

@ -1,13 +1,15 @@
package notes
import "local/notes-server/config"
import "gitea.inhome.blapointe.com/local/notes-server/config"
type Notes struct {
root string
RO bool
}
func New() *Notes {
return &Notes{
root: config.Root,
RO: config.ReadOnly,
}
}

View File

@ -3,7 +3,8 @@ package notes
import (
"bufio"
"errors"
"local/notes-server/filetree"
"io"
"gitea.inhome.blapointe.com/local/notes-server/filetree"
"log"
"os"
"path"
@ -51,42 +52,59 @@ func (n *Notes) Search(phrase string) (string, error) {
if err != nil {
return "", err
}
perffiles := filetree.NewFiles()
files := filetree.NewFiles()
err = filepath.Walk(n.root,
func(walked string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
if !info.Mode().IsRegular() {
return nil
}
p := filetree.NewPathFromLocal(path.Dir(walked))
if ok, _ := searcher.stream(strings.NewReader(info.Name())); ok {
perffiles.Push(p, info)
return nil
}
if size := info.Size(); size < 1 || size > (5*1024*1024) {
return nil
}
ok, err := grepFile(walked, searcher)
ok, err := searcher.file(walked)
if err != nil && err.Error() == "bufio.Scanner: token too long" {
err = nil
}
if err == nil && ok {
p := filetree.NewPathFromLocal(path.Dir(walked))
files.Push(p, info)
}
if err != nil {
log.Printf("failed to scan %v: %v", walked, err)
} else if ok {
files.Push(p, info)
}
return err
},
)
return filetree.Paths(*files).List(true), err
for _, file := range *files {
*perffiles = append(*perffiles, file)
}
return filetree.Paths(*perffiles).List(true), err
}
func grepFile(file string, searcher *searcher) (bool, error) {
func (searcher *searcher) file(file string) (bool, error) {
if d := path.Base(path.Dir(file)); strings.HasPrefix(d, ".") && strings.HasSuffix(d, ".attachments") {
return false, nil
}
if strings.Contains(file, "/.git/") {
return false, nil
}
f, err := os.Open(file)
if err != nil {
return false, err
}
defer f.Close()
scanner := bufio.NewScanner(f)
return searcher.stream(f)
}
func (searcher *searcher) stream(r io.Reader) (bool, error) {
scanner := bufio.NewScanner(r)
for scanner.Scan() {
if searcher.matches(scanner.Bytes()) {
return true, scanner.Err()

View File

@ -34,7 +34,7 @@ func TestSearch(t *testing.T) {
t.Fatal(v, result)
}
result, err = n.Search("4")
result, err = n.Search("number.4")
if err != nil {
t.Fatal(err)
}
@ -45,7 +45,7 @@ func TestSearch(t *testing.T) {
func TestSearchBigFiles(t *testing.T) {
n := New()
n.root = "/usr/local/bin"
n.root = "/usr/gitea.inhome.blapointe.com/local/bin"
_, err := n.Search("this file")
if err != nil {

View File

@ -2,7 +2,7 @@ package notes
import (
"io/ioutil"
"local/notes-server/filetree"
"gitea.inhome.blapointe.com/local/notes-server/filetree"
"os"
"path"
)

View File

@ -2,7 +2,7 @@ package notes
import (
"io/ioutil"
"local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/config"
"os"
"testing"
)

View File

@ -1,24 +0,0 @@
package notes
import (
"html"
"local/notes-server/filetree"
"net/http"
"path"
"strings"
)
func (n *Notes) Create(w http.ResponseWriter, r *http.Request) {
content := r.FormValue("base")
content = html.UnescapeString(content)
content = strings.ReplaceAll(content, "\r", "")
urlPath := path.Join(r.URL.Path, content)
p := filetree.NewPathFromURL(urlPath)
if p.IsDir() {
w.WriteHeader(http.StatusBadRequest)
return
}
url := *r.URL
url.Path = path.Join("/edit/", p.BaseHREF)
http.Redirect(w, r, url.String(), http.StatusSeeOther)
}

View File

@ -1 +0,0 @@
package notes

View File

@ -1,37 +0,0 @@
package notes
import (
"fmt"
"io/ioutil"
"net/http"
"path"
)
func notesDir(p Path, w http.ResponseWriter, r *http.Request) {
dirs, files := lsDir(p)
content := dirs.List()
notesDirHead(p, w)
block(content, w)
fmt.Fprintln(w, files.List())
}
func notesDirHead(p Path, w http.ResponseWriter) {
fmt.Fprintf(w, `
<form action=%q method="get">
<input type="text" name="base"></input>
<button type="submit">Create</button>
</form>
`, path.Join("/create/", p.BaseHREF))
}
func lsDir(path Path) (Paths, Paths) {
dirs := newDirs()
files := newFiles()
found, _ := ioutil.ReadDir(path.Local)
for _, f := range found {
dirs.Push(path, f)
files.Push(path, f)
}
return Paths(*dirs), Paths(*files)
}

View File

@ -1,26 +0,0 @@
package notes
import (
"net/http/httptest"
"testing"
)
func TestLsDir(t *testing.T) {
p := Path{Local: "/usr/local"}
dirs, files := lsDir(p)
if len(dirs) == 0 {
t.Fatal(len(dirs))
}
if len(files) == 0 {
t.Fatal(len(files))
}
t.Log(dirs)
t.Log(files)
}
func TestNotesDir(t *testing.T) {
path := Path{Local: "/usr/local"}
w := httptest.NewRecorder()
notesDir(path, w, nil)
t.Logf("%s", w.Body.Bytes())
}

View File

@ -1,43 +0,0 @@
package notes
import (
"fmt"
"io/ioutil"
"net/http"
"strings"
)
func (s *Server) edit(w http.ResponseWriter, r *http.Request) {
p := NewPathFromURL(r.URL.Path)
if p.IsDir() {
http.NotFound(w, r)
return
}
head(w, r)
editHead(w, p)
editFile(w, p)
foot(w, r)
}
func editHead(w http.ResponseWriter, p Path) {
fmt.Fprintln(w, h2(p.MultiLink()))
}
func editFile(w http.ResponseWriter, p Path) {
href := p.HREF
href = strings.TrimPrefix(href, "/")
hrefs := strings.SplitN(href, "/", 2)
href = hrefs[0]
if len(hrefs) > 1 {
href = hrefs[1]
}
b, _ := ioutil.ReadFile(p.Local)
fmt.Fprintf(w, `
<form action="/submit/%s" method="post" style="width:100%%; height: 90%%">
<table style="width:100%%; height: 90%%">
<textarea name="content" style="width:100%%; min-height:90%%">%s</textarea>
</table>
<button type="submit">Submit</button>
</form>
`, href, b)
}

View File

@ -1 +0,0 @@
package notes

View File

@ -1,29 +0,0 @@
package notes
import (
"fmt"
"io/ioutil"
"net/http"
"path"
"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/html"
"github.com/gomarkdown/markdown/parser"
)
func notesFile(p Path, w http.ResponseWriter, r *http.Request) {
b, _ := ioutil.ReadFile(p.Local)
notesFileHead(p, w)
renderer := html.NewRenderer(html.RendererOptions{
Flags: html.CommonFlags | html.TOC,
})
parser := parser.NewWithExtensions(parser.CommonExtensions | parser.HeadingIDs | parser.AutoHeadingIDs | parser.Titleblock)
content := markdown.ToHTML(b, parser, renderer)
fmt.Fprintf(w, "%s\n", content)
}
func notesFileHead(p Path, w http.ResponseWriter) {
fmt.Fprintf(w, `
<a href=%q><input type="button" value="Edit"></input></a>
`, path.Join("/edit/", p.BaseHREF))
}

View File

@ -1,46 +0,0 @@
package notes
import (
"fmt"
"io/ioutil"
"net/http/httptest"
"os"
"strings"
"testing"
)
func TestNotesFile(t *testing.T) {
f, err := ioutil.TempFile(os.TempDir(), "until*")
if err != nil {
t.Fatal(err)
}
defer os.Remove(f.Name())
fmt.Fprintln(f, `
# Hello
## World
* This
* is
* bullets
| My | table | goes |
|----|-------|------|
| h | e | n |
`)
f.Close()
w := httptest.NewRecorder()
p := Path{Local: f.Name()}
notesFile(p, w, nil)
s := string(w.Body.Bytes())
shouldContain := []string{
"tbody",
"h1",
"h2",
}
for _, should := range shouldContain {
if !strings.Contains(s, should) {
t.Fatalf("%s: %s", should, s)
}
}
t.Logf("%s", s)
}

View File

@ -1,13 +0,0 @@
package notes
import "local/notes-server/config"
type Notes struct {
root string
}
func New() *Notes {
return &Notes{
root: config.Root,
}
}

View File

@ -1,27 +0,0 @@
package notes
import (
"fmt"
"net/http"
)
func (s *Server) notes(w http.ResponseWriter, r *http.Request) {
p := NewPathFromURL(r.URL.Path)
if p.IsDir() {
head(w, r)
notesHead(w, p)
notesDir(p, w, r)
foot(w, r)
} else if p.IsFile() {
head(w, r)
notesHead(w, p)
notesFile(p, w, r)
foot(w, r)
} else {
http.NotFound(w, r)
}
}
func notesHead(w http.ResponseWriter, p Path) {
fmt.Fprintln(w, h2(p.MultiLink()))
}

View File

@ -1 +0,0 @@
package notes

View File

@ -1,31 +0,0 @@
package notes
import (
"fmt"
"html"
"io/ioutil"
"net/http"
"os"
"path"
"strings"
)
func (s *Server) submit(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.NotFound(w, r)
return
}
content := r.FormValue("content")
content = html.UnescapeString(content)
content = strings.ReplaceAll(content, "\r", "")
p := NewPathFromURL(r.URL.Path)
os.MkdirAll(path.Dir(p.Local), os.ModePerm)
if err := ioutil.WriteFile(p.Local, []byte(content), os.ModePerm); err != nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintln(w, err)
} else {
url := *r.URL
url.Path = path.Join("/notes/", p.BaseHREF)
http.Redirect(w, r, url.String(), http.StatusSeeOther)
}
}

View File

@ -1 +0,0 @@
package notes

48
server/attach.go Executable file
View File

@ -0,0 +1,48 @@
package server
import (
"errors"
"io"
"gitea.inhome.blapointe.com/local/notes-server/filetree"
"net/http"
"os"
"path"
"strings"
)
func (s *Server) attach(w http.ResponseWriter, r *http.Request) {
if err := s._attach(w, r); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func (s *Server) _attach(w http.ResponseWriter, r *http.Request) error {
r.ParseMultipartForm(100 << 20)
file, handler, err := r.FormFile("file")
if err != nil {
return err
}
defer file.Close()
ft := filetree.NewPathFromURL(r.URL.Path)
local := ft.Local
target := path.Join(path.Dir(local), "."+path.Base(local)+".attachments", handler.Filename)
os.MkdirAll(path.Dir(target), os.ModePerm)
if fi, err := os.Stat(target); err != nil && !os.IsNotExist(err) {
return err
} else if err == nil && fi.IsDir() {
return errors.New("invalid path")
}
f, err := os.Create(target)
if err != nil {
return err
}
defer f.Close()
if _, err := io.Copy(f, file); err != nil {
return err
}
http.Redirect(w, r, "/notes"+strings.TrimPrefix(ft.HREF, "/attach"), http.StatusSeeOther)
return nil
}

View File

@ -2,8 +2,7 @@ package server
import (
"html"
"local/notes-server/filetree"
"log"
"gitea.inhome.blapointe.com/local/notes-server/filetree"
"net/http"
"path"
"strconv"
@ -11,7 +10,6 @@ import (
)
func (s *Server) comment(w http.ResponseWriter, r *http.Request) {
log.Println("COMMAND", r.Method, r.FormValue("lineno"), r.FormValue("content"))
if r.Method != "POST" {
http.NotFound(w, r)
return

View File

@ -2,7 +2,7 @@ package server
import (
"fmt"
"local/notes-server/filetree"
"gitea.inhome.blapointe.com/local/notes-server/filetree"
"net/http"
)

View File

@ -2,7 +2,7 @@ package server
import (
"fmt"
"local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/config"
"net/http"
)

View File

@ -1,7 +1,7 @@
package server
import (
"local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/config"
"net/http/httptest"
"regexp"
"strings"

View File

@ -2,10 +2,12 @@ package server
import (
"fmt"
"local/notes-server/config"
"local/notes-server/filetree"
"gitea.inhome.blapointe.com/local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/filetree"
"net/http"
"path"
"regexp"
"strings"
)
func (s *Server) notes(w http.ResponseWriter, r *http.Request) {
@ -49,21 +51,23 @@ func (s *Server) file(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
fileHead(w, filetree.NewPathFromURL(r.URL.Path).BaseHREF)
s.fileHead(w, r.URL.Path)
fmt.Fprintln(w, file)
}
func fileHead(w http.ResponseWriter, baseHREF string) {
func (s *Server) fileHead(w http.ResponseWriter, path string) {
baseHREF := filetree.NewPathFromURL(path).BaseHREF
htmlEdit(w, baseHREF)
htmlDelete(w, baseHREF)
s.htmlAttachments(w, path)
}
func htmlEdit(w http.ResponseWriter, baseHREF string) {
if config.ReadOnly {
return
}
fmt.Fprintf(w, `<div style='display:inline-block'>
<a href=%q><input type="button" value="Edit"></input></a>
fmt.Fprintf(w, `<div style='display:inline-block; margin-top: .75em; margin-bottom: .75em;'>
<a href=%q class="button">Edit</a>
</div><br>`, path.Join("/edit/", baseHREF))
}
@ -71,20 +75,53 @@ func htmlDelete(w http.ResponseWriter, baseHREF string) {
if config.ReadOnly {
return
}
fmt.Fprintf(w, `<div style='display:inline-block'>
<a href=%q><input type="button" value="Delete" onclick="return confirm('Delete?');"></input></a>
fmt.Fprintf(w, `<div style='display:inline-block; margin-top: .75em; margin-bottom: .75em;'>
<a href=%q class="button" onclick="return confirm('Delete?');">Delete</a>
</div><br>`, path.Join("/delete/", baseHREF))
}
func (s *Server) htmlAttachments(w http.ResponseWriter, urlPath string) {
dir := path.Dir(urlPath)
f := "." + path.Base(urlPath) + ".attachments"
_, files, _ := s.Notes.Dir(path.Join(dir, f))
form := fmt.Sprintf(`
<form enctype="multipart/form-data" action="/attach/%s" method="post">
<input type="file" name="file" required/>
<input type="submit" value="+"/>
</form>
`, strings.TrimPrefix(urlPath, "/notes/"))
if config.ReadOnly {
form = ""
}
lines := strings.Split(files, "\n")
for i := range lines {
pattern := regexp.MustCompile(`\.(png|jpg|jpeg|gif)">`)
if !pattern.MatchString(lines[i]) {
lines[i] = strings.ReplaceAll(lines[i], "<a", "<a download")
}
lines[i] = strings.ReplaceAll(lines[i], `href="/notes`, `href="/raw`)
}
files = strings.Join(lines, "\n")
fmt.Fprintf(w, `<div style='display:inline-block' class="attachments">
<details>
<summary style="display: flex">
<span style="flex-grow: 2">Attachments</span>
</summary>
%s
%s
</details>
</div><br>`, form, files)
}
func htmlCreate(w http.ResponseWriter, baseHREF string) {
if config.ReadOnly {
return
}
fmt.Fprintf(w, `
<form action=%q method="get">
<input type="text" name="base"></input>
<button type="submit">Create</button>
</form>
<form action=%q method="get">
<input type="text" name="base"></input>
<button type="submit">Create</button>
</form>
`, path.Join("/create/", baseHREF))
}

34
server/raw.go Executable file
View File

@ -0,0 +1,34 @@
package server
import (
"io"
"net/http"
"os"
"gitea.inhome.blapointe.com/local/gziphttp"
"gitea.inhome.blapointe.com/local/notes-server/filetree"
)
func (s *Server) raw(w http.ResponseWriter, r *http.Request) {
if err := s._raw(w, r); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func (s *Server) _raw(w http.ResponseWriter, r *http.Request) error {
gziphttp.SetContentTypeIfMedia(w, r)
p := filetree.NewPathFromURL(r.URL.Path)
if !p.IsFile() {
http.NotFound(w, r)
return nil
}
f, err := os.Open(p.Local)
if err != nil {
return err
}
defer f.Close()
if _, err := io.Copy(w, f); err != nil {
return err
}
return nil
}

View File

@ -2,12 +2,13 @@ package server
import (
"fmt"
"local/gziphttp"
"local/notes-server/config"
"local/router"
"net/http"
"path/filepath"
"strings"
"gitea.inhome.blapointe.com/local/gziphttp"
"gitea.inhome.blapointe.com/local/notes-server/config"
"gitea.inhome.blapointe.com/local/router"
)
func (s *Server) Routes() error {
@ -18,6 +19,9 @@ func (s *Server) Routes() error {
"/": {
handler: s.root,
},
fmt.Sprintf("raw/%s%s", wildcard, wildcard): {
handler: s.gzip(s.authenticate(s.cached(s.raw))),
},
fmt.Sprintf("notes/%s%s", wildcard, wildcard): {
handler: s.gzip(s.authenticate(s.notes)),
},
@ -33,6 +37,9 @@ func (s *Server) Routes() error {
fmt.Sprintf("create/%s%s", wildcard, wildcard): {
handler: s.gzip(s.authenticate(s.create)),
},
fmt.Sprintf("attach/%s%s", wildcard, wildcard): {
handler: s.gzip(s.authenticate(s.attach)),
},
fmt.Sprintf("comment/%s%s", wildcard, wildcard): {
handler: s.gzip(s.authenticate(s.comment)),
},
@ -43,7 +50,13 @@ func (s *Server) Routes() error {
for path, endpoint := range endpoints {
if config.ReadOnly {
for _, prefix := range []string{"edit/", "delete/", "delete/", "create/", "submit/"} {
for _, prefix := range []string{
"edit/",
"delete/",
"create/",
"submit/",
"attach/",
} {
if strings.HasPrefix(path, prefix) {
endpoint.handler = http.NotFound
}

View File

@ -3,7 +3,7 @@ package server
import (
"fmt"
"html"
"local/notes-server/filetree"
"gitea.inhome.blapointe.com/local/notes-server/filetree"
"net/http"
)

View File

@ -1,12 +1,13 @@
package server
import (
"local/notes-server/config"
"local/notes-server/notes"
"local/oauth2/oauth2client"
"local/router"
"log"
"net/http"
"gitea.inhome.blapointe.com/local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/notes"
"gitea.inhome.blapointe.com/local/oauth2/oauth2client"
"gitea.inhome.blapointe.com/local/router"
)
type Server struct {
@ -21,6 +22,13 @@ func New() *Server {
}
}
func (s *Server) cached(foo http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "private, max-age=7776000")
foo(w, r)
}
}
func (s *Server) authenticate(foo http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if config.OAuthServer != "" {

View File

@ -1,8 +1,10 @@
package server
import (
"bytes"
"fmt"
"html"
"local/notes-server/filetree"
"gitea.inhome.blapointe.com/local/notes-server/filetree"
"net/http"
"path"
"strings"
@ -16,6 +18,7 @@ func (s *Server) submit(w http.ResponseWriter, r *http.Request) {
content := r.FormValue("content")
content = html.UnescapeString(content)
content = strings.ReplaceAll(content, "\r", "")
content = trimLines(content)
err := s.Notes.Submit(r.URL.Path, content)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
@ -25,3 +28,12 @@ func (s *Server) submit(w http.ResponseWriter, r *http.Request) {
url.Path = path.Join("/notes/", filetree.NewPathFromURL(r.URL.Path).BaseHREF)
http.Redirect(w, r, url.String(), http.StatusSeeOther)
}
func trimLines(s string) string {
buff := bytes.NewBuffer(nil)
for _, line := range strings.Split(s, "\n") {
fmt.Fprintln(buff, strings.TrimRight(line, "\n \r\t"))
}
fixed := string(buff.Bytes())
return fixed[:len(fixed)-1]
}

36
server/submit_test.go Normal file
View File

@ -0,0 +1,36 @@
package server
import "testing"
func TestTrimLines(t *testing.T) {
t.Run("no newline at end", func(t *testing.T) {
s := `
hello
world`
s += " "
s += " \t"
got := trimLines(s)
want := `
hello
world`
if got != want {
t.Fatalf("want %q, got %q", want, got)
}
})
t.Run("noop", func(t *testing.T) {
s := `hi`
got := trimLines(s)
want := `hi`
if got != want {
t.Fatalf("want %q, got %q", want, got)
}
})
t.Run("newline", func(t *testing.T) {
s := "hi\n"
got := trimLines(s)
want := "hi\n"
if got != want {
t.Fatalf("want %q, got %q", want, got)
}
})
}

View File

@ -1,7 +1,7 @@
package versions
import (
"local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/config"
"time"
git "gopkg.in/src-d/go-git.v4"

View File

@ -2,7 +2,7 @@ package versions
import (
"io/ioutil"
"local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/config"
"os"
"path"
"testing"

38
versions/max_file_size.go Normal file
View File

@ -0,0 +1,38 @@
package versions
import (
"fmt"
"gitea.inhome.blapointe.com/local/notes-server/config"
"strings"
)
func getScript() string {
maxSizeMB := config.MaxSizeMB
if maxSizeMB == 0 {
maxSizeMB = 1
}
return strings.ReplaceAll(script, "{{{MAXSIZE}}}", fmt.Sprint(maxSizeMB<<20))
}
const script = `#!/bin/bash
function main() {
local maxsize={{{MAXSIZE}}}
if [[ "$maxsize" == 0 ]]; then
return
fi
(
git diff --name-only --cached
git diff --name-only
git ls-files --others --exclude-standard
) 2>&1 \
| sort -u \
| while read -r file; do
local size="$(du -sk "$file" | awk '{print $1}')000"
if [ "$size" -gt "$maxsize" ]; then
echo "file=$file, size=$size, max=$maxsize" >&2
git reset HEAD -- "$file"
fi
done
}
main
`

View File

@ -2,8 +2,13 @@ package versions
import (
"fmt"
"local/notes-server/config"
"io/ioutil"
"gitea.inhome.blapointe.com/local/notes-server/config"
"log"
"os"
"os/exec"
"path"
"strings"
"time"
)
@ -15,7 +20,9 @@ func New() (*Versions, error) {
v.cmd("git", "init")
v.cmd("git", "config", "user.email", "user@user.user")
v.cmd("git", "config", "user.name", "user")
return v, nil
s := getScript()
err := ioutil.WriteFile(path.Join(config.Root, "./.git/hooks/pre-commit"), []byte(s), os.ModePerm)
return v, err
}
func (v *Versions) Gitmmit() error {
@ -39,6 +46,9 @@ func (v *Versions) Commit() error {
func (v *Versions) cmd(cmd string, args ...string) error {
command := exec.Command(cmd, args...)
command.Dir = config.Root
_, err := command.CombinedOutput()
out, err := command.CombinedOutput()
if err != nil {
log.Println(cmd, args, ":", strings.TrimSpace(string(out)))
}
return err
}

View File

@ -2,7 +2,7 @@ package versions
import (
"io/ioutil"
"local/notes-server/config"
"gitea.inhome.blapointe.com/local/notes-server/config"
"os"
"path"
"testing"