package mysqldriver import ( "context" "database/sql" "errors" "git.aiterp.net/stufflog/server/internal/slerrors" "git.aiterp.net/stufflog/server/models" sq "github.com/Masterminds/squirrel" "github.com/jmoiron/sqlx" ) type projectRepository struct { db *sqlx.DB } func (r *projectRepository) Find(ctx context.Context, id string) (*models.Project, error) { project := models.Project{} err := r.db.GetContext(ctx, &project, "SELECT * FROM project WHERE project_id=?", id) if err != nil { if err == sql.ErrNoRows { return nil, slerrors.NotFound("Project") } return nil, err } return &project, nil } func (r *projectRepository) List(ctx context.Context, filter models.ProjectFilter) ([]*models.Project, error) { q := sq.Select("project.*").From("project").OrderBy("project_id") if len(filter.ProjectIDs) > 0 { q = q.Where(sq.Eq{"project_id": filter.ProjectIDs}) } if filter.Search != nil { q = q.Where("MATCH (name, description) AGAINST (?)", *filter.Search) } if filter.Permission != nil && filter.Permission.Valid() { q = q.LeftJoin("project_permission ON project.project_id = project_permission.project_id AND project_permission.user_id = ?", filter.Permission.UserID) if filter.Permission.MaxLevel >= filter.Permission.MinLevel { q = q.Where(sq.And{ sq.GtOrEq{"project_permission.access_level": filter.Permission.MinLevel}, sq.LtOrEq{"project_permission.access_level": filter.Permission.MaxLevel}, }) } else { q = q.Where(sq.GtOrEq{"project_permission.access_level": filter.Permission.MinLevel}) } } query, args, err := q.ToSql() if err != nil { return nil, err } results := make([]*models.Project, 0, 16) err = r.db.SelectContext(ctx, &results, query, args...) if err != nil { if err == sql.ErrNoRows { return []*models.Project{}, nil } return nil, err } return results, nil } func (r *projectRepository) Insert(ctx context.Context, project models.Project) (*models.Project, error) { if !project.ValidKey() { return nil, errors.New("invalid project id") } _, err := r.db.NamedExecContext(ctx, ` INSERT INTO project (project_id, name, description, daily_points) VALUES (:project_id, :name, :description, :daily_points) `, project) return &project, err } func (r *projectRepository) Save(ctx context.Context, project models.Project) error { _, err := r.db.NamedExecContext(ctx, ` UPDATE project SET name=:name, description=:description, daily_points=:daily_points WHERE project_id=:project_id `, project) return err } func (r *projectRepository) ListPermissions(ctx context.Context, project models.Project) ([]*models.ProjectPermission, error) { permissions := make([]*models.ProjectPermission, 0, 4) err := r.db.SelectContext(ctx, &permissions, "SELECT * FROM project_permission WHERE project_id=?", project.ID) if err != nil { return nil, err } return permissions, nil } func (r *projectRepository) GetPermission(ctx context.Context, project models.Project, user models.User) (*models.ProjectPermission, error) { permission := models.ProjectPermission{} err := r.db.GetContext(ctx, &permission, "SELECT * FROM project_permission WHERE project_id=? AND user_id=?", project.ID, user.ID) if err != nil { if err == sql.ErrNoRows { return &models.ProjectPermission{ ProjectID: project.ID, UserID: user.ID, Level: models.ProjectPermissionLevelNoAccess, }, nil } return nil, err } return &permission, nil } func (r *projectRepository) GetUserPermissions(ctx context.Context, user models.User, projectIDs []string) ([]*models.ProjectPermission, error) { query, args, err := sq.Select("*").From("project_permission").Where(sq.Eq{ "user_id": user.ID, "project_id": projectIDs, }).ToSql() if err != nil { return nil, err } permissions := make([]*models.ProjectPermission, 0, 8) err = r.db.GetContext(ctx, &permissions, query, args...) if err != nil && err != sql.ErrNoRows { return nil, err } filled := make(map[string]bool, len(permissions)) for _, permission := range permissions { filled[permission.ProjectID] = true } for _, projectID := range projectIDs { if filled[projectID] { continue } permissions = append(permissions, &models.ProjectPermission{ ProjectID: projectID, UserID: user.ID, Level: models.ProjectPermissionLevelNoAccess, }) } return permissions, nil } func (r *projectRepository) GetIssuePermission(ctx context.Context, issue models.Issue, user models.User) (*models.ProjectPermission, error) { return r.GetPermission(ctx, models.Project{ID: issue.ProjectID}, user) } func (r *projectRepository) SetPermission(ctx context.Context, permission models.ProjectPermission) error { _, err := r.db.NamedExecContext(ctx, ` REPLACE INTO project_permission (project_id, user_id, access_level) VALUES (:project_id, :user_id, :access_level) `, permission) return err } func (r *projectRepository) Delete(ctx context.Context, project models.Project) error { _, err := r.db.ExecContext(ctx, "DELETE FROM project WHERE project_id=?", project.ID) if err != nil { return err } _, err = r.db.ExecContext(ctx, "DELETE FROM project_permission WHERE project_id=?", project.ID) if err != nil { return err } _, err = r.db.ExecContext(ctx, "DELETE FROM project_status WHERE project_id=?", project.ID) if err != nil { return err } return nil }