Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
package-lock.json
*.db
21 changes: 11 additions & 10 deletions db.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ import (

// Link is the structure stored for each go short link.
type Link struct {
Short string // the "foo" part of http://go/foo
Long string // the target URL or text/template pattern to run
Created time.Time
LastEdit time.Time // when the link was last edited
Owner string // user@domain
Short string // the "foo" part of http://go/foo
Long string // the target URL or text/template pattern to run
Created time.Time
LastEdit time.Time // when the link was last edited
Owner string // user@domain
GloballyEditable bool // when set, link is editable by everyone on the tailnet
}

// ClickStats is the number of clicks a set of links have received in a given
Expand Down Expand Up @@ -67,14 +68,14 @@ func NewSQLiteDB(f string) (*SQLiteDB, error) {
// The caller owns the returned values.
func (s *SQLiteDB) LoadAll() ([]*Link, error) {
var links []*Link
rows, err := s.db.Query("SELECT Short, Long, Created, LastEdit, Owner FROM Links")
rows, err := s.db.Query("SELECT Short, Long, Created, LastEdit, Owner, GloballyEditable FROM Links")
if err != nil {
return nil, err
}
for rows.Next() {
link := new(Link)
var created, lastEdit int64
err := rows.Scan(&link.Short, &link.Long, &created, &lastEdit, &link.Owner)
err := rows.Scan(&link.Short, &link.Long, &created, &lastEdit, &link.Owner, &link.GloballyEditable)
if err != nil {
return nil, err
}
Expand All @@ -93,8 +94,8 @@ func (s *SQLiteDB) LoadAll() ([]*Link, error) {
func (s *SQLiteDB) Load(short string) (*Link, error) {
link := new(Link)
var created, lastEdit int64
row := s.db.QueryRow("SELECT Short, Long, Created, LastEdit, Owner FROM Links WHERE ID = ?1 LIMIT 1", linkID(short))
err := row.Scan(&link.Short, &link.Long, &created, &lastEdit, &link.Owner)
row := s.db.QueryRow("SELECT Short, Long, Created, LastEdit, Owner, GloballyEditable FROM Links WHERE ID = ?1 LIMIT 1", linkID(short))
err := row.Scan(&link.Short, &link.Long, &created, &lastEdit, &link.Owner, &link.GloballyEditable)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
err = fs.ErrNotExist
Expand All @@ -108,7 +109,7 @@ func (s *SQLiteDB) Load(short string) (*Link, error) {

// Save saves a Link.
func (s *SQLiteDB) Save(link *Link) error {
result, err := s.db.Exec("INSERT OR REPLACE INTO Links (ID, Short, Long, Created, LastEdit, Owner) VALUES (?, ?, ?, ?, ?, ?)", linkID(link.Short), link.Short, link.Long, link.Created.Unix(), link.LastEdit.Unix(), link.Owner)
result, err := s.db.Exec("INSERT OR REPLACE INTO Links (ID, Short, Long, Created, LastEdit, Owner, GloballyEditable) VALUES (?, ?, ?, ?, ?, ?, ?)", linkID(link.Short), link.Short, link.Long, link.Created.Unix(), link.LastEdit.Unix(), link.Owner, link.GloballyEditable)
if err != nil {
return err
}
Expand Down
9 changes: 8 additions & 1 deletion golink.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,10 @@ func serveDetail(w http.ResponseWriter, r *http.Request) {
data.Link.Owner = login
}

if link.GloballyEditable {
data.Editable = true
}

detailTmpl.Execute(w, data)
}

Expand Down Expand Up @@ -456,7 +460,7 @@ func serveSave(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), http.StatusInternalServerError)
}

if link != nil && link.Owner != "" && link.Owner != login {
if link != nil && link.Owner != "" && link.Owner != login && !link.GloballyEditable {
exists, err := userExists(r.Context(), link.Owner)
if err != nil {
log.Printf("looking up tailnet user %q: %v", link.Owner, err)
Expand Down Expand Up @@ -484,6 +488,8 @@ func serveSave(w http.ResponseWriter, r *http.Request) {
owner = login
}

globallyEditable := r.FormValue("globally-editable") == "on"

now := time.Now().UTC()
if link == nil {
link = &Link{
Expand All @@ -495,6 +501,7 @@ func serveSave(w http.ResponseWriter, r *http.Request) {
link.Long = long
link.LastEdit = now
link.Owner = owner
link.GloballyEditable = globallyEditable
if err := db.Save(link); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
Expand Down
3 changes: 2 additions & 1 deletion schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ CREATE TABLE IF NOT EXISTS Links (
Long TEXT NOT NULL DEFAULT "",
Created INTEGER NOT NULL DEFAULT (strftime('%s', 'now')), -- unix seconds
LastEdit INTEGER NOT NULL DEFAULT (strftime('%s', 'now')), -- unix seconds
Owner TEXT NOT NULL DEFAULT ""
Owner TEXT NOT NULL DEFAULT "",
GloballyEditable INTEGER NOT NULL DEFAULT FALSE
);

CREATE TABLE IF NOT EXISTS Stats (
Expand Down
2 changes: 2 additions & 0 deletions tmpl/detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ <h2 class="text-xl font-bold pb-2">Link Details</h2>

<label for=owner class="text-sm font-bold block mt-4">Owner</label>
<input id=owner name=owner required type=text size=25 placeholder="Owner" value="{{.Link.Owner}}"{{if not .Editable}} disabled{{end}} class="p-2 rounded-md border-gray-300 placeholder:text-gray-400 disabled:bg-gray-100">
<input id=globally-editable name=globally-editable type=checkbox {{if .Link.GloballyEditable}} checked{{end}} class="p-2 rounded-md border-gray-300 disabled:bg-gray-100">
<label for=globally-editable>Editable by anyone</label>

<dl>
<dt class="text-sm font-bold mt-6">Date Created</dt>
Expand Down