Beispiel #1
0
func manageCollaborators(w *web) {
	var form struct {
		ProjectName   string
		Collaborators []string
	}
	w.decode(&form)
	proj := getProject(w.user, w.user.Id, form.ProjectName)

	// We need to do a delete followed by an insert, which means we need
	// exclusion for this project to prevent race conditions.
	lockKey := fmt.Sprintf("%s-%s", proj.Name, proj.Owner.Id)
	locker.Lock(lockKey)
	defer locker.Unlock(lockKey)

	csql.Tx(db, func(tx *sql.Tx) {
		csql.Exec(tx, `
			DELETE FROM
				collaborator
			WHERE
				project_owner = $1 AND project_name = $2
		`, proj.Owner.Id, proj.Name)
		for _, collaborator := range form.Collaborators {
			u := findUserById(collaborator)
			csql.Exec(tx, `
				INSERT INTO collaborator
					(project_owner, project_name, userid)
				VALUES
					($1, $2, $3)
			`, proj.Owner.Id, proj.Name, u.Id)
		}
	})

	w.json(w.r.PostForm)
}
Beispiel #2
0
// Set associates the plain text password given with the user that is uniquely
// identified by id. The password is hashed with bcrypt. If there is a problem
// with hashing or with storing the password, an error is returned.
//
// This may be called on a new user.
func (s *Store) Set(id, password string) (cerr error) {
	defer csql.Safe(&cerr)

	hash, err := bcrypt.GenerateFromPassword(
		[]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return err
	}

	// This lock can be avoided if we use some sort of upsert.
	// It's possible with Postgres, but this is just way easier.
	locker.Lock(id)
	defer locker.Unlock(id)

	n := csql.Count(s, `
		SELECT COUNT(*) FROM `+SqlTableName+` WHERE id = $1
		`, id)
	if n == 0 {
		csql.Exec(s, `
			INSERT INTO `+SqlTableName+` (id, hash) VALUES ($1, $2)
			`, id, hash)
	} else {
		csql.Exec(s, `
			UPDATE `+SqlTableName+` SET id = $1, hash = $2 WHERE id = $1
			`, id, hash)
	}
	return nil
}
Beispiel #3
0
func insertDocument(
	creator *lcmUser,
	proj *project,
	display string,
	recorded time.Time,
	categories []string,
	content string,
) (*document, error) {
	d := &document{
		Project:    proj,
		Display:    display,
		Name:       displayToName(display),
		Recorded:   recorded,
		Categories: categories,
		Content:    content,
		CreatedBy:  creator,
		Created:    time.Now().UTC(),
		Modified:   time.Now().UTC(),
	}
	if err := d.validate(); err != nil {
		return nil, err
	}
	csql.Exec(db, `
		INSERT INTO document (
			project_owner, project_name, name, recorded, categories,
			content, created_by, created, modified
		) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
		`,
		d.Project.Owner.Id, d.Project.Name, d.Name, d.Recorded,
		d.Categories, d.Content, d.CreatedBy.Id, d.Created, d.Modified)
	return d, nil
}
Beispiel #4
0
func doIndices(
	db *DB,
	getSql func(index, *DB) string,
	tables ...string,
) (err error) {
	defer csql.Safe(&err)

	trgmEnabled := db.IsFuzzyEnabled()
	var q string
	var ok bool
	for _, idx := range indices {
		if idx.isFulltext() && !trgmEnabled {
			// Only show the error message if we're on PostgreSQL.
			if db.Driver == "postgres" {
				log.Printf("Skipping fulltext index '%s' since "+
					"the pg_trgm extension is not enabled.", idx.sqlName())
			}
			continue
		}
		if len(tables) == 0 || fun.In(idx.table, tables) {
			q += getSql(idx, db) + "; "
			ok = true
		}
	}
	if ok {
		csql.Exec(db, q)
	}
	return
}
Beispiel #5
0
func connect(conf configPgsql) *lcmDB {
	conns := fmt.Sprintf(
		"user=%s password=%s host=%s port=%d dbname=%s sslmode=disable",
		conf.User, conf.Password, conf.Host, conf.Port, conf.Database)

	pgsqlDB, err := migration.Open("postgres", conns, schemaMigrations)
	if err != nil {
		log.Fatalf("Could not connect to PostgreSQL (%s@%s/%s): %s",
			conf.User, conf.Host, conf.Database, err)
	}

	// All time operations in the database are done in UTC.
	// Times for the user (in their timezone) are mostly handled in template
	// helper functions.
	csql.Exec(pgsqlDB, "SET timezone = UTC")
	return &lcmDB{pgsqlDB, conf}
}
Beispiel #6
0
// insertProject will add the details given as a project to the database.
// An error is returned if the data doesn't validate.
func insertProject(owner *lcmUser, displayName string) (*project, error) {
	proj := &project{
		Owner:   owner,
		Name:    displayToName(displayName),
		Display: displayName,
		Added:   time.Now().UTC(),
	}
	if err := proj.validate(); err != nil {
		return nil, err
	}
	csql.Exec(db, `
		INSERT INTO project 
			(owner, name, created)
		VALUES
			($1, $2, $3)
		`, proj.Owner.Id, proj.Name, proj.Added)
	return proj, nil
}
Beispiel #7
0
// Results executes the parameters of the search and returns the results.
func (s *Searcher) Results() (rs []Result, err error) {
	defer csql.Safe(&err)

	// Set the similarity threshold first.
	if s.db.IsFuzzyEnabled() {
		csql.Exec(s.db, "SELECT set_limit($1)", s.similarThreshold)
	}

	if s.subTvshow != nil {
		if err := s.subTvshow.choose(s, s.chooser); err != nil {
			return nil, err
		}
	}
	if s.subCredits != nil {
		if err := s.subCredits.choose(s, s.chooser); err != nil {
			return nil, err
		}
	}
	if s.subCast != nil {
		if err := s.subCast.choose(s, s.chooser); err != nil {
			return nil, err
		}
	}

	var rows *sql.Rows
	if len(s.name) == 0 {
		rows = csql.Query(s.db, s.sql())
	} else {
		rows = csql.Query(s.db, s.sql(), strings.Join(s.name, " "))
	}
	csql.ForRow(rows, func(scanner csql.RowScanner) {
		var r Result
		var ent string
		csql.Scan(scanner, &ent, &r.Id, &r.Name, &r.Year,
			&r.Similarity, &r.Attrs,
			&r.Rank.Votes, &r.Rank.Rank,
			&r.Credit.ActorId, &r.Credit.MediaId, &r.Credit.Character,
			&r.Credit.Position, &r.Credit.Attrs)
		r.Entity = imdb.Entities[ent]
		rs = append(rs, r)
	})
	return
}
Beispiel #8
0
// delete will delete the project from the database. This includes all
// attached collaborators and documents.
func (proj *project) delete() {
	csql.Exec(db, `
		DELETE FROM project
		WHERE owner = $1 AND name = $2
	`, proj.Owner.Id, proj.Name)
}