Compare commits

...

3 Commits

18 changed files with 253 additions and 242 deletions
+5 -5
View File
@@ -1042,8 +1042,8 @@ func (s *Store) ListSSHAccessProfilesForUser(userID string) ([]models.SSHAccessP
p.owner_scope = ?
AND p.enabled = 1
AND s.enabled = 1
AND (p.valid_after = 0 OR p.valid_after <= strftime('%s','now'))
AND (p.valid_before = 0 OR p.valid_before >= strftime('%s','now'))
AND (p.valid_after = 0 OR p.valid_after <= CAST(strftime('%s','now') AS INTEGER))
AND (p.valid_before = 0 OR p.valid_before >= CAST(strftime('%s','now') AS INTEGER))
AND (
(t.target_type = 'user' AND tu.public_id = ?)
OR
@@ -1234,9 +1234,9 @@ func (s *Store) GetSSHAccessProfileForUser(userID string, id string) (models.SSH
p.owner_scope = ?
AND p.enabled = 1
AND s.enabled = 1
AND (p.valid_after = 0 OR p.valid_after <= strftime('%s','now'))
AND (p.valid_before = 0 OR p.valid_before >= strftime('%s','now'))
AND (
AND (p.valid_after = 0 OR p.valid_after <= CAST(strftime('%s','now') AS INTEGER))
AND (p.valid_before = 0 OR p.valid_before >= CAST(strftime('%s','now') AS INTEGER))
AND (
(t.target_type = 'user' AND tu.public_id = ?)
OR
(t.target_type = 'group' AND ug.disabled = 0 AND (ug.scope = 'all_users' OR gu.public_id = ?))
+68 -155
View File
@@ -11,7 +11,6 @@ import "codit/internal/util"
func (s *Store) CreateUser(user models.User, passwordHash string) (models.User, error) {
var id string
var err error
var now time.Time
var nowUnix int64
if user.ID == "" {
id, err = util.NewID()
@@ -20,44 +19,39 @@ func (s *Store) CreateUser(user models.User, passwordHash string) (models.User,
}
user.ID = id
}
now = time.Now().UTC()
nowUnix = now.Unix()
nowUnix = time.Now().UTC().Unix()
user.CreatedAt = nowUnix
user.UpdatedAt = nowUnix
_, err = s.Exec(`
INSERT INTO users (public_id, username, display_name, email, password_hash, is_admin, disabled, auth_provider_id, totp_required, external_subject, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, CASE WHEN ? = '' THEN NULL ELSE (SELECT id FROM auth_providers WHERE public_id = ?) END, ?, ?, ?, ?)
`, user.ID, user.Username, user.DisplayName, user.Email, passwordHash, user.IsAdmin, user.Disabled, user.AuthProviderID, user.AuthProviderID, user.TOTPRequired, user.ExternalSubject, now, now)
`, user.ID, user.Username, user.DisplayName, user.Email, passwordHash, user.IsAdmin, user.Disabled, user.AuthProviderID, user.AuthProviderID, user.TOTPRequired, user.ExternalSubject, nowUnix, nowUnix)
return user, err
}
func (s *Store) UpdateUser(user models.User) error {
var err error
var now time.Time
var nowUnix int64
now = time.Now().UTC()
nowUnix = now.Unix()
nowUnix = time.Now().UTC().Unix()
user.UpdatedAt = nowUnix
_, err = s.Exec(`UPDATE users SET display_name = ?, email = ?, is_admin = ?, disabled = ?, totp_required = ?, updated_at = ? WHERE public_id = ?`,
user.DisplayName, user.Email, user.IsAdmin, user.Disabled, user.TOTPRequired, now, user.ID)
user.DisplayName, user.Email, user.IsAdmin, user.Disabled, user.TOTPRequired, nowUnix, user.ID)
return err
}
func (s *Store) UpdateUserWithPassword(user models.User, passwordHash string) error {
var err error
var now time.Time
var nowUnix int64
var tx *sql.Tx
var owned bool
now = time.Now().UTC()
nowUnix = now.Unix()
nowUnix = time.Now().UTC().Unix()
user.UpdatedAt = nowUnix
tx, owned, err = s.begin()
if err != nil {
return err
}
_, err = tx.Exec(`UPDATE users SET display_name = ?, email = ?, is_admin = ?, disabled = ?, totp_required = ?, password_hash = ?, updated_at = ? WHERE public_id = ?`,
user.DisplayName, user.Email, user.IsAdmin, user.Disabled, user.TOTPRequired, passwordHash, now, user.ID)
user.DisplayName, user.Email, user.IsAdmin, user.Disabled, user.TOTPRequired, passwordHash, nowUnix, user.ID)
if err != nil {
rollbackIfOwned(tx, owned)
return err
@@ -71,23 +65,19 @@ func (s *Store) UpdateUserWithPassword(user models.User, passwordHash string) er
func (s *Store) SetUserPassword(userID, passwordHash string) error {
var err error
_, err = s.Exec(`UPDATE users SET password_hash = ?, updated_at = ? WHERE public_id = ?`, passwordHash, time.Now().UTC(), userID)
_, err = s.Exec(`UPDATE users SET password_hash = ?, updated_at = ? WHERE public_id = ?`, passwordHash, time.Now().UTC().Unix(), userID)
return err
}
func (s *Store) GetUserByID(id string) (models.User, error) {
var user models.User
var row *sql.Row
var created time.Time
var updated time.Time
var err error
row = s.QueryRow(`SELECT u.public_id, u.username, u.display_name, u.email, u.is_admin, u.disabled, COALESCE(ap.public_id, ''), COALESCE(t.enabled, 0), u.totp_required, u.created_at, u.updated_at FROM users u LEFT JOIN auth_providers ap ON ap.id = u.auth_provider_id LEFT JOIN user_totp t ON t.user_id = u.id WHERE u.public_id = ?`, id)
err = row.Scan(&user.ID, &user.Username, &user.DisplayName, &user.Email, &user.IsAdmin, &user.Disabled, &user.AuthProviderID, &user.TOTPEnabled, &user.TOTPRequired, &created, &updated)
err = row.Scan(&user.ID, &user.Username, &user.DisplayName, &user.Email, &user.IsAdmin, &user.Disabled, &user.AuthProviderID, &user.TOTPEnabled, &user.TOTPRequired, &user.CreatedAt, &user.UpdatedAt)
if err != nil {
return user, err
}
user.CreatedAt = created.Unix()
user.UpdatedAt = updated.Unix()
return user, nil
}
@@ -96,15 +86,11 @@ func (s *Store) GetUserByUsername(username string) (models.User, string, error)
var passwordHash sql.NullString
var row *sql.Row
var err error
var created time.Time
var updated time.Time
row = s.QueryRow(`SELECT u.public_id, u.username, u.display_name, u.email, u.is_admin, u.disabled, COALESCE(ap.public_id, ''), u.password_hash, COALESCE(t.enabled, 0), u.totp_required, u.created_at, u.updated_at FROM users u LEFT JOIN auth_providers ap ON ap.id = u.auth_provider_id LEFT JOIN user_totp t ON t.user_id = u.id WHERE u.username = ?`, username)
err = row.Scan(&user.ID, &user.Username, &user.DisplayName, &user.Email, &user.IsAdmin, &user.Disabled, &user.AuthProviderID, &passwordHash, &user.TOTPEnabled, &user.TOTPRequired, &created, &updated)
err = row.Scan(&user.ID, &user.Username, &user.DisplayName, &user.Email, &user.IsAdmin, &user.Disabled, &user.AuthProviderID, &passwordHash, &user.TOTPEnabled, &user.TOTPRequired, &user.CreatedAt, &user.UpdatedAt)
if err != nil {
return user, passwordHash.String, err
}
user.CreatedAt = created.Unix()
user.UpdatedAt = updated.Unix()
return user, passwordHash.String, nil
}
@@ -113,20 +99,16 @@ func (s *Store) ListUsers() ([]models.User, error) {
var err error
var users []models.User
var u models.User
var created time.Time
var updated time.Time
rows, err = s.Query(`SELECT u.public_id, u.username, u.display_name, u.email, u.is_admin, u.disabled, COALESCE(ap.public_id, ''), COALESCE(t.enabled, 0), u.totp_required, u.created_at, u.updated_at FROM users u LEFT JOIN auth_providers ap ON ap.id = u.auth_provider_id LEFT JOIN user_totp t ON t.user_id = u.id ORDER BY u.username`)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
err = rows.Scan(&u.ID, &u.Username, &u.DisplayName, &u.Email, &u.IsAdmin, &u.Disabled, &u.AuthProviderID, &u.TOTPEnabled, &u.TOTPRequired, &created, &updated)
err = rows.Scan(&u.ID, &u.Username, &u.DisplayName, &u.Email, &u.IsAdmin, &u.Disabled, &u.AuthProviderID, &u.TOTPEnabled, &u.TOTPRequired, &u.CreatedAt, &u.UpdatedAt)
if err != nil {
return nil, err
}
u.CreatedAt = created.Unix()
u.UpdatedAt = updated.Unix()
users = append(users, u)
}
return users, rows.Err()
@@ -167,8 +149,6 @@ func (s *Store) DeleteUser(id string) error {
func (s *Store) GetUserByProviderAndSub(providerPublicID string, sub string) (models.User, error) {
var user models.User
var row *sql.Row
var created time.Time
var updated time.Time
var err error
row = s.QueryRow(`
SELECT u.public_id, u.username, u.display_name, u.email, u.is_admin, u.disabled,
@@ -179,12 +159,10 @@ func (s *Store) GetUserByProviderAndSub(providerPublicID string, sub string) (mo
WHERE ap.public_id = ? AND u.external_subject = ?
`, strings.TrimSpace(providerPublicID), strings.TrimSpace(sub))
err = row.Scan(&user.ID, &user.Username, &user.DisplayName, &user.Email, &user.IsAdmin, &user.Disabled,
&user.AuthProviderID, &user.ExternalSubject, &user.TOTPEnabled, &user.TOTPRequired, &created, &updated)
&user.AuthProviderID, &user.ExternalSubject, &user.TOTPEnabled, &user.TOTPRequired, &user.CreatedAt, &user.UpdatedAt)
if err != nil {
return user, err
}
user.CreatedAt = created.Unix()
user.UpdatedAt = updated.Unix()
return user, nil
}
@@ -368,24 +346,20 @@ func splitCSVValue(value string) []string {
func (s *Store) SetUserDisabled(id string, disabled bool) error {
var err error
var now time.Time
now = time.Now().UTC()
_, err = s.Exec(`UPDATE users SET disabled = ?, updated_at = ? WHERE public_id = ?`, disabled, now, id)
_, err = s.Exec(`UPDATE users SET disabled = ?, updated_at = ? WHERE public_id = ?`, disabled, time.Now().UTC().Unix(), id)
return err
}
func (s *Store) CreateAPIKey(userID string, name string, tokenHash string, prefix string, expiresAt int64) (models.APIKey, error) {
var key models.APIKey
var err error
var now time.Time
var nowUnix int64
var id string
id, err = util.NewID()
if err != nil {
return key, err
}
now = time.Now().UTC()
nowUnix = now.Unix()
nowUnix = time.Now().UTC().Unix()
key = models.APIKey{
ID: id,
UserID: userID,
@@ -604,19 +578,14 @@ func (s *Store) GetUserByAPIKeyHash(tokenHash string) (models.User, error) {
var tx *sql.Tx
var owned bool
var row *sql.Row
var created time.Time
var updated time.Time
var keyID int64
var now time.Time
var nowUnix int64
var err error
var currentUnix int64
tx, owned, err = s.begin()
if err != nil {
return user, err
}
now = time.Now().UTC()
currentUnix = now.Unix()
nowUnix = time.Now().UTC().Unix()
row = tx.QueryRow(`
SELECT u.public_id, u.username, u.display_name, u.email, u.is_admin, u.disabled, COALESCE(ap.public_id, ''), u.created_at, u.updated_at, k.id
FROM api_keys k
@@ -627,16 +596,13 @@ func (s *Store) GetUserByAPIKeyHash(tokenHash string) (models.User, error) {
AND k.disabled = 0
AND (k.expires_at = 0 OR k.expires_at > ?)
LIMIT 1
`, tokenHash, currentUnix)
err = row.Scan(&user.ID, &user.Username, &user.DisplayName, &user.Email, &user.IsAdmin, &user.Disabled, &user.AuthProviderID, &created, &updated, &keyID)
`, tokenHash, nowUnix)
err = row.Scan(&user.ID, &user.Username, &user.DisplayName, &user.Email, &user.IsAdmin, &user.Disabled, &user.AuthProviderID, &user.CreatedAt, &user.UpdatedAt, &keyID)
if err != nil {
rollbackIfOwned(tx, owned)
return user, err
}
user.CreatedAt = created.Unix()
user.UpdatedAt = updated.Unix()
now = time.Now().UTC()
nowUnix = now.Unix()
nowUnix = time.Now().UTC().Unix()
_, err = tx.Exec(`UPDATE api_keys SET last_used_at = ? WHERE id = ?`, nowUnix, keyID)
if err != nil {
rollbackIfOwned(tx, owned)
@@ -653,7 +619,7 @@ func (s *Store) CreateSession(userID string, token string, expiresAt time.Time,
var err error
_, err = s.Exec(`INSERT INTO sessions (id, user_id, token, expires_at, created_at, totp_verified)
VALUES (?, (SELECT id FROM users WHERE public_id = ?), ?, ?, ?, ?)`,
mustID(), userID, token, expiresAt, time.Now().UTC(), totpVerified)
mustID(), userID, token, expiresAt.Unix(), time.Now().UTC().Unix(), totpVerified)
return err
}
@@ -671,18 +637,16 @@ func (s *Store) DeleteSession(token string) error {
func (s *Store) DeleteExpiredSessions(now time.Time) error {
var err error
_, err = s.Exec(`DELETE FROM sessions WHERE expires_at < ?`, now.UTC())
_, err = s.Exec(`DELETE FROM sessions WHERE expires_at < ?`, now.UTC().Unix())
return err
}
func (s *Store) GetSessionUser(token string) (models.User, time.Time, bool, error) {
var user models.User
var expires time.Time
var expiresUnix int64
var totpVerified bool
var row *sql.Row
var err error
var created time.Time
var updated time.Time
row = s.QueryRow(`
SELECT u.public_id, u.username, u.display_name, u.email, u.is_admin, u.disabled, COALESCE(ap.public_id, ''), COALESCE(t.enabled, 0), u.totp_required,
(u.totp_required OR EXISTS (
@@ -698,20 +662,17 @@ func (s *Store) GetSessionUser(token string) (models.User, time.Time, bool, erro
LEFT JOIN auth_providers ap ON ap.id = u.auth_provider_id
WHERE s.token = ? AND u.disabled = 0
`, token)
err = row.Scan(&user.ID, &user.Username, &user.DisplayName, &user.Email, &user.IsAdmin, &user.Disabled, &user.AuthProviderID, &user.TOTPEnabled, &user.TOTPRequired, &user.TOTPEffectiveRequired, &totpVerified, &created, &updated, &expires)
err = row.Scan(&user.ID, &user.Username, &user.DisplayName, &user.Email, &user.IsAdmin, &user.Disabled, &user.AuthProviderID, &user.TOTPEnabled, &user.TOTPRequired, &user.TOTPEffectiveRequired, &totpVerified, &user.CreatedAt, &user.UpdatedAt, &expiresUnix)
if err != nil {
return user, time.Time{}, false, err
}
user.CreatedAt = created.Unix()
user.UpdatedAt = updated.Unix()
user.TOTPSetupRequired = user.TOTPEffectiveRequired && !user.TOTPEnabled
return user, expires, totpVerified, nil
return user, time.Unix(expiresUnix, 0).UTC(), totpVerified, nil
}
func (s *Store) CreateProject(project models.Project) (models.Project, error) {
var id string
var err error
var now time.Time
var nowUnix int64
var tx *sql.Tx
var owned bool
@@ -722,8 +683,7 @@ func (s *Store) CreateProject(project models.Project) (models.Project, error) {
}
project.ID = id
}
now = time.Now().UTC()
nowUnix = now.Unix()
nowUnix = time.Now().UTC().Unix()
project.CreatedAt = nowUnix
project.UpdatedAt = nowUnix
if project.UpdatedBy == "" {
@@ -734,10 +694,10 @@ func (s *Store) CreateProject(project models.Project) (models.Project, error) {
return project, err
}
if project.HomePage == "" {
project.HomePage = "info"
project.HomePage = "settings"
}
_, err = tx.Exec(`INSERT INTO projects (public_id, slug, name, description, home_page, created_by, updated_by, created_at, updated_at, created_at_unix, updated_at_unix)
VALUES (?, ?, ?, ?, ?, (SELECT id FROM users WHERE public_id = ?), (SELECT id FROM users WHERE public_id = ?), ?, ?, ?, ?)`,
_, err = tx.Exec(`INSERT INTO projects (public_id, slug, name, description, home_page, created_by, updated_by, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, (SELECT id FROM users WHERE public_id = ?), (SELECT id FROM users WHERE public_id = ?), ?, ?)`,
project.ID,
project.Slug,
project.Name,
@@ -745,8 +705,6 @@ func (s *Store) CreateProject(project models.Project) (models.Project, error) {
project.HomePage,
project.CreatedBy,
project.UpdatedBy,
now,
now,
project.CreatedAt,
project.UpdatedAt,
)
@@ -771,16 +729,15 @@ func (s *Store) CreateProject(project models.Project) (models.Project, error) {
func (s *Store) UpdateProject(project models.Project) error {
var err error
if project.HomePage == "" {
project.HomePage = "info"
project.HomePage = "settings"
}
_, err = s.Exec(`UPDATE projects SET slug = ?, name = ?, description = ?, home_page = ?, updated_at = ?, updated_by = (SELECT id FROM users WHERE public_id = ?), updated_at_unix = ? WHERE public_id = ?`,
_, err = s.Exec(`UPDATE projects SET slug = ?, name = ?, description = ?, home_page = ?, updated_at = ?, updated_by = (SELECT id FROM users WHERE public_id = ?) WHERE public_id = ?`,
project.Slug,
project.Name,
project.Description,
project.HomePage,
time.Unix(project.UpdatedAt, 0).UTC(),
project.UpdatedBy,
project.UpdatedAt,
project.UpdatedBy,
project.ID,
)
return err
@@ -793,7 +750,7 @@ func (s *Store) GetProject(id string) (models.Project, error) {
SELECT p.public_id, p.slug, p.name, p.description, p.home_page,
c.public_id, u.public_id,
COALESCE(c.username, ''), COALESCE(u.username, ''),
p.created_at_unix, p.updated_at_unix
p.created_at, p.updated_at
FROM projects p
LEFT JOIN users c ON c.id = p.created_by
LEFT JOIN users u ON u.id = p.updated_by
@@ -822,7 +779,7 @@ func (s *Store) GetProjectBySlug(slug string) (models.Project, error) {
SELECT p.public_id, p.slug, p.name, p.description, p.home_page,
c.public_id, u.public_id,
COALESCE(c.username, ''), COALESCE(u.username, ''),
p.created_at_unix, p.updated_at_unix
p.created_at, p.updated_at
FROM projects p
LEFT JOIN users c ON c.id = p.created_by
LEFT JOIN users u ON u.id = p.updated_by
@@ -856,7 +813,7 @@ func (s *Store) ListProjects() ([]models.Project, error) {
SELECT p.public_id, p.slug, p.name, p.description, p.home_page,
c.public_id, u.public_id,
COALESCE(c.username, ''), COALESCE(u.username, ''),
p.created_at_unix, p.updated_at_unix
p.created_at, p.updated_at
FROM projects p
LEFT JOIN users c ON c.id = p.created_by
LEFT JOIN users u ON u.id = p.updated_by
@@ -897,7 +854,7 @@ func (s *Store) ListProjectsForUser(userID string) ([]models.Project, error) {
SELECT p.public_id, p.slug, p.name, p.description, p.home_page,
c.public_id, u.public_id,
COALESCE(c.username, ''), COALESCE(u.username, ''),
p.created_at_unix, p.updated_at_unix
p.created_at, p.updated_at
FROM projects p
LEFT JOIN users c ON c.id = p.created_by
LEFT JOIN users u ON u.id = p.updated_by
@@ -962,7 +919,7 @@ func (s *Store) ListProjectsForPrincipal(principalID string) ([]models.Project,
SELECT p.public_id, p.slug, p.name, p.description, p.home_page,
c.public_id, u.public_id,
COALESCE(c.username, ''), COALESCE(u.username, ''),
p.created_at_unix, p.updated_at_unix
p.created_at, p.updated_at
FROM projects p
LEFT JOIN users c ON c.id = p.created_by
LEFT JOIN users u ON u.id = p.updated_by
@@ -1017,7 +974,7 @@ func (s *Store) ListProjectsFiltered(limit int, offset int, query string) ([]mod
`SELECT p.public_id, p.slug, p.name, p.description, p.home_page,
c.public_id, u.public_id,
COALESCE(c.username, ''), COALESCE(u.username, ''),
p.created_at_unix, p.updated_at_unix
p.created_at, p.updated_at
FROM projects p
LEFT JOIN users c ON c.id = p.created_by
LEFT JOIN users u ON u.id = p.updated_by
@@ -1030,7 +987,7 @@ func (s *Store) ListProjectsFiltered(limit int, offset int, query string) ([]mod
`SELECT p.public_id, p.slug, p.name, p.description, p.home_page,
c.public_id, u.public_id,
COALESCE(c.username, ''), COALESCE(u.username, ''),
p.created_at_unix, p.updated_at_unix
p.created_at, p.updated_at
FROM projects p
LEFT JOIN users c ON c.id = p.created_by
LEFT JOIN users u ON u.id = p.updated_by
@@ -1084,7 +1041,7 @@ func (s *Store) ListProjectsFilteredForUser(userID string, limit int, offset int
`SELECT p.public_id, p.slug, p.name, p.description, p.home_page,
c.public_id, u.public_id,
COALESCE(c.username, ''), COALESCE(u.username, ''),
p.created_at_unix, p.updated_at_unix
p.created_at, p.updated_at
FROM projects p
LEFT JOIN users c ON c.id = p.created_by
LEFT JOIN users u ON u.id = p.updated_by
@@ -1122,7 +1079,7 @@ func (s *Store) ListProjectsFilteredForUser(userID string, limit int, offset int
`SELECT p.public_id, p.slug, p.name, p.description, p.home_page,
c.public_id, u.public_id,
COALESCE(c.username, ''), COALESCE(u.username, ''),
p.created_at_unix, p.updated_at_unix
p.created_at, p.updated_at
FROM projects p
LEFT JOIN users c ON c.id = p.created_by
LEFT JOIN users u ON u.id = p.updated_by
@@ -1201,7 +1158,7 @@ func (s *Store) ListProjectsFilteredForPrincipal(principalID string, limit int,
`SELECT p.public_id, p.slug, p.name, p.description, p.home_page,
c.public_id, u.public_id,
COALESCE(c.username, ''), COALESCE(u.username, ''),
p.created_at_unix, p.updated_at_unix
p.created_at, p.updated_at
FROM projects p
LEFT JOIN users c ON c.id = p.created_by
LEFT JOIN users u ON u.id = p.updated_by
@@ -1222,7 +1179,7 @@ func (s *Store) ListProjectsFilteredForPrincipal(principalID string, limit int,
`SELECT p.public_id, p.slug, p.name, p.description, p.home_page,
c.public_id, u.public_id,
COALESCE(c.username, ''), COALESCE(u.username, ''),
p.created_at_unix, p.updated_at_unix
p.created_at, p.updated_at
FROM projects p
LEFT JOIN users c ON c.id = p.created_by
LEFT JOIN users u ON u.id = p.updated_by
@@ -1497,7 +1454,6 @@ func (s *Store) GetProjectMemberRole(projectID, userID string) (string, error) {
func (s *Store) CreateRepo(repo models.Repo) (models.Repo, error) {
var id string
var err error
var now time.Time
var nowUnix int64
if repo.ID == "" {
id, err = util.NewID()
@@ -1506,12 +1462,11 @@ func (s *Store) CreateRepo(repo models.Repo) (models.Repo, error) {
}
repo.ID = id
}
now = time.Now().UTC()
nowUnix = now.Unix()
nowUnix = time.Now().UTC().Unix()
repo.CreatedAt = nowUnix
_, err = s.Exec(`INSERT INTO repos (public_id, project_id, name, type, path, created_by, created_at)
VALUES (?, (SELECT id FROM projects WHERE public_id = ?), ?, ?, ?, (SELECT id FROM users WHERE public_id = ?), ?)`,
repo.ID, repo.ProjectID, repo.Name, repo.Type, repo.Path, repo.CreatedBy, now)
repo.ID, repo.ProjectID, repo.Name, repo.Type, repo.Path, repo.CreatedBy, nowUnix)
return repo, err
}
@@ -1532,18 +1487,16 @@ func (s *Store) RepoNameExists(projectID string, name string, repoType string) (
func (s *Store) GetRepo(id string) (models.Repo, error) {
var repo models.Repo
var row *sql.Row
var created time.Time
var err error
row = s.QueryRow(`SELECT r.public_id, p.public_id, r.name, r.type, r.path, u.public_id, r.created_at
FROM repos r
JOIN projects p ON p.id = r.project_id
JOIN users u ON u.id = r.created_by
WHERE r.public_id = ?`, id)
err = row.Scan(&repo.ID, &repo.ProjectID, &repo.Name, &repo.Type, &repo.Path, &repo.CreatedBy, &created)
err = row.Scan(&repo.ID, &repo.ProjectID, &repo.Name, &repo.Type, &repo.Path, &repo.CreatedBy, &repo.CreatedAt)
if err != nil {
return repo, err
}
repo.CreatedAt = created.Unix()
return repo, nil
}
@@ -1567,7 +1520,6 @@ func (s *Store) GetRepoByProjectNameType(projectID string, name string, repoType
var repo models.Repo
var row *sql.Row
var err error
var created time.Time
row = s.QueryRow(`SELECT r.public_id, p.public_id, r.name, r.type, r.path, u.public_id, r.created_at
FROM repos r
JOIN projects p ON p.id = r.project_id
@@ -1575,11 +1527,10 @@ func (s *Store) GetRepoByProjectNameType(projectID string, name string, repoType
WHERE r.project_id = (SELECT id FROM projects WHERE public_id = ?)
AND r.name = ? AND r.type = ?`,
projectID, name, repoType)
err = row.Scan(&repo.ID, &repo.ProjectID, &repo.Name, &repo.Type, &repo.Path, &repo.CreatedBy, &created)
err = row.Scan(&repo.ID, &repo.ProjectID, &repo.Name, &repo.Type, &repo.Path, &repo.CreatedBy, &repo.CreatedAt)
if err != nil {
return repo, err
}
repo.CreatedAt = created.Unix()
return repo, nil
}
@@ -1589,7 +1540,6 @@ func (s *Store) ListRepos(projectID string) ([]models.Repo, error) {
var repos []models.Repo
var r models.Repo
var isForeign int
var created time.Time
rows, err = s.Query(`
SELECT r.public_id, p.public_id, r.name, r.type, r.path, u.public_id, r.created_at, 0 AS is_foreign
FROM repos r
@@ -1611,11 +1561,10 @@ func (s *Store) ListRepos(projectID string) ([]models.Repo, error) {
}
defer rows.Close()
for rows.Next() {
err = rows.Scan(&r.ID, &r.ProjectID, &r.Name, &r.Type, &r.Path, &r.CreatedBy, &created, &isForeign)
err = rows.Scan(&r.ID, &r.ProjectID, &r.Name, &r.Type, &r.Path, &r.CreatedBy, &r.CreatedAt, &isForeign)
if err != nil {
return nil, err
}
r.CreatedAt = created.Unix()
r.IsForeign = isForeign != 0
repos = append(repos, r)
}
@@ -1627,7 +1576,6 @@ func (s *Store) ListReposOwned(projectID string) ([]models.Repo, error) {
var err error
var repos []models.Repo
var r models.Repo
var created time.Time
rows, err = s.Query(`
SELECT r.public_id, p.public_id, r.name, r.type, r.path, u.public_id, r.created_at
FROM repos r
@@ -1641,11 +1589,10 @@ func (s *Store) ListReposOwned(projectID string) ([]models.Repo, error) {
}
defer rows.Close()
for rows.Next() {
err = rows.Scan(&r.ID, &r.ProjectID, &r.Name, &r.Type, &r.Path, &r.CreatedBy, &created)
err = rows.Scan(&r.ID, &r.ProjectID, &r.Name, &r.Type, &r.Path, &r.CreatedBy, &r.CreatedAt)
if err != nil {
return nil, err
}
r.CreatedAt = created.Unix()
repos = append(repos, r)
}
return repos, rows.Err()
@@ -1656,7 +1603,6 @@ func (s *Store) ListAllRepos() ([]models.Repo, error) {
var err error
var repos []models.Repo
var r models.Repo
var created time.Time
rows, err = s.Query(`
SELECT r.public_id, p.public_id, r.name, r.type, r.path, u.public_id, r.created_at
FROM repos r
@@ -1669,11 +1615,10 @@ func (s *Store) ListAllRepos() ([]models.Repo, error) {
}
defer rows.Close()
for rows.Next() {
err = rows.Scan(&r.ID, &r.ProjectID, &r.Name, &r.Type, &r.Path, &r.CreatedBy, &created)
err = rows.Scan(&r.ID, &r.ProjectID, &r.Name, &r.Type, &r.Path, &r.CreatedBy, &r.CreatedAt)
if err != nil {
return nil, err
}
r.CreatedAt = created.Unix()
repos = append(repos, r)
}
return repos, rows.Err()
@@ -1684,7 +1629,6 @@ func (s *Store) ListReposByProjectIDs(projectIDs []string) ([]models.Repo, error
var err error
var repos []models.Repo
var r models.Repo
var created time.Time
var placeholders []string
var args []interface{}
var i int
@@ -1715,11 +1659,10 @@ func (s *Store) ListReposByProjectIDs(projectIDs []string) ([]models.Repo, error
}
defer rows.Close()
for rows.Next() {
err = rows.Scan(&r.ID, &r.ProjectID, &r.Name, &r.Type, &r.Path, &r.CreatedBy, &created)
err = rows.Scan(&r.ID, &r.ProjectID, &r.Name, &r.Type, &r.Path, &r.CreatedBy, &r.CreatedAt)
if err != nil {
return nil, err
}
r.CreatedAt = created.Unix()
repos = append(repos, r)
}
return repos, rows.Err()
@@ -1781,7 +1724,7 @@ func (s *Store) AttachRepoToProject(projectID string, repoID string) error {
var err error
_, err = s.Exec(`INSERT INTO project_repos (project_id, repo_id, created_at)
VALUES ((SELECT id FROM projects WHERE public_id = ?), (SELECT id FROM repos WHERE public_id = ?), ?)`,
projectID, repoID, time.Now().UTC())
projectID, repoID, time.Now().UTC().Unix())
return err
}
@@ -1825,7 +1768,6 @@ func (s *Store) ListAvailableReposForProject(projectID string, query string, lim
var err error
var repos []models.Repo
var r models.Repo
var created time.Time
if limit <= 0 {
limit = 100
}
@@ -1871,11 +1813,10 @@ func (s *Store) ListAvailableReposForProject(projectID string, query string, lim
}
defer rows.Close()
for rows.Next() {
err = rows.Scan(&r.ID, &r.ProjectID, &r.Name, &r.Type, &r.Path, &r.CreatedBy, &created)
err = rows.Scan(&r.ID, &r.ProjectID, &r.Name, &r.Type, &r.Path, &r.CreatedBy, &r.CreatedAt)
if err != nil {
return nil, err
}
r.CreatedAt = created.Unix()
r.IsForeign = false
repos = append(repos, r)
}
@@ -1885,7 +1826,6 @@ func (s *Store) ListAvailableReposForProject(projectID string, query string, lim
func (s *Store) CreateIssue(issue models.Issue) (models.Issue, error) {
var id string
var err error
var now time.Time
var nowUnix int64
if issue.ID == "" {
id, err = util.NewID()
@@ -1894,8 +1834,7 @@ func (s *Store) CreateIssue(issue models.Issue) (models.Issue, error) {
}
issue.ID = id
}
now = time.Now().UTC()
nowUnix = now.Unix()
nowUnix = time.Now().UTC().Unix()
issue.CreatedAt = nowUnix
issue.UpdatedAt = nowUnix
if issue.Status == "" {
@@ -1904,27 +1843,23 @@ func (s *Store) CreateIssue(issue models.Issue) (models.Issue, error) {
_, err = s.Exec(`
INSERT INTO issues (public_id, project_id, title, body, status, created_by, assignee_id, created_at, updated_at)
VALUES (?, (SELECT id FROM projects WHERE public_id = ?), ?, ?, ?, (SELECT id FROM users WHERE public_id = ?), (SELECT id FROM users WHERE public_id = ?), ?, ?)
`, issue.ID, issue.ProjectID, issue.Title, issue.Body, issue.Status, issue.CreatedBy, issue.AssigneeID, now, now)
`, issue.ID, issue.ProjectID, issue.Title, issue.Body, issue.Status, issue.CreatedBy, issue.AssigneeID, nowUnix, nowUnix)
return issue, err
}
func (s *Store) UpdateIssue(issue models.Issue) error {
var err error
var now time.Time
var nowUnix int64
now = time.Now().UTC()
nowUnix = now.Unix()
nowUnix = time.Now().UTC().Unix()
issue.UpdatedAt = nowUnix
_, err = s.Exec(`UPDATE issues SET title = ?, body = ?, status = ?, assignee_id = (SELECT id FROM users WHERE public_id = ?), updated_at = ? WHERE public_id = ?`,
issue.Title, issue.Body, issue.Status, issue.AssigneeID, now, issue.ID)
issue.Title, issue.Body, issue.Status, issue.AssigneeID, nowUnix, issue.ID)
return err
}
func (s *Store) GetIssue(id string) (models.Issue, error) {
var issue models.Issue
var row *sql.Row
var created time.Time
var updated time.Time
var err error
row = s.QueryRow(`SELECT i.public_id, p.public_id, i.title, i.body, i.status, cu.public_id, COALESCE(au.public_id, ''), i.created_at, i.updated_at
FROM issues i
@@ -1932,12 +1867,10 @@ func (s *Store) GetIssue(id string) (models.Issue, error) {
JOIN users cu ON cu.id = i.created_by
LEFT JOIN users au ON au.id = i.assignee_id
WHERE i.public_id = ?`, id)
err = row.Scan(&issue.ID, &issue.ProjectID, &issue.Title, &issue.Body, &issue.Status, &issue.CreatedBy, &issue.AssigneeID, &created, &updated)
err = row.Scan(&issue.ID, &issue.ProjectID, &issue.Title, &issue.Body, &issue.Status, &issue.CreatedBy, &issue.AssigneeID, &issue.CreatedAt, &issue.UpdatedAt)
if err != nil {
return issue, err
}
issue.CreatedAt = created.Unix()
issue.UpdatedAt = updated.Unix()
return issue, nil
}
@@ -1946,8 +1879,6 @@ func (s *Store) ListIssues(projectID string) ([]models.Issue, error) {
var err error
var issues []models.Issue
var issue models.Issue
var created time.Time
var updated time.Time
rows, err = s.Query(`SELECT i.public_id, p.public_id, i.title, i.body, i.status, cu.public_id, COALESCE(au.public_id, ''), i.created_at, i.updated_at
FROM issues i
JOIN projects p ON p.id = i.project_id
@@ -1960,12 +1891,10 @@ func (s *Store) ListIssues(projectID string) ([]models.Issue, error) {
}
defer rows.Close()
for rows.Next() {
err = rows.Scan(&issue.ID, &issue.ProjectID, &issue.Title, &issue.Body, &issue.Status, &issue.CreatedBy, &issue.AssigneeID, &created, &updated)
err = rows.Scan(&issue.ID, &issue.ProjectID, &issue.Title, &issue.Body, &issue.Status, &issue.CreatedBy, &issue.AssigneeID, &issue.CreatedAt, &issue.UpdatedAt)
if err != nil {
return nil, err
}
issue.CreatedAt = created.Unix()
issue.UpdatedAt = updated.Unix()
issues = append(issues, issue)
}
return issues, rows.Err()
@@ -1974,7 +1903,6 @@ func (s *Store) ListIssues(projectID string) ([]models.Issue, error) {
func (s *Store) AddIssueComment(comment models.IssueComment) (models.IssueComment, error) {
var id string
var err error
var now time.Time
var nowUnix int64
if comment.ID == "" {
id, err = util.NewID()
@@ -1983,19 +1911,17 @@ func (s *Store) AddIssueComment(comment models.IssueComment) (models.IssueCommen
}
comment.ID = id
}
now = time.Now().UTC()
nowUnix = now.Unix()
nowUnix = time.Now().UTC().Unix()
comment.CreatedAt = nowUnix
_, err = s.Exec(`INSERT INTO issue_comments (public_id, issue_id, body, created_by, created_at)
VALUES (?, (SELECT id FROM issues WHERE public_id = ?), ?, (SELECT id FROM users WHERE public_id = ?), ?)`,
comment.ID, comment.IssueID, comment.Body, comment.CreatedBy, now)
comment.ID, comment.IssueID, comment.Body, comment.CreatedBy, nowUnix)
return comment, err
}
func (s *Store) CreateWikiPage(page models.WikiPage) (models.WikiPage, error) {
var id string
var err error
var now time.Time
var nowUnix int64
if page.ID == "" {
id, err = util.NewID()
@@ -2004,23 +1930,20 @@ func (s *Store) CreateWikiPage(page models.WikiPage) (models.WikiPage, error) {
}
page.ID = id
}
now = time.Now().UTC()
nowUnix = now.Unix()
nowUnix = time.Now().UTC().Unix()
page.UpdatedAt = nowUnix
_, err = s.Exec(`INSERT INTO wiki_pages (public_id, project_id, title, slug, body, created_by, updated_at)
VALUES (?, (SELECT id FROM projects WHERE public_id = ?), ?, ?, ?, (SELECT id FROM users WHERE public_id = ?), ?)`,
page.ID, page.ProjectID, page.Title, page.Slug, page.Body, page.CreatedBy, now)
page.ID, page.ProjectID, page.Title, page.Slug, page.Body, page.CreatedBy, nowUnix)
return page, err
}
func (s *Store) UpdateWikiPage(page models.WikiPage) error {
var err error
var now time.Time
var nowUnix int64
now = time.Now().UTC()
nowUnix = now.Unix()
nowUnix = time.Now().UTC().Unix()
page.UpdatedAt = nowUnix
_, err = s.Exec(`UPDATE wiki_pages SET title = ?, body = ?, updated_at = ? WHERE public_id = ?`, page.Title, page.Body, now, page.ID)
_, err = s.Exec(`UPDATE wiki_pages SET title = ?, body = ?, updated_at = ? WHERE public_id = ?`, page.Title, page.Body, nowUnix, page.ID)
return err
}
@@ -2029,7 +1952,6 @@ func (s *Store) ListWikiPages(projectID string) ([]models.WikiPage, error) {
var err error
var pages []models.WikiPage
var page models.WikiPage
var updated time.Time
rows, err = s.Query(`SELECT w.public_id, p.public_id, w.title, w.slug, w.body, u.public_id, w.updated_at
FROM wiki_pages w
JOIN projects p ON p.id = w.project_id
@@ -2041,11 +1963,10 @@ func (s *Store) ListWikiPages(projectID string) ([]models.WikiPage, error) {
}
defer rows.Close()
for rows.Next() {
err = rows.Scan(&page.ID, &page.ProjectID, &page.Title, &page.Slug, &page.Body, &page.CreatedBy, &updated)
err = rows.Scan(&page.ID, &page.ProjectID, &page.Title, &page.Slug, &page.Body, &page.CreatedBy, &page.UpdatedAt)
if err != nil {
return nil, err
}
page.UpdatedAt = updated.Unix()
pages = append(pages, page)
}
return pages, rows.Err()
@@ -2054,25 +1975,22 @@ func (s *Store) ListWikiPages(projectID string) ([]models.WikiPage, error) {
func (s *Store) GetWikiPage(id string) (models.WikiPage, error) {
var page models.WikiPage
var row *sql.Row
var updated time.Time
var err error
row = s.QueryRow(`SELECT w.public_id, p.public_id, w.title, w.slug, w.body, u.public_id, w.updated_at
FROM wiki_pages w
JOIN projects p ON p.id = w.project_id
JOIN users u ON u.id = w.created_by
WHERE w.public_id = ?`, id)
err = row.Scan(&page.ID, &page.ProjectID, &page.Title, &page.Slug, &page.Body, &page.CreatedBy, &updated)
err = row.Scan(&page.ID, &page.ProjectID, &page.Title, &page.Slug, &page.Body, &page.CreatedBy, &page.UpdatedAt)
if err != nil {
return page, err
}
page.UpdatedAt = updated.Unix()
return page, nil
}
func (s *Store) CreateUpload(upload models.Upload) (models.Upload, error) {
var id string
var err error
var now time.Time
var nowUnix int64
if upload.ID == "" {
id, err = util.NewID()
@@ -2081,30 +1999,27 @@ func (s *Store) CreateUpload(upload models.Upload) (models.Upload, error) {
}
upload.ID = id
}
now = time.Now().UTC()
nowUnix = now.Unix()
nowUnix = time.Now().UTC().Unix()
upload.CreatedAt = nowUnix
_, err = s.Exec(`INSERT INTO uploads (public_id, project_id, filename, content_type, size, storage_path, created_by, created_at)
VALUES (?, (SELECT id FROM projects WHERE public_id = ?), ?, ?, ?, ?, (SELECT id FROM users WHERE public_id = ?), ?)`,
upload.ID, upload.ProjectID, upload.Filename, upload.ContentType, upload.Size, upload.StoragePath, upload.CreatedBy, now)
upload.ID, upload.ProjectID, upload.Filename, upload.ContentType, upload.Size, upload.StoragePath, upload.CreatedBy, nowUnix)
return upload, err
}
func (s *Store) GetUpload(id string) (models.Upload, error) {
var upload models.Upload
var row *sql.Row
var created time.Time
var err error
row = s.QueryRow(`SELECT up.public_id, p.public_id, up.filename, up.content_type, up.size, up.storage_path, u.public_id, up.created_at
FROM uploads up
JOIN projects p ON p.id = up.project_id
JOIN users u ON u.id = up.created_by
WHERE up.public_id = ?`, id)
err = row.Scan(&upload.ID, &upload.ProjectID, &upload.Filename, &upload.ContentType, &upload.Size, &upload.StoragePath, &upload.CreatedBy, &created)
err = row.Scan(&upload.ID, &upload.ProjectID, &upload.Filename, &upload.ContentType, &upload.Size, &upload.StoragePath, &upload.CreatedBy, &upload.CreatedAt)
if err != nil {
return upload, err
}
upload.CreatedAt = created.Unix()
return upload, nil
}
@@ -2113,7 +2028,6 @@ func (s *Store) ListUploads(projectID string) ([]models.Upload, error) {
var err error
var uploads []models.Upload
var upload models.Upload
var created time.Time
rows, err = s.Query(`SELECT up.public_id, p.public_id, up.filename, up.content_type, up.size, up.storage_path, u.public_id, up.created_at
FROM uploads up
JOIN projects p ON p.id = up.project_id
@@ -2125,11 +2039,10 @@ func (s *Store) ListUploads(projectID string) ([]models.Upload, error) {
}
defer rows.Close()
for rows.Next() {
err = rows.Scan(&upload.ID, &upload.ProjectID, &upload.Filename, &upload.ContentType, &upload.Size, &upload.StoragePath, &upload.CreatedBy, &created)
err = rows.Scan(&upload.ID, &upload.ProjectID, &upload.Filename, &upload.ContentType, &upload.Size, &upload.StoragePath, &upload.CreatedBy, &upload.CreatedAt)
if err != nil {
return nil, err
}
upload.CreatedAt = created.Unix()
uploads = append(uploads, upload)
}
return uploads, rows.Err()
+7 -11
View File
@@ -14,20 +14,16 @@ type UserTOTP struct {
func (s *Store) GetUserTOTP(userID string) (UserTOTP, error) {
var item UserTOTP
var row *sql.Row
var created time.Time
var updated time.Time
var err error
row = s.QueryRow(`
SELECT COALESCE(t.secret_encrypted, ''), COALESCE(t.pending_secret_encrypted, ''), COALESCE(t.enabled, 0), t.created_at, t.updated_at
FROM user_totp t JOIN users u ON u.id = t.user_id
WHERE u.public_id = ?
`, userID)
err = row.Scan(&item.SecretEncrypted, &item.PendingSecretEncrypted, &item.Enabled, &created, &updated)
err = row.Scan(&item.SecretEncrypted, &item.PendingSecretEncrypted, &item.Enabled, &item.CreatedAt, &item.UpdatedAt)
if err != nil {
return item, err
}
item.CreatedAt = created.Unix()
item.UpdatedAt = updated.Unix()
return item, nil
}
@@ -52,25 +48,25 @@ func (s *Store) UserRequiresTOTP(userID string) (bool, error) {
func (s *Store) UpsertUserTOTPPending(userID string, pendingSecretEncrypted string) error {
var err error
var now time.Time
now = time.Now().UTC()
var nowUnix int64
nowUnix = time.Now().UTC().Unix()
_, err = s.Exec(`
INSERT INTO user_totp (user_id, secret_encrypted, pending_secret_encrypted, enabled, created_at, updated_at)
VALUES ((SELECT id FROM users WHERE public_id = ?), '', ?, 0, ?, ?)
ON CONFLICT(user_id) DO UPDATE SET pending_secret_encrypted = excluded.pending_secret_encrypted, updated_at = excluded.updated_at
`, userID, pendingSecretEncrypted, now, now)
`, userID, pendingSecretEncrypted, nowUnix, nowUnix)
return err
}
func (s *Store) EnableUserTOTP(userID string, secretEncrypted string) error {
var err error
var now time.Time
now = time.Now().UTC()
var nowUnix int64
nowUnix = time.Now().UTC().Unix()
_, err = s.Exec(`
INSERT INTO user_totp (user_id, secret_encrypted, pending_secret_encrypted, enabled, created_at, updated_at)
VALUES ((SELECT id FROM users WHERE public_id = ?), ?, '', 1, ?, ?)
ON CONFLICT(user_id) DO UPDATE SET secret_encrypted = excluded.secret_encrypted, pending_secret_encrypted = '', enabled = 1, updated_at = excluded.updated_at
`, userID, secretEncrypted, now, now)
`, userID, secretEncrypted, nowUnix, nowUnix)
return err
}
+6 -3
View File
@@ -1815,7 +1815,7 @@ func (api *API) UpdateProject(w http.ResponseWriter, r *http.Request, params map
project.HomePage = normalizeProjectHomePage(req.HomePage)
}
if project.HomePage == "" {
project.HomePage = "info"
project.HomePage = "settings"
}
user, _ = middleware.UserFromContext(r.Context())
project.UpdatedBy = user.ID
@@ -5448,10 +5448,13 @@ func normalizeRole(role string) string {
func normalizeProjectHomePage(value string) string {
var v string
v = strings.ToLower(strings.TrimSpace(value))
if v == "repos" || v == "issues" || v == "wiki" || v == "files" || v == "info" {
if v == "info" {
return "settings"
}
if v == "repos" || v == "issues" || v == "wiki" || v == "files" || v == "settings" {
return v
}
return "info"
return "settings"
}
+4
View File
@@ -1762,6 +1762,10 @@ func (api *API) CreateSSHSessionForSelf(w http.ResponseWriter, r *http.Request,
WriteJSONWithErrorReason(w, r, http.StatusBadRequest, "server_id does not match access profile")
return
}
if !profile.Server.Enabled {
WriteJSONWithErrorReason(w, r, http.StatusBadRequest, "ssh server is disabled")
return
}
item = models.SSHSession{
ProfileID: profile.ID,
ServerID: profile.ServerID,
+12 -9
View File
@@ -9,15 +9,15 @@ func TestUserJSONTags(t *testing.T) {
var err error
var decoded map[string]interface{}
u = User{
ID: "u1",
Username: "alice",
DisplayName: "Alice",
Email: "a@x",
IsAdmin: true,
Disabled: true,
AuthSource: "db",
CreatedAt: 1,
UpdatedAt: 2,
ID: "u1",
Username: "alice",
DisplayName: "Alice",
Email: "a@x",
IsAdmin: true,
Disabled: true,
AuthProviderID: "p1",
CreatedAt: 1,
UpdatedAt: 2,
}
data, err = json.Marshal(u)
if err != nil {
@@ -37,6 +37,9 @@ func TestUserJSONTags(t *testing.T) {
if _, ok := decoded["disabled"]; !ok {
t.Fatalf("missing disabled json key")
}
if _, ok := decoded["auth_provider_id"]; !ok {
t.Fatalf("missing auth_provider_id json key")
}
}
func TestAPIKeyJSONTags(t *testing.T) {
+1 -1
View File
@@ -41,7 +41,7 @@ CREATE TABLE IF NOT EXISTS projects (
slug TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
description TEXT NOT NULL,
home_page TEXT NOT NULL DEFAULT 'info',
home_page TEXT NOT NULL DEFAULT 'settings',
created_by INTEGER NOT NULL,
updated_by INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL,
+106
View File
@@ -0,0 +1,106 @@
BEGIN;
-- users: created_at, updated_at
ALTER TABLE users ADD COLUMN created_at_new INTEGER NOT NULL DEFAULT 0;
ALTER TABLE users ADD COLUMN updated_at_new INTEGER NOT NULL DEFAULT 0;
UPDATE users SET
created_at_new = CASE WHEN typeof(created_at) = 'integer' THEN created_at ELSE COALESCE(CAST(strftime('%s', substr(created_at, 1, 19)) AS INTEGER), 0) END,
updated_at_new = CASE WHEN typeof(updated_at) = 'integer' THEN updated_at ELSE COALESCE(CAST(strftime('%s', substr(updated_at, 1, 19)) AS INTEGER), 0) END;
ALTER TABLE users DROP COLUMN created_at;
ALTER TABLE users DROP COLUMN updated_at;
ALTER TABLE users RENAME COLUMN created_at_new TO created_at;
ALTER TABLE users RENAME COLUMN updated_at_new TO updated_at;
-- sessions: expires_at, created_at
ALTER TABLE sessions ADD COLUMN expires_at_new INTEGER NOT NULL DEFAULT 0;
ALTER TABLE sessions ADD COLUMN created_at_new INTEGER NOT NULL DEFAULT 0;
UPDATE sessions SET
expires_at_new = CASE WHEN typeof(expires_at) = 'integer' THEN expires_at ELSE COALESCE(CAST(strftime('%s', substr(expires_at, 1, 19)) AS INTEGER), 0) END,
created_at_new = CASE WHEN typeof(created_at) = 'integer' THEN created_at ELSE COALESCE(CAST(strftime('%s', substr(created_at, 1, 19)) AS INTEGER), 0) END;
ALTER TABLE sessions DROP COLUMN expires_at;
ALTER TABLE sessions DROP COLUMN created_at;
ALTER TABLE sessions RENAME COLUMN expires_at_new TO expires_at;
ALTER TABLE sessions RENAME COLUMN created_at_new TO created_at;
-- user_totp: created_at, updated_at
ALTER TABLE user_totp ADD COLUMN created_at_new INTEGER NOT NULL DEFAULT 0;
ALTER TABLE user_totp ADD COLUMN updated_at_new INTEGER NOT NULL DEFAULT 0;
UPDATE user_totp SET
created_at_new = CASE WHEN typeof(created_at) = 'integer' THEN created_at ELSE COALESCE(CAST(strftime('%s', substr(created_at, 1, 19)) AS INTEGER), 0) END,
updated_at_new = CASE WHEN typeof(updated_at) = 'integer' THEN updated_at ELSE COALESCE(CAST(strftime('%s', substr(updated_at, 1, 19)) AS INTEGER), 0) END;
ALTER TABLE user_totp DROP COLUMN created_at;
ALTER TABLE user_totp DROP COLUMN updated_at;
ALTER TABLE user_totp RENAME COLUMN created_at_new TO created_at;
ALTER TABLE user_totp RENAME COLUMN updated_at_new TO updated_at;
-- projects: special case - use created_at_unix/updated_at_unix as source of truth
ALTER TABLE projects ADD COLUMN created_at_new INTEGER NOT NULL DEFAULT 0;
ALTER TABLE projects ADD COLUMN updated_at_new INTEGER NOT NULL DEFAULT 0;
UPDATE projects SET
created_at_new = CASE WHEN created_at_unix != 0 THEN created_at_unix
WHEN typeof(created_at) = 'integer' THEN created_at
ELSE COALESCE(CAST(strftime('%s', substr(created_at, 1, 19)) AS INTEGER), 0) END,
updated_at_new = CASE WHEN updated_at_unix != 0 THEN updated_at_unix
WHEN typeof(updated_at) = 'integer' THEN updated_at
ELSE COALESCE(CAST(strftime('%s', substr(updated_at, 1, 19)) AS INTEGER), 0) END;
ALTER TABLE projects DROP COLUMN created_at;
ALTER TABLE projects DROP COLUMN updated_at;
ALTER TABLE projects DROP COLUMN created_at_unix;
ALTER TABLE projects DROP COLUMN updated_at_unix;
ALTER TABLE projects RENAME COLUMN created_at_new TO created_at;
ALTER TABLE projects RENAME COLUMN updated_at_new TO updated_at;
-- project_members: created_at
ALTER TABLE project_members ADD COLUMN created_at_new INTEGER NOT NULL DEFAULT 0;
UPDATE project_members SET
created_at_new = CASE WHEN typeof(created_at) = 'integer' THEN created_at ELSE COALESCE(CAST(strftime('%s', substr(created_at, 1, 19)) AS INTEGER), 0) END;
ALTER TABLE project_members DROP COLUMN created_at;
ALTER TABLE project_members RENAME COLUMN created_at_new TO created_at;
-- repos: created_at
ALTER TABLE repos ADD COLUMN created_at_new INTEGER NOT NULL DEFAULT 0;
UPDATE repos SET
created_at_new = CASE WHEN typeof(created_at) = 'integer' THEN created_at ELSE COALESCE(CAST(strftime('%s', substr(created_at, 1, 19)) AS INTEGER), 0) END;
ALTER TABLE repos DROP COLUMN created_at;
ALTER TABLE repos RENAME COLUMN created_at_new TO created_at;
-- issues: created_at, updated_at
ALTER TABLE issues ADD COLUMN created_at_new INTEGER NOT NULL DEFAULT 0;
ALTER TABLE issues ADD COLUMN updated_at_new INTEGER NOT NULL DEFAULT 0;
UPDATE issues SET
created_at_new = CASE WHEN typeof(created_at) = 'integer' THEN created_at ELSE COALESCE(CAST(strftime('%s', substr(created_at, 1, 19)) AS INTEGER), 0) END,
updated_at_new = CASE WHEN typeof(updated_at) = 'integer' THEN updated_at ELSE COALESCE(CAST(strftime('%s', substr(updated_at, 1, 19)) AS INTEGER), 0) END;
ALTER TABLE issues DROP COLUMN created_at;
ALTER TABLE issues DROP COLUMN updated_at;
ALTER TABLE issues RENAME COLUMN created_at_new TO created_at;
ALTER TABLE issues RENAME COLUMN updated_at_new TO updated_at;
-- issue_comments: created_at
ALTER TABLE issue_comments ADD COLUMN created_at_new INTEGER NOT NULL DEFAULT 0;
UPDATE issue_comments SET
created_at_new = CASE WHEN typeof(created_at) = 'integer' THEN created_at ELSE COALESCE(CAST(strftime('%s', substr(created_at, 1, 19)) AS INTEGER), 0) END;
ALTER TABLE issue_comments DROP COLUMN created_at;
ALTER TABLE issue_comments RENAME COLUMN created_at_new TO created_at;
-- wiki_pages: updated_at
ALTER TABLE wiki_pages ADD COLUMN updated_at_new INTEGER NOT NULL DEFAULT 0;
UPDATE wiki_pages SET
updated_at_new = CASE WHEN typeof(updated_at) = 'integer' THEN updated_at ELSE COALESCE(CAST(strftime('%s', substr(updated_at, 1, 19)) AS INTEGER), 0) END;
ALTER TABLE wiki_pages DROP COLUMN updated_at;
ALTER TABLE wiki_pages RENAME COLUMN updated_at_new TO updated_at;
-- uploads: created_at
ALTER TABLE uploads ADD COLUMN created_at_new INTEGER NOT NULL DEFAULT 0;
UPDATE uploads SET
created_at_new = CASE WHEN typeof(created_at) = 'integer' THEN created_at ELSE COALESCE(CAST(strftime('%s', substr(created_at, 1, 19)) AS INTEGER), 0) END;
ALTER TABLE uploads DROP COLUMN created_at;
ALTER TABLE uploads RENAME COLUMN created_at_new TO created_at;
-- project_repos: created_at
ALTER TABLE project_repos ADD COLUMN created_at_new INTEGER NOT NULL DEFAULT 0;
UPDATE project_repos SET
created_at_new = CASE WHEN typeof(created_at) = 'integer' THEN created_at ELSE COALESCE(CAST(strftime('%s', substr(created_at, 1, 19)) AS INTEGER), 0) END;
ALTER TABLE project_repos DROP COLUMN created_at;
ALTER TABLE project_repos RENAME COLUMN created_at_new TO created_at;
COMMIT;
+6 -6
View File
@@ -39,12 +39,12 @@ func createTestUser(t *testing.T, store *db.Store, username string) models.User
t.Fatalf("hash password: %v", err)
}
user = models.User{
Username: username,
DisplayName: username,
Email: username + "@local",
IsAdmin: false,
Disabled: false,
AuthSource: "db",
Username: username,
DisplayName: username,
Email: username + "@local",
IsAdmin: false,
Disabled: false,
AuthProviderID: "",
}
user, err = store.CreateUser(user, passwordHash)
if err != nil {
+1 -1
View File
@@ -97,7 +97,7 @@ export interface Project {
slug: string
name: string
description: string
home_page?: 'info' | 'repos' | 'issues' | 'wiki' | 'files'
home_page?: 'settings' | 'repos' | 'issues' | 'wiki' | 'files'
created_by?: string
updated_by?: string
created_by_name?: string
+2 -2
View File
@@ -8,7 +8,7 @@ import LoginPage from '../pages/LoginPage'
import ProjectsPage from '../pages/ProjectsPage'
import GlobalReposPage from '../pages/GlobalReposPage'
import ProjectEntryPage from '../pages/ProjectEntryPage'
import ProjectHomePage from '../pages/ProjectHomePage'
import ProjectSettingsPage from '../pages/ProjectSettingsPage'
import ReposPage from '../pages/ReposPage'
import AdminUsersPage from '../pages/AdminUsersPage'
import AdminUserGroupsPage from '../pages/AdminUserGroupsPage'
@@ -87,7 +87,7 @@ export const routes: RouteObject[] = [
)
},
{ path: 'projects/:projectId', element: <ProjectEntryPage /> },
{ path: 'projects/:projectId/info', element: <ProjectHomePage /> },
{ path: 'projects/:projectId/settings', element: <ProjectSettingsPage /> },
{ path: 'projects/:projectId/repos', element: <ReposPage /> },
{ path: 'projects/:projectId/repos/:repoId', element: withRouteSuspense(<RepoDetailPage />) },
{ path: 'projects/:projectId/repos/:repoId/branches', element: withRouteSuspense(<BranchesPage />) },
@@ -15,7 +15,7 @@ import remarkGfm from 'remark-gfm'
import FormDialogContent from './FormDialogContent'
import SelectField from './SelectField'
export type ProjectHomePageValue = 'info' | 'repos' | 'issues' | 'wiki' | 'files'
export type ProjectHomePageValue = 'settings' | 'repos' | 'issues' | 'wiki' | 'files'
export type ProjectDescriptionTab = 'write' | 'preview'
type ProjectFormDialogProps = {
@@ -76,7 +76,7 @@ export default function ProjectFormDialog(props: ProjectFormDialogProps) {
<MenuItem value="issues">Issues</MenuItem>
<MenuItem value="wiki">Wiki</MenuItem>
<MenuItem value="files">Files</MenuItem>
<MenuItem value="info">Settings</MenuItem>
<MenuItem value="settings">Settings</MenuItem>
</SelectField>
<Box sx={{ mt: 1 }}>
<Tabs
+1 -1
View File
@@ -76,7 +76,7 @@ export default function ProjectNavBar(props: ProjectNavBarProps) {
</Button>
<Button
component={Link}
to={`/projects/${projectId}/info`}
to={`/projects/${projectId}/settings`}
startIcon={<InfoOutlinedIcon />}
sx={{ justifyContent: 'flex-start', minWidth: 0, width: 'fit-content' }}
>
+1 -1
View File
@@ -675,7 +675,7 @@ export default function DashboardPage() {
{project.slug} · updated {fmt(project.updated_at || project.created_at || 0)}
</Typography>
</Box>
<Chip size="small" variant="outlined" label={project.home_page || 'info'} />
<Chip size="small" variant="outlined" label={project.home_page || 'settings'} />
</Box>
))}
</Box>
+2 -2
View File
@@ -8,7 +8,7 @@ function targetPath(projectId: string, homePage?: string) {
if (homePage === 'issues') return `/projects/${projectId}/issues`
if (homePage === 'wiki') return `/projects/${projectId}/wiki`
if (homePage === 'files') return `/projects/${projectId}/files`
return `/projects/${projectId}/info`
return `/projects/${projectId}/settings`
}
export default function ProjectEntryPage() {
@@ -23,7 +23,7 @@ export default function ProjectEntryPage() {
navigate(targetPath(projectId, project.home_page), { replace: true })
})
.catch(() => {
navigate(`/projects/${projectId}/info`, { replace: true })
navigate(`/projects/${projectId}/settings`, { replace: true })
})
}, [projectId, navigate])
@@ -14,17 +14,17 @@ import DeleteIcon from '@mui/icons-material/Delete'
import ConfirmDeleteDialog from '../components/ConfirmDeleteDialog'
import ProjectFormDialog from '../components/ProjectFormDialog'
import { ProjectDescriptionTab, ProjectHomePageValue } from '../components/ProjectFormDialog'
import SelectField from '../components/SelectField'
import PageAlert from '../components/PageAlert'
import Autocomplete from '../components/Autocomplete'
export default function ProjectHomePage() {
export default function ProjectSettingsPage() {
const { projectId } = useParams()
const [project, setProject] = useState<Project | null>(null)
const [editOpen, setEditOpen] = useState(false)
const [editSlug, setEditSlug] = useState('')
const [editName, setEditName] = useState('')
const [editDescription, setEditDescription] = useState('')
const [editHomePage, setEditHomePage] = useState<ProjectHomePageValue>('info')
const [editHomePage, setEditHomePage] = useState<ProjectHomePageValue>('settings')
const [editDescTab, setEditDescTab] = useState<ProjectDescriptionTab>('write')
const [editError, setEditError] = useState<string | null>(null)
const [savingEdit, setSavingEdit] = useState(false)
@@ -103,7 +103,7 @@ export default function ProjectHomePage() {
setEditSlug(project.slug)
setEditName(project.name)
setEditDescription(project.description || '')
setEditHomePage(project.home_page || 'info')
setEditHomePage(project.home_page || 'settings')
setEditDescTab('write')
setEditError(null)
setEditOpen(true)
@@ -358,23 +358,16 @@ export default function ProjectHomePage() {
actions={
canManageMembers ? (
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center', flexWrap: 'wrap', justifyContent: 'flex-end' }}>
<SelectField
select
<Autocomplete<User, false, false, false>
size="small"
label="User"
value={newMemberUserID}
onChange={(event) => setNewMemberUserID(event.target.value)}
options={memberUsers.filter((user: User) => !members.some((member: ProjectMember) => member.user_id === user.id))}
value={memberUsers.find((user: User) => user.id === newMemberUserID) || null}
onChange={(_, value) => setNewMemberUserID(value?.id || '')}
getOptionLabel={(user: User) => user.display_name ? `${user.display_name} (${user.username})` : user.username}
isOptionEqualToValue={(option: User, value: User) => option.id === value.id}
sx={{ minWidth: 260 }}
>
<MenuItem value="">Select user</MenuItem>
{memberUsers
.filter((user) => !members.some((member) => member.user_id === user.id))
.map((user) => (
<MenuItem key={user.id} value={user.id}>
{user.display_name ? `${user.display_name} (${user.username})` : user.username}
</MenuItem>
))}
</SelectField>
renderInput={(params) => <TextField {...params} label="User" placeholder="Select user" />}
/>
<ToggleButtonGroup
size="small"
exclusive
@@ -450,23 +443,16 @@ export default function ProjectHomePage() {
actions={
canManageMembers ? (
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center', flexWrap: 'wrap', justifyContent: 'flex-end' }}>
<SelectField
select
<Autocomplete<UserGroup, false, false, false>
size="small"
label="Group"
value={newGroupRoleGroupID}
onChange={(event) => setNewGroupRoleGroupID(event.target.value)}
sx={{ minWidth: 220 }}
>
<MenuItem value="">Select group</MenuItem>
{allGroups
.filter((group) => !groupRoles.some((role) => role.group_id === group.id))
.map((group) => (
<MenuItem key={group.id} value={group.id}>
{group.name}
</MenuItem>
))}
</SelectField>
options={allGroups.filter((group: UserGroup) => !groupRoles.some((role: ProjectGroupRole) => role.group_id === group.id))}
value={allGroups.find((group: UserGroup) => group.id === newGroupRoleGroupID) || null}
onChange={(_, value) => setNewGroupRoleGroupID(value?.id || '')}
getOptionLabel={(group: UserGroup) => group.name}
isOptionEqualToValue={(option: UserGroup, value: UserGroup) => option.id === value.id}
sx={{ minWidth: 260 }}
renderInput={(params) => <TextField {...params} label="Group" placeholder="Select group" />}
/>
<ToggleButtonGroup
size="small"
exclusive
+6 -6
View File
@@ -21,7 +21,7 @@ export default function ProjectsPage() {
const [editSlug, setEditSlug] = useState('')
const [editName, setEditName] = useState('')
const [editDescription, setEditDescription] = useState('')
const [editHomePage, setEditHomePage] = useState<ProjectHomePageValue>('info')
const [editHomePage, setEditHomePage] = useState<ProjectHomePageValue>('settings')
const [editDescTab, setEditDescTab] = useState<ProjectDescriptionTab>('write')
const [editError, setEditError] = useState<string | null>(null)
const [createOpen, setCreateOpen] = useState(false)
@@ -30,7 +30,7 @@ export default function ProjectsPage() {
const [createError, setCreateError] = useState<string | null>(null)
const [creating, setCreating] = useState(false)
const [createDescription, setCreateDescription] = useState('')
const [createHomePage, setCreateHomePage] = useState<ProjectHomePageValue>('info')
const [createHomePage, setCreateHomePage] = useState<ProjectHomePageValue>('settings')
const [createDescTab, setCreateDescTab] = useState<ProjectDescriptionTab>('write')
const [savingEdit, setSavingEdit] = useState(false)
const [deleteProject, setDeleteProject] = useState<Project | null>(null)
@@ -103,7 +103,7 @@ export default function ProjectsPage() {
setCreateSlug('')
setCreateName('')
setCreateDescription('')
setCreateHomePage('info')
setCreateHomePage('settings')
setCreateDescTab('write')
setCreateOpen(false)
} catch (err) {
@@ -119,7 +119,7 @@ export default function ProjectsPage() {
setEditSlug(project.slug)
setEditName(project.name)
setEditDescription(project.description || '')
setEditHomePage(project.home_page || 'info')
setEditHomePage(project.home_page || 'settings')
setEditDescTab('write')
setEditError(null)
}
@@ -145,7 +145,7 @@ export default function ProjectsPage() {
setEditSlug('')
setEditName('')
setEditDescription('')
setEditHomePage('info')
setEditHomePage('settings')
} catch (err) {
const message = err instanceof Error ? err.message : 'Failed to update project'
setEditError(message)
@@ -213,7 +213,7 @@ export default function ProjectsPage() {
setCreateSlug('')
setCreateName('')
setCreateDescription('')
setCreateHomePage('info')
setCreateHomePage('settings')
setCreateDescTab('write')
}
+2 -2
View File
@@ -80,7 +80,7 @@ export default function ReposPage() {
const [projectEditSlug, setProjectEditSlug] = useState('')
const [projectEditName, setProjectEditName] = useState('')
const [projectEditDescription, setProjectEditDescription] = useState('')
const [projectEditHomePage, setProjectEditHomePage] = useState<ProjectHomePageValue>('info')
const [projectEditHomePage, setProjectEditHomePage] = useState<ProjectHomePageValue>('settings')
const [projectEditDescTab, setProjectEditDescTab] = useState<ProjectDescriptionTab>('write')
const [projectEditError, setProjectEditError] = useState<string | null>(null)
const [savingProjectEdit, setSavingProjectEdit] = useState(false)
@@ -352,7 +352,7 @@ export default function ReposPage() {
setProjectEditSlug(project.slug)
setProjectEditName(project.name)
setProjectEditDescription(project.description || '')
setProjectEditHomePage(project.home_page || 'info')
setProjectEditHomePage(project.home_page || 'settings')
setProjectEditDescTab('write')
setProjectEditError(null)
setProjectEditOpen(true)