socialnetworknews-api

git clone git://archive.git.mtrnord.blog/SocialNetworkNews/socialnetworknews-api.git
Log | Files | Refs | LICENSE

webserver.go (10034B)


      1 package api
      2 
      3 import (
      4 	"encoding/csv"
      5 	"encoding/json"
      6 	"fmt"
      7 	"github.com/SocialNetworkNews/SocialNetworkNews_API/api/util"
      8 	"github.com/SocialNetworkNews/SocialNetworkNews_API/config"
      9 	"github.com/SocialNetworkNews/SocialNetworkNews_API/db"
     10 	"github.com/SocialNetworkNews/SocialNetworkNews_API/twitter"
     11 	TLoginStructs "github.com/dghubble/go-twitter/twitter"
     12 	"github.com/dgraph-io/badger"
     13 	"github.com/gorilla/mux"
     14 	"github.com/pkg/errors"
     15 	"github.com/satori/go.uuid"
     16 	"log"
     17 	"net/http"
     18 	"os"
     19 	"path/filepath"
     20 	"strconv"
     21 	"strings"
     22 	"time"
     23 )
     24 
     25 type TweetsError struct {
     26 	err        string //error description
     27 	statusCode int    // HTTP Code
     28 }
     29 
     30 func (e *TweetsError) Error() string {
     31 	return e.err
     32 }
     33 
     34 func (e *TweetsError) StatusCode() int {
     35 	return e.statusCode
     36 }
     37 
     38 func Yesterday(w http.ResponseWriter, r *http.Request) {
     39 	vars := mux.Vars(r)
     40 	// TODO Use Database or File Structure (probably File Structure)
     41 	uuidVar := vars["uuid"]
     42 	fmt.Println("UUID: ", uuidVar)
     43 
     44 	tweets, err := getTweets()
     45 	if err != nil {
     46 		if tErr, ok := err.(*TweetsError); ok {
     47 			http.Error(w, tErr.Error(), tErr.StatusCode())
     48 		} else {
     49 			http.Error(w, err.Error(), http.StatusInternalServerError)
     50 		}
     51 	}
     52 	w.Header().Set("Content-Type", "application/json")
     53 	w.Header().Set("API-VERSION", util.APIVersion)
     54 	w.WriteHeader(http.StatusOK)
     55 	w.Write(tweets)
     56 }
     57 
     58 type Paper struct {
     59 	Name        string `json:"name,omitempty"`
     60 	UUID        string `json:"uuid,omitempty"`
     61 	Description string `json:"description,omitempty"`
     62 	PaperImage  string `json:"paper_image,omitempty"`
     63 	Author      Author `json:"author,omitempty"`
     64 }
     65 
     66 type Author struct {
     67 	UUID           string `json:"uuid,omitempty"`
     68 	Username       string `json:"username,omitempty"`
     69 	ProfileIMGURL  string `json:"profile_image_url,omitempty"`
     70 	TwitterProfile string `json:"twitter_profile,omitempty"`
     71 	GoogleProfile  string `json:"google_profile,omitempty"`
     72 	GithubProfile  string `json:"github_profile,omitempty"`
     73 }
     74 
     75 func Papers(w http.ResponseWriter, r *http.Request) {
     76 	var data []byte
     77 	switch r.Method {
     78 	case "GET":
     79 		papers, err := getPapers(false, "")
     80 		if err != nil {
     81 			http.Error(w, err.Error(), http.StatusInternalServerError)
     82 			return
     83 		}
     84 
     85 		data = papers
     86 	case "POST":
     87 		decoder := json.NewDecoder(r.Body)
     88 		var t []Paper
     89 		err := decoder.Decode(&t)
     90 		if err != nil {
     91 			decodeErr := errors.WithMessage(err, "Decoding JSON Body")
     92 			http.Error(w, decodeErr.Error(), http.StatusInternalServerError)
     93 			return
     94 		}
     95 		defer r.Body.Close()
     96 
     97 		papers, err := addPapers(t)
     98 		if err != nil {
     99 			addErr := errors.WithMessage(err, "Adding Papers")
    100 			http.Error(w, addErr.Error(), http.StatusInternalServerError)
    101 			return
    102 		}
    103 		data = papers
    104 	}
    105 	w.Header().Set("Content-Type", "application/json")
    106 	w.Header().Set("API-VERSION", util.APIVersion)
    107 	w.WriteHeader(http.StatusOK)
    108 	w.Write(data)
    109 }
    110 
    111 func PaperFunc(w http.ResponseWriter, r *http.Request) {
    112 	vars := mux.Vars(r)
    113 	uuidVar := vars["uuid"]
    114 
    115 	var data []byte
    116 	switch r.Method {
    117 	case "GET":
    118 		papers, err := getPapers(true, uuidVar)
    119 		if err != nil {
    120 			http.Error(w, err.Error(), http.StatusInternalServerError)
    121 			return
    122 		}
    123 
    124 		data = papers
    125 	}
    126 	w.Header().Set("Content-Type", "application/json")
    127 	w.Header().Set("API-VERSION", util.APIVersion)
    128 	w.WriteHeader(http.StatusOK)
    129 	w.Write(data)
    130 }
    131 
    132 func getAuthorData(id string) (*Author, error) {
    133 	author := &Author{}
    134 	dataDB, err := db.OpenDB()
    135 	if err != nil {
    136 		return nil, err
    137 	}
    138 
    139 	DBerr := dataDB.View(func(txn *badger.Txn) error {
    140 		username, UErrR := db.Get(txn, []byte(fmt.Sprintf("users|username|T|%s", id)))
    141 		if UErrR != nil {
    142 			UErr := errors.WithMessage(UErrR, fmt.Sprintf("users|username|T|%s", id))
    143 			return UErr
    144 		}
    145 		author.Username = fmt.Sprintf("%s", username)
    146 
    147 		author.UUID = id
    148 
    149 		TIDB, TIDerrR := db.Get(txn, []byte(fmt.Sprintf("users|id|T|%s", id)))
    150 		if TIDerrR != nil {
    151 			TIDerr := errors.WithMessage(TIDerrR, fmt.Sprintf("users|T|%s|data", id))
    152 			return TIDerr
    153 		}
    154 		TID := fmt.Sprintf("%s", TIDB)
    155 
    156 		data, DErrR := db.Get(txn, []byte(fmt.Sprintf("users|T|%s|data", TID)))
    157 		if DErrR != nil {
    158 			DErr := errors.WithMessage(DErrR, fmt.Sprintf("users|T|%s|data", TID))
    159 			return DErr
    160 		}
    161 		TUserData := TLoginStructs.User{}
    162 		UMerrR := json.Unmarshal(data, &TUserData)
    163 		if UMerrR != nil {
    164 			UMerr := errors.WithMessage(UMerrR, "Decode TwitterData")
    165 			return UMerr
    166 		}
    167 		author.TwitterProfile = TUserData.URL
    168 		author.ProfileIMGURL = TUserData.ProfileImageURLHttps
    169 		return nil
    170 	})
    171 
    172 	return author, DBerr
    173 }
    174 
    175 func addPapers(data []Paper) ([]byte, error) {
    176 	papersDB, openErr := db.OpenDB()
    177 	if openErr != nil {
    178 		dbErr := errors.WithMessage(openErr, "Opening DB")
    179 		return nil, dbErr
    180 	}
    181 
    182 	var papers []Paper
    183 
    184 	for _, p := range data {
    185 		puuid, UUIDerr := uuid.NewV4()
    186 		if UUIDerr != nil {
    187 			uuidErr := errors.WithMessage(UUIDerr, "Generating UUID")
    188 			return nil, uuidErr
    189 		}
    190 		newUUID := puuid.String()
    191 		newName := p.Name
    192 		newDesc := p.Description
    193 		newAuthor := p.Author.UUID
    194 		newPIMG := p.PaperImage
    195 
    196 		DBErrR := papersDB.Update(func(txn *badger.Txn) error {
    197 			nameErrR := txn.Set([]byte(fmt.Sprintf("papers|paper|%s|name", newUUID)), []byte(newName))
    198 			if nameErrR != nil {
    199 				nameErr := errors.WithMessage(nameErrR, fmt.Sprintf("papers|paper|%s|name", newUUID))
    200 				return nameErr
    201 			}
    202 
    203 			descErrR := txn.Set([]byte(fmt.Sprintf("papers|paper|%s|description", newUUID)), []byte(newDesc))
    204 			if descErrR != nil {
    205 				descErr := errors.WithMessage(descErrR, fmt.Sprintf("papers|paper|%s|description", newUUID))
    206 				return descErr
    207 			}
    208 
    209 			pIMGErrR := txn.Set([]byte(fmt.Sprintf("papers|paper|%s|image", newUUID)), []byte(newPIMG))
    210 			if pIMGErrR != nil {
    211 				pIMGErr := errors.WithMessage(pIMGErrR, fmt.Sprintf("papers|paper|%s|image", newUUID))
    212 				return pIMGErr
    213 			}
    214 
    215 			authorErrR := txn.Set([]byte(fmt.Sprintf("papers|paper|%s|author", newUUID)), []byte(newAuthor))
    216 
    217 			return errors.WithMessage(authorErrR, fmt.Sprintf("papers|paper|%s|author", newUUID))
    218 		})
    219 		if DBErrR != nil {
    220 			DBErr := errors.WithMessage(DBErrR, "Database Request")
    221 			return nil, DBErr
    222 		}
    223 
    224 		paper := Paper{}
    225 		paper.UUID = newUUID
    226 		paper.Name = newName
    227 		paper.PaperImage = newPIMG
    228 		author, AuthorDataErrR := getAuthorData(newAuthor)
    229 		if AuthorDataErrR != nil {
    230 			AuthorDataErr := errors.WithMessage(AuthorDataErrR, "Author Data Request")
    231 			return nil, AuthorDataErr
    232 		}
    233 		paper.Author = *author
    234 
    235 		papers = append(papers, paper)
    236 	}
    237 
    238 	papersArray, MErrR := json.Marshal(papers)
    239 	if MErrR != nil {
    240 		MErr := errors.WithMessage(MErrR, "Encoding Papers Data")
    241 		return nil, MErr
    242 	}
    243 
    244 	return papersArray, nil
    245 }
    246 
    247 func getPapers(full bool, uuid string) ([]byte, error) {
    248 	papersDB, openErr := db.OpenDB()
    249 	if openErr != nil {
    250 		return nil, openErr
    251 	}
    252 
    253 	var papers []Paper
    254 	paper := Paper{}
    255 
    256 	papersDB.View(func(txn *badger.Txn) error {
    257 		opts := badger.DefaultIteratorOptions
    258 		opts.PrefetchSize = 10
    259 		it := txn.NewIterator(opts)
    260 		var prefix []byte
    261 		if full {
    262 			prefix = []byte(fmt.Sprintf("papers|paper|%s", uuid))
    263 		} else {
    264 			prefix = []byte("papers|paper|")
    265 		}
    266 
    267 		known := make(map[string]bool)
    268 
    269 		for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() {
    270 			item := it.Item()
    271 			key := item.Key()
    272 			stringKey := fmt.Sprintf("%s", key)
    273 			stringKeySlice := strings.Split(stringKey, "|")
    274 			var stringKeyEnd string
    275 			if full {
    276 				stringKeyEnd = ""
    277 			} else {
    278 				stringKeyEnd = stringKeySlice[len(stringKeySlice)-2]
    279 			}
    280 
    281 			if known[stringKeyEnd] {
    282 				continue
    283 			}
    284 			known[stringKeyEnd] = true
    285 			paper.UUID = stringKeyEnd
    286 
    287 			nameResult, QueryErr := db.Get(txn, []byte(fmt.Sprintf("%s%s|name", prefix, stringKeyEnd)))
    288 			if QueryErr != nil {
    289 				return errors.WithMessage(QueryErr, fmt.Sprintf("%s%s|name", prefix, stringKeyEnd))
    290 			}
    291 
    292 			paperIMGResult, QueryErr := db.Get(txn, []byte(fmt.Sprintf("%s%s|image", prefix, stringKeyEnd)))
    293 			if QueryErr != nil {
    294 				return errors.WithMessage(QueryErr, fmt.Sprintf("%s%s|image", prefix, stringKeyEnd))
    295 			}
    296 
    297 			descResult, QueryErr := db.Get(txn, []byte(fmt.Sprintf("%s%s|description", prefix, stringKeyEnd)))
    298 			if QueryErr != nil {
    299 				return errors.WithMessage(QueryErr, fmt.Sprintf("%s%s|description", prefix, stringKeyEnd))
    300 			}
    301 
    302 			paper.PaperImage = fmt.Sprintf("%s", paperIMGResult)
    303 			paper.Name = fmt.Sprintf("%s", nameResult)
    304 			paper.Description = fmt.Sprintf("%s", descResult)
    305 
    306 			if full {
    307 				AUUIDResult, QueryErr := db.Get(txn, []byte(fmt.Sprintf("%s%s|author", prefix, stringKeyEnd)))
    308 				if QueryErr != nil {
    309 					return errors.WithMessage(QueryErr, fmt.Sprintf("%s%s|author", prefix, stringKeyEnd))
    310 				}
    311 				authorID := fmt.Sprintf("%s", AUUIDResult)
    312 				log.Println(authorID)
    313 				author, err := getAuthorData(authorID)
    314 				if err != nil {
    315 					return err
    316 				}
    317 				paper.Author = *author
    318 			}
    319 		}
    320 		return nil
    321 	})
    322 
    323 	log.Printf("%+v", paper)
    324 	papers = append(papers, paper)
    325 
    326 	var papersArray []byte
    327 	var err error
    328 	if full {
    329 		papersArray, err = json.Marshal(papers[0])
    330 		if err != nil {
    331 			return nil, err
    332 		}
    333 	} else {
    334 		papersArray, err = json.Marshal(papers)
    335 		if err != nil {
    336 			return nil, err
    337 		}
    338 	}
    339 
    340 	return papersArray, nil
    341 }
    342 
    343 func getTweets() ([]byte, error) {
    344 	api := twitter.NewTwitterAPIStruct()
    345 
    346 	// open output file
    347 	currentTime := time.Now().Local()
    348 	currentTime = currentTime.AddDate(0, 0, -1)
    349 	filePath := config.ConfigPath()
    350 	filename := fmt.Sprintf("tweets_%s.csv", currentTime.Format("2006_01_02"))
    351 	dataFilePath := filepath.Join(filePath, "data", filename)
    352 
    353 	fo, err := os.Open(dataFilePath)
    354 	if err != nil {
    355 		return nil, &TweetsError{err.Error(), 404}
    356 	}
    357 
    358 	// close fo on exit and check for its returned error
    359 	defer func() {
    360 		if err := fo.Close(); err != nil {
    361 			panic(err)
    362 		}
    363 	}()
    364 
    365 	r := csv.NewReader(fo)
    366 	data, readErr := r.ReadAll()
    367 	if readErr != nil {
    368 		return nil, readErr
    369 	}
    370 
    371 	var tweets []int64
    372 	for _, t := range data {
    373 		i, err := strconv.ParseInt(t[0], 10, 64)
    374 		if err != nil {
    375 			return nil, err
    376 		}
    377 		tweets = append(tweets, i)
    378 	}
    379 
    380 	tweetObject, err := api.GetTweets(tweets)
    381 	if err != nil {
    382 		return nil, err
    383 	}
    384 	return tweetObject, nil
    385 }