Skip to content

Commit

Permalink
Merge pull request #85 from ynufes-tech/feature/45
Browse files Browse the repository at this point in the history
GCSパッケージの作成 / Response APIの作成 (WIP)
  • Loading branch information
Shion1305 committed May 12, 2024
2 parents ce99fb6 + 85a473d commit bf262bf
Show file tree
Hide file tree
Showing 13 changed files with 480 additions and 17 deletions.
14 changes: 14 additions & 0 deletions pkg/gcs/bucket.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package gcs

import "cloud.google.com/go/storage"

type BucketRef struct {
bucket *storage.BucketHandle
}

func (r BucketRef) Folder(name string) *FolderRef {
return &FolderRef{
basePath: name,
bucket: nil,
}
}
25 changes: 25 additions & 0 deletions pkg/gcs/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package gcs

import (
"cloud.google.com/go/storage"
"context"
)

type Client struct {
client *storage.Client
}

func NewClient(ctx context.Context) (*Client, error) {
client, err := storage.NewClient(ctx)

if err != nil {
return nil, err
}
return &Client{client: client}, nil
}

func (c Client) Bucket(name string) *BucketRef {
return &BucketRef{
bucket: c.client.Bucket(name),
}
}
72 changes: 72 additions & 0 deletions pkg/gcs/folder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package gcs

import (
"cloud.google.com/go/storage"
"context"
"google.golang.org/api/iterator"
)

type FolderRef struct {
// basePath should be the prefix of object name
// e.g. basePath = "foo/bar/", object name = "foo/bar/baz"
// e.g. basePath = "ynufes/", object name = "ynufes/shion"
basePath string
bucket *storage.BucketHandle
}

func (f FolderRef) Object(name string) ObjectRef {
return ObjectRef{
objName: f.basePath + name,
bucket: f.bucket,
}
}

func (f FolderRef) Folder(name string) FolderRef {
return FolderRef{
basePath: f.basePath + name + "/",
bucket: f.bucket,
}
}

func (f FolderRef) List(ctx context.Context) ([]FolderRef, []ObjectRef, error) {
results := f.bucket.Objects(ctx, &storage.Query{
Prefix: f.basePath,
Delimiter: "/",
})
var folders []FolderRef
var objects []ObjectRef
for {
next, err := results.Next()
if err == iterator.Done {
break
}
if err != nil {
return nil, nil, err
}

if next.Prefix != "" {
folders = append(folders, FolderRef{
basePath: next.Prefix,
bucket: f.bucket,
})
} else {
objects = append(objects, ObjectRef{
objName: next.Name,
bucket: f.bucket,
})
}
}
return folders, objects, nil
}

func (f FolderRef) Upload(ctx context.Context, name string, data []byte) (*ObjectRef, error) {
w := f.bucket.Object(f.basePath + name).NewWriter(ctx)
defer w.Close()
if _, err := w.Write(data); err != nil {
return nil, err
}
return &ObjectRef{
objName: f.basePath + name,
bucket: f.bucket,
}, nil
}
46 changes: 46 additions & 0 deletions pkg/gcs/object.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package gcs

import (
"cloud.google.com/go/storage"
"context"
"io"
"time"
)

type (
ObjectRef struct {
objName string
bucket *storage.BucketHandle
}
SignedObjectLink string
)

func (r ObjectRef) Name() string {
return r.objName
}

func (r ObjectRef) Download(ctx context.Context) ([]byte, error) {
reader, err := r.bucket.Object(r.objName).NewReader(ctx)
if err != nil {
return nil, err
}
defer reader.Close()

data, err := io.ReadAll(reader)
if err != nil {
return nil, err
}
return data, nil
}

func (r ObjectRef) IssueLink() (SignedObjectLink, error) {
url, err := r.bucket.SignedURL(r.objName, &storage.SignedURLOptions{
Method: "GET",
Expires: time.Now().Add(time.Minute * 1),
Scheme: storage.SigningSchemeV4,
})
if err != nil {
return "", err
}
return SignedObjectLink(url), nil
}
21 changes: 20 additions & 1 deletion pkg/typecast/cast.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
package typecast

import "errors"
import (
"errors"
"fmt"
)

func ConvertToStringMapInterface(v interface{}) (map[string]interface{}, error) {
m, ok := v.(map[interface{}]interface{})
if !ok {
return nil, fmt.Errorf("ConvertToStringMapInterface: %v is not a map", v)
}
res := make(map[string]interface{})
for k, v := range m {
key, ok := k.(string)
if !ok {
return nil, fmt.Errorf("ConvertToStringMapInterface: map key %v is not a string", k)
}
res[key] = v
}
return res, nil
}

func ConvertToStringMapString(v interface{}) (map[string]string, error) {
m, ok := v.(map[string]string)
Expand Down
11 changes: 11 additions & 0 deletions svc/pkg/domain/command/response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package command

import (
"context"
"ynufes-mypage-backend/svc/pkg/domain/model/response"
)

type Response interface {
Create(ctx context.Context, resp *response.Response) error
Set(ctx context.Context, resp response.Response) error
}
1 change: 1 addition & 0 deletions svc/pkg/domain/model/id/id.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ type (
FormID util.ID
SectionID util.ID
QuestionID util.ID
ResponseID util.ID
OrgIDs []OrgID
RoleID util.ID
)
Expand Down
29 changes: 25 additions & 4 deletions svc/pkg/domain/model/response/aggregate.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,37 @@ package response

import (
"ynufes-mypage-backend/svc/pkg/domain/model/id"
"ynufes-mypage-backend/svc/pkg/domain/model/util"
)

type (
Response struct {
ID ID
ID id.ResponseID
OrgID id.OrgID
AuthorID id.UserID
FormID id.FormID
Data map[string]interface{}
Data map[id.QuestionID]QuestionResponse
}
QuestionResponse struct {
QuestionID id.QuestionID
ResponseData map[string]interface{}
}
ID util.ID
)

func NewResponse(
rid id.ResponseID,
oid id.OrgID,
aid id.UserID,
fid id.FormID,
data map[id.QuestionID]QuestionResponse,
) Response {
return Response{
rid, oid, aid, fid, data,
}
}

func NewQuestionResponse(
qid id.QuestionID,
data map[string]interface{},
) QuestionResponse {
return QuestionResponse{qid, data}
}
14 changes: 14 additions & 0 deletions svc/pkg/domain/query/response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package query

import (
"context"
"ynufes-mypage-backend/svc/pkg/domain/model/id"
"ynufes-mypage-backend/svc/pkg/domain/model/response"
)

type Response interface {
GetByID(ctx context.Context, oid id.ResponseID) (*response.Response, error)
ListByFormID(ctx context.Context, fid id.FormID) ([]response.Response, error)
ListByOrgID(ctx context.Context, oid id.OrgID) ([]response.Response, error)
ListByAuthorID(ctx context.Context, uid id.UserID) ([]response.Response, error)
}
72 changes: 60 additions & 12 deletions svc/pkg/infra/entity/response/aggregate.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,68 @@ const ResponseRootName = "Responses"

type (
Response struct {
ID id.UserID `json:"-"`
OrgID int64 `json:"org_id"`
AuthorID int64 `json:"author_id"`
FormID int64 `json:"form_id"`
Data map[string]interface{} `json:"data"`
ID id.ResponseID `json:"-"`
OrgID string `json:"org_id"`
AuthorID string `json:"author_id"`
FormID string `json:"form_id"`
QuestionResponses map[string]QuestionResponse `json:"questions"`
}
QuestionResponse struct {
QuestionID id.QuestionID `json:"-"`
ResponseData map[string]interface{} `json:"data"`
}
)

func NewResponse(
rid id.ResponseID,
oid string,
aid string,
fid string,
data map[string]QuestionResponse,
) Response {
return Response{
rid, oid, aid, fid, data,
}
}

func NewQuestionResponse(
qid id.QuestionID, data map[string]interface{},
) QuestionResponse {
return QuestionResponse{qid, data}
}

func (r Response) ToModel() (*response.Response, error) {
return &response.Response{
ID: r.ID,
OrgID: identity.NewID(r.OrgID),
AuthorID: identity.NewID(r.AuthorID),
FormID: identity.NewID(r.FormID),
Data: r.Data,
}, nil
orgID, err := identity.ImportID(r.OrgID)
if err != nil {
return nil, err
}
authorID, err := identity.ImportID(r.AuthorID)
if err != nil {
return nil, err
}
formID, err := identity.ImportID(r.FormID)
if err != nil {
return nil, err
}

data := make(map[id.QuestionID]response.QuestionResponse, len(r.QuestionResponses))
for k, v := range r.QuestionResponses {
qid, err := identity.ImportID(k)
if err != nil {
return nil, err
}
data[qid] = response.QuestionResponse{
QuestionID: qid,
ResponseData: v.ResponseData,
}
}

resp := response.NewResponse(
r.ID,
orgID,
authorID,
formID,
data,
)
return &resp, nil
}
Loading

0 comments on commit bf262bf

Please sign in to comment.