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 }