diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..c415c295634db4b88fa7891a07ce3e6722217f55 --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +## Start + +Start the server: + + # cd src/myaktion && go run main.go + +## Use the REST API + +### Add a campaign + + # curl -H "Content-Type: application/json" -d '{"name":"Covid","organizerName":"Martin","donationMinimum":2,"targetAmount":100,"account":{"name":"Martin","bankName":"DKB","number":"123456"}}' localhost:8000/campaign + +### Get campaign data + +To retrieve all the persisted campaign objects, send this GET request: + + # curl localhost:8000/campaigns + +For retrieving just a specific campaign, append the campaign's ID. E.g. for retrieving the +campaign with ID 1, call: + + # curl localhost:8000/campaigns/1 + +### Delete a campaign + +The following command deletes the campaign with ID 1: + + # curl -X DELETE localhost:8000/campaigns/1 + +### Update a campaign + +The following command updates the campaign with ID 1: + + # curl -X PUT -H "Content-Type: application/json" -d '{"name":"Corona","organizerName":"Marcus","donationMinimum":2,"targetAmount":100}' localhost:8000/campaigns/1 + +### Add a donation to a campaign + +This command adds a donation to the campaign with ID 1: + + # curl -H "Content-Type: application/json" -d '{"Amount":20,"donorName":"Martin","receiptRequested":true,"status":"IN_PROCESS","account":{"name":"Martin","bankName":"DKB","number":"123456"}}' localhost:8000/campaigns/1/donation diff --git a/src/myaktion/handler/campaign.go b/src/myaktion/handler/campaign.go index 9627a21ae8d165af7c2d84114c6a51d308c02214..705a2b93e33d74933e4f9063c483aafc0e33b682 100644 --- a/src/myaktion/handler/campaign.go +++ b/src/myaktion/handler/campaign.go @@ -11,7 +11,7 @@ import ( ) func CreateCampaign(w http.ResponseWriter, r *http.Request) { - campaign, err := GetCampaign(r) + campaign, err := getCampaign(r) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return @@ -34,7 +34,69 @@ func GetCampaigns(w http.ResponseWriter, _ *http.Request) { sendJson(w, campaigns) } -func GetCampaign(r *http.Request) (*model.Campaign, error) { +func GetCampaign(w http.ResponseWriter, r *http.Request) { + id, err := getId(r) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + campaign, err := service.GetCampaign(id) + if err != nil { + log.Errorf("Failure retrieving campaign with ID %v: %v", id, err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if campaign == nil { + http.Error(w, "404 campaign not found", http.StatusNotFound) + return + } + sendJson(w, campaign) +} + +func UpdateCampaign(w http.ResponseWriter, r *http.Request) { + id, err := getId(r) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + campaign, err := getCampaign(r) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + campaign, err = service.UpdateCampaign(id, campaign) + if err != nil { + log.Errorf("Failure updating campaign with ID %v: %v", id, err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if campaign == nil { + http.Error(w, "404 campaign not found", http.StatusNotFound) + return + } + sendJson(w, campaign) +} + +func DeleteCampaign(w http.ResponseWriter, r *http.Request) { + id, err := getId(r) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + campaign, err := service.DeleteCampaign(id) + if err != nil { + log.Errorf("Failure deleting campaign with ID %v: %v", id, err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if campaign == nil { + http.Error(w, "404 campaign not found", http.StatusNotFound) + return + } + sendJson(w, result{Success: "OK"}) +} + +func getCampaign(r *http.Request) (*model.Campaign, error) { var campaign model.Campaign err := json.NewDecoder(r.Body).Decode(&campaign) if err != nil { diff --git a/src/myaktion/handler/donation.go b/src/myaktion/handler/donation.go new file mode 100644 index 0000000000000000000000000000000000000000..081cd4a1af72b54fe41c4be4554637164a8b6ec8 --- /dev/null +++ b/src/myaktion/handler/donation.go @@ -0,0 +1,42 @@ +package handler + +import ( + "encoding/json" + "net/http" + + log "github.com/sirupsen/logrus" + + "gitlab.reutlingen-university.de/go-exercises/myaktion-go/src/myaktion/model" + "gitlab.reutlingen-university.de/go-exercises/myaktion-go/src/myaktion/service" +) + +func AddDonation(w http.ResponseWriter, r *http.Request) { + id, err := getId(r) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + donation, err := getDonation(r) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + // TODO: if the campaign doesn't exist, return 404 - don't show FK error + err = service.AddDonation(id, donation) + if err != nil { + log.Errorf("Failure adding donation to campaign with ID %v: %v", id, err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + sendJson(w, donation) +} + +func getDonation(r *http.Request) (*model.Donation, error) { + var donation model.Donation + err := json.NewDecoder(r.Body).Decode(&donation) + if err != nil { + log.Errorf("Can't serialize request body to donation struct: %v", err) + return nil, err + } + return &donation, nil +} diff --git a/src/myaktion/main.go b/src/myaktion/main.go index 6b34f1d7feb72d1ea1e0c593cd7db55d5482ce65..9d36f99e604dfa5ec2901b88ff20393e46726054 100644 --- a/src/myaktion/main.go +++ b/src/myaktion/main.go @@ -31,6 +31,10 @@ func main() { router.HandleFunc("/health", handler.Health).Methods("GET") router.HandleFunc("/campaign", handler.CreateCampaign).Methods("POST") router.HandleFunc("/campaigns", handler.GetCampaigns).Methods("GET") + router.HandleFunc("/campaigns/{id}", handler.GetCampaign).Methods("GET") + router.HandleFunc("/campaigns/{id}", handler.UpdateCampaign).Methods("PUT") + router.HandleFunc("/campaigns/{id}", handler.DeleteCampaign).Methods("DELETE") + router.HandleFunc("/campaigns/{id}/donation", handler.AddDonation).Methods("POST") if err := http.ListenAndServe(":8000", router); err != nil { log.Fatal(err) } diff --git a/src/myaktion/service/campaign.go b/src/myaktion/service/campaign.go index 3c508034dfff10b770bf6d0ec9696d07b08abe29..33632a8c58f6e3468742c33c58443ee37926fb1c 100644 --- a/src/myaktion/service/campaign.go +++ b/src/myaktion/service/campaign.go @@ -1,7 +1,9 @@ package service import ( - "log" + "fmt" + + log "github.com/sirupsen/logrus" "gitlab.reutlingen-university.de/go-exercises/myaktion-go/src/myaktion/model" ) @@ -31,3 +33,39 @@ func GetCampaigns() ([]model.Campaign, error) { } return campaigns, nil } + +func GetCampaign(id uint) (*model.Campaign, error) { + campaign := campaignStore[id] + if campaign == nil { + return nil, fmt.Errorf("no campaign with ID %d", id) + } + log.Tracef("Retrieved: %v", campaign) + return campaign, nil +} + +func UpdateCampaign(id uint, campaign *model.Campaign) (*model.Campaign, error) { + existingCampaign, err := GetCampaign(id) + if err != nil { + return existingCampaign, err + } + existingCampaign.Name = campaign.Name + existingCampaign.OrganizerName = campaign.OrganizerName + existingCampaign.TargetAmount = campaign.TargetAmount + existingCampaign.DonationMinimum = campaign.DonationMinimum + entry := log.WithField("ID", id) + entry.Info("Successfully updated campaign.") + entry.Tracef("Updated: %v", campaign) + return existingCampaign, nil +} + +func DeleteCampaign(id uint) (*model.Campaign, error) { + campaign, err := GetCampaign(id) + if err != nil { + return campaign, err + } + delete(campaignStore, id) + entry := log.WithField("ID", id) + entry.Info("Successfully deleted campaign.") + entry.Tracef("Deleted: %v", campaign) + return campaign, nil +} diff --git a/src/myaktion/service/donation.go b/src/myaktion/service/donation.go new file mode 100644 index 0000000000000000000000000000000000000000..ccd22a6b8b7ae2488f2602e2f05a70d0bd23afda --- /dev/null +++ b/src/myaktion/service/donation.go @@ -0,0 +1,19 @@ +package service + +import ( + log "github.com/sirupsen/logrus" + + "gitlab.reutlingen-university.de/go-exercises/myaktion-go/src/myaktion/model" +) + +func AddDonation(campaignId uint, donation *model.Donation) error { + campaign, err := GetCampaign(campaignId) + if err != nil { + return err + } + campaign.Donations = append(campaign.Donations, *donation) + entry := log.WithField("ID", campaignId) + entry.Info("Successfully added new donation to campaign.") + entry.Tracef("Stored: %v", donation) + return nil +}