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
|
package forge
import (
"errors"
"html/template"
"net/http"
"os"
"path/filepath"
"strings"
)
const renameSchema = `
create table if not exists renames (
old text primary key,
user integer not null references users(id) on delete cascade
);
`
func (s *Store) RenameUser(id int64, old, name string) error {
if !validName(name) {
return errors.New("Names are lowercase letters, digits, dot, dash or underscore, at most 39 characters")
}
tx, err := s.db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
if _, err := tx.Exec(`update users set name = ? where id = ?`, name, id); err != nil {
if strings.Contains(err.Error(), "UNIQUE") {
return errors.New("That name is taken")
}
return err
}
tx.Exec(`delete from renames where old = ?`, name)
if _, err := tx.Exec(`insert into renames(old, user) values (?, ?) on conflict(old) do update set user = excluded.user`, old, id); err != nil {
return err
}
return tx.Commit()
}
func (s *Store) Renamed(old string) (User, bool) {
var id int64
if s.db.QueryRow(`select r.user from renames r where r.old = ? and not exists (select 1 from users where name = r.old)`, old).Scan(&id) != nil {
return User{}, false
}
u, err := s.userByID(id)
return u, err == nil
}
func (s *Server) rename(w http.ResponseWriter, r *http.Request) {
u := s.require(w, r)
if u == nil {
return
}
fail := func(msg string) {
http.Redirect(w, r, "/settings?error="+template.URLQueryEscaper(msg)+"#username", http.StatusSeeOther)
}
name := strings.ToLower(strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(r.FormValue("name")), "~")))
if name == u.Name {
http.Redirect(w, r, "/settings", http.StatusSeeOther)
return
}
if _, ok := s.store.CheckPassword(u.Name, r.FormValue("password")); !ok {
s.limiter.fail(clientIP(r))
fail("Password is wrong")
return
}
if err := s.store.RenameUser(u.ID, u.Name, name); err != nil {
fail(err.Error())
return
}
from, to := filepath.Join(s.root, "repos", u.Name), filepath.Join(s.root, "repos", name)
os.Remove(to)
if err := os.Rename(from, to); err != nil && !os.IsNotExist(err) {
s.store.RenameUser(u.ID, name, u.Name)
fail("Could not move your repositories")
return
}
http.Redirect(w, r, "/settings", http.StatusSeeOther)
}
|