<commit_before>package marathon

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"errors"
	log "github.com/Sirupsen/logrus"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
)

type Marathon struct {
	Location    string
	Protocol    string
	Username    string
	Password    string
	NoVerifySsl bool
}

type PortMapping struct {
	ContainerPort int    `json:"containerPort"`
	HostPort      int    `json:"hostPort"`
	ServicePort   int    `json:"servicePort"`
	Protocol      string `json:"protocol"`
}

type Parameter struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

type Docker struct {
	Image          string        `json:"image"`
	Parameters     []Parameter   `json:"parameters"`
	Privileged     bool          `json:"privileged"`
	Network        string        `json:"network"`
	PortMappings   []PortMapping `json:"portMappings"`
	ForcePullImage bool          `json:"forcePullImage"`
}

type Volume struct {
	ContainerPath string `json:"containerPath"`
	HostPath      string `json:"hostPath"`
	Mode          string `json:"mode"`
}

type Container struct {
	Docker  *Docker  `json:"docker"`
	Type    string   `json:"type"`
	Volumes []Volume `json:"volumes"`
}

type HealthCheck struct {
	Path                   string `json:"path"`
	PortIndex              int    `json:"portIndex"`
	Protocol               string `json:"protocol"`
	GracePeriodSeconds     int    `json:"gracePeriodSeconds"`
	IntervalSeconds        int    `json:"intervalSeconds"`
	TimeoutSeconds         int    `json:"timeoutSeconds"`
	MaxConsecutiveFailures int    `json:"maxConsecutiveFailures"`
}

type UpgradeStrategy struct {
	MinimumHealthCapacity float64 `json:"minimumHealthCapacity"`
	MaximumOverCapacity   float64 `json:"maximumOverCapacity"`
}

type App struct {
	Args            []string          `json:"args"`
	BackoffFactor   float64           `json:"backoffFactor"`
	BackoffSeconds  int               `json:"backoffSeconds"`
	Cmd             string            `json:"cmd"`
	Constraints     [][]string        `json:"constraints"`
	Container       *Container        `json:"container"`
	CPUs            float64           `json:"cpus"`
	Dependencies    []string          `json:"dependencies"`
	Disk            float64           `json:"disk"`
	Env             map[string]string `json:"env"`
	Executor        string            `json:"executor"`
	Labels          map[string]string `json:"labels"`
	HealthChecks    []HealthCheck     `json:"healthChecks"`
	ID              string            `json:"id"`
	Instances       int               `json:"instances"`
	Mem             float64           `json:"mem"`
	Ports           []int             `json:"ports"`
	RequirePorts    bool              `json:"requirePorts"`
	StoreUrls       []string          `json:"storeUrls"`
	UpgradeStrategy UpgradeStrategy   `json:"upgradeStrategy"`
	Uris            []string          `json:"uris"`
	User            string            `json:"user,omitempty"`
	Version         string            `json:"version,omitempty"`
}

type AppResponse struct {
	Apps []*App `json:"apps"`
}

func NewMarathon(location, protocol string, username string, password string, verifySsl bool) (*Marathon, error) {
	return &Marathon{location, protocol, username, password, verifySsl}, nil
}

func (m Marathon) ToApp(appJson string) (*App, error) {
	app := &App{}
	err := json.Unmarshal([]byte(appJson), app)
	return app, err
}

func (m Marathon) Apps() ([]*App, error) {
	response, err := m.get("/v2/apps")

	if err != nil || (response.StatusCode != 200) {
		return nil, err
	}

	body, err := m.responseBody(response)
	if err != nil {
		return nil, err
	}

	apps := &AppResponse{}
	err = json.Unmarshal(body, apps)
	return apps.Apps, err
}

func (m Marathon) CreateApp(app *App) (string, error) {
	jsonBlob, err := json.Marshal(app)
	if err != nil {
		return "", nil
	}

	log.Debugf("app json: %s", string(jsonBlob))

	response, err := m.post("/v2/apps", jsonBlob)

	if err != nil {
		return "", err
	}

	switch response.StatusCode {
	case 409:
		return "", errors.New("409 Conflict - application already exists")
	default:
		return m.responseText(response)
	}
}

func (m Marathon) DestroyApp(appId string) (string, error) {
	response, err := m.delete("/v2/apps" + appId)
	if err != nil || (response.StatusCode != 200) {
		return "", err
	}

	return m.responseText(response)
}

func (m Marathon) get(url string) (*http.Response, error) {
	return m.doRequest("GET", url, nil)
}

func (m Marathon) delete(url string) (*http.Response, error) {
	return m.doRequest("DELETE", url, nil)
}

func (m Marathon) post(url string, data []byte) (*http.Response, error) {
	return m.doRequest("POST", url, data)
}

func (m Marathon) doRequest(method string, path string, data []byte) (*http.Response, error) {
	url := m.url(path)
	client := m.getClient()

	var buf io.Reader
	if len(data) > 0 {
		buf = bytes.NewBuffer(data)
	}

	log.Debugf("%s %s", method, url)
	request, err := http.NewRequest(method, url, buf)
	request.Header.Add("Content-Type", "application/json")
	request.Header.Add("Accept", "application/json")

	if m.Username != "" && m.Password != "" {
		request.SetBasicAuth(m.Username, m.Password)
	}

	if err != nil {
		log.WithFields(log.Fields{
			"method": method,
			"url":    url,
		}).Error(err)
		return nil, err
	}

	response, err := client.Do(request)
	m.logHTTP(response, method, url, err)

	return response, err
}

func (m Marathon) getClient() *http.Client {
	client := &http.Client{}
	client.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: m.NoVerifySsl,
		},
	}

	return client
}

func (m Marathon) url(path string) string {
	marathon := url.URL{
		Scheme: m.Protocol,
		Host:   m.Location,
		Path:   path,
	}

	return marathon.String()
}

func (m Marathon) responseBody(response *http.Response) ([]byte, error) {
	if response == nil {
		return nil, nil
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		log.Errorf("Could not read response body: %v", err)
		return nil, err
	}

	return body, nil
}

func (m Marathon) responseText(response *http.Response) (string, error) {
	responseText := ""

	body, err := m.responseBody(response)
	if err != nil {
		return responseText, err
	}

	if len(body) > 0 {
		responseText = string(body)
	}

	return responseText, nil
}

func (m Marathon) logHTTP(resp *http.Response, method string, url string, err error) {
	fields := log.Fields{
		"url":    url,
		"method": method,
	}

	if resp != nil {
		fields["status"] = resp.Status
		fields["statusCode"] = resp.StatusCode
	}

	if err != nil {
		log.WithFields(fields).Error(err.Error())
	} else {
		log.WithFields(fields).Debugf("%s %s", method, url)
	}
}
<commit_msg>fix marathon json marshaling<commit_after>package marathon

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"errors"
	log "github.com/Sirupsen/logrus"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
)

type Marathon struct {
	Location    string
	Protocol    string
	Username    string
	Password    string
	NoVerifySsl bool
}

type PortMapping struct {
	ContainerPort int    `json:"containerPort,omitempty"`
	HostPort      int    `json:"hostPort,omitempty"`
	ServicePort   int    `json:"servicePort,omitempty"`
	Protocol      string `json:"protocol,omitempty"`
}

type Parameter struct {
	Key   string `json:"key,omitempty"`
	Value string `json:"value,omitempty"`
}

type Docker struct {
	Image          string        `json:"image,omitempty"`
	Parameters     []Parameter   `json:"parameters,omitempty"`
	Privileged     bool          `json:"privileged,omitempty"`
	Network        string        `json:"network,omitempty"`
	PortMappings   []PortMapping `json:"portMappings,omitempty"`
	ForcePullImage bool          `json:"forcePullImage,omitempty"`
}

type Volume struct {
	ContainerPath string `json:"containerPath,omitempty"`
	HostPath      string `json:"hostPath,omitempty"`
	Mode          string `json:"mode,omitempty"`
}

type Container struct {
	Docker  *Docker  `json:"docker,omitempty"`
	Type    string   `json:"type,omitempty"`
	Volumes []Volume `json:"volumes,omitempty"`
}

type HealthCheck struct {
	Path                   string `json:"path,omitempty"`
	PortIndex              int    `json:"portIndex,omitempty"`
	Protocol               string `json:"protocol,omitempty"`
	GracePeriodSeconds     int    `json:"gracePeriodSeconds,omitempty"`
	IntervalSeconds        int    `json:"intervalSeconds,omitempty"`
	TimeoutSeconds         int    `json:"timeoutSeconds,omitempty"`
	MaxConsecutiveFailures int    `json:"maxConsecutiveFailures,omitempty"`
}

type UpgradeStrategy struct {
	MinimumHealthCapacity float64 `json:"minimumHealthCapacity,omitempty"`
	MaximumOverCapacity   float64 `json:"maximumOverCapacity,omitempty"`
}

type App struct {
	Args            []string          `json:"args,omitempty"`
	BackoffFactor   float64           `json:"backoffFactor,omitempty"`
	BackoffSeconds  int               `json:"backoffSeconds,omitempty"`
	Cmd             string            `json:"cmd,omitempty"`
	Constraints     [][]string        `json:"constraints,omitempty"`
	Container       *Container        `json:"container,omitempty"`
	CPUs            float64           `json:"cpus,omitempty"`
	Dependencies    []string          `json:"dependencies,omitempty"`
	Disk            float64           `json:"disk,omitempty"`
	Env             map[string]string `json:"env,omitempty"`
	Executor        string            `json:"executor,omitempty"`
	Labels          map[string]string `json:"labels,omitempty"`
	HealthChecks    []HealthCheck     `json:"healthChecks,omitempty"`
	ID              string            `json:"id,omitempty"`
	Instances       int               `json:"instances,omitempty"`
	Mem             float64           `json:"mem,omitempty"`
	Ports           []int             `json:"ports,omitempty"`
	RequirePorts    bool              `json:"requirePorts,omitempty"`
	StoreUrls       []string          `json:"storeUrls,omitempty"`
	UpgradeStrategy UpgradeStrategy   `json:"upgradeStrategy,omitempty"`
	Uris            []string          `json:"uris,omitempty"`
	User            string            `json:"user,omitempty"`
	Version         string            `json:"version,omitempty"`
}

type AppResponse struct {
	Apps []*App `json:"apps"`
}

func NewMarathon(location, protocol string, username string, password string, verifySsl bool) (*Marathon, error) {
	return &Marathon{location, protocol, username, password, verifySsl}, nil
}

func (m Marathon) ToApp(appJson string) (*App, error) {
	app := &App{}
	err := json.Unmarshal([]byte(appJson), app)
	return app, err
}

func (m Marathon) Apps() ([]*App, error) {
	response, err := m.get("/v2/apps")

	if err != nil || (response.StatusCode != 200) {
		return nil, err
	}

	body, err := m.responseBody(response)
	if err != nil {
		return nil, err
	}

	apps := &AppResponse{}
	err = json.Unmarshal(body, apps)
	return apps.Apps, err
}

func (m Marathon) CreateApp(app *App) (string, error) {
	jsonBlob, err := json.Marshal(app)
	if err != nil {
		return "", nil
	}

	log.Debugf("app json: %s", string(jsonBlob))

	response, err := m.post("/v2/apps", jsonBlob)

	if err != nil {
		return "", err
	}

	switch response.StatusCode {
	case 409:
		return "", errors.New("409 Conflict - application already exists")
	default:
		return m.responseText(response)
	}
}

func (m Marathon) DestroyApp(appId string) (string, error) {
	response, err := m.delete("/v2/apps" + appId)
	if err != nil || (response.StatusCode != 200) {
		return "", err
	}

	return m.responseText(response)
}

func (m Marathon) get(url string) (*http.Response, error) {
	return m.doRequest("GET", url, nil)
}

func (m Marathon) delete(url string) (*http.Response, error) {
	return m.doRequest("DELETE", url, nil)
}

func (m Marathon) post(url string, data []byte) (*http.Response, error) {
	return m.doRequest("POST", url, data)
}

func (m Marathon) doRequest(method string, path string, data []byte) (*http.Response, error) {
	url := m.url(path)
	client := m.getClient()

	var buf io.Reader
	if len(data) > 0 {
		buf = bytes.NewBuffer(data)
	}

	log.Debugf("%s %s", method, url)
	request, err := http.NewRequest(method, url, buf)
	request.Header.Add("Content-Type", "application/json")
	request.Header.Add("Accept", "application/json")

	if m.Username != "" && m.Password != "" {
		request.SetBasicAuth(m.Username, m.Password)
	}

	if err != nil {
		log.WithFields(log.Fields{
			"method": method,
			"url":    url,
		}).Error(err)
		return nil, err
	}

	response, err := client.Do(request)
	m.logHTTP(response, method, url, err)

	return response, err
}

func (m Marathon) getClient() *http.Client {
	client := &http.Client{}
	client.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: m.NoVerifySsl,
		},
	}

	return client
}

func (m Marathon) url(path string) string {
	marathon := url.URL{
		Scheme: m.Protocol,
		Host:   m.Location,
		Path:   path,
	}

	return marathon.String()
}

func (m Marathon) responseBody(response *http.Response) ([]byte, error) {
	if response == nil {
		return nil, nil
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		log.Errorf("Could not read response body: %v", err)
		return nil, err
	}

	return body, nil
}

func (m Marathon) responseText(response *http.Response) (string, error) {
	responseText := ""

	body, err := m.responseBody(response)
	if err != nil {
		return responseText, err
	}

	if len(body) > 0 {
		responseText = string(body)
	}

	return responseText, nil
}

func (m Marathon) logHTTP(resp *http.Response, method string, url string, err error) {
	fields := log.Fields{
		"url":    url,
		"method": method,
	}

	if resp != nil {
		fields["status"] = resp.Status
		fields["statusCode"] = resp.StatusCode
	}

	if err != nil {
		log.WithFields(fields).Error(err.Error())
	} else {
		log.WithFields(fields).Debugf("%s %s", method, url)
	}
}
<|endoftext|>


<commit_before><commit_msg>bugfix(shared-link): Create asset parent directory<commit_after><|endoftext|>


<commit_before>// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package org

import (
	"path"
	"strings"

	"github.com/Unknwon/com"

	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/auth"
	"code.gitea.io/gitea/modules/base"
	"code.gitea.io/gitea/modules/context"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/routers/utils"
)

const (
	// tplTeams template path for teams list page
	tplTeams base.TplName = "org/team/teams"
	// tplTeamNew template path for create new team page
	tplTeamNew base.TplName = "org/team/new"
	// tplTeamMembers template path for showing team members page
	tplTeamMembers base.TplName = "org/team/members"
	// tplTeamRepositories template path for showing team repositories page
	tplTeamRepositories base.TplName = "org/team/repositories"
)

// Teams render teams list page
func Teams(ctx *context.Context) {
	org := ctx.Org.Organization
	ctx.Data["Title"] = org.FullName
	ctx.Data["PageIsOrgTeams"] = true

	for _, t := range org.Teams {
		if err := t.GetMembers(); err != nil {
			ctx.ServerError("GetMembers", err)
			return
		}
	}
	ctx.Data["Teams"] = org.Teams

	ctx.HTML(200, tplTeams)
}

// TeamsAction response for join, leave, remove, add operations to team
func TeamsAction(ctx *context.Context) {
	uid := com.StrTo(ctx.Query("uid")).MustInt64()
	if uid == 0 {
		ctx.Redirect(ctx.Org.OrgLink + "/teams")
		return
	}

	page := ctx.Query("page")
	var err error
	switch ctx.Params(":action") {
	case "join":
		if !ctx.Org.IsOwner {
			ctx.Error(404)
			return
		}
		err = ctx.Org.Team.AddMember(ctx.User.ID)
	case "leave":
		err = ctx.Org.Team.RemoveMember(ctx.User.ID)
	case "remove":
		if !ctx.Org.IsOwner {
			ctx.Error(404)
			return
		}
		err = ctx.Org.Team.RemoveMember(uid)
		page = "team"
	case "add":
		if !ctx.Org.IsOwner {
			ctx.Error(404)
			return
		}
		uname := utils.RemoveUsernameParameterSuffix(strings.ToLower(ctx.Query("uname")))
		var u *models.User
		u, err = models.GetUserByName(uname)
		if err != nil {
			if models.IsErrUserNotExist(err) {
				ctx.Flash.Error(ctx.Tr("form.user_not_exist"))
				ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName)
			} else {
				ctx.ServerError(" GetUserByName", err)
			}
			return
		}

		if u.IsOrganization() {
			ctx.Flash.Error(ctx.Tr("form.cannot_add_org_to_team"))
			ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName)
			return
		}

		if ctx.Org.Team.IsMember(u.ID) {
			ctx.Flash.Error(ctx.Tr("org.teams.add_duplicate_users"))
		} else {
			err = ctx.Org.Team.AddMember(u.ID)
		}

		page = "team"
	}

	if err != nil {
		if models.IsErrLastOrgOwner(err) {
			ctx.Flash.Error(ctx.Tr("form.last_org_owner"))
		} else {
			log.Error(3, "Action(%s): %v", ctx.Params(":action"), err)
			ctx.JSON(200, map[string]interface{}{
				"ok":  false,
				"err": err.Error(),
			})
			return
		}
	}

	switch page {
	case "team":
		ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName)
	case "home":
		ctx.Redirect(ctx.Org.Organization.HomeLink())
	default:
		ctx.Redirect(ctx.Org.OrgLink + "/teams")
	}
}

// TeamsRepoAction operate team's repository
func TeamsRepoAction(ctx *context.Context) {
	if !ctx.Org.IsOwner {
		ctx.Error(404)
		return
	}

	var err error
	switch ctx.Params(":action") {
	case "add":
		repoName := path.Base(ctx.Query("repo_name"))
		var repo *models.Repository
		repo, err = models.GetRepositoryByName(ctx.Org.Organization.ID, repoName)
		if err != nil {
			if models.IsErrRepoNotExist(err) {
				ctx.Flash.Error(ctx.Tr("org.teams.add_nonexistent_repo"))
				ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName + "/repositories")
				return
			}
			ctx.ServerError("GetRepositoryByName", err)
			return
		}
		err = ctx.Org.Team.AddRepository(repo)
	case "remove":
		err = ctx.Org.Team.RemoveRepository(com.StrTo(ctx.Query("repoid")).MustInt64())
	}

	if err != nil {
		log.Error(3, "Action(%s): '%s' %v", ctx.Params(":action"), ctx.Org.Team.Name, err)
		ctx.ServerError("TeamsRepoAction", err)
		return
	}
	ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName + "/repositories")
}

// NewTeam render create new team page
func NewTeam(ctx *context.Context) {
	ctx.Data["Title"] = ctx.Org.Organization.FullName
	ctx.Data["PageIsOrgTeams"] = true
	ctx.Data["PageIsOrgTeamsNew"] = true
	ctx.Data["Team"] = &models.Team{}
	ctx.Data["Units"] = models.Units
	ctx.HTML(200, tplTeamNew)
}

// NewTeamPost response for create new team
func NewTeamPost(ctx *context.Context, form auth.CreateTeamForm) {
	ctx.Data["Title"] = ctx.Org.Organization.FullName
	ctx.Data["PageIsOrgTeams"] = true
	ctx.Data["PageIsOrgTeamsNew"] = true
	ctx.Data["Units"] = models.Units

	t := &models.Team{
		OrgID:       ctx.Org.Organization.ID,
		Name:        form.TeamName,
		Description: form.Description,
		Authorize:   models.ParseAccessMode(form.Permission),
	}
	if t.Authorize < models.AccessModeAdmin {
		var units = make([]*models.TeamUnit, 0, len(form.Units))
		for _, tp := range form.Units {
			units = append(units, &models.TeamUnit{
				OrgID: ctx.Org.Organization.ID,
				Type:  tp,
			})
		}
		t.Units = units
	}

	ctx.Data["Team"] = t

	if ctx.HasError() {
		ctx.HTML(200, tplTeamNew)
		return
	}

	if t.Authorize < models.AccessModeAdmin && len(form.Units) == 0 {
		ctx.RenderWithErr(ctx.Tr("form.team_no_units_error"), tplTeamNew, &form)
		return
	}

	if err := models.NewTeam(t); err != nil {
		ctx.Data["Err_TeamName"] = true
		switch {
		case models.IsErrTeamAlreadyExist(err):
			ctx.RenderWithErr(ctx.Tr("form.team_name_been_taken"), tplTeamNew, &form)
		default:
			ctx.ServerError("NewTeam", err)
		}
		return
	}
	log.Trace("Team created: %s/%s", ctx.Org.Organization.Name, t.Name)
	ctx.Redirect(ctx.Org.OrgLink + "/teams/" + t.LowerName)
}

// TeamMembers render team members page
func TeamMembers(ctx *context.Context) {
	ctx.Data["Title"] = ctx.Org.Team.Name
	ctx.Data["PageIsOrgTeams"] = true
	if err := ctx.Org.Team.GetMembers(); err != nil {
		ctx.ServerError("GetMembers", err)
		return
	}
	ctx.HTML(200, tplTeamMembers)
}

// TeamRepositories show the repositories of team
func TeamRepositories(ctx *context.Context) {
	ctx.Data["Title"] = ctx.Org.Team.Name
	ctx.Data["PageIsOrgTeams"] = true
	if err := ctx.Org.Team.GetRepositories(); err != nil {
		ctx.ServerError("GetRepositories", err)
		return
	}
	ctx.HTML(200, tplTeamRepositories)
}

// EditTeam render team edit page
func EditTeam(ctx *context.Context) {
	ctx.Data["Title"] = ctx.Org.Organization.FullName
	ctx.Data["PageIsOrgTeams"] = true
	ctx.Data["team_name"] = ctx.Org.Team.Name
	ctx.Data["desc"] = ctx.Org.Team.Description
	ctx.Data["Units"] = models.Units
	ctx.HTML(200, tplTeamNew)
}

// EditTeamPost response for modify team information
func EditTeamPost(ctx *context.Context, form auth.CreateTeamForm) {
	t := ctx.Org.Team
	ctx.Data["Title"] = ctx.Org.Organization.FullName
	ctx.Data["PageIsOrgTeams"] = true
	ctx.Data["Team"] = t
	ctx.Data["Units"] = models.Units

	isAuthChanged := false
	if !t.IsOwnerTeam() {
		// Validate permission level.
		auth := models.ParseAccessMode(form.Permission)

		t.Name = form.TeamName
		if t.Authorize != auth {
			isAuthChanged = true
			t.Authorize = auth
		}
	}
	t.Description = form.Description
	if t.Authorize < models.AccessModeAdmin {
		var units = make([]models.TeamUnit, 0, len(form.Units))
		for _, tp := range form.Units {
			units = append(units, models.TeamUnit{
				OrgID:  t.OrgID,
				TeamID: t.ID,
				Type:   tp,
			})
		}
		models.UpdateTeamUnits(t, units)
	} else {
		models.UpdateTeamUnits(t, nil)
	}

	if ctx.HasError() {
		ctx.HTML(200, tplTeamNew)
		return
	}

	if t.Authorize < models.AccessModeAdmin && len(form.Units) == 0 {
		ctx.RenderWithErr(ctx.Tr("form.team_no_units_error"), tplTeamNew, &form)
		return
	}

	if err := models.UpdateTeam(t, isAuthChanged); err != nil {
		ctx.Data["Err_TeamName"] = true
		switch {
		case models.IsErrTeamAlreadyExist(err):
			ctx.RenderWithErr(ctx.Tr("form.team_name_been_taken"), tplTeamNew, &form)
		default:
			ctx.ServerError("UpdateTeam", err)
		}
		return
	}
	ctx.Redirect(ctx.Org.OrgLink + "/teams/" + t.LowerName)
}

// DeleteTeam response for the delete team request
func DeleteTeam(ctx *context.Context) {
	if err := models.DeleteTeam(ctx.Org.Team); err != nil {
		ctx.Flash.Error("DeleteTeam: " + err.Error())
	} else {
		ctx.Flash.Success(ctx.Tr("org.teams.delete_team_success"))
	}

	ctx.JSON(200, map[string]interface{}{
		"redirect": ctx.Org.OrgLink + "/teams",
	})
}
<commit_msg>Fixed bug where team with admin privelege type doesn't get any unit attached to the team (#4719)<commit_after>// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package org

import (
	"path"
	"strings"

	"github.com/Unknwon/com"

	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/auth"
	"code.gitea.io/gitea/modules/base"
	"code.gitea.io/gitea/modules/context"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/routers/utils"
)

const (
	// tplTeams template path for teams list page
	tplTeams base.TplName = "org/team/teams"
	// tplTeamNew template path for create new team page
	tplTeamNew base.TplName = "org/team/new"
	// tplTeamMembers template path for showing team members page
	tplTeamMembers base.TplName = "org/team/members"
	// tplTeamRepositories template path for showing team repositories page
	tplTeamRepositories base.TplName = "org/team/repositories"
)

// Teams render teams list page
func Teams(ctx *context.Context) {
	org := ctx.Org.Organization
	ctx.Data["Title"] = org.FullName
	ctx.Data["PageIsOrgTeams"] = true

	for _, t := range org.Teams {
		if err := t.GetMembers(); err != nil {
			ctx.ServerError("GetMembers", err)
			return
		}
	}
	ctx.Data["Teams"] = org.Teams

	ctx.HTML(200, tplTeams)
}

// TeamsAction response for join, leave, remove, add operations to team
func TeamsAction(ctx *context.Context) {
	uid := com.StrTo(ctx.Query("uid")).MustInt64()
	if uid == 0 {
		ctx.Redirect(ctx.Org.OrgLink + "/teams")
		return
	}

	page := ctx.Query("page")
	var err error
	switch ctx.Params(":action") {
	case "join":
		if !ctx.Org.IsOwner {
			ctx.Error(404)
			return
		}
		err = ctx.Org.Team.AddMember(ctx.User.ID)
	case "leave":
		err = ctx.Org.Team.RemoveMember(ctx.User.ID)
	case "remove":
		if !ctx.Org.IsOwner {
			ctx.Error(404)
			return
		}
		err = ctx.Org.Team.RemoveMember(uid)
		page = "team"
	case "add":
		if !ctx.Org.IsOwner {
			ctx.Error(404)
			return
		}
		uname := utils.RemoveUsernameParameterSuffix(strings.ToLower(ctx.Query("uname")))
		var u *models.User
		u, err = models.GetUserByName(uname)
		if err != nil {
			if models.IsErrUserNotExist(err) {
				ctx.Flash.Error(ctx.Tr("form.user_not_exist"))
				ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName)
			} else {
				ctx.ServerError(" GetUserByName", err)
			}
			return
		}

		if u.IsOrganization() {
			ctx.Flash.Error(ctx.Tr("form.cannot_add_org_to_team"))
			ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName)
			return
		}

		if ctx.Org.Team.IsMember(u.ID) {
			ctx.Flash.Error(ctx.Tr("org.teams.add_duplicate_users"))
		} else {
			err = ctx.Org.Team.AddMember(u.ID)
		}

		page = "team"
	}

	if err != nil {
		if models.IsErrLastOrgOwner(err) {
			ctx.Flash.Error(ctx.Tr("form.last_org_owner"))
		} else {
			log.Error(3, "Action(%s): %v", ctx.Params(":action"), err)
			ctx.JSON(200, map[string]interface{}{
				"ok":  false,
				"err": err.Error(),
			})
			return
		}
	}

	switch page {
	case "team":
		ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName)
	case "home":
		ctx.Redirect(ctx.Org.Organization.HomeLink())
	default:
		ctx.Redirect(ctx.Org.OrgLink + "/teams")
	}
}

// TeamsRepoAction operate team's repository
func TeamsRepoAction(ctx *context.Context) {
	if !ctx.Org.IsOwner {
		ctx.Error(404)
		return
	}

	var err error
	switch ctx.Params(":action") {
	case "add":
		repoName := path.Base(ctx.Query("repo_name"))
		var repo *models.Repository
		repo, err = models.GetRepositoryByName(ctx.Org.Organization.ID, repoName)
		if err != nil {
			if models.IsErrRepoNotExist(err) {
				ctx.Flash.Error(ctx.Tr("org.teams.add_nonexistent_repo"))
				ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName + "/repositories")
				return
			}
			ctx.ServerError("GetRepositoryByName", err)
			return
		}
		err = ctx.Org.Team.AddRepository(repo)
	case "remove":
		err = ctx.Org.Team.RemoveRepository(com.StrTo(ctx.Query("repoid")).MustInt64())
	}

	if err != nil {
		log.Error(3, "Action(%s): '%s' %v", ctx.Params(":action"), ctx.Org.Team.Name, err)
		ctx.ServerError("TeamsRepoAction", err)
		return
	}
	ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName + "/repositories")
}

// NewTeam render create new team page
func NewTeam(ctx *context.Context) {
	ctx.Data["Title"] = ctx.Org.Organization.FullName
	ctx.Data["PageIsOrgTeams"] = true
	ctx.Data["PageIsOrgTeamsNew"] = true
	ctx.Data["Team"] = &models.Team{}
	ctx.Data["Units"] = models.Units
	ctx.HTML(200, tplTeamNew)
}

// NewTeamPost response for create new team
func NewTeamPost(ctx *context.Context, form auth.CreateTeamForm) {
	ctx.Data["Title"] = ctx.Org.Organization.FullName
	ctx.Data["PageIsOrgTeams"] = true
	ctx.Data["PageIsOrgTeamsNew"] = true
	ctx.Data["Units"] = models.Units

	t := &models.Team{
		OrgID:       ctx.Org.Organization.ID,
		Name:        form.TeamName,
		Description: form.Description,
		Authorize:   models.ParseAccessMode(form.Permission),
	}

	if t.Authorize < models.AccessModeOwner {
		var units = make([]*models.TeamUnit, 0, len(form.Units))
		for _, tp := range form.Units {
			units = append(units, &models.TeamUnit{
				OrgID: ctx.Org.Organization.ID,
				Type:  tp,
			})
		}
		t.Units = units
	}

	ctx.Data["Team"] = t

	if ctx.HasError() {
		ctx.HTML(200, tplTeamNew)
		return
	}

	if t.Authorize < models.AccessModeAdmin && len(form.Units) == 0 {
		ctx.RenderWithErr(ctx.Tr("form.team_no_units_error"), tplTeamNew, &form)
		return
	}

	if err := models.NewTeam(t); err != nil {
		ctx.Data["Err_TeamName"] = true
		switch {
		case models.IsErrTeamAlreadyExist(err):
			ctx.RenderWithErr(ctx.Tr("form.team_name_been_taken"), tplTeamNew, &form)
		default:
			ctx.ServerError("NewTeam", err)
		}
		return
	}
	log.Trace("Team created: %s/%s", ctx.Org.Organization.Name, t.Name)
	ctx.Redirect(ctx.Org.OrgLink + "/teams/" + t.LowerName)
}

// TeamMembers render team members page
func TeamMembers(ctx *context.Context) {
	ctx.Data["Title"] = ctx.Org.Team.Name
	ctx.Data["PageIsOrgTeams"] = true
	if err := ctx.Org.Team.GetMembers(); err != nil {
		ctx.ServerError("GetMembers", err)
		return
	}
	ctx.HTML(200, tplTeamMembers)
}

// TeamRepositories show the repositories of team
func TeamRepositories(ctx *context.Context) {
	ctx.Data["Title"] = ctx.Org.Team.Name
	ctx.Data["PageIsOrgTeams"] = true
	if err := ctx.Org.Team.GetRepositories(); err != nil {
		ctx.ServerError("GetRepositories", err)
		return
	}
	ctx.HTML(200, tplTeamRepositories)
}

// EditTeam render team edit page
func EditTeam(ctx *context.Context) {
	ctx.Data["Title"] = ctx.Org.Organization.FullName
	ctx.Data["PageIsOrgTeams"] = true
	ctx.Data["team_name"] = ctx.Org.Team.Name
	ctx.Data["desc"] = ctx.Org.Team.Description
	ctx.Data["Units"] = models.Units
	ctx.HTML(200, tplTeamNew)
}

// EditTeamPost response for modify team information
func EditTeamPost(ctx *context.Context, form auth.CreateTeamForm) {
	t := ctx.Org.Team
	ctx.Data["Title"] = ctx.Org.Organization.FullName
	ctx.Data["PageIsOrgTeams"] = true
	ctx.Data["Team"] = t
	ctx.Data["Units"] = models.Units

	isAuthChanged := false
	if !t.IsOwnerTeam() {
		// Validate permission level.
		auth := models.ParseAccessMode(form.Permission)

		t.Name = form.TeamName
		if t.Authorize != auth {
			isAuthChanged = true
			t.Authorize = auth
		}
	}
	t.Description = form.Description
	if t.Authorize < models.AccessModeOwner {
		var units = make([]models.TeamUnit, 0, len(form.Units))
		for _, tp := range form.Units {
			units = append(units, models.TeamUnit{
				OrgID:  t.OrgID,
				TeamID: t.ID,
				Type:   tp,
			})
		}
		models.UpdateTeamUnits(t, units)
	} else {
		models.UpdateTeamUnits(t, nil)
	}

	if ctx.HasError() {
		ctx.HTML(200, tplTeamNew)
		return
	}

	if t.Authorize < models.AccessModeAdmin && len(form.Units) == 0 {
		ctx.RenderWithErr(ctx.Tr("form.team_no_units_error"), tplTeamNew, &form)
		return
	}

	if err := models.UpdateTeam(t, isAuthChanged); err != nil {
		ctx.Data["Err_TeamName"] = true
		switch {
		case models.IsErrTeamAlreadyExist(err):
			ctx.RenderWithErr(ctx.Tr("form.team_name_been_taken"), tplTeamNew, &form)
		default:
			ctx.ServerError("UpdateTeam", err)
		}
		return
	}
	ctx.Redirect(ctx.Org.OrgLink + "/teams/" + t.LowerName)
}

// DeleteTeam response for the delete team request
func DeleteTeam(ctx *context.Context) {
	if err := models.DeleteTeam(ctx.Org.Team); err != nil {
		ctx.Flash.Error("DeleteTeam: " + err.Error())
	} else {
		ctx.Flash.Success(ctx.Tr("org.teams.delete_team_success"))
	}

	ctx.JSON(200, map[string]interface{}{
		"redirect": ctx.Org.OrgLink + "/teams",
	})
}
<|endoftext|>


<commit_before>package handlers

import (
	"fmt"
	"github.com/voutasaurus/Blue/models"
	"html/template"
	"net/http"
)

// public vars

var GetList = make(chan models.ListRetrieve)
var AddList = make(chan models.AddRequest)
var RemoveList = make(chan string)

// private vars

var lastList InfoBookmarks
var templates = template.Must(template.ParseFiles(
	"www/index.html",
	"www/new.html",
	"www/old.html"))

type InfoBookmarks struct {
	List    models.Bookmarks
	Message string
}

// public functions

func MakeRedirHandler(pass string) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		var key string
		if pass != "" {
			key = pass
		} else {
			key = r.FormValue("pass")
		}
		if r.Method == "POST" && key != "" {
			// receive POSTed data
			l := loadList(key)
			if l.List.Key == "" {
				l.Message = "We couldn't find a list with your key \"" + key + "\"."
			}
			lastList = *l
			renderTemplate(w, "index", l)
		} else {
			renderTemplate(w, "index", new(InfoBookmarks))
		}
	}
}

func NewHandler(w http.ResponseWriter, r *http.Request) {
	caller := r.FormValue("formId")
	fmt.Println(caller)
	switch caller {
	case "addUrl": // do this once db is up and running
		if r.Method == "POST" {
			l := lastList
			err := r.ParseForm()
			if err == nil { // this should never fail
				urls := r.Form["url"]
				descs := r.Form["desc"]
				//fmt.Println(urls, descs)
				bookmarks := new(models.Bookmarks)
				for key := range urls {
					bookmarks.List = append(bookmarks.List, models.Bookmark{"http://" + urls[key], descs[key]})
					//fmt.Println(bookmarks.List)
				}
				reply := make(chan string)
				AddList <- models.AddRequest{*bookmarks, reply}
				newKey := <-reply
				if newKey != "" {
					l = *loadList(newKey)
					l.Message = "Successfully saved your links with key \"" + newKey + "\"."
				}
			}
			lastList = l
			renderTemplate(w, "new", &l)
		}
	case "getList": // wrong page, try ./
		MakeRedirHandler(r.FormValue("pass"))(w, r)
	default: // we just got here! come on guys, seriously...
		renderTemplate(w, "new", &InfoBookmarks{Message: "There's nothing here yet..."})
	}
}

// private functions

func loadList(key string) *InfoBookmarks {
	// implement later
	reply := make(chan models.Bookmarks)
	GetList <- models.ListRetrieve{key, reply}
	newList := <-reply
	return &InfoBookmarks{newList, ""}
}

func renderTemplate(w http.ResponseWriter, tmpl string, l *InfoBookmarks) {
	err := templates.ExecuteTemplate(w, tmpl+".html", l)
	if err != nil {
		fmt.Println("Template " + tmpl + " cannot be rendered")
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
<commit_msg>Including more docs. :)<commit_after>// Package handlers contains the handlers for the web server
// portion of Blue.
package handlers

import (
	"fmt"
	"github.com/voutasaurus/Blue/models"
	"html/template"
	"net/http"
)

// GetList is a channel for handling requests to retrieve lists.
var GetList = make(chan models.ListRetrieve)

// AddList is a channel for handling requests to add new lists.
var AddList = make(chan models.AddRequest)

// RemoveList is a channel for handling requests to remove lists.
var RemoveList = make(chan string)

// lastList is a hacky solution to displaying the previously
// accessed list.
var lastList InfoBookmarks

// templates is a list of HTML templates which are parsed for the
// handler.
var templates = template.Must(template.ParseFiles(
	"www/index.html",
	"www/new.html",
	"www/old.html"))

// InfoBookmarks is a hacky solution type which contains a list
// of bookmarks, along with a message for the HTML template
// to display (such as an error, or as the type is named, information.)
type InfoBookmarks struct {
	List    models.Bookmarks
	Message string
}

// MakeRedirHandler creates and serves a handler for redirecting pages.
// It is possibly misnamed; it only ever redirects users back to the
// index page at the "/" path.
func MakeRedirHandler(pass string) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		var key string
		if pass != "" {
			key = pass
		} else {
			key = r.FormValue("pass")
		}
		if r.Method == "POST" && key != "" {
			// receive POSTed data
			l := loadList(key)
			if l.List.Key == "" {
				l.Message = "We couldn't find a list with your key \"" + key + "\"."
			}
			lastList = *l
			renderTemplate(w, "index", l)
		} else {
			renderTemplate(w, "index", new(InfoBookmarks))
		}
	}
}

// NewHandler creates and serves a handler for the "create a new list"
// page.
func NewHandler(w http.ResponseWriter, r *http.Request) {
	caller := r.FormValue("formId")
	fmt.Println(caller)
	switch caller {
	case "addUrl": // do this once db is up and running
		if r.Method == "POST" {
			l := lastList
			err := r.ParseForm()
			if err == nil { // this should never fail
				urls := r.Form["url"]
				descs := r.Form["desc"]
				//fmt.Println(urls, descs)
				bookmarks := new(models.Bookmarks)
				for key := range urls {
					bookmarks.List = append(bookmarks.List, models.Bookmark{"http://" + urls[key], descs[key]})
					//fmt.Println(bookmarks.List)
				}
				reply := make(chan string)
				AddList <- models.AddRequest{*bookmarks, reply}
				newKey := <-reply
				if newKey != "" {
					l = *loadList(newKey)
					l.Message = "Successfully saved your links with key \"" + newKey + "\"."
				}
			}
			lastList = l
			renderTemplate(w, "new", &l)
		}
	case "getList": // wrong page, try ./
		MakeRedirHandler(r.FormValue("pass"))(w, r)
	default: // we just got here! come on guys, seriously...
		renderTemplate(w, "new", &InfoBookmarks{Message: "There's nothing here yet..."})
	}
}

// loadList retrieves an existing list from the database.
func loadList(key string) *InfoBookmarks {
	// implement later
	reply := make(chan models.Bookmarks)
	GetList <- models.ListRetrieve{key, reply}
	newList := <-reply
	return &InfoBookmarks{newList, ""}
}

// renderTemplate displays the correctly templated HTML so the
// user can access the page.
func renderTemplate(w http.ResponseWriter, tmpl string, l *InfoBookmarks) {
	err := templates.ExecuteTemplate(w, tmpl+".html", l)
	if err != nil {
		fmt.Println("Template " + tmpl + " cannot be rendered")
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
<|endoftext|>


<commit_before>package qtypes

import (
	"fmt"
	"errors"
	"github.com/docker/docker/api/types"
)

type ContainerInventory struct {
	Data   map[string]types.ContainerJSON
	IDtoIP map[string]string
}

func NewContainerInventory() ContainerInventory {
	return ContainerInventory{
		Data: map[string]types.ContainerJSON{},
		IDtoIP: map[string]string{},
	}
}

func NewPlainContainerInventory() ContainerInventory {
	return ContainerInventory{
		Data: map[string]types.ContainerJSON{},
	}
}

func (ci *ContainerInventory) SetCnt(key string, cnt types.ContainerJSON) (err error) {
	ci.Data[key] = cnt
	return
}

func (ci *ContainerInventory) GetCnt(key string) (cnt types.ContainerJSON, err error) {
	if cnt, ok := ci.Data[key];ok {
		return cnt, err
	}
	err = errors.New(fmt.Sprintf("No container found with key '%s'", key))
	return
}

func (ci *ContainerInventory) GetCntByID(id string) (cnt types.ContainerJSON, err error) {
	if cnt, ok := ci.Data[id];ok {
		return cnt, err
	}
	return cnt, err
}

func (ci *ContainerInventory) GetCntByIP(ip string) (cnt types.ContainerJSON, err error) {
	for id, v := range ci.IDtoIP {
		if ip == v {
			return ci.GetCntByID(id)
		}

	}
	return cnt, err
}

func (ci *ContainerInventory) SetCntByEvent(ce ContainerEvent) (err error) {
	id := ce.Event.Actor.ID
	event := ce.Event
	if event.Type != "container" {
		return
	}
	switch event.Action {
	case "die", "destroy":
		if _, ok := ci.IDtoIP[id]; ok {
			delete(ci.IDtoIP, id)
		}
		if _, ok := ci.Data[id]; ok {
			delete(ci.Data, id)
		}
		return
	case "start":
		cnt := ce.Container
		if err != nil {
			return err
		}
		ci.Data[id] = cnt
		if cnt.State.Running {
			for _, v := range cnt.NetworkSettings.Networks {
				ci.IDtoIP[id] = v.IPAddress
			}
		} else {
			fmt.Printf("cnt.State: %v\n", cnt.State)
		}
	}
	return err
}

func (ci *ContainerInventory) GetCntByEvent(ce ContainerEvent) (cnt types.ContainerJSON, err error) {
	id := ce.Event.Actor.ID
	cnt = ce.Container
	if ce.Event.Type != "container" {
		return
	}
	switch ce.Event.Action {
	case "die", "destroy":
		if _, ok := ci.IDtoIP[id]; ok {
			delete(ci.IDtoIP, id)
		}
		if _, ok := ci.Data[id]; ok {
			delete(ci.Data, id)
		}
		return
	case "start":
		ci.Data[id] = cnt
		if cnt.State.Running {
			for _, v := range cnt.NetworkSettings.Networks {
				ci.IDtoIP[id] = v.IPAddress
			}
		}
	}
	return cnt, err
}<commit_msg>reuse ci.GetCnt<commit_after>package qtypes

import (
	"fmt"
	"errors"
	"github.com/docker/docker/api/types"
)

type ContainerInventory struct {
	Data   map[string]types.ContainerJSON
	IDtoIP map[string]string
}

func NewContainerInventory() ContainerInventory {
	return ContainerInventory{
		Data: map[string]types.ContainerJSON{},
		IDtoIP: map[string]string{},
	}
}

func NewPlainContainerInventory() ContainerInventory {
	return ContainerInventory{
		Data: map[string]types.ContainerJSON{},
	}
}

func (ci *ContainerInventory) SetCnt(key string, cnt types.ContainerJSON) (err error) {
	ci.Data[key] = cnt
	return
}

func (ci *ContainerInventory) GetCnt(key string) (cnt types.ContainerJSON, err error) {
	if cnt, ok := ci.Data[key];ok {
		return cnt, err
	}
	err = errors.New(fmt.Sprintf("No container found with key '%s'", key))
	return
}

func (ci *ContainerInventory) GetCntByID(id string) (cnt types.ContainerJSON, err error) {
	return ci.GetCnt(id)
}

func (ci *ContainerInventory) GetCntByIP(ip string) (cnt types.ContainerJSON, err error) {
	for id, v := range ci.IDtoIP {
		if ip == v {
			return ci.GetCntByID(id)
		}

	}
	return cnt, err
}

func (ci *ContainerInventory) SetCntByEvent(ce ContainerEvent) (err error) {
	id := ce.Event.Actor.ID
	event := ce.Event
	if event.Type != "container" {
		return
	}
	switch event.Action {
	case "die", "destroy":
		if _, ok := ci.IDtoIP[id]; ok {
			delete(ci.IDtoIP, id)
		}
		if _, ok := ci.Data[id]; ok {
			delete(ci.Data, id)
		}
		return
	case "start":
		cnt := ce.Container
		if err != nil {
			return err
		}
		ci.Data[id] = cnt
		if cnt.State.Running {
			for _, v := range cnt.NetworkSettings.Networks {
				ci.IDtoIP[id] = v.IPAddress
			}
		} else {
			fmt.Printf("cnt.State: %v\n", cnt.State)
		}
	}
	return err
}

func (ci *ContainerInventory) GetCntByEvent(ce ContainerEvent) (cnt types.ContainerJSON, err error) {
	id := ce.Event.Actor.ID
	cnt = ce.Container
	if ce.Event.Type != "container" {
		return
	}
	switch ce.Event.Action {
	case "die", "destroy":
		if _, ok := ci.IDtoIP[id]; ok {
			delete(ci.IDtoIP, id)
		}
		if _, ok := ci.Data[id]; ok {
			delete(ci.Data, id)
		}
		return
	case "start":
		ci.Data[id] = cnt
		if cnt.State.Running {
			for _, v := range cnt.NetworkSettings.Networks {
				ci.IDtoIP[id] = v.IPAddress
			}
		}
	}
	return cnt, err
}<|endoftext|>


<commit_before>package main

import (
	_ "time"
	"crypto/rand"
	"encoding/json"
	"fmt"
	"github.com/gorilla/sessions"
	"io"
	"net/http"
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	"runtime"
	"errors"
	"html/template"
)

var templates = template.Must(template.ParseFiles("index.html"))

const MESSAGE_QUEUE_SIZE = 10

const STATUS_FAILURE = "{\"status\":\"failure\"}"

var authKey = []byte("somesecretauth")
var store sessions.Store

var pool *Pool
var clients map[int64]*Client

var db *sql.DB

type Pool struct {
	in  chan *Client
	out chan *Room
}

type Client struct {
	id      int64
	in      chan string
	out     chan string
	retChan chan *Room
}

type Room struct {
	id      []byte
	client1 *Client
	client2 *Client
}

func (p *Pool) Pair() {
	for {
		c1, c2 := <-p.in, <-p.in

		for c1.id == c2.id {
			c2 = <- p.in
		}

		fmt.Println("match found for ", c1.id, " and ", c2.id)

		b := make([]byte, 32)
		n, err := io.ReadFull(rand.Reader, b)
		if err != nil || n != 32 {
			return
		}

		room := &Room{b, c1, c2}

		c1.in, c2.in = c2.out, c1.out

		c1.retChan <- room
		c2.retChan <- room
	}
}

func newPool() *Pool {
	pool := &Pool{
		in:  make(chan *Client),
		out: make(chan *Room),
	}

	go pool.Pair()

	return pool
}

func UIDFromSession(w http.ResponseWriter, r *http.Request) (int64, error) {
	session, _ := store.Get(r, "session")
	userid := session.Values["userid"]

	if userid == nil {
		return 0, errors.New("no cookie set")
	}
	return userid.(int64), nil
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	db, _ = sql.Open("mysql", "root:pass@/suitup")
	defer db.Close()

	store = sessions.NewCookieStore(authKey)

	pool = newPool()
	clients = make(map[int64]*Client)

	http.HandleFunc("/", mainHandle)

	http.HandleFunc("/login", login)

	http.HandleFunc("/message/check", checkMessage)
	http.HandleFunc("/message/send", sendMessage)

	http.HandleFunc("/question/new", newQuestion)

	http.HandleFunc("/chatroom/join", joinChatRoom)
	http.HandleFunc("/chatroom/leave", leaveChatRoom)

	http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("/home/suitup/hackmit/assets/"))))
	http.ListenAndServe(":8080", nil)
}

func mainHandle(w http.ResponseWriter, r *http.Request) {
	templates.ExecuteTemplate(w, "index.html", nil)
}

func joinChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	prev := clients[uid]
	if (prev != nil) {
		close(prev.out)
		delete(clients, uid)
	}

	fmt.Println("join ", uid)

	retChan := make(chan *Room)
	client := &Client{
		id:      uid,
		in:      nil,
		out:     make(chan string, MESSAGE_QUEUE_SIZE),
		retChan: retChan,
	}
	clients[uid] = client
	pool.in <- client

	chatroom := <- retChan

	fmt.Println("joinChatRoom-chatroom.id: ", chatroom.id)

	fmt.Fprint(w, "{\"status\":\"success\",\"crid\":\"", asciify(chatroom.id), "\"}")
}

func asciify(ba []byte) string {
	ret := make([]byte, len(ba))
	for i, b := range ba {
		ret[i] = (b % 26) + 97
	}
	return string(ret)
}

func leaveChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, _ := UIDFromSession(w, r)
	client := clients[uid]

	fmt.Println("leave ", uid)

	close(client.out)

	client.in = nil
	client.out = make(chan string)
	pool.in <- client

	fmt.Fprint(w, "{\"status\":\"success\"}")
}

func sendMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	fmt.Println("send ", uid)

	message := r.FormValue("s")

	// message := r.PostFormValue("message")

	client := clients[uid]

	if client != nil && client.out != nil {
		client.out <- message
		fmt.Fprint(w, "{\"status\":\"success\"}")
	} else {
		fmt.Fprint(w, STATUS_FAILURE)
	}
}

func checkMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	fmt.Println("check ", uid)

	client := clients[uid]

	if client != nil {
		select {
		case message, ok := <- client.in:
			if ok {
				fmt.Fprint(w, message)
			} else {
				fmt.Println("channel closed")
				client.out = nil
				fmt.Fprint(w, "{\"status\":\"failure\"}")
			}
		default:
			fmt.Fprint(w, "")
		}

	} else {
		fmt.Fprint(w, "")
	}
}

type Question struct {
	Id 	int64			`json:"id"`
	Title string		`json:"title"`
	Body string			`json:"body"`
	Difficulty int 		`json:"diff"`
}

type User struct {
    Id            	int64      	`json:"id"`
    FacebookId  	string		`json:fbid"`
    Username 		string		`json:username"`
    Email 			string		`json:email"`
    Level 			int64		`json:lvl"`
    Score 			int64		`json:score"`
}

func newQuestion(w http.ResponseWriter, r *http.Request) {
	row := db.QueryRow("SELECT * FROM questions ORDER BY RAND()")
	q := new(Question)
	err := row.Scan(&q.Id, &q.Title, &q.Body, &q.Difficulty)

	if err != nil {
		fmt.Println(err)
		fmt.Fprint(w, STATUS_FAILURE)
	}

	b, err := json.Marshal(q)
	if err != nil {
		fmt.Println(err)
		fmt.Fprint(w, STATUS_FAILURE)
	}

	fmt.Fprint(w, string(b))
}

func login(w http.ResponseWriter, r *http.Request) {
	inputToken := r.FormValue("access_token")
	if len(inputToken) != 0 {
		uid := GetMe(inputToken)

		// row := db.QueryRow("SELECT id FROM users")
		row := db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
		user := new(User)
		err := row.Scan(&user.Id)

		if err != nil {
			_, err = db.Exec("INSERT INTO users (facebook_id, username, email, level, points) VALUES (?, ?, ?, 0, 0)", uid, "", "")
			if err != nil {
				fmt.Fprint(w, STATUS_FAILURE)
				return
			} else {
				row = db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
				err = row.Scan(&user.Id)
				if err != nil {
					fmt.Fprint(w, STATUS_FAILURE)
					return
				}
			}

		}

		session, _ := store.Get(r, "session")
		session.Values["userid"] = user.Id
		session.Save(r, w)

		fmt.Fprint(w, "{\"status\":\"success\"}")
	}
}

func readHttpBody(response *http.Response) string {
	bodyBuffer := make([]byte, 1000)
	var str string

	count, err := response.Body.Read(bodyBuffer)

	for ; count > 0; count, err = response.Body.Read(bodyBuffer) {

		if err != nil {

		}

		str += string(bodyBuffer[:count])
	}

	return str

}

func getUncachedResponse(uri string) (*http.Response, error) {
	request, err := http.NewRequest("GET", uri, nil)

	if err == nil {
		request.Header.Add("Cache-Control", "no-cache")

		client := new(http.Client)

		return client.Do(request)
	}

	if (err != nil) {
	}
	return nil, err

}

func GetMe(token string) string {
	response, err := getUncachedResponse("https://graph.facebook.com/me?access_token="+token)

	if err == nil {

		var jsonBlob interface{}

		responseBody := readHttpBody(response)

		if responseBody != "" {
			err = json.Unmarshal([]byte(responseBody), &jsonBlob)

			if err == nil {
				jsonObj := jsonBlob.(map[string]interface{})
				return jsonObj["id"].(string)
			}
		}
		return err.Error()
	}

	return err.Error()
}

func handleError(err error) {
	if err != nil {
		fmt.Println(err)
	}
}
<commit_msg>status from message<commit_after>package main

import (
	_ "time"
	"crypto/rand"
	"encoding/json"
	"fmt"
	"github.com/gorilla/sessions"
	"io"
	"net/http"
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	"runtime"
	"errors"
	"html/template"
)

var templates = template.Must(template.ParseFiles("index.html"))

const MESSAGE_QUEUE_SIZE = 10

const STATUS_FAILURE = "{\"status\":\"failure\"}"

var authKey = []byte("somesecretauth")
var store sessions.Store

var pool *Pool
var clients map[int64]*Client

var db *sql.DB

type Pool struct {
	in  chan *Client
	out chan *Room
}

type Client struct {
	id      int64
	in      chan string
	out     chan string
	retChan chan *Room
}

type Room struct {
	id      []byte
	client1 *Client
	client2 *Client
}

func (p *Pool) Pair() {
	for {
		c1, c2 := <-p.in, <-p.in

		for c1.id == c2.id {
			c2 = <- p.in
		}

		fmt.Println("match found for ", c1.id, " and ", c2.id)

		b := make([]byte, 32)
		n, err := io.ReadFull(rand.Reader, b)
		if err != nil || n != 32 {
			return
		}

		room := &Room{b, c1, c2}

		c1.in, c2.in = c2.out, c1.out

		c1.retChan <- room
		c2.retChan <- room
	}
}

func newPool() *Pool {
	pool := &Pool{
		in:  make(chan *Client),
		out: make(chan *Room),
	}

	go pool.Pair()

	return pool
}

func UIDFromSession(w http.ResponseWriter, r *http.Request) (int64, error) {
	session, _ := store.Get(r, "session")
	userid := session.Values["userid"]

	if userid == nil {
		return 0, errors.New("no cookie set")
	}
	return userid.(int64), nil
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	db, _ = sql.Open("mysql", "root:pass@/suitup")
	defer db.Close()

	store = sessions.NewCookieStore(authKey)

	pool = newPool()
	clients = make(map[int64]*Client)

	http.HandleFunc("/", mainHandle)

	http.HandleFunc("/login", login)

	http.HandleFunc("/message/check", checkMessage)
	http.HandleFunc("/message/send", sendMessage)

	http.HandleFunc("/question/new", newQuestion)

	http.HandleFunc("/chatroom/join", joinChatRoom)
	http.HandleFunc("/chatroom/leave", leaveChatRoom)

	http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("/home/suitup/hackmit/assets/"))))
	http.ListenAndServe(":8080", nil)
}

func mainHandle(w http.ResponseWriter, r *http.Request) {
	templates.ExecuteTemplate(w, "index.html", nil)
}

func joinChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	prev := clients[uid]
	if (prev != nil) {
		close(prev.out)
		delete(clients, uid)
	}

	fmt.Println("join ", uid)

	retChan := make(chan *Room)
	client := &Client{
		id:      uid,
		in:      nil,
		out:     make(chan string, MESSAGE_QUEUE_SIZE),
		retChan: retChan,
	}
	clients[uid] = client
	pool.in <- client

	chatroom := <- retChan

	fmt.Println("joinChatRoom-chatroom.id: ", chatroom.id)

	fmt.Fprint(w, "{\"status\":\"success\",\"crid\":\"", asciify(chatroom.id), "\"}")
}

func asciify(ba []byte) string {
	ret := make([]byte, len(ba))
	for i, b := range ba {
		ret[i] = (b % 26) + 97
	}
	return string(ret)
}

func leaveChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, _ := UIDFromSession(w, r)
	client := clients[uid]

	fmt.Println("leave ", uid)

	close(client.out)

	client.in = nil
	client.out = make(chan string)
	pool.in <- client

	fmt.Fprint(w, "{\"status\":\"success\"}")
}

func sendMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	fmt.Println("send ", uid)

	message := r.FormValue("s")

	// message := r.PostFormValue("message")

	client := clients[uid]

	if client != nil && client.out != nil {
		client.out <- message
		fmt.Fprint(w, "{\"status\":\"success\"}")
	} else {
		fmt.Fprint(w, STATUS_FAILURE)
	}
}

func checkMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	fmt.Println("check ", uid)

	client := clients[uid]

	if client != nil {
		select {
		case message, ok := <- client.in:
			if ok {
				fmt.Fprint(w, "{\"status\":\"success\",\"s\":\"",message, "\"}")
			} else {
				fmt.Println("channel closed")
				client.out = nil
				fmt.Fprint(w, "{\"status\":\"failure\"}")
			}
		default:
			fmt.Fprint(w, "{\"status\":\"success\",\"s\":\"\"}")
		}

	} else {
		fmt.Fprint(w, "{\"status\":\"success\",\"s\":\"\"}")
	}
}

type Question struct {
	Id 	int64			`json:"id"`
	Title string		`json:"title"`
	Body string			`json:"body"`
	Difficulty int 		`json:"diff"`
}

type User struct {
    Id            	int64      	`json:"id"`
    FacebookId  	string		`json:fbid"`
    Username 		string		`json:username"`
    Email 			string		`json:email"`
    Level 			int64		`json:lvl"`
    Score 			int64		`json:score"`
}

func newQuestion(w http.ResponseWriter, r *http.Request) {
	row := db.QueryRow("SELECT * FROM questions ORDER BY RAND()")
	q := new(Question)
	err := row.Scan(&q.Id, &q.Title, &q.Body, &q.Difficulty)

	if err != nil {
		fmt.Println(err)
		fmt.Fprint(w, STATUS_FAILURE)
	}

	b, err := json.Marshal(q)
	if err != nil {
		fmt.Println(err)
		fmt.Fprint(w, STATUS_FAILURE)
	}

	fmt.Fprint(w, string(b))
}

func login(w http.ResponseWriter, r *http.Request) {
	inputToken := r.FormValue("access_token")
	if len(inputToken) != 0 {
		uid := GetMe(inputToken)

		// row := db.QueryRow("SELECT id FROM users")
		row := db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
		user := new(User)
		err := row.Scan(&user.Id)

		if err != nil {
			_, err = db.Exec("INSERT INTO users (facebook_id, username, email, level, points) VALUES (?, ?, ?, 0, 0)", uid, "", "")
			if err != nil {
				fmt.Fprint(w, STATUS_FAILURE)
				return
			} else {
				row = db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
				err = row.Scan(&user.Id)
				if err != nil {
					fmt.Fprint(w, STATUS_FAILURE)
					return
				}
			}

		}

		session, _ := store.Get(r, "session")
		session.Values["userid"] = user.Id
		session.Save(r, w)

		fmt.Fprint(w, "{\"status\":\"success\"}")
	}
}

func readHttpBody(response *http.Response) string {
	bodyBuffer := make([]byte, 1000)
	var str string

	count, err := response.Body.Read(bodyBuffer)

	for ; count > 0; count, err = response.Body.Read(bodyBuffer) {

		if err != nil {

		}

		str += string(bodyBuffer[:count])
	}

	return str

}

func getUncachedResponse(uri string) (*http.Response, error) {
	request, err := http.NewRequest("GET", uri, nil)

	if err == nil {
		request.Header.Add("Cache-Control", "no-cache")

		client := new(http.Client)

		return client.Do(request)
	}

	if (err != nil) {
	}
	return nil, err

}

func GetMe(token string) string {
	response, err := getUncachedResponse("https://graph.facebook.com/me?access_token="+token)

	if err == nil {

		var jsonBlob interface{}

		responseBody := readHttpBody(response)

		if responseBody != "" {
			err = json.Unmarshal([]byte(responseBody), &jsonBlob)

			if err == nil {
				jsonObj := jsonBlob.(map[string]interface{})
				return jsonObj["id"].(string)
			}
		}
		return err.Error()
	}

	return err.Error()
}

func handleError(err error) {
	if err != nil {
		fmt.Println(err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package safehttp

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"strings"
	"sync"
)

// IncomingRequest TODO
type IncomingRequest struct {
	req       *http.Request
	Header    Header
	parseOnce sync.Once
	TLS       *tls.ConnectionState
	URL       *URL
}

// NewIncomingRequest creates an IncomingRequest
// from an http.Request.
func NewIncomingRequest(req *http.Request) *IncomingRequest {
	return &IncomingRequest{
		req:    req,
		Header: newHeader(req.Header),
		TLS:    req.TLS,
		URL:    &URL{url: req.URL},
	}
}

// Host returns the host the request is targeted to.
// TODO(@mihalimara22): Remove this after the safehttp.URL type has been
// implemented.
func (r *IncomingRequest) Host() string {
	return r.req.Host
}

// Path returns the relative path of the URL in decoded format (e.g. %47%6f%2f
// becomes /Go/).
// TODO(@mihalimara22): Remove this after the safehttp.URL type has been     //
// implemented.
func (r *IncomingRequest) Path() string {
	return r.req.URL.Path
}

// PostForm parses the form parameters provided in the body of a POST, PATCH or
// PUT request that does not have Content-Type: multipart/form-data. It returns
// the parsed form parameters as a Form object, if no error occurred. If a parsing
// error occurs it will return it, together with a nil Form. Unless we expect the
// header Content-Type: multipart/form-data in a POST request, this method should
// always be used for forms in POST requests.
func (r *IncomingRequest) PostForm() (*Form, error) {
	var err error
	r.parseOnce.Do(func() {
		if r.req.Method != "POST" && r.req.Method != "PATCH" && r.req.Method != "PUT" {
			err = fmt.Errorf("got request method %s, want POST/PATCH/PUT", r.req.Method)
			return
		}

		if ct := r.req.Header.Get("Content-Type"); ct != "application/x-www-form-urlencoded" {
			err = fmt.Errorf("invalid method called for Content-Type: %s", ct)
			return
		}
		err = r.req.ParseForm()
	})
	if err != nil {
		return nil, err
	}
	return &Form{values: r.req.PostForm}, nil
}

// MultipartForm parses the form parameters provided in the body of a POST,
// PATCH or PUT request that has Content-Type set to multipart/form-data. It
// returns a MultipartForm object containing the parsed form parameters and
// files, if no error occurred, or the parsing error together with a nil
// MultipartForm otherwise. When a form file is passed as part of a request,
// maxMemory determines the upper limit of how much of the file can be stored in
// main memory. If the file is bigger than maxMemory, capped at 32 MB, the
// remaining part is going to  be stored on disk. This method should  only be
// used when the user expects a POST request with the Content-Type: multipart/form-data header.
func (r *IncomingRequest) MultipartForm(maxMemory int64) (*MultipartForm, error) {
	var err error
	r.parseOnce.Do(func() {
		// Ensures no more than 32 MB are stored in memory when a form file is
		// passed as part of the request. If this is bigger than 32 MB, the rest
		// will be stored on disk.
		const defaultMaxMemory = 32 << 20
		if r.req.Method != "POST" && r.req.Method != "PATCH" && r.req.Method != "PUT" {
			err = fmt.Errorf("got request method %s, want POST/PATCH/PUT", r.req.Method)
			return
		}

		if ct := r.req.Header.Get("Content-Type"); !strings.HasPrefix(ct, "multipart/form-data") {
			err = fmt.Errorf("invalid method called for Content-Type: %s", ct)
			return
		}
		if maxMemory < 0 || maxMemory > defaultMaxMemory {
			maxMemory = defaultMaxMemory
		}

		err = r.req.ParseMultipartForm(maxMemory)
	})
	if err != nil {
		return nil, err
	}
	return &MultipartForm{
			Form: Form{
				values: r.req.MultipartForm.Value,
			}},
		nil
}
<commit_msg>Add separa sync.Once primitives for each form type<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package safehttp

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"strings"
	"sync"
)

// IncomingRequest TODO
type IncomingRequest struct {
	req                *http.Request
	Header             Header
	postParseOnce      sync.Once
	multipartParseOnce sync.Once
	TLS                *tls.ConnectionState
	URL                *URL
}

// NewIncomingRequest creates an IncomingRequest
// from an http.Request.
func NewIncomingRequest(req *http.Request) *IncomingRequest {
	return &IncomingRequest{
		req:    req,
		Header: newHeader(req.Header),
		TLS:    req.TLS,
		URL:    &URL{url: req.URL},
	}
}

// Host returns the host the request is targeted to.
// TODO(@mihalimara22): Remove this after the safehttp.URL type has been
// implemented.
func (r *IncomingRequest) Host() string {
	return r.req.Host
}

// Path returns the relative path of the URL in decoded format (e.g. %47%6f%2f
// becomes /Go/).
// TODO(@mihalimara22): Remove this after the safehttp.URL type has been     //
// implemented.
func (r *IncomingRequest) Path() string {
	return r.req.URL.Path
}

// PostForm parses the form parameters provided in the body of a POST, PATCH or
// PUT request that does not have Content-Type: multipart/form-data. It returns
// the parsed form parameters as a Form object, if no error occurred. If a parsing
// error occurs it will return it, together with a nil Form. Unless we expect the
// header Content-Type: multipart/form-data in a POST request, this method should
// always be used for forms in POST requests.
func (r *IncomingRequest) PostForm() (*Form, error) {
	var err error
	r.postParseOnce.Do(func() {
		if r.req.Method != "POST" && r.req.Method != "PATCH" && r.req.Method != "PUT" {
			err = fmt.Errorf("got request method %s, want POST/PATCH/PUT", r.req.Method)
			return
		}

		if ct := r.req.Header.Get("Content-Type"); ct != "application/x-www-form-urlencoded" {
			err = fmt.Errorf("invalid method called for Content-Type: %s", ct)
			return
		}
		err = r.req.ParseForm()
	})
	if err != nil {
		return nil, err
	}
	return &Form{values: r.req.PostForm}, nil
}

// MultipartForm parses the form parameters provided in the body of a POST,
// PATCH or PUT request that has Content-Type set to multipart/form-data. It
// returns a MultipartForm object containing the parsed form parameters and
// files, if no error occurred, or the parsing error together with a nil
// MultipartForm otherwise. When a form file is passed as part of a request,
// maxMemory determines the upper limit of how much of the file can be stored in
// main memory. If the file is bigger than maxMemory, capped at 32 MB, the
// remaining part is going to  be stored on disk. This method should  only be
// used when the user expects a POST request with the Content-Type: multipart/form-data header.
func (r *IncomingRequest) MultipartForm(maxMemory int64) (*MultipartForm, error) {
	var err error
	// Ensures no more than 32 MB are stored in memory when a form file is
	// passed as part of the request. If this is bigger than 32 MB, the rest
	// will be stored on disk.
	const defaultMaxMemory = 32 << 20
	r.multipartParseOnce.Do(func() {
		if r.req.Method != "POST" && r.req.Method != "PATCH" && r.req.Method != "PUT" {
			err = fmt.Errorf("got request method %s, want POST/PATCH/PUT", r.req.Method)
			return
		}

		if ct := r.req.Header.Get("Content-Type"); !strings.HasPrefix(ct, "multipart/form-data") {
			err = fmt.Errorf("invalid method called for Content-Type: %s", ct)
			return
		}
		if maxMemory < 0 || maxMemory > defaultMaxMemory {
			maxMemory = defaultMaxMemory
		}

		err = r.req.ParseMultipartForm(maxMemory)
	})
	if err != nil {
		return nil, err
	}
	return &MultipartForm{
			Form: Form{
				values: r.req.MultipartForm.Value,
			}},
		nil
}
<|endoftext|>


<commit_before>package fzf

import (
	"testing"

	"github.com/junegunn/fzf/src/algo"
)

func TestParseTermsExtended(t *testing.T) {
	terms := parseTerms(ModeExtended,
		"aaa 'bbb ^ccc ddd$ !eee !'fff !^ggg !hhh$")
	if len(terms) != 8 ||
		terms[0].typ != termFuzzy || terms[0].inv ||
		terms[1].typ != termExact || terms[1].inv ||
		terms[2].typ != termPrefix || terms[2].inv ||
		terms[3].typ != termSuffix || terms[3].inv ||
		terms[4].typ != termFuzzy || !terms[4].inv ||
		terms[5].typ != termExact || !terms[5].inv ||
		terms[6].typ != termPrefix || !terms[6].inv ||
		terms[7].typ != termSuffix || !terms[7].inv {
		t.Errorf("%s", terms)
	}
	for idx, term := range terms {
		if len(term.text) != 3 {
			t.Errorf("%s", term)
		}
		if idx > 0 && len(term.origText) != 4+idx/5 {
			t.Errorf("%s", term)
		}
	}
}

func TestParseTermsExtendedExact(t *testing.T) {
	terms := parseTerms(ModeExtendedExact,
		"aaa 'bbb ^ccc ddd$ !eee !'fff !^ggg !hhh$")
	if len(terms) != 8 ||
		terms[0].typ != termExact || terms[0].inv || len(terms[0].text) != 3 ||
		terms[1].typ != termExact || terms[1].inv || len(terms[1].text) != 4 ||
		terms[2].typ != termPrefix || terms[2].inv || len(terms[2].text) != 3 ||
		terms[3].typ != termSuffix || terms[3].inv || len(terms[3].text) != 3 ||
		terms[4].typ != termExact || !terms[4].inv || len(terms[4].text) != 3 ||
		terms[5].typ != termExact || !terms[5].inv || len(terms[5].text) != 4 ||
		terms[6].typ != termPrefix || !terms[6].inv || len(terms[6].text) != 3 ||
		terms[7].typ != termSuffix || !terms[7].inv || len(terms[7].text) != 3 {
		t.Errorf("%s", terms)
	}
}

func TestParseTermsEmpty(t *testing.T) {
	terms := parseTerms(ModeExtended, "' $ ^ !' !^ !$")
	if len(terms) != 0 {
		t.Errorf("%s", terms)
	}
}

func TestExact(t *testing.T) {
	defer clearPatternCache()
	clearPatternCache()
	pattern := BuildPattern(ModeExtended, CaseSmart,
		[]Range{}, nil, []rune("'abc"))
	runes := []rune("aabbcc abc")
	sidx, eidx := algo.ExactMatchNaive(pattern.caseSensitive, &runes, pattern.terms[0].text)
	if sidx != 7 || eidx != 10 {
		t.Errorf("%s / %d / %d", pattern.terms, sidx, eidx)
	}
}

func TestCaseSensitivity(t *testing.T) {
	defer clearPatternCache()
	clearPatternCache()
	pat1 := BuildPattern(ModeFuzzy, CaseSmart, []Range{}, nil, []rune("abc"))
	clearPatternCache()
	pat2 := BuildPattern(ModeFuzzy, CaseSmart, []Range{}, nil, []rune("Abc"))
	clearPatternCache()
	pat3 := BuildPattern(ModeFuzzy, CaseIgnore, []Range{}, nil, []rune("abc"))
	clearPatternCache()
	pat4 := BuildPattern(ModeFuzzy, CaseIgnore, []Range{}, nil, []rune("Abc"))
	clearPatternCache()
	pat5 := BuildPattern(ModeFuzzy, CaseRespect, []Range{}, nil, []rune("abc"))
	clearPatternCache()
	pat6 := BuildPattern(ModeFuzzy, CaseRespect, []Range{}, nil, []rune("Abc"))

	if string(pat1.text) != "abc" || pat1.caseSensitive != false ||
		string(pat2.text) != "Abc" || pat2.caseSensitive != true ||
		string(pat3.text) != "abc" || pat3.caseSensitive != false ||
		string(pat4.text) != "abc" || pat4.caseSensitive != false ||
		string(pat5.text) != "abc" || pat5.caseSensitive != true ||
		string(pat6.text) != "Abc" || pat6.caseSensitive != true {
		t.Error("Invalid case conversion")
	}
}

func TestOrigTextAndTransformed(t *testing.T) {
	strptr := func(str string) *string {
		return &str
	}
	pattern := BuildPattern(ModeExtended, CaseSmart, []Range{}, nil, []rune("jg"))
	tokens := Tokenize(strptr("junegunn"), nil)
	trans := Transform(tokens, []Range{Range{1, 1}})

	for _, mode := range []Mode{ModeFuzzy, ModeExtended} {
		chunk := Chunk{
			&Item{
				text:        strptr("junegunn"),
				origText:    strptr("junegunn.choi"),
				transformed: trans},
		}
		pattern.mode = mode
		matches := pattern.matchChunk(&chunk)
		if *matches[0].text != "junegunn" || *matches[0].origText != "junegunn.choi" ||
			matches[0].offsets[0][0] != 0 || matches[0].offsets[0][1] != 5 ||
			matches[0].transformed != trans {
			t.Error("Invalid match result", matches)
		}
	}
}
<commit_msg>Update test case<commit_after>package fzf

import (
	"testing"

	"github.com/junegunn/fzf/src/algo"
)

func TestParseTermsExtended(t *testing.T) {
	terms := parseTerms(ModeExtended, CaseSmart,
		"aaa 'bbb ^ccc ddd$ !eee !'fff !^ggg !hhh$")
	if len(terms) != 8 ||
		terms[0].typ != termFuzzy || terms[0].inv ||
		terms[1].typ != termExact || terms[1].inv ||
		terms[2].typ != termPrefix || terms[2].inv ||
		terms[3].typ != termSuffix || terms[3].inv ||
		terms[4].typ != termFuzzy || !terms[4].inv ||
		terms[5].typ != termExact || !terms[5].inv ||
		terms[6].typ != termPrefix || !terms[6].inv ||
		terms[7].typ != termSuffix || !terms[7].inv {
		t.Errorf("%s", terms)
	}
	for idx, term := range terms {
		if len(term.text) != 3 {
			t.Errorf("%s", term)
		}
		if idx > 0 && len(term.origText) != 4+idx/5 {
			t.Errorf("%s", term)
		}
	}
}

func TestParseTermsExtendedExact(t *testing.T) {
	terms := parseTerms(ModeExtendedExact, CaseSmart,
		"aaa 'bbb ^ccc ddd$ !eee !'fff !^ggg !hhh$")
	if len(terms) != 8 ||
		terms[0].typ != termExact || terms[0].inv || len(terms[0].text) != 3 ||
		terms[1].typ != termExact || terms[1].inv || len(terms[1].text) != 4 ||
		terms[2].typ != termPrefix || terms[2].inv || len(terms[2].text) != 3 ||
		terms[3].typ != termSuffix || terms[3].inv || len(terms[3].text) != 3 ||
		terms[4].typ != termExact || !terms[4].inv || len(terms[4].text) != 3 ||
		terms[5].typ != termExact || !terms[5].inv || len(terms[5].text) != 4 ||
		terms[6].typ != termPrefix || !terms[6].inv || len(terms[6].text) != 3 ||
		terms[7].typ != termSuffix || !terms[7].inv || len(terms[7].text) != 3 {
		t.Errorf("%s", terms)
	}
}

func TestParseTermsEmpty(t *testing.T) {
	terms := parseTerms(ModeExtended, CaseSmart, "' $ ^ !' !^ !$")
	if len(terms) != 0 {
		t.Errorf("%s", terms)
	}
}

func TestExact(t *testing.T) {
	defer clearPatternCache()
	clearPatternCache()
	pattern := BuildPattern(ModeExtended, CaseSmart,
		[]Range{}, nil, []rune("'abc"))
	runes := []rune("aabbcc abc")
	sidx, eidx := algo.ExactMatchNaive(pattern.caseSensitive, &runes, pattern.terms[0].text)
	if sidx != 7 || eidx != 10 {
		t.Errorf("%s / %d / %d", pattern.terms, sidx, eidx)
	}
}

func TestCaseSensitivity(t *testing.T) {
	defer clearPatternCache()
	clearPatternCache()
	pat1 := BuildPattern(ModeFuzzy, CaseSmart, []Range{}, nil, []rune("abc"))
	clearPatternCache()
	pat2 := BuildPattern(ModeFuzzy, CaseSmart, []Range{}, nil, []rune("Abc"))
	clearPatternCache()
	pat3 := BuildPattern(ModeFuzzy, CaseIgnore, []Range{}, nil, []rune("abc"))
	clearPatternCache()
	pat4 := BuildPattern(ModeFuzzy, CaseIgnore, []Range{}, nil, []rune("Abc"))
	clearPatternCache()
	pat5 := BuildPattern(ModeFuzzy, CaseRespect, []Range{}, nil, []rune("abc"))
	clearPatternCache()
	pat6 := BuildPattern(ModeFuzzy, CaseRespect, []Range{}, nil, []rune("Abc"))

	if string(pat1.text) != "abc" || pat1.caseSensitive != false ||
		string(pat2.text) != "Abc" || pat2.caseSensitive != true ||
		string(pat3.text) != "abc" || pat3.caseSensitive != false ||
		string(pat4.text) != "abc" || pat4.caseSensitive != false ||
		string(pat5.text) != "abc" || pat5.caseSensitive != true ||
		string(pat6.text) != "Abc" || pat6.caseSensitive != true {
		t.Error("Invalid case conversion")
	}
}

func TestOrigTextAndTransformed(t *testing.T) {
	strptr := func(str string) *string {
		return &str
	}
	pattern := BuildPattern(ModeExtended, CaseSmart, []Range{}, nil, []rune("jg"))
	tokens := Tokenize(strptr("junegunn"), nil)
	trans := Transform(tokens, []Range{Range{1, 1}})

	for _, mode := range []Mode{ModeFuzzy, ModeExtended} {
		chunk := Chunk{
			&Item{
				text:        strptr("junegunn"),
				origText:    strptr("junegunn.choi"),
				transformed: trans},
		}
		pattern.mode = mode
		matches := pattern.matchChunk(&chunk)
		if *matches[0].text != "junegunn" || *matches[0].origText != "junegunn.choi" ||
			matches[0].offsets[0][0] != 0 || matches[0].offsets[0][1] != 5 ||
			matches[0].transformed != trans {
			t.Error("Invalid match result", matches)
		}
	}
}
<|endoftext|>


<commit_before>/*
 * (c) 2014, Caoimhe Chaos <caoimhechaos@protonmail.com>,
 *	     Starship Factory. All rights reserved.
 *
 * Redistribution and use in source  and binary forms, with or without
 * modification, are permitted  provided that the following conditions
 * are met:
 *
 * * Redistributions of  source code  must retain the  above copyright
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this  list of conditions and the  following disclaimer in
 *   the  documentation  and/or  other  materials  provided  with  the
 *   distribution.
 * * Neither  the name  of the Starship Factory  nor the  name  of its
 *   contributors may  be used to endorse or  promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS"  AND ANY EXPRESS  OR IMPLIED WARRANTIES  OF MERCHANTABILITY
 * AND FITNESS  FOR A PARTICULAR  PURPOSE ARE DISCLAIMED. IN  NO EVENT
 * SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED  TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE,  DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT  LIABILITY,  OR  TORT  (INCLUDING NEGLIGENCE  OR  OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
	"database/cassandra"
	"encoding/json"
	"io/ioutil"
	"log"
	"math/big"
	"mime/multipart"
	"net/http"
	"net/url"
	"time"

	"ancient-solutions.com/ancientauth"
	"code.google.com/p/goprotobuf/proto"
)

type applicantListType struct {
	Applicants               []*MemberWithKey `json:"applicants"`
	ApprovalCsrfToken        string           `json:"approval_csrf_token"`
	RejectionCsrfToken       string           `json:"rejection_csrf_token"`
	AgreementUploadCsrfToken string           `json:"agreement_upload_csrf_token"`
}

type ApplicantListHandler struct {
	admingroup string
	auth       *ancientauth.Authenticator
	database   *MembershipDB
	pagesize   int32
}

var applicantApprovalURL *url.URL
var applicantRejectionURL *url.URL
var applicantAgreementUploadURL *url.URL

func init() {
	var err error
	applicantApprovalURL, err = url.Parse("/admin/api/accept")
	if err != nil {
		log.Fatal("Error parsing static approval URL: ", err)
	}
	applicantRejectionURL, err = url.Parse("/admin/api/reject")
	if err != nil {
		log.Fatal("Error parsing static rejection URL: ", err)
	}
	applicantAgreementUploadURL, err = url.Parse("/admin/api/agreement-upload")
	if err != nil {
		log.Fatal("Error parsing static agreement upload URL: ", err)
	}
}

// Output a JSON list of all applicants currently waiting to become members.
func (a *ApplicantListHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	var applist applicantListType
	var enc *json.Encoder
	var err error

	if !a.auth.IsAuthenticatedScope(req, a.admingroup) {
		rw.WriteHeader(http.StatusUnauthorized)
		return
	}

	if req.FormValue("single") == "true" && len(req.FormValue("start")) > 0 {
		var memberreq *MembershipAgreement
		var mwk *MemberWithKey
		var bigint *big.Int = big.NewInt(0)
		var uuid cassandra.UUID
		var ok bool
		bigint, ok = bigint.SetString(req.FormValue("start"), 10)
		if !ok {
			rw.WriteHeader(http.StatusInternalServerError)
			rw.Write([]byte("Unable to parse " + req.FormValue("start") +
				" as a number"))
			return
		}
		uuid = cassandra.UUIDFromBytes(bigint.Bytes())
		memberreq, _, err = a.database.GetMembershipRequest(
			uuid.String(), "application", "applicant:")
		if err != nil {
			rw.WriteHeader(http.StatusInternalServerError)
			rw.Write([]byte("Unable to retrieve the membership request " +
				uuid.String() + ": " + err.Error()))
			return
		}
		mwk = new(MemberWithKey)
		mwk.Key = string([]byte(uuid))
		proto.Merge(&mwk.Member, memberreq.GetMemberData())
		applist.Applicants = []*MemberWithKey{mwk}
	} else {
		applist.Applicants, err = a.database.EnumerateMembershipRequests(
			req.FormValue("criterion"), req.FormValue("start"), a.pagesize)
		if err != nil {
			log.Print("Error enumerating applications: ", err)
			rw.WriteHeader(http.StatusInternalServerError)
			rw.Write([]byte("Error enumerating applications: " + err.Error()))
			return
		}
	}

	applist.AgreementUploadCsrfToken, err = a.auth.GenCSRFToken(
		req, applicantAgreementUploadURL, 10*time.Minute)
	if err != nil {
		log.Print("Error generating CSRF token: ", err)
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte("Error generating CSRF token: " + err.Error()))
		return
	}

	applist.ApprovalCsrfToken, err = a.auth.GenCSRFToken(
		req, applicantApprovalURL, 10*time.Minute)
	if err != nil {
		log.Print("Error generating CSRF token: ", err)
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte("Error generating CSRF token: " + err.Error()))
		return
	}

	applist.RejectionCsrfToken, err = a.auth.GenCSRFToken(
		req, applicantRejectionURL, 10*time.Minute)
	if err != nil {
		log.Print("Error generating CSRF token: ", err)
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte("Error generating CSRF token: " + err.Error()))
		return
	}

	rw.Header().Set("Content-Type", "application/json; encoding=utf8")
	enc = json.NewEncoder(rw)
	if err = enc.Encode(applist); err != nil {
		log.Print("Error JSON encoding member list: ", err)
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte("Error encoding result: " + err.Error()))
		return
	}
}

// Object for approving membership applications.
type MemberAcceptHandler struct {
	admingroup string
	auth       *ancientauth.Authenticator
	database   *MembershipDB
}

func (m *MemberAcceptHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	var user string = m.auth.GetAuthenticatedUser(req)
	var id string = req.PostFormValue("uuid")
	var ok bool
	var err error

	if user == "" {
		rw.WriteHeader(http.StatusUnauthorized)
		return
	}

	if len(m.admingroup) > 0 && !m.auth.IsAuthenticatedScope(req, m.admingroup) {
		rw.WriteHeader(http.StatusForbidden)
		rw.Write([]byte("User not authorized for this service"))
		return
	}

	ok, err = m.auth.VerifyCSRFToken(req, req.PostFormValue("csrf_token"), false)
	if err != nil && err != ancientauth.CSRFToken_WeakProtectionError {
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte(err.Error()))
		log.Print("Error verifying CSRF token: ", err)
		return
	}
	if !ok {
		rw.WriteHeader(http.StatusForbidden)
		rw.Write([]byte("CSRF token validation failed"))
		log.Print("Invalid CSRF token reveived")
		return
	}

	err = m.database.MoveApplicantToNewMember(id, user)
	if err != nil {
		log.Print("Error moving applicant ", id, " to new user: ", err)
		rw.WriteHeader(http.StatusLengthRequired)
		rw.Write([]byte(err.Error()))
		return
	}

	rw.WriteHeader(http.StatusOK)
	rw.Write([]byte("{}"))
}

// Object for rejecting membership applications.
type MemberRejectHandler struct {
	admingroup string
	auth       *ancientauth.Authenticator
	database   *MembershipDB
}

func (m *MemberRejectHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	var user string = m.auth.GetAuthenticatedUser(req)
	var id string = req.PostFormValue("uuid")
	var ok bool
	var err error

	if user == "" {
		rw.WriteHeader(http.StatusUnauthorized)
		return
	}

	if len(m.admingroup) > 0 && !m.auth.IsAuthenticatedScope(req, m.admingroup) {
		rw.WriteHeader(http.StatusForbidden)
	}

	ok, err = m.auth.VerifyCSRFToken(req, req.PostFormValue("csrf_token"), false)
	if err != nil && err != ancientauth.CSRFToken_WeakProtectionError {
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte(err.Error()))
		log.Print("Error verifying CSRF token: ", err)
		return
	}
	if !ok {
		rw.WriteHeader(http.StatusForbidden)
		rw.Write([]byte("CSRF token validation failed"))
		log.Print("Invalid CSRF token reveived")
		return
	}

	err = m.database.MoveApplicantToTrash(id, user)
	if err != nil {
		log.Print("Error moving applicant ", id, " to trash: ", err)
		rw.WriteHeader(http.StatusLengthRequired)
		rw.Write([]byte(err.Error()))
		return
	}

	rw.WriteHeader(http.StatusOK)
	rw.Write([]byte("{}"))
}

// Object for uploading membership agreements.
type MemberAgreementUploadHandler struct {
	admingroup string
	auth       *ancientauth.Authenticator
	database   *MembershipDB
}

func (m *MemberAgreementUploadHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	var user string = m.auth.GetAuthenticatedUser(req)
	var id string = req.FormValue("uuid")
	var mf multipart.File
	var agreement_data []byte
	var ok bool
	var err error

	if user == "" {
		rw.WriteHeader(http.StatusUnauthorized)
		return
	}

	if len(m.admingroup) > 0 && !m.auth.IsAuthenticatedScope(req, m.admingroup) {
		rw.WriteHeader(http.StatusForbidden)
	}

	req.URL.RawQuery = ""
	req.ParseMultipartForm(5 * 1048576)

	ok, err = m.auth.VerifyCSRFToken(req, req.FormValue("csrf_token"), false)
	if err != nil && err != ancientauth.CSRFToken_WeakProtectionError {
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte(err.Error()))
		log.Print("Error verifying CSRF token: ", err)
		return
	}
	if !ok {
		rw.WriteHeader(http.StatusForbidden)
		rw.Write([]byte("CSRF token validation failed"))
		log.Print("Invalid CSRF token reveived")
		return
	}

	mf, _, err = req.FormFile("0")
	if err != nil {
		rw.WriteHeader(http.StatusBadRequest)
		rw.Write([]byte("Unable to retrieve uploaded file: " + err.Error()))
		log.Print("Unable to retrieve uploaded file: ", err)
		return
	}

	agreement_data, err = ioutil.ReadAll(mf)
	if err != nil {
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte("Error reading in agreement data: " + err.Error()))
		log.Print("Error reading in agreement data: ", err)
		return
	}

	mf.Close()

	err = m.database.StoreMembershipAgreement(id, agreement_data)
	if err != nil {
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte("Error storing membership agreement: " + err.Error()))
		log.Print("Error storing membership agreement: ", err)
		return
	}

	rw.Header().Set("Content-Type", "application/json")
	rw.WriteHeader(http.StatusOK)
	rw.Write([]byte("{}"))
}
<commit_msg>The key should be set to the user-readable version for the fronted.<commit_after>/*
 * (c) 2014, Caoimhe Chaos <caoimhechaos@protonmail.com>,
 *	     Starship Factory. All rights reserved.
 *
 * Redistribution and use in source  and binary forms, with or without
 * modification, are permitted  provided that the following conditions
 * are met:
 *
 * * Redistributions of  source code  must retain the  above copyright
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this  list of conditions and the  following disclaimer in
 *   the  documentation  and/or  other  materials  provided  with  the
 *   distribution.
 * * Neither  the name  of the Starship Factory  nor the  name  of its
 *   contributors may  be used to endorse or  promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS"  AND ANY EXPRESS  OR IMPLIED WARRANTIES  OF MERCHANTABILITY
 * AND FITNESS  FOR A PARTICULAR  PURPOSE ARE DISCLAIMED. IN  NO EVENT
 * SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED  TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE,  DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT  LIABILITY,  OR  TORT  (INCLUDING NEGLIGENCE  OR  OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
	"database/cassandra"
	"encoding/json"
	"io/ioutil"
	"log"
	"math/big"
	"mime/multipart"
	"net/http"
	"net/url"
	"time"

	"ancient-solutions.com/ancientauth"
	"code.google.com/p/goprotobuf/proto"
)

type applicantListType struct {
	Applicants               []*MemberWithKey `json:"applicants"`
	ApprovalCsrfToken        string           `json:"approval_csrf_token"`
	RejectionCsrfToken       string           `json:"rejection_csrf_token"`
	AgreementUploadCsrfToken string           `json:"agreement_upload_csrf_token"`
}

type ApplicantListHandler struct {
	admingroup string
	auth       *ancientauth.Authenticator
	database   *MembershipDB
	pagesize   int32
}

var applicantApprovalURL *url.URL
var applicantRejectionURL *url.URL
var applicantAgreementUploadURL *url.URL

func init() {
	var err error
	applicantApprovalURL, err = url.Parse("/admin/api/accept")
	if err != nil {
		log.Fatal("Error parsing static approval URL: ", err)
	}
	applicantRejectionURL, err = url.Parse("/admin/api/reject")
	if err != nil {
		log.Fatal("Error parsing static rejection URL: ", err)
	}
	applicantAgreementUploadURL, err = url.Parse("/admin/api/agreement-upload")
	if err != nil {
		log.Fatal("Error parsing static agreement upload URL: ", err)
	}
}

// Output a JSON list of all applicants currently waiting to become members.
func (a *ApplicantListHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	var applist applicantListType
	var enc *json.Encoder
	var err error

	if !a.auth.IsAuthenticatedScope(req, a.admingroup) {
		rw.WriteHeader(http.StatusUnauthorized)
		return
	}

	if req.FormValue("single") == "true" && len(req.FormValue("start")) > 0 {
		var memberreq *MembershipAgreement
		var mwk *MemberWithKey
		var bigint *big.Int = big.NewInt(0)
		var uuid cassandra.UUID
		var ok bool
		bigint, ok = bigint.SetString(req.FormValue("start"), 10)
		if !ok {
			rw.WriteHeader(http.StatusInternalServerError)
			rw.Write([]byte("Unable to parse " + req.FormValue("start") +
				" as a number"))
			return
		}
		uuid = cassandra.UUIDFromBytes(bigint.Bytes())
		memberreq, _, err = a.database.GetMembershipRequest(
			uuid.String(), "application", "applicant:")
		if err != nil {
			rw.WriteHeader(http.StatusInternalServerError)
			rw.Write([]byte("Unable to retrieve the membership request " +
				uuid.String() + ": " + err.Error()))
			return
		}
		mwk = new(MemberWithKey)
		mwk.Key = uuid.String()
		proto.Merge(&mwk.Member, memberreq.GetMemberData())
		applist.Applicants = []*MemberWithKey{mwk}
	} else {
		applist.Applicants, err = a.database.EnumerateMembershipRequests(
			req.FormValue("criterion"), req.FormValue("start"), a.pagesize)
		if err != nil {
			log.Print("Error enumerating applications: ", err)
			rw.WriteHeader(http.StatusInternalServerError)
			rw.Write([]byte("Error enumerating applications: " + err.Error()))
			return
		}
	}

	applist.AgreementUploadCsrfToken, err = a.auth.GenCSRFToken(
		req, applicantAgreementUploadURL, 10*time.Minute)
	if err != nil {
		log.Print("Error generating CSRF token: ", err)
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte("Error generating CSRF token: " + err.Error()))
		return
	}

	applist.ApprovalCsrfToken, err = a.auth.GenCSRFToken(
		req, applicantApprovalURL, 10*time.Minute)
	if err != nil {
		log.Print("Error generating CSRF token: ", err)
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte("Error generating CSRF token: " + err.Error()))
		return
	}

	applist.RejectionCsrfToken, err = a.auth.GenCSRFToken(
		req, applicantRejectionURL, 10*time.Minute)
	if err != nil {
		log.Print("Error generating CSRF token: ", err)
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte("Error generating CSRF token: " + err.Error()))
		return
	}

	rw.Header().Set("Content-Type", "application/json; encoding=utf8")
	enc = json.NewEncoder(rw)
	if err = enc.Encode(applist); err != nil {
		log.Print("Error JSON encoding member list: ", err)
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte("Error encoding result: " + err.Error()))
		return
	}
}

// Object for approving membership applications.
type MemberAcceptHandler struct {
	admingroup string
	auth       *ancientauth.Authenticator
	database   *MembershipDB
}

func (m *MemberAcceptHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	var user string = m.auth.GetAuthenticatedUser(req)
	var id string = req.PostFormValue("uuid")
	var ok bool
	var err error

	if user == "" {
		rw.WriteHeader(http.StatusUnauthorized)
		return
	}

	if len(m.admingroup) > 0 && !m.auth.IsAuthenticatedScope(req, m.admingroup) {
		rw.WriteHeader(http.StatusForbidden)
		rw.Write([]byte("User not authorized for this service"))
		return
	}

	ok, err = m.auth.VerifyCSRFToken(req, req.PostFormValue("csrf_token"), false)
	if err != nil && err != ancientauth.CSRFToken_WeakProtectionError {
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte(err.Error()))
		log.Print("Error verifying CSRF token: ", err)
		return
	}
	if !ok {
		rw.WriteHeader(http.StatusForbidden)
		rw.Write([]byte("CSRF token validation failed"))
		log.Print("Invalid CSRF token reveived")
		return
	}

	err = m.database.MoveApplicantToNewMember(id, user)
	if err != nil {
		log.Print("Error moving applicant ", id, " to new user: ", err)
		rw.WriteHeader(http.StatusLengthRequired)
		rw.Write([]byte(err.Error()))
		return
	}

	rw.WriteHeader(http.StatusOK)
	rw.Write([]byte("{}"))
}

// Object for rejecting membership applications.
type MemberRejectHandler struct {
	admingroup string
	auth       *ancientauth.Authenticator
	database   *MembershipDB
}

func (m *MemberRejectHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	var user string = m.auth.GetAuthenticatedUser(req)
	var id string = req.PostFormValue("uuid")
	var ok bool
	var err error

	if user == "" {
		rw.WriteHeader(http.StatusUnauthorized)
		return
	}

	if len(m.admingroup) > 0 && !m.auth.IsAuthenticatedScope(req, m.admingroup) {
		rw.WriteHeader(http.StatusForbidden)
	}

	ok, err = m.auth.VerifyCSRFToken(req, req.PostFormValue("csrf_token"), false)
	if err != nil && err != ancientauth.CSRFToken_WeakProtectionError {
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte(err.Error()))
		log.Print("Error verifying CSRF token: ", err)
		return
	}
	if !ok {
		rw.WriteHeader(http.StatusForbidden)
		rw.Write([]byte("CSRF token validation failed"))
		log.Print("Invalid CSRF token reveived")
		return
	}

	err = m.database.MoveApplicantToTrash(id, user)
	if err != nil {
		log.Print("Error moving applicant ", id, " to trash: ", err)
		rw.WriteHeader(http.StatusLengthRequired)
		rw.Write([]byte(err.Error()))
		return
	}

	rw.WriteHeader(http.StatusOK)
	rw.Write([]byte("{}"))
}

// Object for uploading membership agreements.
type MemberAgreementUploadHandler struct {
	admingroup string
	auth       *ancientauth.Authenticator
	database   *MembershipDB
}

func (m *MemberAgreementUploadHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	var user string = m.auth.GetAuthenticatedUser(req)
	var id string = req.FormValue("uuid")
	var mf multipart.File
	var agreement_data []byte
	var ok bool
	var err error

	if user == "" {
		rw.WriteHeader(http.StatusUnauthorized)
		return
	}

	if len(m.admingroup) > 0 && !m.auth.IsAuthenticatedScope(req, m.admingroup) {
		rw.WriteHeader(http.StatusForbidden)
	}

	req.URL.RawQuery = ""
	req.ParseMultipartForm(5 * 1048576)

	ok, err = m.auth.VerifyCSRFToken(req, req.FormValue("csrf_token"), false)
	if err != nil && err != ancientauth.CSRFToken_WeakProtectionError {
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte(err.Error()))
		log.Print("Error verifying CSRF token: ", err)
		return
	}
	if !ok {
		rw.WriteHeader(http.StatusForbidden)
		rw.Write([]byte("CSRF token validation failed"))
		log.Print("Invalid CSRF token reveived")
		return
	}

	mf, _, err = req.FormFile("0")
	if err != nil {
		rw.WriteHeader(http.StatusBadRequest)
		rw.Write([]byte("Unable to retrieve uploaded file: " + err.Error()))
		log.Print("Unable to retrieve uploaded file: ", err)
		return
	}

	agreement_data, err = ioutil.ReadAll(mf)
	if err != nil {
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte("Error reading in agreement data: " + err.Error()))
		log.Print("Error reading in agreement data: ", err)
		return
	}

	mf.Close()

	err = m.database.StoreMembershipAgreement(id, agreement_data)
	if err != nil {
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte("Error storing membership agreement: " + err.Error()))
		log.Print("Error storing membership agreement: ", err)
		return
	}

	rw.Header().Set("Content-Type", "application/json")
	rw.WriteHeader(http.StatusOK)
	rw.Write([]byte("{}"))
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package rpctest

import (
	"errors"
	"math"
	"math/big"
	"runtime"
	"time"

	"github.com/btcsuite/btcd/blockchain"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcd/txscript"
	"github.com/btcsuite/btcd/wire"
	"github.com/btcsuite/btcutil"
)

var (
	miningPriv, _     = btcutil.DecodeWIF("FqVc9zp1C66n57VC7Qr5j7fLBFZ42zCmMf6efni425jNkzSbMpmJ")
	miningAddr, _     = decodeAddr("SXzLf64rFYJT5mBgQpLGnfxrL7heDzP9hD")
	miningPkScript, _ = txscript.PayToAddrScript(miningAddr)

	activeNetParams = &chaincfg.SimNetParams
)

// decodeAddr attempts to decode the passed string as an address.
func decodeAddr(addr string) (btcutil.Address, error) {
	utilAddr, err := btcutil.DecodeAddress(addr, &chaincfg.SimNetParams)
	if err != nil {
		return nil, err
	}
	return utilAddr, nil
}

// solveBlock attempts to find a nonce which makes the passed block header
// hash to a value less than the target difficulty. When a successful solution
// is found true is returned and the nonce field of the passed header is
// updated with the solution. False is returned if no solution exists.
func solveBlock(header *wire.BlockHeader, targetDifficulty *big.Int) bool {
	// sbResult is used by the solver goroutines to send results.
	type sbResult struct {
		found bool
		nonce uint32
	}

	// solver accepts a block header and a nonce range to test. It is
	// intended to be run as a goroutine.
	quit := make(chan bool)
	results := make(chan sbResult)
	solver := func(header *wire.BlockHeader, startNonce, stopNonce uint32) {
		// We need to modify the nonce field of the header, so make sure
		// we work with a copy of the original header.
		hdrCopy := *header
		for i := startNonce; i >= startNonce && i <= stopNonce; i++ {
			select {
			case <-quit:
				return
			default:
				hdrCopy.Nonce = i
				hash, _ := hdrCopy.BlockSha()
				if blockchain.ShaHashToBig(&hash).Cmp(targetDifficulty) <= 0 {
					results <- sbResult{true, i}
					return
				}
			}
		}
		results <- sbResult{false, 0}
	}

	startNonce := uint32(0)
	stopNonce := uint32(math.MaxUint32)
	numCores := uint32(runtime.NumCPU())
	noncesPerCore := (stopNonce - startNonce) / numCores
	for i := uint32(0); i < numCores; i++ {
		rangeStart := startNonce + (noncesPerCore * i)
		rangeStop := startNonce + (noncesPerCore * (i + 1)) - 1
		if i == numCores-1 {
			rangeStop = stopNonce
		}
		go solver(header, rangeStart, rangeStop)
	}
	for i := uint32(0); i < numCores; i++ {
		result := <-results
		if result.found {
			close(quit)
			header.Nonce = result.nonce
			return true
		}
	}

	return false
}

// standardCoinbaseScript returns a standard script suitable for use as the
// signature script of the coinbase transaction of a new block. In particular,
// it starts with the block height that is required by version 2 blocks and adds
// the extra nonce as well as additional coinbase flags.
func standardCoinbaseScript(nextBlockHeight int64, extraNonce uint64) ([]byte, error) {
	return txscript.NewScriptBuilder().AddInt64(nextBlockHeight).
		AddUint64(extraNonce).Script()
}

// createCoinbaseTx returns a coinbase transaction paying an appropriate subsidy
// based on the passed block height to the provided address.
func createCoinbaseTx(coinbaseScript []byte, nextBlockHeight int64, addr btcutil.Address) (*btcutil.Tx, error) {
	// Create the script to pay to the provided payment address.
	pkScript, err := txscript.PayToAddrScript(addr)
	if err != nil {
		return nil, err
	}

	tx := wire.NewMsgTx()
	tx.AddTxIn(&wire.TxIn{
		// Coinbase transactions have no inputs, so previous outpoint is
		// zero hash and max index.
		PreviousOutPoint: *wire.NewOutPoint(&wire.ShaHash{},
			wire.MaxPrevOutIndex),
		SignatureScript: coinbaseScript,
		Sequence:        wire.MaxTxInSequenceNum,
	})
	tx.AddTxOut(&wire.TxOut{
		Value: blockchain.CalcBlockSubsidy(nextBlockHeight,
			activeNetParams),
		PkScript: pkScript,
	})
	return btcutil.NewTx(tx), nil
}

// CreateBlock creates a new block building from the previous block.
func createBlock(prevBlock *btcutil.Block, inclusionTxs []*btcutil.Tx) (*btcutil.Block, error) {
	prevHash, err := prevBlock.Sha()
	if err != nil {
		return nil, err
	}
	blockHeight := prevBlock.Height() + 1

	// Add one second to the previous block unless it's the genesis block in
	// which case use the current time.
	var ts time.Time
	if blockHeight == 0 {
		ts = time.Unix(time.Now().Unix(), 0)
	} else {
		ts = prevBlock.MsgBlock().Header.Timestamp.Add(time.Second)
	}

	extraNonce := uint64(0)
	coinbaseScript, err := standardCoinbaseScript(blockHeight, extraNonce)
	if err != nil {
		return nil, err
	}
	coinbaseTx, err := createCoinbaseTx(coinbaseScript, blockHeight, miningAddr)
	if err != nil {
		return nil, err
	}

	// Create a new block ready to be solved.
	blockTxns := []*btcutil.Tx{coinbaseTx}
	if inclusionTxs != nil {
		blockTxns = append(blockTxns, inclusionTxs...)
	}
	merkles := blockchain.BuildMerkleTreeStore(blockTxns)
	var block wire.MsgBlock
	block.Header = wire.BlockHeader{
		Version:    1,
		PrevBlock:  *prevHash,
		MerkleRoot: *merkles[len(merkles)-1],
		Timestamp:  ts,
		Bits:       activeNetParams.PowLimitBits,
	}
	for _, tx := range blockTxns {
		if err := block.AddTransaction(tx.MsgTx()); err != nil {
			return nil, err
		}
	}

	found := solveBlock(&block.Header, activeNetParams.PowLimit)
	if !found {
		return nil, errors.New("Unable to solve block")
	}

	utilBlock := btcutil.NewBlock(&block)
	utilBlock.SetHeight(blockHeight)
	return utilBlock, nil
}
<commit_msg>remove block_gen.go, the generate RPC command replaces it<commit_after><|endoftext|>