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> &nbsp; &nbsp; \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;'> &nbsp; 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  }