Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
b2c5b7b
This is the list.go file that will list all tasks in the csv file.
Jun 21, 2016
06be104
Added base files
kindermoumoute Jun 21, 2016
499cd35
Merge pull request #1 from kindermoumoute/basefiles
Jun 21, 2016
4eced71
Merge branch 'master' of https://github.com/zachary-trudo/go-api-exam…
Jun 21, 2016
33a9ad0
Merge pull request #1 from zachary-trudo/master
nichelle-hall Jun 21, 2016
ab3025c
updated get gile to include the list function
Jun 21, 2016
233827f
.gitignore added
Chrysaor716 Jun 21, 2016
8cb699a
Updated main.go
kindermoumoute Jun 21, 2016
296baba
Merge pull request #10 from kindermoumoute/basefiles
kindermoumoute Jun 21, 2016
c399381
Merge branch 'master' of https://github.com/zachary-trudo/go-api-exam…
Chrysaor716 Jun 21, 2016
2bfcce1
Added simple-rest-server to .gitignore
Chrysaor716 Jun 21, 2016
df9ce3c
testing
Chrysaor716 Jun 21, 2016
f2e086d
Removed test file
Chrysaor716 Jun 21, 2016
4519778
Merge pull request #11 from Chrysaor716/master
Jun 21, 2016
a7b5438
Added checkout.go with associated funciton. Also added a 'getIndexByT…
Jun 21, 2016
c95f5f7
Updated function for use with Olivier's future changes.
Jun 21, 2016
19475a7
Add Handler + simultaneous access + Task global struct
kindermoumoute Jun 21, 2016
b08bc67
Merge pull request #14 from kindermoumoute/basefiles
Jun 21, 2016
fa48c9e
Merged my current changes with Olivier's
Jun 21, 2016
4c48300
Finishing merge with Olivier
Jun 21, 2016
2cf6fa4
Changing how I lock and unlock
Jun 21, 2016
d0d3035
Merge branch 'master' of https://github.com/NichelleBot/go-api-exampl…
Jun 21, 2016
eb262f0
Merge branch 'master' of https://github.com/zachary-trudo/go-api-exam…
Jun 21, 2016
1cedf76
Finished ups some changes - added remove.
Jun 21, 2016
df17d37
Edited the ListTask function to return JSON file.
Jun 21, 2016
8e39341
Renamed panic into ifPanic
kindermoumoute Jun 21, 2016
7b2c0ce
Merge pull request #15 from kindermoumoute/basefiles
kindermoumoute Jun 21, 2016
ae28be2
Merge pull request #3 from NichelleBot/nichelle
kindermoumoute Jun 21, 2016
2516ad1
Search implementation
Chrysaor716 Jun 22, 2016
686b391
Merging Christina's work
Jun 22, 2016
84ce4b5
Added a homepage
Jun 22, 2016
4a592d9
Merge branch 'master' into zach
Jun 22, 2016
7857f29
Changed locations of functions and removed files.
Jun 22, 2016
1032948
Merge pull request #13 from zachary-trudo/zach
Jun 22, 2016
4ef7767
Fixed some bugs - replaced put.go since I accidentally deleted it
Jun 22, 2016
a51a28d
Merge pull request #18 from zachary-trudo/zach
Jun 22, 2016
dc9a5ee
Autogenerating html example.
Jun 22, 2016
e614be3
Fix 0 items in csv bug
Jun 22, 2016
13a10c2
Now able to search for results and have the display - If no results a…
Jun 22, 2016
f42f6f8
Fixed bugs in delete functionality.
Jun 22, 2016
14696b6
New pathing
kindermoumoute Jun 22, 2016
6f72818
Merge pull request #23 from kindermoumoute/basefiles
kindermoumoute Jun 22, 2016
a3bb57e
Added 400 error
Jun 22, 2016
1c40a32
Fixing Merge issues
Jun 22, 2016
4d5c77a
Merge pull request #21 from zachary-trudo/zach
kindermoumoute Jun 22, 2016
98a0c16
Last changes and Tom's comments
kindermoumoute Jun 23, 2016
b50ff55
Merge pull request #24 from kindermoumoute/basefiles
kindermoumoute Jun 23, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
*.o
*.a
*.so

# Folders
_obj
_test

# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out

*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*

_testmain.go

*.exe
*.test
.idea
tmp/
*.tmp
scratch/
build/
*.swp
profile.cov
gin-bin

# we don't vendor godep _workspace
**/Godeps/_workspace/**

# OSX stuff
.DS_Store

# Default name of executable
simple-rest-server/simple-rest-server
69 changes: 69 additions & 0 deletions simple-rest-server/delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package main

import (
"encoding/json"
"fmt"
"github.com/julienschmidt/httprouter"
"io/ioutil"
"log"
"net/http"
)

type Remove struct {
ID int `json:"id"`
}

// Delete API call
func DeleteTask(respWriter http.ResponseWriter, request *http.Request, _ httprouter.Params) {
var remove Remove
body, err := ioutil.ReadAll(request.Body)
if err != nil {
fmt.Fprintln(respWriter, "Bad request: %v", err)
log.Println(err)
respWriter.WriteHeader(400)
}
err = json.Unmarshal(body, &remove)
if err != nil {
fmt.Fprintln(respWriter, "Bad request: %v", err)
log.Println(err)
respWriter.WriteHeader(400)
}

index, err := removeTaskByID(remove.ID)
if index == -1 {
fmt.Fprintln(respWriter, "Task ID not found. Unable to delete")
} else {
fmt.Fprintln(respWriter, "Task ID: "+string(index)+" found.")
}
if err != nil {
fmt.Fprintln(respWriter, "Bad request: %v", err)
log.Println(err)
respWriter.WriteHeader(400)
}
}

func removeTaskByID(taskID int) (int, error) {
index, err := getIndexByTaskID(taskID)
if err != nil {
log.Println(err)
return index, err
}

if index == -1 {
return index, err
} else if index == 0 {
accessTasks.Lock()
allTasks = allTasks[1:]
accessTasks.Unlock()
} else if index == len(allTasks)-1 {
accessTasks.Lock()
allTasks = allTasks[:len(allTasks)-1]
accessTasks.Unlock()
} else {
accessTasks.Lock()
allTasks = append(allTasks[:index-1], allTasks[index+1:]...)
accessTasks.Unlock()
}
accessTasks.Unlock()
return index, err
}
121 changes: 121 additions & 0 deletions simple-rest-server/get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package main

import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"strconv"
"strings"
"time"

"github.com/julienschmidt/httprouter"
)

type Search struct {
Word string `json:"search"`
TimeBefore time.Time `json:"before"`
}

func htmlParagraph(text *string, paragraph string) {
*text += "\n<p>" + paragraph + "</p>"
}

func Index(respWriter http.ResponseWriter, request *http.Request, params httprouter.Params) {
htmlOut := `Todo List API.`
htmlParagraph(&htmlOut, "/add")
htmlParagraph(&htmlOut, "/delete")
htmlParagraph(&htmlOut, "/search")
htmlParagraph(&htmlOut, "/list")
htmlParagraph(&htmlOut, "/checkoff")

respWriter.Header().Set("Content-Type", "text/html; charset=utf-8")
respWriter.Write([]byte(htmlOut))
}

func ListTask(respWriter http.ResponseWriter, request *http.Request, params httprouter.Params) {
output, _ := json.MarshalIndent(allTasks, "", " ")
fmt.Fprintln(respWriter, string(output))
}

func GetTask(respWriter http.ResponseWriter, request *http.Request, params httprouter.Params) {
i, err := strconv.Atoi(params.ByName("id"))
if err != nil {
fmt.Fprintf(respWriter, "Bad request: %v", err)
respWriter.WriteHeader(400)
return
}
i, err = getIndexByTaskID(i)
if err != nil {
fmt.Fprintf(respWriter, "Bad request: %v", err)
respWriter.WriteHeader(400)
return
}
output, _ := json.MarshalIndent(allTasks[i], "", " ")
fmt.Fprintln(respWriter, string(output))
}

func SearchTask(respWriter http.ResponseWriter, request *http.Request, params httprouter.Params) {
var query Search
body, err := ioutil.ReadAll(request.Body)
if err != nil {
fmt.Println(err)
fmt.Fprintln(respWriter, "Bad request: %v", err)
log.Println(err)
respWriter.WriteHeader(400)
}
err = json.Unmarshal(body, &query)
if err != nil {
fmt.Fprintln(respWriter, "Bad request: %v", err)
log.Println(err)
respWriter.WriteHeader(400)
}

var indicies []int
fmt.Fprintln(respWriter, "Searching for "+query.Word)
timezero := time.Time{}
if query.Word != "" {
indicies = append(indicies, searchByWord(query.Word)[:]...)
} else if query.TimeBefore != timezero {
indicies = append(indicies, searchByTime(query.TimeBefore)[:]...)
} else {
fmt.Println("Undefined search query")
}

if len(indicies) == 0 {
fmt.Fprintln(respWriter, "No Results!!!!!")
}
for _, index := range indicies {
accessTasks.Lock()
prettyJson, err := json.MarshalIndent(allTasks[index], "", " ")
accessTasks.Unlock()
if err != nil {
log.Print(err)
return
}
fmt.Fprintln(respWriter, string(prettyJson))
}
}

func searchByWord(query string) (result []int) {
accessTasks.Lock()
for i, task := range allTasks {
if strings.Contains(task.Task, query) {
result = append(result, i)
}
}
accessTasks.Unlock()
return
}

func searchByTime(query time.Time) (result []int) {
accessTasks.Lock()
for i, task := range allTasks {
if task.TimeAdded.Before(query) || task.TimeAdded == query {
result = append(result, i)
}
}
accessTasks.Unlock()
return
}
115 changes: 104 additions & 11 deletions simple-rest-server/main.go
Original file line number Diff line number Diff line change
@@ -1,30 +1,123 @@
package main

import (
"encoding/csv"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"sync"
"time"

"github.com/julienschmidt/httprouter"
)

func Index(respWriter http.ResponseWriter, request *http.Request, _ httprouter.Params) {
fmt.Fprintln(respWriter, "ToDo RESTful App")
type Task struct {
ID int
Checked bool `json:"checked"`
TimeAdded time.Time `json:"time_added"`
Deadline time.Time `json:"deadline"`
Task string `json:"task"`
}

func TodoIndex(respWriter http.ResponseWriter, request *http.Request, _ httprouter.Params) {
fmt.Fprintln(respWriter, "Return ToDo List")
}
var (
allTasks []Task
accessTasks = &sync.Mutex{}
)

func TodoShow(respWriter http.ResponseWriter, request *http.Request, params httprouter.Params) {
fmt.Fprintf(respWriter, "Show Details for ToDo '%s'\n", params.ByName("todoId"))
}
const (
timeFormat = time.RFC3339
)

func main() {

// Loading the csv file into the RAM
csvfile, err := os.Open("tasks.csv")
ifPanic(err)

// Loading csv with csv Library returns [][]string
rawCSVdata, err := csv.NewReader(csvfile).ReadAll()
ifPanic(err)

// For each line in csv do....
for i, each := range rawCSVdata {
timeAdded, err := time.Parse(timeFormat, each[2])
ifPanic(err)
deadline, err := time.Parse(timeFormat, each[3])
ifPanic(err)
status := false
if each[1] == "true" {
status = true
}
allTasks = append(allTasks, Task{ID: i, Task: each[4], TimeAdded: timeAdded, Deadline: deadline, Checked: status})
}

// Autosave every minutes
csvfile.Close()

// go func() starts a new process.
go func() {
for {
saveCSV()
time.Sleep(5 * time.Second)
}
}()

// Start the API
router := httprouter.New()
router.GET("/", Index)
router.GET("/todos", TodoIndex)
router.GET("/todos/:todoId", TodoShow)

router.GET("/v1/task", ListTask)
router.POST("/v1/task", AddTask)
//router.PUT("/v1/task", nil)
//router.DELETE("/v1/task", nil)

router.GET("/v1/task/:id", GetTask)
//router.POST("/v1/task/:id", nil)
router.PUT("/v1/task/:id", Modify)
router.DELETE("/v1/task/:id", DeleteTask)

router.GET("/v1/query", SearchTask)

log.Fatal(http.ListenAndServe(":8080", router))
}

// Function to save the CSV
func saveCSV() error {
myString := ""
accessTasks.Lock()
for _, each := range allTasks {
myString += fmt.Sprintf("%v,%v,%v,%v,\"%v\"\n", each.ID, each.Checked, each.TimeAdded.Format(timeFormat), each.Deadline.Format(timeFormat), each.Task)
}
err := ioutil.WriteFile("tasks.csv", []byte(myString), 0644)
accessTasks.Unlock()
return err
}

func ifPanic(err error) {
if err != nil {
// Maybe change to log later
fmt.Println(err)
os.Exit(1)
}
}

func getIndexByTaskID(taskID int) (index int, err error) {
// If we didn't find the task ID - return an error and set the index to -1...
err = errors.New("GetIndexByTaskID: TaskID " + string(taskID) + " Not Found.")
index = -1

accessTasks.Lock()

// Search for the taskID and return the index.
for i, line := range allTasks {
if taskID == line.ID {
index = i
err = nil
break
}
}
accessTasks.Unlock()
return
}
Loading