freckie

Update: database shcema

1 -package endpoints
2 -
3 -import (
4 - "classroom/functions"
5 - "encoding/json"
6 - "fmt"
7 - "io/ioutil"
8 - "net/http"
9 - "strings"
10 -
11 - "github.com/julienschmidt/httprouter"
12 -)
13 -
14 -// POST /timetables/<file_id>/<sheet_id>/allow
15 -func (e *Endpoints) AllowlistPost(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
16 - // Get user email
17 - var email string
18 - if _email, ok := r.Header["X-User-Email"]; ok {
19 - email = _email[0]
20 - } else {
21 - functions.ResponseError(w, 401, "X-User-Email 헤더를 보내세요.")
22 - return
23 - }
24 -
25 - // Get Path Parameters
26 - fileID := ps.ByName("file_id")
27 - sheetID := ps.ByName("sheet_id")
28 -
29 - // Check Permission
30 - var _count, _isSuper int64
31 - timetable := fmt.Sprintf("%s,%s", fileID, sheetID)
32 - row := e.DB.QueryRow(`
33 - SELECT count(timetable_id)
34 - FROM allowlist
35 - WHERE timetable_id=?;
36 - `, timetable)
37 - if err := row.Scan(&_count); err == nil {
38 - if _count <= 0 {
39 - functions.ResponseError(w, 404, "존재하지 않는 timetable.")
40 - return
41 - }
42 - }
43 -
44 - row = e.DB.QueryRow(`
45 - SELECT (
46 - SELECT count(a.timetable_id)
47 - FROM allowlist AS a, users AS u
48 - WHERE a.user_id=u.id
49 - AND a.timetable_id=?
50 - AND u.email=?
51 - ) AS count,
52 - (
53 - SELECT is_super FROM users WHERE email=?
54 - ) AS is_super;
55 - `, timetable, email, email)
56 - if err := row.Scan(&_count, &_isSuper); err == nil {
57 - if _isSuper != 1 {
58 - functions.ResponseError(w, 403, "관리자만 접근할 수 있는 기능입니다.")
59 - return
60 - }
61 - if _count <= 0 {
62 - functions.ResponseError(w, 403, "timetable에 접근할 권한이 부족합니다.")
63 - return
64 - }
65 - } else {
66 - functions.ResponseError(w, 500, "예기치 못한 에러 : "+err.Error())
67 - return
68 - }
69 -
70 - // Parse Request Data
71 - type reqDataStruct struct {
72 - Email *string `json:"email"`
73 - }
74 - var reqData reqDataStruct
75 - if strings.Contains(r.Header.Get("Content-Type"), "application/json") {
76 - body, err := ioutil.ReadAll(r.Body)
77 - if err != nil {
78 - functions.ResponseError(w, 500, "예기치 못한 에러 : "+err.Error())
79 - return
80 - }
81 - json.Unmarshal(body, &reqData)
82 - } else {
83 - functions.ResponseError(w, 400, "JSON 형식만 가능합니다.")
84 - return
85 - }
86 - if reqData.Email == nil {
87 - functions.ResponseError(w, 400, "파라미터를 전부 보내주세요.")
88 - return
89 - }
90 -
91 - // Querying
92 - _, err := e.DB.Exec(`
93 - INSERT INTO allowlist
94 - VALUES (?, (
95 - SELECT id FROM users WHERE email=?
96 - ));
97 - `, timetable, *(reqData.Email))
98 - if err != nil {
99 - functions.ResponseError(w, 500, "예기치 못한 에러 : "+err.Error())
100 - return
101 - }
102 -
103 - functions.ResponseOK(w, "success", nil)
104 -}
105 -
106 -// DELETE /timetables/<file_id>/<sheet_id>/allow
107 -func (e *Endpoints) AllowlistDelete(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
108 - // Get user email
109 - var email string
110 - if _email, ok := r.Header["X-User-Email"]; ok {
111 - email = _email[0]
112 - } else {
113 - functions.ResponseError(w, 401, "X-User-Email 헤더를 보내세요.")
114 - return
115 - }
116 -
117 - // Get Path Parameters
118 - fileID := ps.ByName("file_id")
119 - sheetID := ps.ByName("sheet_id")
120 -
121 - // Check Permission
122 - var _count, _isSuper int64
123 - timetable := fmt.Sprintf("%s,%s", fileID, sheetID)
124 - row := e.DB.QueryRow(`
125 - SELECT count(timetable_id)
126 - FROM allowlist
127 - WHERE timetable_id=?;
128 - `, timetable)
129 - if err := row.Scan(&_count); err == nil {
130 - if _count <= 0 {
131 - functions.ResponseError(w, 404, "존재하지 않는 timetable.")
132 - return
133 - }
134 - }
135 -
136 - row = e.DB.QueryRow(`
137 - SELECT (
138 - SELECT count(a.timetable_id)
139 - FROM allowlist AS a, users AS u
140 - WHERE a.user_id=u.id
141 - AND a.timetable_id=?
142 - AND u.email=?
143 - ) AS count,
144 - (
145 - SELECT is_super FROM users WHERE email=?
146 - ) AS is_super;
147 - `, timetable, email, email)
148 - if err := row.Scan(&_count, &_isSuper); err == nil {
149 - if _isSuper != 1 {
150 - functions.ResponseError(w, 403, "관리자만 접근할 수 있는 기능입니다.")
151 - return
152 - }
153 - if _count <= 0 {
154 - functions.ResponseError(w, 403, "timetable에 접근할 권한이 부족합니다.")
155 - return
156 - }
157 - } else {
158 - functions.ResponseError(w, 500, "예기치 못한 에러 : "+err.Error())
159 - return
160 - }
161 -
162 - // Parse Request Data
163 - type reqDataStruct struct {
164 - Email *string `json:"email"`
165 - }
166 - var reqData reqDataStruct
167 - if strings.Contains(r.Header.Get("Content-Type"), "application/json") {
168 - body, err := ioutil.ReadAll(r.Body)
169 - if err != nil {
170 - functions.ResponseError(w, 500, "예기치 못한 에러 : "+err.Error())
171 - return
172 - }
173 - json.Unmarshal(body, &reqData)
174 - } else {
175 - functions.ResponseError(w, 400, "JSON 형식만 가능합니다.")
176 - return
177 - }
178 - if reqData.Email == nil {
179 - functions.ResponseError(w, 400, "파라미터를 전부 보내주세요.")
180 - return
181 - }
182 -
183 - // Querying
184 - _, err := e.DB.Exec(`
185 - DELETE FROM allowlist
186 - WHERE timetable_id=?
187 - AND user_id=(SELECT id FROM users WHERE email=?);
188 - `, timetable, *(reqData.Email))
189 - if err != nil {
190 - functions.ResponseError(w, 500, "예기치 못한 에러 : "+err.Error())
191 - return
192 - }
193 -
194 - functions.ResponseOK(w, "success", nil)
195 -}
...@@ -12,7 +12,7 @@ import ( ...@@ -12,7 +12,7 @@ import (
12 "github.com/julienschmidt/httprouter" 12 "github.com/julienschmidt/httprouter"
13 ) 13 )
14 14
15 -// GET /timetables/<file_id>/<sheet_id>/cell 15 +// GET /files/<file_id>/<sheet_id>/cell
16 func (e *Endpoints) CellGet(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { 16 func (e *Endpoints) CellGet(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
17 // Get user email 17 // Get user email
18 var email string 18 var email string
...@@ -57,28 +57,32 @@ func (e *Endpoints) CellGet(w http.ResponseWriter, r *http.Request, ps httproute ...@@ -57,28 +57,32 @@ func (e *Endpoints) CellGet(w http.ResponseWriter, r *http.Request, ps httproute
57 } 57 }
58 58
59 // Check Permission 59 // Check Permission
60 - var _count, isSuper int64 60 + var _count int64
61 - timetable := fmt.Sprintf("%s,%s", fileID, sheetID) 61 + var isSuper, sheetIDAuto sql.NullInt64
62 row := e.DB.QueryRow(` 62 row := e.DB.QueryRow(`
63 - SELECT count(timetable_id) 63 + SELECT
64 - FROM allowlist 64 + (SELECT count(s.id)
65 - WHERE timetable_id=?; 65 + FROM sheets AS s, files AS f
66 - `, timetable) 66 + WHERE s.file_id=f.id
67 - if err := row.Scan(&_count); err == nil { 67 + AND f.id=?
68 - if _count <= 0 { 68 + AND s.id=?) AS count,
69 - functions.ResponseError(w, 404, "존재하지 않는 timetable.") 69 + (SELECT id_auto
70 + FROM sheets
71 + WHERE id=?) AS id_auto,
72 + (SELECT is_super
73 + FROM users
74 + WHERE email=?) AS is_super;
75 + `, fileID, sheetID, sheetID, email)
76 + if err := row.Scan(&_count, &sheetIDAuto, &isSuper); err == nil {
77 + if _count != 1 || !sheetIDAuto.Valid {
78 + functions.ResponseError(w, 404, "해당 파일이나 시트가 존재하지 않습니다.")
70 return 79 return
71 } 80 }
72 - } 81 + if !isSuper.Valid {
73 - 82 + functions.ResponseError(w, 401, "등록되지 않은 사용자입니다.")
74 - row = e.DB.QueryRow(`
75 - SELECT is_super FROM users WHERE email=?
76 - `, email)
77 - if err := row.Scan(&isSuper); err != nil {
78 - if err == sql.ErrNoRows {
79 - functions.ResponseError(w, 401, "해당 유저가 존재하지 않음")
80 return 83 return
81 } 84 }
85 + } else {
82 functions.ResponseError(w, 500, "예기치 못한 에러 : "+err.Error()) 86 functions.ResponseError(w, 500, "예기치 못한 에러 : "+err.Error())
83 return 87 return
84 } 88 }
...@@ -93,8 +97,8 @@ func (e *Endpoints) CellGet(w http.ResponseWriter, r *http.Request, ps httproute ...@@ -93,8 +97,8 @@ func (e *Endpoints) CellGet(w http.ResponseWriter, r *http.Request, ps httproute
93 FROM transactions AS t, users AS u 97 FROM transactions AS t, users AS u
94 WHERE t.user_id=u.id 98 WHERE t.user_id=u.id
95 AND t.transaction_type=1 99 AND t.transaction_type=1
96 - AND t.timetable_id=? 100 + AND t.sheet_id=?
97 - AND t.cell_column=?;`, timetable, cellColumn) 101 + AND t.cell_column=?;`, sheetIDAuto.Int64, cellColumn)
98 if err != nil { 102 if err != nil {
99 if err == sql.ErrNoRows { 103 if err == sql.ErrNoRows {
100 resp.CellsCount = 0 104 resp.CellsCount = 0
......
...@@ -15,7 +15,7 @@ import ( ...@@ -15,7 +15,7 @@ import (
15 "github.com/julienschmidt/httprouter" 15 "github.com/julienschmidt/httprouter"
16 ) 16 )
17 17
18 -// POST /timetables/<file_id>/<sheet_id>/reservation 18 +// POST /files/<file_id>/<sheet_id>/reservation
19 func (e *Endpoints) ReservationPost(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { 19 func (e *Endpoints) ReservationPost(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
20 // Get user email 20 // Get user email
21 var email string 21 var email string
...@@ -31,18 +31,38 @@ func (e *Endpoints) ReservationPost(w http.ResponseWriter, r *http.Request, ps h ...@@ -31,18 +31,38 @@ func (e *Endpoints) ReservationPost(w http.ResponseWriter, r *http.Request, ps h
31 sheetID := ps.ByName("sheet_id") 31 sheetID := ps.ByName("sheet_id")
32 32
33 // Check Permission 33 // Check Permission
34 - var _timetableName string 34 + var _count int64
35 - timetable := fmt.Sprintf("%s,%s", fileID, sheetID) 35 + var isSuper, sheetIDAuto sql.NullInt64
36 + var sheetName sql.NullString
36 row := e.DB.QueryRow(` 37 row := e.DB.QueryRow(`
37 - SELECT name 38 + SELECT
38 - FROM timetables 39 + (SELECT count(s.id)
39 - WHERE timetable_id=?; 40 + FROM sheets AS s, files AS f
40 - `, timetable) 41 + WHERE s.file_id=f.id
41 - if err := row.Scan(&_timetableName); err != nil { 42 + AND f.id=?
42 - if err == sql.ErrNoRows { 43 + AND s.id=?) AS count,
43 - functions.ResponseError(w, 404, "존재하지 않는 timetable.") 44 + (SELECT name
45 + FROM sheets
46 + WHERE id=?) AS sheet_name,
47 + (SELECT id_auto
48 + FROM sheets
49 + WHERE id=?) AS id_auto,
50 + (SELECT is_super
51 + FROM users
52 + WHERE email=?) AS is_super;
53 + `, fileID, sheetID, sheetID, sheetID, email)
54 + if err := row.Scan(&_count, &sheetName, &sheetIDAuto, &isSuper); err == nil {
55 + if _count != 1 || !sheetName.Valid || !sheetIDAuto.Valid {
56 + functions.ResponseError(w, 404, "해당 파일이나 시트가 존재하지 않습니다.")
57 + return
58 + }
59 + if !isSuper.Valid {
60 + functions.ResponseError(w, 401, "등록되지 않은 사용자입니다.")
44 return 61 return
45 } 62 }
63 + } else {
64 + functions.ResponseError(w, 500, "예기치 못한 에러 : "+err.Error())
65 + return
46 } 66 }
47 67
48 // Parse Request Data 68 // Parse Request Data
...@@ -86,9 +106,9 @@ func (e *Endpoints) ReservationPost(w http.ResponseWriter, r *http.Request, ps h ...@@ -86,9 +106,9 @@ func (e *Endpoints) ReservationPost(w http.ResponseWriter, r *http.Request, ps h
86 SELECT cell_start, cell_end 106 SELECT cell_start, cell_end
87 FROM transactions 107 FROM transactions
88 WHERE transaction_type=1 108 WHERE transaction_type=1
89 - AND timetable_id=? 109 + AND sheet_id=?
90 AND cell_column=?; 110 AND cell_column=?;
91 - `, timetable, *(reqData.Column)) 111 + `, sheetIDAuto.Int64, *(reqData.Column))
92 if err == sql.ErrNoRows { 112 if err == sql.ErrNoRows {
93 isPossible = true 113 isPossible = true
94 } 114 }
...@@ -119,11 +139,11 @@ loopCheckingValidation: ...@@ -119,11 +139,11 @@ loopCheckingValidation:
119 139
120 // Querying 140 // Querying
121 res, err := tx.Exec(` 141 res, err := tx.Exec(`
122 - INSERT INTO transactions (transaction_type, user_id, timetable_id, lecture, capacity, cell_column, cell_start, cell_end, professor) 142 + INSERT INTO transactions (transaction_type, user_id, sheet_id, lecture, capacity, cell_column, cell_start, cell_end, professor)
123 VALUES (1, ( 143 VALUES (1, (
124 SELECT id FROM users WHERE email=? 144 SELECT id FROM users WHERE email=?
125 ), ?, ?, ?, ?, ?, ?, ?); 145 ), ?, ?, ?, ?, ?, ?, ?);
126 - `, email, timetable, *(reqData.Lecture), *(reqData.Capacity), *(reqData.Column), *(reqData.Start), *(reqData.End), *(reqData.Professor)) 146 + `, email, sheetIDAuto.Int64, *(reqData.Lecture), *(reqData.Capacity), *(reqData.Column), *(reqData.Start), *(reqData.End), *(reqData.Professor))
127 if err != nil { 147 if err != nil {
128 functions.ResponseError(w, 500, err.Error()) 148 functions.ResponseError(w, 500, err.Error())
129 return 149 return
...@@ -134,14 +154,13 @@ loopCheckingValidation: ...@@ -134,14 +154,13 @@ loopCheckingValidation:
134 sheetIDint, _ := strconv.Atoi(sheetID) 154 sheetIDint, _ := strconv.Atoi(sheetID)
135 sr := utils.NewSheetsRequest( 155 sr := utils.NewSheetsRequest(
136 fileID, 156 fileID,
137 - _timetableName, 157 + sheetName.String,
138 int64(sheetIDint), 158 int64(sheetIDint),
139 *(reqData.Column), 159 *(reqData.Column),
140 int64(*(reqData.Start)), 160 int64(*(reqData.Start)),
141 int64(*(reqData.End)), 161 int64(*(reqData.End)),
142 cellValue, 162 cellValue,
143 ) 163 )
144 - fmt.Println(sr)
145 err = e.Sheets.WriteAndMerge(sr) 164 err = e.Sheets.WriteAndMerge(sr)
146 if err != nil { 165 if err != nil {
147 functions.ResponseError(w, 500, "예기치 못한 에러 : "+err.Error()) 166 functions.ResponseError(w, 500, "예기치 못한 에러 : "+err.Error())
...@@ -171,7 +190,7 @@ loopCheckingValidation: ...@@ -171,7 +190,7 @@ loopCheckingValidation:
171 functions.ResponseOK(w, "success", resp) 190 functions.ResponseOK(w, "success", resp)
172 } 191 }
173 192
174 -// DELETE /timetables/<file_id>/<sheet_id>/reservation/<reservation_id> 193 +// DELETE /files/<file_id>/<sheet_id>/reservation/<reservation_id>
175 func (e *Endpoints) ReservationDelete(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { 194 func (e *Endpoints) ReservationDelete(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
176 // Get user email 195 // Get user email
177 var email string 196 var email string
...@@ -188,29 +207,33 @@ func (e *Endpoints) ReservationDelete(w http.ResponseWriter, r *http.Request, ps ...@@ -188,29 +207,33 @@ func (e *Endpoints) ReservationDelete(w http.ResponseWriter, r *http.Request, ps
188 reservationID := ps.ByName("reservation_id") 207 reservationID := ps.ByName("reservation_id")
189 208
190 // Check Permission 209 // Check Permission
191 - var isSuper int64 210 + var _count int64
192 - var _timetableName string 211 + var isSuper sql.NullInt64
193 - timetable := fmt.Sprintf("%s,%s", fileID, sheetID) 212 + var sheetName sql.NullString
194 row := e.DB.QueryRow(` 213 row := e.DB.QueryRow(`
195 - SELECT name 214 + SELECT
196 - FROM timetables 215 + (SELECT count(s.id)
197 - WHERE timetable_id=?; 216 + FROM sheets AS s, files AS f
198 - `, timetable) 217 + WHERE s.file_id=f.id
199 - if err := row.Scan(&_timetableName); err != nil { 218 + AND f.id=?
200 - if err == sql.ErrNoRows { 219 + AND s.id=?) AS count,
201 - functions.ResponseError(w, 404, "존재하지 않는 timetable.") 220 + (SELECT name
221 + FROM sheets
222 + WHERE id=?) AS sheet_name,
223 + (SELECT is_super
224 + FROM users
225 + WHERE email=?) AS is_super;
226 + `, fileID, sheetID, sheetID, email)
227 + if err := row.Scan(&_count, &sheetName, &isSuper); err == nil {
228 + if _count != 1 || !sheetName.Valid {
229 + functions.ResponseError(w, 404, "해당 파일이나 시트가 존재하지 않습니다.")
202 return 230 return
203 } 231 }
204 - } 232 + if !isSuper.Valid {
205 - 233 + functions.ResponseError(w, 401, "등록되지 않은 사용자입니다.")
206 - row = e.DB.QueryRow(`
207 - SELECT is_super FROM users WHERE email=?
208 - `, email)
209 - if err := row.Scan(&isSuper); err != nil {
210 - if err == sql.ErrNoRows {
211 - functions.ResponseError(w, 401, "해당 유저가 존재하지 않음")
212 return 234 return
213 } 235 }
236 + } else {
214 functions.ResponseError(w, 500, "예기치 못한 에러 : "+err.Error()) 237 functions.ResponseError(w, 500, "예기치 못한 에러 : "+err.Error())
215 return 238 return
216 } 239 }
...@@ -241,7 +264,7 @@ func (e *Endpoints) ReservationDelete(w http.ResponseWriter, r *http.Request, ps ...@@ -241,7 +264,7 @@ func (e *Endpoints) ReservationDelete(w http.ResponseWriter, r *http.Request, ps
241 functions.ResponseError(w, 500, "예기치 못한 에러 발생 : "+err.Error()) 264 functions.ResponseError(w, 500, "예기치 못한 에러 발생 : "+err.Error())
242 return 265 return
243 } 266 }
244 - if isSuper == 0 { 267 + if isSuper.Int64 == 0 {
245 if _email != email { 268 if _email != email {
246 functions.ResponseError(w, 403, "예약 접근 권한 부족") 269 functions.ResponseError(w, 403, "예약 접근 권한 부족")
247 return 270 return
...@@ -269,7 +292,7 @@ func (e *Endpoints) ReservationDelete(w http.ResponseWriter, r *http.Request, ps ...@@ -269,7 +292,7 @@ func (e *Endpoints) ReservationDelete(w http.ResponseWriter, r *http.Request, ps
269 sheetIDint, _ := strconv.Atoi(sheetID) 292 sheetIDint, _ := strconv.Atoi(sheetID)
270 sr := utils.NewSheetsRequest( 293 sr := utils.NewSheetsRequest(
271 fileID, 294 fileID,
272 - _timetableName, 295 + sheetName.String,
273 int64(sheetIDint), 296 int64(sheetIDint),
274 _cellColumn, 297 _cellColumn,
275 _cellStart, 298 _cellStart,
......
...@@ -30,7 +30,7 @@ func (e *Endpoints) UsersGet(w http.ResponseWriter, r *http.Request, ps httprout ...@@ -30,7 +30,7 @@ func (e *Endpoints) UsersGet(w http.ResponseWriter, r *http.Request, ps httprout
30 `, email) 30 `, email)
31 if err := row.Scan(&isSuper); err != nil { 31 if err := row.Scan(&isSuper); err != nil {
32 if err == sql.ErrNoRows { 32 if err == sql.ErrNoRows {
33 - functions.ResponseError(w, 401, "해당 유저가 존재하지 않") 33 + functions.ResponseError(w, 401, "해당 유저가 존재하지 않습니다.")
34 return 34 return
35 } 35 }
36 functions.ResponseError(w, 500, "예기치 못한 에러 : "+err.Error()) 36 functions.ResponseError(w, 500, "예기치 못한 에러 : "+err.Error())
......
...@@ -74,11 +74,9 @@ func main() { ...@@ -74,11 +74,9 @@ func main() {
74 router.GET("/api", ep.IndexGet) 74 router.GET("/api", ep.IndexGet)
75 router.GET("/api/users", ep.UsersGet) 75 router.GET("/api/users", ep.UsersGet)
76 router.POST("/api/users", ep.UsersPost) 76 router.POST("/api/users", ep.UsersPost)
77 - router.GET("/api/timetables/:file_id/:sheet_id/cell", ep.CellGet) 77 + router.GET("/api/files/:file_id/:sheet_id/cell", ep.CellGet)
78 - router.POST("/api/timetables/:file_id/:sheet_id/allow", ep.AllowlistPost) 78 + router.POST("/api/files/:file_id/:sheet_id/reservation", ep.ReservationPost)
79 - router.DELETE("/api/timetables/:file_id/:sheet_id/allow", ep.AllowlistDelete) 79 + router.DELETE("/api/files/:file_id/:sheet_id/reservation/:reservation_id", ep.ReservationDelete)
80 - router.POST("/api/timetables/:file_id/:sheet_id/reservation", ep.ReservationPost)
81 - router.DELETE("/api/timetables/:file_id/:sheet_id/reservation/:reservation_id", ep.ReservationDelete)
82 80
83 // Local Mode 81 // Local Mode
84 portStr := strconv.Itoa(cfg.Server.Port) 82 portStr := strconv.Itoa(cfg.Server.Port)
......
...@@ -96,12 +96,12 @@ func (s *SheetsService) RemoveValue(sr SheetsRequest) error { ...@@ -96,12 +96,12 @@ func (s *SheetsService) RemoveValue(sr SheetsRequest) error {
96 Requests: []*sheets.Request{req, req2}, 96 Requests: []*sheets.Request{req, req2},
97 } 97 }
98 98
99 - _, err := s.srv.Spreadsheets.BatchUpdate(sr.SpreadSheetID, rb).Context(s.ctx).Do() 99 + _, err := s.srv.Spreadsheets.Values.Clear(sr.SpreadSheetID, sr.RangeStr, &sheets.ClearValuesRequest{}).Do()
100 if err != nil { 100 if err != nil {
101 return err 101 return err
102 } 102 }
103 103
104 - _, err = s.srv.Spreadsheets.Values.Clear(sr.SpreadSheetID, sr.RangeStr, &sheets.ClearValuesRequest{}).Do() 104 + _, err = s.srv.Spreadsheets.BatchUpdate(sr.SpreadSheetID, rb).Context(s.ctx).Do()
105 if err != nil { 105 if err != nil {
106 return err 106 return err
107 } 107 }
......