github.com/rpdict/ponzu@v0.10.1-0.20190226054626-477f29d6bf5e/system/api/delete.go (about)

     1  package api
     2  
     3  import (
     4  	"encoding/json"
     5  	"log"
     6  	"net/http"
     7  
     8  	"github.com/rpdict/ponzu/system/db"
     9  	"github.com/rpdict/ponzu/system/item"
    10  )
    11  
    12  // Deleteable accepts or rejects update POST requests to endpoints such as:
    13  // /api/content/delete?type=Review&id=1
    14  type Deleteable interface {
    15  	// Delete enables external clients to delete content of a specific type
    16  	Delete(http.ResponseWriter, *http.Request) error
    17  }
    18  
    19  func deleteContentHandler(res http.ResponseWriter, req *http.Request) {
    20  	if req.Method != http.MethodPost {
    21  		res.WriteHeader(http.StatusMethodNotAllowed)
    22  		return
    23  	}
    24  
    25  	err := req.ParseMultipartForm(1024 * 1024 * 4) // maxMemory 4MB
    26  	if err != nil {
    27  		log.Println("[Delete] error:", err)
    28  		res.WriteHeader(http.StatusInternalServerError)
    29  		return
    30  	}
    31  
    32  	t := req.URL.Query().Get("type")
    33  	if t == "" {
    34  		res.WriteHeader(http.StatusBadRequest)
    35  		return
    36  	}
    37  
    38  	p, found := item.Types[t]
    39  	if !found {
    40  		log.Println("[Delete] attempt to delete content of unknown type:", t, "from:", req.RemoteAddr)
    41  		res.WriteHeader(http.StatusNotFound)
    42  		return
    43  	}
    44  
    45  	id := req.URL.Query().Get("id")
    46  	if !db.IsValidID(id) {
    47  		log.Println("[Delete] attempt to delete content with missing or invalid id from:", req.RemoteAddr)
    48  		res.WriteHeader(http.StatusBadRequest)
    49  		return
    50  	}
    51  
    52  	post := p()
    53  
    54  	ext, ok := post.(Deleteable)
    55  	if !ok {
    56  		log.Println("[Delete] rejected non-deleteable type:", t, "from:", req.RemoteAddr)
    57  		res.WriteHeader(http.StatusBadRequest)
    58  		return
    59  	}
    60  
    61  	hook, ok := post.(item.Hookable)
    62  	if !ok {
    63  		log.Println("[Delete] error: Type", t, "does not implement item.Hookable or embed item.Item.")
    64  		res.WriteHeader(http.StatusBadRequest)
    65  		return
    66  	}
    67  
    68  	b, err := db.Content(t + ":" + id)
    69  	if err != nil {
    70  		log.Println("Error in db.Content ", t+":"+id, err)
    71  		res.WriteHeader(http.StatusBadRequest)
    72  		return
    73  	}
    74  
    75  	err = json.Unmarshal(b, post)
    76  	if err != nil {
    77  		log.Println("Error unmarshalling ", t, "=", id, err, " Hooks will be called on a zero-value.")
    78  	}
    79  
    80  	err = hook.BeforeAPIDelete(res, req)
    81  	if err != nil {
    82  		log.Println("[Delete] error calling BeforeAPIDelete:", err)
    83  		if err == ErrNoAuth {
    84  			// BeforeAPIDelete can check user.IsValid(req) for auth
    85  			res.WriteHeader(http.StatusUnauthorized)
    86  		}
    87  		return
    88  	}
    89  
    90  	err = ext.Delete(res, req)
    91  	if err != nil {
    92  		log.Println("[Delete] error calling Delete:", err)
    93  		if err == ErrNoAuth {
    94  			// Delete can check user.IsValid(req) or other forms of validation for auth
    95  			res.WriteHeader(http.StatusUnauthorized)
    96  		}
    97  		return
    98  	}
    99  
   100  	err = hook.BeforeDelete(res, req)
   101  	if err != nil {
   102  		log.Println("[Delete] error calling BeforeSave:", err)
   103  		return
   104  	}
   105  
   106  	err = db.DeleteContent(t + ":" + id)
   107  	if err != nil {
   108  		log.Println("[Delete] error calling DeleteContent:", err)
   109  		res.WriteHeader(http.StatusInternalServerError)
   110  		return
   111  	}
   112  
   113  	err = hook.AfterDelete(res, req)
   114  	if err != nil {
   115  		log.Println("[Delete] error calling AfterDelete:", err)
   116  		return
   117  	}
   118  
   119  	err = hook.AfterAPIDelete(res, req)
   120  	if err != nil {
   121  		log.Println("[Delete] error calling AfterAPIDelete:", err)
   122  		return
   123  	}
   124  
   125  	// create JSON response to send data back to client
   126  	var data = map[string]interface{}{
   127  		"id":     id,
   128  		"status": "deleted",
   129  		"type":   t,
   130  	}
   131  
   132  	resp := map[string]interface{}{
   133  		"data": []map[string]interface{}{
   134  			data,
   135  		},
   136  	}
   137  
   138  	j, err := json.Marshal(resp)
   139  	if err != nil {
   140  		log.Println("[Delete] error marshalling response to JSON:", err)
   141  		res.WriteHeader(http.StatusInternalServerError)
   142  		return
   143  	}
   144  
   145  	res.Header().Set("Content-Type", "application/json")
   146  	_, err = res.Write(j)
   147  	if err != nil {
   148  		log.Println("[Delete] error writing response:", err)
   149  		return
   150  	}
   151  
   152  }