github.com/pbberlin/tools@v0.0.0-20160910141205-7aa5421c2169/appengine/blobstore_mgt/upload2.go (about) 1 package blobstore_mgt 2 3 import ( 4 "html/template" 5 "net/http" 6 "net/url" 7 8 "fmt" 9 "path" 10 11 "github.com/pbberlin/tools/dsu" 12 "github.com/pbberlin/tools/net/http/loghttp" 13 "github.com/pbberlin/tools/stringspb" 14 "google.golang.org/appengine" 15 "google.golang.org/appengine/blobstore" 16 "google.golang.org/appengine/datastore" 17 "google.golang.org/appengine/image" 18 "google.golang.org/appengine/user" 19 20 "bytes" 21 "strings" 22 "time" 23 24 aelog "google.golang.org/appengine/log" 25 ) 26 27 const upload2HTML = ` 28 <form action="{{.}}" method="POST" enctype="multipart/form-data"> 29 Upload File: <input type="file" name="post_field_file"><br> 30 <input type="text" name="title" value="enter Title"><br> 31 <input type="text" name="descr" value="enter Description" size=60><br> 32 <input type="submit" name="submit" value="Submit"> 33 </form> 34 ` 35 36 var upload2 = template.Must(template.New("topLevelTemplateName").Parse(upload2HTML)) 37 38 const restrictForm = ` 39 <form 40 method="post" 41 aaaction="/blob2" 42 enctype="application/x-www-form-urlencoded" 43 > 44 <input type="text" name="nameFilter" value="nameFilter"><br> 45 <input type="submit" name="submit" value="Submit"> 46 </form> 47 ` 48 49 const openHTML = ` 50 <html> 51 <body style='margin:8px;'> 52 <style> * { margin: 4 0 } </style> 53 <style> 54 .ib { 55 vertical-align:middle; 56 display:inline-block; 57 width:95px; 58 } 59 </style> 60 ` 61 62 const closeHTML = ` 63 </body> 64 </html>` 65 66 func submitUpload(w http.ResponseWriter, r *http.Request, m map[string]interface{}) { 67 68 c := appengine.NewContext(r) 69 uploadURL, err := blobstore.UploadURL(c, "/blob2/processing-new-upload", nil) 70 loghttp.E(w, r, err, false) 71 72 w.Header().Set("Content-type", "text/html; charset=utf-8") 73 err = upload2.Execute(w, uploadURL) 74 loghttp.E(w, r, err, false) 75 } 76 77 func processUpload(w http.ResponseWriter, r *http.Request, m map[string]interface{}) { 78 79 b1 := new(bytes.Buffer) 80 defer func() { 81 w.Header().Set("Content-type", "text/html; charset=utf-8") 82 w.Write(b1.Bytes()) 83 }() 84 85 blobs, otherFormFields, err := MyParseUpload(r) 86 loghttp.E(w, r, err, false, fmt.Errorf("Fehler beim Parsen: %v", err)) 87 88 // s1 := stringspb.IndentedDump(blobs) 89 // if len(s1) > 2 { 90 // b1.WriteString("<br>blob: " + s1) 91 // } 92 93 // s2 := stringspb.IndentedDump(otherFormFields) 94 // if len(s2) > 2 { 95 // b1.WriteString("<br>otherF: " + s2+"<br>") 96 // } 97 98 numFiles := len(blobs["post_field_file"]) // this always yields (int)1 99 numOther := len(otherFormFields["post_field_file"]) 100 if numFiles == 0 && numOther == 0 { 101 //http.Redirect(w, r, "/blob2/upload", http.StatusFound) 102 b1.WriteString("<a href='/blob2/upload' >No file uploaded? Try again.</a><br>") 103 b1.WriteString("<a href='/blob2' >List</a><br>") 104 return 105 } 106 107 if numFiles > 0 { 108 109 blob0 := blobs["post_field_file"][0] 110 111 dataStoreClone(w, r, blob0, otherFormFields) 112 113 urlSuccessX := "/blob2/serve-full?blobkey=" + string(blob0.BlobKey) 114 urlThumb := "/blob2/thumb?blobkey=" + string(blob0.BlobKey) 115 b1.WriteString("<a href='/blob2' >List</a><br>") 116 b1.WriteString("<a href='" + urlSuccessX + "' >View Full: " + fmt.Sprintf("%v", blob0) + " - view it</a><br>\n") 117 b1.WriteString("<a href='" + urlThumb + "' >View Thumbnail</a><br>\n") 118 119 } 120 121 //http.Redirect(w, r, urlSuccess, http.StatusFound) 122 } 123 124 func serveFull(w http.ResponseWriter, r *http.Request, m map[string]interface{}) { 125 blobstore.Send(w, appengine.BlobKey(r.FormValue("blobkey"))) 126 } 127 128 // working differently as in Python 129 // //blob2s := blobstore.BlobInfo.gql("ORDER BY creation DESC") 130 func blobList(w http.ResponseWriter, r *http.Request, m map[string]interface{}) { 131 132 c := appengine.NewContext(r) 133 134 b1 := new(bytes.Buffer) 135 defer func() { 136 w.Header().Set("Content-type", "text/html; charset=utf-8") 137 b1.WriteString(closeHTML) 138 w.Write(b1.Bytes()) 139 }() 140 141 errFormParse := r.ParseForm() 142 if errFormParse != nil { 143 b1.WriteString(fmt.Sprintf("Form parse Error %v", errFormParse)) 144 return 145 } 146 147 s1 := "" 148 b1.WriteString(openHTML) 149 b1.WriteString(restrictForm) 150 151 nameFilter := r.PostFormValue("nameFilter") 152 nameFilter = strings.TrimSpace(nameFilter) 153 154 if nameFilter == "" { 155 return 156 } else { 157 tn := time.Now() 158 f := "2006-01-02 15:04:05" 159 f = "January 02" 160 prefix := tn.Format(f) 161 // nameFilter = fmt.Sprintf("%v %s", prefix,nameFilter ) 162 if !strings.HasPrefix(nameFilter, prefix) || len(nameFilter) == len(prefix) { 163 b1.WriteString(fmt.Sprintf("cannot filter by %v", nameFilter)) 164 return 165 } else { 166 nameFilter = nameFilter[len(prefix):] 167 } 168 } 169 170 u := user.Current(c) 171 if u != nil { 172 b1.WriteString(fmt.Sprintf("%v %v %v<br>\n", u.ID, u.Email, u.FederatedIdentity)) 173 } else { 174 b1.WriteString("nobody calling on the phone<br>") 175 } 176 177 // c := appengine.NewContext(r) 178 q := datastore.NewQuery("__BlobInfo__") 179 if nameFilter != "" { 180 181 // nameFilter = strings.ToLower(nameFilter) 182 b1.WriteString(fmt.Sprintf("Filtering by %v-%v<br>", nameFilter, stringspb.IncrementString(nameFilter))) 183 184 q = datastore.NewQuery("__BlobInfo__").Filter("filename >=", nameFilter) 185 q = q.Filter("filename <", stringspb.IncrementString(nameFilter)) 186 187 } 188 for t := q.Run(c); ; { 189 var bi BlobInfo 190 dsKey, err := t.Next(&bi) 191 192 if err == datastore.Done { 193 // aelog.Infof(c," No Results (any more) blob-list %v", err) 194 break 195 } 196 // other err 197 if err != nil { 198 loghttp.E(w, r, err, false) 199 return 200 } 201 202 //s1 = fmt.Sprintf("key %v %v %v %v %v %v<br>\n", dsKey.AppID(),dsKey.Namespace() , dsKey.Parent(), dsKey.Kind(), dsKey.StringID(), dsKey.IntID()) 203 //b1.WriteString( s1 ) 204 205 //s1 = fmt.Sprintf("blobinfo: %v %v<br>\n", bi.Filename, bi.Size) 206 //b1.WriteString( s1 ) 207 208 ext := path.Ext(bi.Filename) 209 base := path.Base(bi.Filename) 210 base = base[:len(base)-len(ext)] 211 212 //b1.WriteString( fmt.Sprintf("-%v- -%v-",base, ext) ) 213 214 base = strings.Replace(base, "_", " ", -1) 215 base = strings.Title(base) 216 ext = strings.ToLower(ext) 217 218 titledFilename := base + ext 219 if strings.HasPrefix(titledFilename, "Backup") { 220 showBackup := r.FormValue("backup") 221 if len(showBackup) < 1 { 222 continue 223 } 224 } 225 226 s1 = fmt.Sprintf("<a class='ib' style='width:280px;margin-right:20px' target='_view' href='/blob2/serve-full?blobkey=%v'>%v</a> \n", dsKey.StringID(), titledFilename) 227 b1.WriteString(s1) 228 229 if bi.ContentType == "image/png" || bi.ContentType == "image/jpeg" { 230 s1 = fmt.Sprintf("<img class='ib' style='width:40px;' src='/_ah/img/%v%v' />\n", 231 dsKey.StringID(), "=s200-c") 232 b1.WriteString(s1) 233 234 s1 = fmt.Sprintf("<a class='ib' target='_view' href='/_ah/img/%v%v'>Thumb</a>\n", 235 dsKey.StringID(), "=s200-c") 236 b1.WriteString(s1) 237 238 } else { 239 s1 = fmt.Sprintf("<span class='ib' style='width:145px;'> no thb</span>") 240 b1.WriteString(s1) 241 } 242 243 s1 = fmt.Sprintf("<a class='ib' target='_rename_delete' href='/blob2/rename-delete?action=delete&blobkey=%v'>Delete</a>\n", 244 dsKey.StringID()) 245 b1.WriteString(s1) 246 247 s1 = fmt.Sprintf(` 248 <span class='ib' style='width:450px; border: 1px solid #aaa'> 249 <form target='_rename_delete' action='/blob2/rename-delete' > 250 <input name='blobkey' value='%v' type='hidden'/> 251 <input name='action' value='rename' type='hidden'/> 252 <input name='filename' value='%v' size='42'/> 253 <input type='submit' value='Rename' /> 254 </form> 255 </span> 256 `, dsKey.StringID(), bi.Filename) 257 b1.WriteString(s1) 258 259 b1.WriteString("<br><br>\n\n") 260 261 } 262 263 b1.WriteString("<a accesskey='u' href='/blob2/upload' ><b>U</b>pload</a><br>") 264 b1.WriteString(`<a href='https://appengine.google.com/blobstore/explorer?&app_id=s~libertarian-islands' 265 >Delete via Console</a><br>`) 266 267 } 268 269 func renameOrDelete(w http.ResponseWriter, r *http.Request, m map[string]interface{}) { 270 271 lg, b := loghttp.BuffLoggerUniversal(w, r) 272 _ = b 273 274 c := appengine.NewContext(r) 275 276 b1 := new(bytes.Buffer) 277 s1 := "" 278 279 defer func() { 280 w.Header().Set("Content-type", "text/html; charset=utf-8") 281 w.Write(b1.Bytes()) 282 }() 283 284 // c := appengine.NewContext(r) 285 286 bk := r.FormValue("blobkey") 287 if bk == "" { 288 b1.WriteString("No blob key given<br>") 289 return 290 } else { 291 s1 = fmt.Sprintf("Blob key given %q<br>", bk) 292 b1.WriteString(s1) 293 } 294 295 dsKey := datastore.NewKey(c, "__BlobInfo__", bk, 0, nil) 296 297 q := datastore.NewQuery("__BlobInfo__").Filter("__key__=", dsKey) 298 299 var bi BlobInfo 300 var found bool 301 302 for t := q.Run(c); ; { 303 _, err := t.Next(&bi) 304 if err == datastore.Done { 305 aelog.Infof(c, " No Results (any more), blob-rename-delete %v", err) 306 break 307 } 308 // other err 309 if err != nil { 310 lg(err) 311 return 312 } 313 found = true 314 break 315 } 316 317 if found { 318 ac := r.FormValue("action") 319 if ac == "delete" { 320 b1.WriteString("deletion ") 321 322 // first the binary data 323 keyBlob, err := blobstore.BlobKeyForFile(c, bi.Filename) 324 lg(err) 325 326 if err != nil { 327 b1.WriteString(fmt.Sprintf(" ... failed (1) %v", err)) 328 } else { 329 err = blobstore.Delete(c, keyBlob) 330 lg(err) 331 if err != nil { 332 b1.WriteString(fmt.Sprintf(" ... failed (2) %v<br>", err)) 333 } else { 334 // now the datastore record 335 err = datastore.Delete(c, dsKey) 336 lg(err) 337 if err != nil { 338 b1.WriteString(fmt.Sprintf(" ... failed (3) %v<br>%#v<br>", err, dsKey)) 339 } else { 340 b1.WriteString(" ... succeeded<br>") 341 } 342 343 } 344 } 345 } 346 347 if ac == "rename" { 348 b1.WriteString("renaming ") 349 350 nfn := r.FormValue("filename") 351 if nfn == "" || len(nfn) < 4 { 352 b1.WriteString(" ... failed - at LEAST 4 chars required<br>") 353 return 354 } 355 nfn = strings.ToLower(nfn) 356 bi.Filename = nfn 357 _, err := datastore.Put(c, dsKey, &bi) 358 lg(err) 359 if err != nil { 360 b1.WriteString(fmt.Sprintf(" ... failed. %v", err)) 361 } else { 362 b1.WriteString(" ... succeeded<br>") 363 } 364 } 365 366 } else { 367 b1.WriteString("no blob found for given blobkey<br>") 368 } 369 b1.WriteString("<a href='/blob2'>Back to list</a><br>") 370 371 } 372 373 func serveThumb(w http.ResponseWriter, r *http.Request, m map[string]interface{}) { 374 375 c := appengine.NewContext(r) 376 377 // c := appengine.NewContext(r) 378 k := appengine.BlobKey(r.FormValue("blobkey")) 379 380 var o image.ServingURLOptions = *new(image.ServingURLOptions) 381 o.Size = 200 382 o.Crop = true 383 url, err := image.ServingURL(c, k, &o) 384 385 loghttp.E(w, r, err, false) 386 387 http.Redirect(w, r, url.String(), http.StatusFound) 388 } 389 390 // This was an attempt, to "catch" the uploaded blob 391 // and store it by myself into the datastore - 392 // where I would be able to delete it. 393 // But this failed - the actual blob data does not even reach the appengine. 394 // Only the blob-info data. 395 func dataStoreClone(w http.ResponseWriter, r *http.Request, 396 blob0 *BlobInfo, otherFormFields url.Values) { 397 398 return 399 400 c := appengine.NewContext(r) 401 402 wbl := dsu.WrapBlob{} 403 wbl.Category = "print" 404 wbl.Name = otherFormFields["title"][0] + " - " + otherFormFields["descr"][0] 405 wbl.Name += " - " + stringspb.LowerCasedUnderscored(blob0.Filename) 406 wbl.Desc = fmt.Sprintf("%v", blob0.BlobKey) 407 wbl.S = blob0.ContentType 408 if len(otherFormFields["post_field_file"]) > 0 { 409 filecontent := otherFormFields["post_field_file"][0] 410 wbl.VByte = []byte(filecontent) 411 } 412 keyX2 := "bl" + time.Now().Format("060102_1504-05") 413 _, errDS := dsu.BufPut(c, wbl, keyX2) 414 loghttp.E(w, r, errDS, false) 415 416 } 417 418 func init() { 419 http.HandleFunc("/print", loghttp.Adapter(blobList)) 420 http.HandleFunc("/blob2", loghttp.Adapter(blobList)) 421 http.HandleFunc("/blob2/upload", loghttp.Adapter(submitUpload)) 422 http.HandleFunc("/blob2/processing-new-upload", loghttp.Adapter(processUpload)) 423 http.HandleFunc("/blob2/serve-full", loghttp.Adapter(serveFull)) 424 http.HandleFunc("/blob2/thumb", loghttp.Adapter(serveThumb)) 425 http.HandleFunc("/blob2/rename-delete", loghttp.Adapter(renameOrDelete)) 426 }