<commit_before>package v1

import (
	"encoding/json"
	"github.com/fritzpay/paymentd/pkg/metadata"
	"github.com/fritzpay/paymentd/pkg/paymentd/principal"
	"github.com/fritzpay/paymentd/pkg/service"
	"github.com/gorilla/mux"
	"gopkg.in/inconshreveable/log15.v2"
	"net/http"
	"time"
)

type PrincipalAdminAPIResponse struct {
	AdminAPIResponse
}

// handler to create or change a principal
//
// PUT creates new principal
// POST can be used to change the principals metadata
func (a *AdminAPI) PrincipalRequest() http.Handler {

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		log := a.log.New(log15.Ctx{"method": "PrincipalRequest"})

		switch r.Method {
		case "PUT":
			a.putNewPrincipal(w, r)
		case "POST":
			a.postChangePrincipal(w, r)
		default:
			ErrMethod.Write(w)
			log.Info("http method not supported", log15.Ctx{"requestMethod": r.Method})
		}
	})
}

// handler to display a specific existing principal
func (a *AdminAPI) PrincipalGetRequest() http.Handler {

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		log := a.log.New(log15.Ctx{"method": "PrincipalGetRequest"})

		// get principal by name
		vars := mux.Vars(r)
		principalName := vars["name"]

		log = log.New(log15.Ctx{"principalName": principalName})

		db := a.ctx.PrincipalDB(service.ReadOnly)
		pr, err := principal.PrincipalByNameDB(db, principalName)
		if err == principal.ErrPrincipalNotFound {
			ErrNotFound.Write(w)
			log.Info("principal not found")
			return
		}
		if err != nil {
			ErrDatabase.Write(w)
			log.Error("DB get by name failed", log15.Ctx{"err": err})
			return
		}
		md, err := metadata.MetadataByPrimaryDB(db, principal.MetadataModel, pr.ID)
		if err != nil {
			ErrDatabase.Write(w)
			log.Error("get metadata failed", log15.Ctx{"err": err})
			return
		}
		if len(md) > 0 {
			pr.Metadata = md.Values()
		}

		// create service response object
		resp := PrincipalAdminAPIResponse{}
		resp.Status = StatusSuccess
		resp.Info = "principal " + pr.Name + " found"
		resp.Response = pr
		err = resp.Write(w)
		if err != nil {
			log.Error("write error", log15.Ctx{"err": err})
			return
		}
	})
}

func (a *AdminAPI) putNewPrincipal(w http.ResponseWriter, r *http.Request) {
	log := a.log.New(log15.Ctx{"method": "putNewPrincipal"})

	// create new principal
	jd := json.NewDecoder(r.Body)
	pr := principal.Principal{}
	err := jd.Decode(&pr)
	r.Body.Close()
	if err != nil {
		ErrReadJson.Write(w)
		log.Error("json decode failed", log15.Ctx{"err": err})
		return
	}

	auth, err := getAuthContainer(r)
	if err != nil {
		log.Crit("context auth error", log15.Ctx{"err": err})
		ErrSystem.Write(w)
		return
	}
	pr.CreatedBy = auth[AuthUserIDKey].(string)
	// set created time
	pr.Created = time.Now()

	// check if principal exists
	db := a.ctx.PrincipalDB()
	_, err = principal.PrincipalByNameDB(db, pr.Name)
	if err == principal.ErrPrincipalNotFound {
		// insert pr if not exists
		// start dbtx to save metadata and pr together
		tx, err := db.Begin()
		if err != nil {
			ErrDatabase.Write(w)
			log.Error("Tx begin failed.", log15.Ctx{"err": err})
		}

		// insert pr
		err = principal.InsertPrincipalTx(tx, &pr)
		if err != nil {
			tx.Rollback()
			ErrSystem.Write(w)
			log.Error("TX insert failed.", log15.Ctx{"err": err})
			return
		}

		// insert metadata
		md := metadata.MetadataFromValues(pr.Metadata, pr.CreatedBy)
		err = metadata.InsertMetadataTx(tx, principal.MetadataModel, pr.ID, md)
		if err != nil {
			tx.Rollback()
			ErrDatabase.Write(w)
			log.Error("TX metadata insert failed.", log15.Ctx{"err": err})
			return
		}
		//commit tx
		err = tx.Commit()
		if err != nil {
			tx.Rollback()
			ErrSystem.Write(w)
			log.Error("TX commit failed.", log15.Ctx{"err": err})
			return
		}
	} else if err != nil {
		// other db error
		ErrSystem.Write(w)
		log.Error("DB get by name failed.", log15.Ctx{"err": err})
		return
	} else {
		// already exists
		ErrConflict.Write(w)
		log.Warn("principal already exist: " + string(pr.ID) + " " + pr.Name)
		return
	}

	// get data explicit from DB
	pr, err = principal.PrincipalByNameDB(db, pr.Name)
	if err != nil {
		ErrSystem.Write(w)
		log.Error("DB get by name failed.", log15.Ctx{"err": err})
		return
	}
	md, err := metadata.MetadataByPrimaryDB(db, principal.MetadataModel, pr.ID)
	if len(md) > 0 {
		pr.Metadata = md.Values()
	}
	if err != nil {
		log.Error("get metadata failed.", log15.Ctx{"err": err})
		return
	}

	resp := PrincipalAdminAPIResponse{}
	resp.HttpStatus = http.StatusOK
	resp.Status = StatusSuccess
	resp.Response = pr
	resp.Info = "principal " + pr.Name + " created"
	err = resp.Write(w)
	if err != nil {
		ErrSystem.Write(w)
		log.Error("write error", log15.Ctx{"err": err})
		return
	}
}

// post method to add and change the metadata
func (a *AdminAPI) postChangePrincipal(w http.ResponseWriter, r *http.Request) {
	log := a.log.New(log15.Ctx{"method": "Principal Request"})
	log.Info("Method:" + r.Method)

	// get Metadata from post variables
	jd := json.NewDecoder(r.Body)
	pr := principal.Principal{}
	err := jd.Decode(&pr)
	r.Body.Close()
	if err != nil {
		ErrReadJson.Write(w)
		log.Error("json decode failed: ", log15.Ctx{"err": err})
		return
	}
	postedMetadata := pr.Metadata

	// validation createdBy has to be set
	if len(pr.CreatedBy) < 1 {
		ErrInval.Write(w)
		log.Info("CreatedBy has to be set:" + pr.Name)<commit_msg>refactor, linearize put principal<commit_after>package v1

import (
	"encoding/json"
	"github.com/fritzpay/paymentd/pkg/metadata"
	"github.com/fritzpay/paymentd/pkg/paymentd/principal"
	"github.com/fritzpay/paymentd/pkg/service"
	"github.com/gorilla/mux"
	"gopkg.in/inconshreveable/log15.v2"
	"net/http"
	"time"
)

type PrincipalAdminAPIResponse struct {
	AdminAPIResponse
}

// handler to create or change a principal
//
// PUT creates new principal
// POST can be used to change the principals metadata
func (a *AdminAPI) PrincipalRequest() http.Handler {

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		log := a.log.New(log15.Ctx{"method": "PrincipalRequest"})

		switch r.Method {
		case "PUT":
			a.putNewPrincipal(w, r)
		case "POST":
			a.postChangePrincipal(w, r)
		default:
			ErrMethod.Write(w)
			log.Info("http method not supported", log15.Ctx{"requestMethod": r.Method})
		}
	})
}

// handler to display a specific existing principal
func (a *AdminAPI) PrincipalGetRequest() http.Handler {

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		log := a.log.New(log15.Ctx{"method": "PrincipalGetRequest"})

		// get principal by name
		vars := mux.Vars(r)
		principalName := vars["name"]

		log = log.New(log15.Ctx{"principalName": principalName})

		db := a.ctx.PrincipalDB(service.ReadOnly)
		pr, err := principal.PrincipalByNameDB(db, principalName)
		if err == principal.ErrPrincipalNotFound {
			ErrNotFound.Write(w)
			log.Info("principal not found")
			return
		}
		if err != nil {
			ErrDatabase.Write(w)
			log.Error("DB get by name failed", log15.Ctx{"err": err})
			return
		}
		md, err := metadata.MetadataByPrimaryDB(db, principal.MetadataModel, pr.ID)
		if err != nil {
			ErrDatabase.Write(w)
			log.Error("get metadata failed", log15.Ctx{"err": err})
			return
		}
		if len(md) > 0 {
			pr.Metadata = md.Values()
		}

		// create service response object
		resp := PrincipalAdminAPIResponse{}
		resp.Status = StatusSuccess
		resp.Info = "principal " + pr.Name + " found"
		resp.Response = pr
		err = resp.Write(w)
		if err != nil {
			log.Error("write error", log15.Ctx{"err": err})
			return
		}
	})
}

func (a *AdminAPI) putNewPrincipal(w http.ResponseWriter, r *http.Request) {
	log := a.log.New(log15.Ctx{"method": "putNewPrincipal"})

	// create new principal
	jd := json.NewDecoder(r.Body)
	pr := principal.Principal{}
	err := jd.Decode(&pr)
	r.Body.Close()
	if err != nil {
		ErrReadJson.Write(w)
		log.Error("json decode failed", log15.Ctx{"err": err})
		return
	}

	log = log.New(log15.Ctx{"principalName": pr.Name})

	auth, err := getAuthContainer(r)
	if err != nil {
		log.Crit("context auth error", log15.Ctx{"err": err})
		ErrSystem.Write(w)
		return
	}
	pr.CreatedBy = auth[AuthUserIDKey].(string)
	// set created time
	pr.Created = time.Now()

	// check if principal exists
	db := a.ctx.PrincipalDB()
	_, err = principal.PrincipalByNameDB(db, pr.Name)
	if err != nil && err != principal.ErrPrincipalNotFound {
		// other db error
		log.Error("DB get by name failed", log15.Ctx{"err": err})
		ErrSystem.Write(w)
		return
	} else if err == nil {
		// already exists
		log.Warn("principal already exists")
		ErrConflict.Write(w)
		return
	}

	// insert pr if not exists
	// start dbtx to save metadata and pr together
	tx, err := db.Begin()
	if err != nil {
		log.Crit("Tx begin failed", log15.Ctx{"err": err})
		ErrDatabase.Write(w)
		return
	}

	// insert pr
	err = principal.InsertPrincipalTx(tx, &pr)
	if err != nil {
		tx.Rollback()
		ErrDatabase.Write(w)
		log.Error("TX insert failed.", log15.Ctx{"err": err})
		return
	}

	// insert metadata
	md := metadata.MetadataFromValues(pr.Metadata, pr.CreatedBy)
	err = metadata.InsertMetadataTx(tx, principal.MetadataModel, pr.ID, md)
	if err != nil {
		tx.Rollback()
		log.Error("TX metadata insert failed.", log15.Ctx{"err": err})
		ErrDatabase.Write(w)
		return
	}

	//commit tx
	err = tx.Commit()
	if err != nil {
		ErrDatabase.Write(w)
		log.Crit("TX commit failed.", log15.Ctx{"err": err})
		return
	}

	// get data explicit from DB
	pr, err = principal.PrincipalByNameDB(db, pr.Name)
	if err != nil {
		log.Error("DB get by name failed.", log15.Ctx{"err": err})
		ErrDatabase.Write(w)
		return
	}
	md, err = metadata.MetadataByPrimaryDB(db, principal.MetadataModel, pr.ID)
	if len(md) > 0 {
		pr.Metadata = md.Values()
	}
	if err != nil {
		log.Error("get metadata failed.", log15.Ctx{"err": err})
		ErrDatabase.Write(w)
		return
	}

	resp := PrincipalAdminAPIResponse{}
	resp.HttpStatus = http.StatusOK
	resp.Status = StatusSuccess
	resp.Response = pr
	resp.Info = "principal " + pr.Name + " created"
	err = resp.Write(w)
	if err != nil {
		log.Error("write error", log15.Ctx{"err": err})
		ErrSystem.Write(w)
		return
	}
}

// post method to add and change the metadata
func (a *AdminAPI) postChangePrincipal(w http.ResponseWriter, r *http.Request) {
	log := a.log.New(log15.Ctx{"method": "Principal Request"})
	log.Info("Method:" + r.Method)

	// get Metadata from post variables
	jd := json.NewDecoder(r.Body)
	pr := principal.Principal{}
	err := jd.Decode(&pr)
	r.Body.Close()
	if err != nil {
		ErrReadJson.Write(w)
		log.Error("json decode failed: ", log15.Ctx{"err": err})
		return
	}
	postedMetadata := pr.Metadata

	// validation createdBy has to be set
	if len(pr.CreatedBy) < 1 {
		ErrInval.Write(w)
		log.Info("CreatedBy has to be set:" + pr.Name)
{'fraction_non_alphanumeric': 0.15278915278915278, 'fraction_numerical': 0.008736008736008737, 'mean_word_length': 3.720790378006873, 'pattern_counts': {'":': 45, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1532789', 'n_tokens_mistral': 4219, 'n_tokens_neox': 3877, 'n_words': 927}