<commit_before>package service

import (
	"bytes"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"time"

	"github.com/builderscon/octav/octav/db"
	"github.com/builderscon/octav/octav/model"
	"github.com/builderscon/octav/octav/tools"
	"github.com/lestrrat/go-pdebug"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
	"google.golang.org/cloud/storage"
)

func (v *Sponsor) getMediaBucketName() string {
	v.bucketOnce.Do(func() {
		if v.MediaBucketName == "" {
			v.MediaBucketName = os.Getenv("GOOGLE_STORAGE_MEDIA_BUCKET")
		}
	})
	return v.MediaBucketName
}

func (v *Sponsor) getStorageClient(ctx context.Context) *storage.Client {
	v.storageOnce.Do(func() {
		if v.Storage == nil {
			client, err := defaultStorageClient(ctx)
			if err != nil {
				panic(err.Error())
			}
			v.Storage = client
		}
	})
	return v.Storage
}

func (v *Sponsor) populateRowForCreate(vdb *db.Sponsor, payload model.CreateSponsorRequest) error {
	vdb.EID = tools.UUID()

	vdb.ConferenceID = payload.ConferenceID
	vdb.Name = payload.Name
	vdb.LogoURL1 = payload.LogoURL1
	vdb.URL = payload.URL
	vdb.GroupName = payload.GroupName
	vdb.SortOrder = payload.SortOrder

	if payload.LogoURL2.Valid() {
		vdb.LogoURL2.Valid = true
		vdb.LogoURL2.String = payload.LogoURL2.String
	}

	if payload.LogoURL3.Valid() {
		vdb.LogoURL3.Valid = true
		vdb.LogoURL3.String = payload.LogoURL3.String
	}

	return nil
}

func (v *Sponsor) populateRowForUpdate(vdb *db.Sponsor, payload model.UpdateSponsorRequest) error {
	if payload.Name.Valid() {
		vdb.Name = payload.Name.String
	}

	if payload.LogoURL1.Valid() {
		vdb.LogoURL1 = payload.LogoURL1.String
	}

	if payload.URL.Valid() {
		vdb.URL = payload.URL.String
	}

	if payload.GroupName.Valid() {
		vdb.GroupName = payload.GroupName.String
	}

	if payload.SortOrder.Valid() {
		vdb.SortOrder = int(payload.SortOrder.Int)
	}

	if payload.LogoURL2.Valid() {
		vdb.LogoURL2.Valid = true
		vdb.LogoURL2.String = payload.LogoURL2.String
	}

	if payload.LogoURL3.Valid() {
		vdb.LogoURL3.Valid = true
		vdb.LogoURL3.String = payload.LogoURL3.String
	}

	return nil
}

type finalizeFunc func() error

func (ff finalizeFunc) FinalizeFunc() func() error {
	return ff
}

// Ignorable always returns true, otherwise the caller will have to
// bail out immediately
func (ff finalizeFunc) Ignorable() bool {
	return true
}

func (ff finalizeFunc) Error() string {
	return "operation needs finalization"
}

func (v *Sponsor) CreateFromPayload(ctx context.Context, tx *db.Tx, payload model.AddSponsorRequest, result *model.Sponsor) (err error) {
	su := User{}
	if err := su.IsConferenceAdministrator(tx, payload.ConferenceID, payload.UserID); err != nil {
		return errors.Wrap(err, "creating a featured speaker requires conference administrator privilege")
	}

	if payload.MultipartForm != nil && payload.MultipartForm.File != nil {
		bucketName := v.getMediaBucketName()
		storagecl := v.getStorageClient(ctx)
		if fhs := payload.MultipartForm.File["logo"]; len(fhs) > 0 {
			var imgf multipart.File
			imgf, err = fhs[0].Open()
			if err != nil {
				return errors.Wrap(err, "failed to open logo file from multipart form")
			}

			var imgbuf bytes.Buffer
			if _, err := io.Copy(&imgbuf, imgf); err != nil {
				return errors.Wrap(err, "failed to copy logo image data to memory")
			}
			imgtyp := http.DetectContentType(imgbuf.Bytes())

			// Only work with image/png or image/jpeg
			var suffix string
			switch imgtyp {
			case "image/png":
				suffix = "png"
			case "image/jpeg":
				suffix = "jpeg"
			default:
				return errors.Errorf("Unsupported image type %s", imgtyp)
			}

			// TODO: Validate the image
			// TODO: Avoid Google Storage hardcoding?
			// Upload this to a temporary location, then upon successful write to DB
			// rename it to $conference_id/$sponsor_id
			tmpname := time.Now().UTC().Format("2006-01-02") + "/" + tools.RandomString(64) + "." + suffix
			wc := storagecl.Bucket(bucketName).Object(tmpname).NewWriter(ctx)
			wc.ContentType = imgtyp
			wc.ACL = []storage.ACLRule{{storage.AllUsers, storage.RoleReader}}
			if _, err := io.Copy(wc, &imgbuf); err != nil {
				return errors.Wrap(err, "failed to write image to temporary location")
			}
			// Note: DO NOT defer wc.Close(), as it's part of the write operation.
			// If wc.Close() does not complete w/o errors. the write failed
			if err := wc.Close(); err != nil {
				return errors.Wrap(err, "failed to write image to temporary location")
			}

			defer func() {
				if err != nil || result == nil {
					// no op
					return
				}
				// Even though there was no error, create an error value that has a
				// FinalizeFunc() method, so the callee will recognize it
				err = finalizeFunc(func() error {
					src := storagecl.Bucket(bucketName).Object(tmpname)
					dst := storagecl.Bucket(bucketName).Object(result.ConferenceID + "-" + result.ID + "." + suffix)

					if _, err = src.CopyTo(ctx, dst, nil); err != nil {
						return err
					}
					return nil
				})
			}()
		}
	}
<commit_msg>debug statements<commit_after>package service

import (
	"bytes"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"time"

	"github.com/builderscon/octav/octav/db"
	"github.com/builderscon/octav/octav/model"
	"github.com/builderscon/octav/octav/tools"
	"github.com/lestrrat/go-pdebug"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
	"google.golang.org/cloud/storage"
)

func (v *Sponsor) getMediaBucketName() string {
	v.bucketOnce.Do(func() {
		if v.MediaBucketName == "" {
			v.MediaBucketName = os.Getenv("GOOGLE_STORAGE_MEDIA_BUCKET")
		}
	})
	return v.MediaBucketName
}

func (v *Sponsor) getStorageClient(ctx context.Context) *storage.Client {
	v.storageOnce.Do(func() {
		if v.Storage == nil {
			client, err := defaultStorageClient(ctx)
			if err != nil {
				panic(err.Error())
			}
			v.Storage = client
		}
	})
	return v.Storage
}

func (v *Sponsor) populateRowForCreate(vdb *db.Sponsor, payload model.CreateSponsorRequest) error {
	vdb.EID = tools.UUID()

	vdb.ConferenceID = payload.ConferenceID
	vdb.Name = payload.Name
	vdb.LogoURL1 = payload.LogoURL1
	vdb.URL = payload.URL
	vdb.GroupName = payload.GroupName
	vdb.SortOrder = payload.SortOrder

	if payload.LogoURL2.Valid() {
		vdb.LogoURL2.Valid = true
		vdb.LogoURL2.String = payload.LogoURL2.String
	}

	if payload.LogoURL3.Valid() {
		vdb.LogoURL3.Valid = true
		vdb.LogoURL3.String = payload.LogoURL3.String
	}

	return nil
}

func (v *Sponsor) populateRowForUpdate(vdb *db.Sponsor, payload model.UpdateSponsorRequest) error {
	if payload.Name.Valid() {
		vdb.Name = payload.Name.String
	}

	if payload.LogoURL1.Valid() {
		vdb.LogoURL1 = payload.LogoURL1.String
	}

	if payload.URL.Valid() {
		vdb.URL = payload.URL.String
	}

	if payload.GroupName.Valid() {
		vdb.GroupName = payload.GroupName.String
	}

	if payload.SortOrder.Valid() {
		vdb.SortOrder = int(payload.SortOrder.Int)
	}

	if payload.LogoURL2.Valid() {
		vdb.LogoURL2.Valid = true
		vdb.LogoURL2.String = payload.LogoURL2.String
	}

	if payload.LogoURL3.Valid() {
		vdb.LogoURL3.Valid = true
		vdb.LogoURL3.String = payload.LogoURL3.String
	}

	return nil
}

type finalizeFunc func() error

func (ff finalizeFunc) FinalizeFunc() func() error {
	return ff
}

// Ignorable always returns true, otherwise the caller will have to
// bail out immediately
func (ff finalizeFunc) Ignorable() bool {
	return true
}

func (ff finalizeFunc) Error() string {
	return "operation needs finalization"
}

func (v *Sponsor) CreateFromPayload(ctx context.Context, tx *db.Tx, payload model.AddSponsorRequest, result *model.Sponsor) (err error) {
	su := User{}
	if err := su.IsConferenceAdministrator(tx, payload.ConferenceID, payload.UserID); err != nil {
		return errors.Wrap(err, "creating a featured speaker requires conference administrator privilege")
	}

	if payload.MultipartForm != nil && payload.MultipartForm.File != nil {
		bucketName := v.getMediaBucketName()
		storagecl := v.getStorageClient(ctx)
		if fhs := payload.MultipartForm.File["logo"]; len(fhs) > 0 {
			var imgf multipart.File
			imgf, err = fhs[0].Open()
			if err != nil {
				return errors.Wrap(err, "failed to open logo file from multipart form")
			}

			var imgbuf bytes.Buffer
			if _, err := io.Copy(&imgbuf, imgf); err != nil {
				return errors.Wrap(err, "failed to copy logo image data to memory")
			}
			imgtyp := http.DetectContentType(imgbuf.Bytes())

			// Only work with image/png or image/jpeg
			var suffix string
			switch imgtyp {
			case "image/png":
				suffix = "png"
			case "image/jpeg":
				suffix = "jpeg"
			default:
				return errors.Errorf("Unsupported image type %s", imgtyp)
			}

			// TODO: Validate the image
			// TODO: Avoid Google Storage hardcoding?
			// Upload this to a temporary location, then upon successful write to DB
			// rename it to $conference_id/$sponsor_id
			tmpname := time.Now().UTC().Format("2006-01-02") + "/" + tools.RandomString(64) + "." + suffix
			wc := storagecl.Bucket(bucketName).Object(tmpname).NewWriter(ctx)
			wc.ContentType = imgtyp
			wc.ACL = []storage.ACLRule{{storage.AllUsers, storage.RoleReader}}
			if _, err := io.Copy(wc, &imgbuf); err != nil {
				return errors.Wrap(err, "failed to write image to temporary location")
			}
			// Note: DO NOT defer wc.Close(), as it's part of the write operation.
			// If wc.Close() does not complete w/o errors. the write failed
			if err := wc.Close(); err != nil {
				return errors.Wrap(err, "failed to write image to temporary location")
			}

			defer func() {
				if pdebug.Enabled {
					g := pdebug.Marker("deferred function from service.Sponsor.CreateFromPayload")
					defer g.End()
				}

				if err != nil || result == nil {
					// no op
					return
				}

				if pdebug.Enabled {
					pdebug.Printf("Creating finalizeFunc for this logo upload")
				}
				// Even though there was no error, create an error value that has a
				// FinalizeFunc() method, so the callee will recognize it
				err = finalizeFunc(func() (err error) {
					if pdebug.Enabled {
						g := pdebug.Marker("finalizeFunc for service.Sponsor.CreateFromPayload").BindError(&err)
						defer g.End()
					}
					dstname := result.ConferenceID + "-" + result.ID + "." + suffix
					src := storagecl.Bucket(bucketName).Object(tmpname)
					dst := storagecl.Bucket(bucketName).Object(dstname)

					if _, err = src.CopyTo(ctx, dst, nil); err != nil {
						return errors.Wrapf(err, "failed to copy from '%s' to '%s'", tmpname, dstname)
					}
					return nil
				})
			}()
		}
	}

{'fraction_non_alphanumeric': 0.13092507645259938, 'fraction_numerical': 0.006307339449541285, 'mean_word_length': 3.4569846678023852, 'pattern_counts': {'":': 4, '<': 3, '<?xml version=': 0, '>': 5, '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': '1517991', 'n_tokens_mistral': 4107, 'n_tokens_neox': 3629, 'n_words': 874}