Skip to content

Commit a1d2954

Browse files
committed
Added title for message and make UI better
1 parent 433476f commit a1d2954

18 files changed

Lines changed: 343 additions & 158 deletions

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Micri Message
22

3-
This application is for operating messages based on rest api with simple user authentification, registration and login. It is easy to deploy application on aws with only 2 steps.
3+
This application is for operating messages based on rest api with simple user authentication, registration and login. It is easy to deploy application on aws with only 2 steps.
44

55
## Getting Started
66

@@ -71,7 +71,7 @@ curl -X DELETE -H "Accept: application/json" http://<public-dns>/messages/<:mess
7171
```
7272
* You can create a new message by running:
7373
```
74-
curl -X POST -H "Accept: application/json" http://<public-dns>/messages/create?content=<your-message>
74+
curl -X POST -d "title=8&content=8" -H "Accept: application/json" http://<public-dns>/messages/create
7575
```
7676

7777
Also you can absolutely interact with application through UI!

database/setup.sql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
--create zplatform or zrpe database
1+
-- create micro-message database
22
\echo 'Installing micro-message database!'
33

44
alter user postgres password 'PG_ROOT_PASSWORD';
@@ -32,7 +32,8 @@ ALTER ROLE PG_USER SET search_path = PG_USER;
3232

3333
\c PG_DATABASE PG_USER;
3434
create table message (
35-
id SERIAL PRIMARY KEY,
35+
id SERIAL PRIMARY KEY,
36+
title varchar,
3637
content text,
3738
palindrome boolean
3839
);
@@ -44,4 +45,3 @@ create table users (
4445
email varchar
4546
);
4647

47-

handlers/authHandler_test.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package handlers
2+
3+
import (
4+
"net/http"
5+
"net/http/httptest"
6+
"testing"
7+
8+
"github.com/gin-gonic/gin"
9+
)
10+
11+
//TestEnsursLoggedIn tests EnsureLoggedIn function
12+
func TestEnsureLoggedIn(t *testing.T) {
13+
testCases := map[string]struct {
14+
loggedIn bool
15+
code int
16+
}{
17+
"Test function EnsureLoggedIn without authentication": {
18+
false,
19+
http.StatusUnauthorized,
20+
},
21+
"Test function EnsureLoggedIn with authentication": {
22+
true,
23+
http.StatusOK,
24+
},
25+
}
26+
27+
for caseName, testCase := range testCases {
28+
t.Run(caseName, func(t *testing.T) {
29+
r := getRouter(false)
30+
r.GET("/", setLogIn(testCase.loggedIn), EnsureLoggedIn(), func(c *gin.Context) {
31+
c.Status(http.StatusOK)
32+
})
33+
testAuthHandler(t, r, testCase.code)
34+
})
35+
}
36+
}
37+
38+
//TestEnsursNotLoggedIn tests EnsureNotLoggedIn function
39+
func TestEnsureNotLoggedIn(t *testing.T) {
40+
testCases := map[string]struct {
41+
loggedIn bool
42+
code int
43+
}{
44+
"Test function EnsursNotLoggedIn without authentication": {
45+
false,
46+
http.StatusOK,
47+
},
48+
"Test function EnsursNotLoggedIn with authentication": {
49+
true,
50+
http.StatusUnauthorized,
51+
},
52+
}
53+
54+
for caseName, testCase := range testCases {
55+
t.Run(caseName, func(t *testing.T) {
56+
r := getRouter(false)
57+
r.GET("/", setLogIn(testCase.loggedIn), EnsureNotLoggedIn(), func(c *gin.Context) {
58+
c.Status(http.StatusOK)
59+
})
60+
testAuthHandler(t, r, testCase.code)
61+
})
62+
}
63+
}
64+
65+
func TestSetUserStatusAuthenticated(t *testing.T) {
66+
r := getRouter(false)
67+
r.GET("/", SetUserStatus(), func(c *gin.Context) {
68+
loggedInInterface, exists := c.Get("is_logged_in")
69+
if !exists || !loggedInInterface.(bool) {
70+
t.Fail()
71+
}
72+
})
73+
74+
w := httptest.NewRecorder()
75+
76+
http.SetCookie(w, &http.Cookie{Name: "token", Value: "123"})
77+
78+
req, _ := http.NewRequest("GET", "/", nil)
79+
req.Header = http.Header{"Cookie": w.HeaderMap["Set-Cookie"]}
80+
81+
r.ServeHTTP(w, req)
82+
}
83+
84+
func setLogIn(loggedIn bool) gin.HandlerFunc {
85+
return func(c *gin.Context) {
86+
c.Set("is_logged_in", loggedIn)
87+
}
88+
}

handlers/helpers_test.go

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ func getRouter(withTemplates bool) *gin.Engine {
2727
r := gin.Default()
2828
if withTemplates {
2929
r.LoadHTMLGlob("../templates/*")
30+
r.Use(SetUserStatus())
3031
}
3132
return r
3233
}
@@ -36,7 +37,6 @@ func testHTTPResponse(t *testing.T, r *gin.Engine, req *http.Request, f func(w *
3637

3738
// Create a response recorder
3839
w := httptest.NewRecorder()
39-
4040
// Create the service and process the above request.
4141
r.ServeHTTP(w, req)
4242

@@ -46,12 +46,12 @@ func testHTTPResponse(t *testing.T, r *gin.Engine, req *http.Request, f func(w *
4646
}
4747

4848
func getLoginUser() string {
49-
params := url.Values{}
50-
params.Add("username", "user1")
51-
params.Add("password", "pass1")
52-
params.Add("email", "user1@qlik.com")
49+
params := url.Values{}
50+
params.Add("username", "user1")
51+
params.Add("password", "pass1")
52+
params.Add("email", "user1@qlik.com")
5353

54-
return params.Encode()
54+
return params.Encode()
5555
}
5656

5757
func getRegistrationUser() string {
@@ -62,8 +62,24 @@ func getRegistrationUser() string {
6262
return param.Encode()
6363
}
6464

65+
func getNewMessage() string {
66+
param := url.Values{}
67+
param.Add("title", "test")
68+
param.Add("content", "test123")
69+
70+
return param.Encode()
71+
}
72+
6573
func getDeleteMessage() string {
66-
param := url.Values{}
67-
param.Add("messageid", "1")
68-
return param.Encode()
74+
param := url.Values{}
75+
param.Add("messageid", "1")
76+
return param.Encode()
77+
}
78+
79+
func testAuthHandler(t *testing.T, r *gin.Engine, expectedCode int) {
80+
req, _ := http.NewRequest("GET", "/", nil)
81+
82+
testHTTPResponse(t, r, req, func(w *httptest.ResponseRecorder) bool {
83+
return w.Code == expectedCode
84+
})
6985
}

handlers/messageHandler.go

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,46 +12,44 @@ import (
1212

1313
//ShowIndexPage shows index page and message list inside it
1414
func ShowIndexPage(c *gin.Context) {
15-
messages, _ := store.GetAllMessages()
1615
isLoggedIn, _ := c.Get("is_logged_in")
1716
//fresh index page according to the values
1817
render(c, gin.H{
1918
"is_logged_in": isLoggedIn,
20-
"title": "Welcome to Micro Message!",
21-
"payload": messages}, "index.html")
19+
"title": "Welcome to Micro Message!"}, "index.html")
2220
}
2321

2422
//ShowCreatePage shows create message page
2523
func ShowCreatePage(c *gin.Context) {
26-
isLoggedIn, _ := c.Get("is_logged_in")
24+
isLoggedIn, _ := c.Get("is_logged_in")
2725
render(c, gin.H{
28-
"is_logged_in": isLoggedIn,
29-
"title": "Create Message"}, "create-message.html")
26+
"is_logged_in": isLoggedIn,
27+
"title": "Create Message"}, "create-message.html")
3028
}
3129

3230
//GetMessages shows list of messages and
3331
func GetMessages(c *gin.Context) {
34-
isLoggedIn, _ := c.Get("is_logged_in")
32+
isLoggedIn, _ := c.Get("is_logged_in")
3533
if messages, err := store.GetAllMessages(); err == nil {
3634
render(c, gin.H{
37-
"is_logged_in": isLoggedIn,
38-
"title": "Message List",
39-
"payload": messages}, "messages.html")
35+
"is_logged_in": isLoggedIn,
36+
"title": "Message List",
37+
"payload": messages}, "messages.html")
4038
} else {
4139
c.AbortWithStatus(http.StatusNotFound)
4240
}
4341
}
4442

4543
//GetMessage get message based on message id
4644
func GetMessage(c *gin.Context) {
47-
isLoggedIn, _ := c.Get("is_logged_in")
45+
isLoggedIn, _ := c.Get("is_logged_in")
4846
//convert parameter value from string to integer
4947
if messageId, err := strconv.Atoi(c.Param("messageid")); err == nil {
5048
if message, err := store.GetMessageByID(messageId); err == nil {
5149
render(c, gin.H{
52-
"is_logged_in": isLoggedIn,
53-
"id": message.ID,
54-
"payload": message}, "message.html")
50+
"is_logged_in": isLoggedIn,
51+
"id": message.ID,
52+
"payload": message}, "message.html")
5553
} else {
5654
//if message not found
5755
c.AbortWithError(http.StatusNotFound, err)
@@ -63,14 +61,15 @@ func GetMessage(c *gin.Context) {
6361

6462
//CreateMessage ceates a new message
6563
func CreateMessage(c *gin.Context) {
66-
isLoggedIn, _ := c.Get("is_logged_in")
67-
// Obtain the POSTed content values
64+
isLoggedIn, _ := c.Get("is_logged_in")
65+
// Obtain the POSTed title, content values
66+
title := c.PostForm("title")
6867
content := c.PostForm("content")
69-
if id, err := store.CreateMessage(content); err == nil {
68+
if id, err := store.CreateMessage(title, content); err == nil || id != 0 {
7069
render(c, gin.H{
71-
"is_logged_in": isLoggedIn,
72-
"title": "Submission Successful",
73-
"id": id}, "submission.html")
70+
"is_logged_in": isLoggedIn,
71+
"title": "Submission Successful",
72+
"id": id}, "submission.html")
7473
} else {
7574
c.AbortWithError(http.StatusInternalServerError, errors.New("Failed to create message"))
7675
}
@@ -81,7 +80,7 @@ func DeleteMessage(c *gin.Context) {
8180
if messageId, err := strconv.Atoi(c.Param("messageid")); err == nil {
8281
if err := store.DeleteMessage(messageId); err == nil {
8382
render(c, gin.H{
84-
"title": "Successfully deleted message"}, "delete-successful.html")
83+
"title": "Successfully deleted message"}, "delete-successful.html")
8584
} else {
8685
c.AbortWithError(http.StatusNoContent, fmt.Errorf("Not find corresponding message based in id %d", messageId))
8786
}
@@ -94,10 +93,16 @@ func DeleteMessage(c *gin.Context) {
9493
// If the header doesn't specify this, HTML is rendered, provided that
9594
// the template name is present
9695
func render(c *gin.Context, data gin.H, templateName string) {
96+
loggedInInterface, _ := c.Get("is_logged_in")
97+
data["is_logged_in"] = loggedInInterface.(bool)
98+
9799
switch c.Request.Header.Get("Accept") {
98100
case "application/json":
99101
// Respond with JSON
100102
c.JSON(http.StatusOK, data["payload"])
103+
if data["id"] != "" {
104+
c.JSON(http.StatusOK, data["id"])
105+
}
101106
case "application/xml":
102107
// Respond with XML
103108
c.XML(http.StatusOK, data["payload"])

handlers/messageHandlers_test.go

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"io/ioutil"
55
"net/http"
66
"net/http/httptest"
7+
"strconv"
78
"strings"
89
"testing"
910
)
@@ -30,31 +31,47 @@ func TestShowIndexPageUnauthenticated(t *testing.T) {
3031
}
3132

3233
func TestShowCreatePage(t *testing.T) {
33-
r := getRouter(true)
34-
r.GET("/messages/create", ShowCreatePage)
35-
36-
req, _ := http.NewRequest("GET", "/messages/create", nil)
37-
testHTTPResponse(t, r, req, func(w *httptest.ResponseRecorder) bool {
38-
statusOK := w.Code == http.StatusOK
39-
40-
p, err := ioutil.ReadAll(w.Body)
41-
pageOK := err == nil && strings.Index(string(p), "<title>Create Message</title>") > 0
42-
43-
return statusOK && pageOK
44-
})
34+
r := getRouter(true)
35+
r.GET("/messages/create", ShowCreatePage)
36+
37+
req, _ := http.NewRequest("GET", "/messages/create", nil)
38+
testHTTPResponse(t, r, req, func(w *httptest.ResponseRecorder) bool {
39+
statusOK := w.Code == http.StatusOK
40+
41+
p, err := ioutil.ReadAll(w.Body)
42+
pageOK := err == nil && strings.Index(string(p), "<title>Create Message</title>") > 0
43+
44+
return statusOK && pageOK
45+
})
4546
}
4647

4748
func TestGetMessages(t *testing.T) {
48-
r := getRouter(true)
49-
r.GET("/messages", GetMessages)
50-
51-
req, _ := http.NewRequest("GET", "/messages", nil)
52-
testHTTPResponse(t, r, req, func(w *httptest.ResponseRecorder) bool {
53-
statusOK := w.Code == http.StatusOK
54-
55-
p, err := ioutil.ReadAll(w.Body)
56-
pageOK := err == nil && strings.Index(string(p), "<title>Message List</title>") > 0
57-
58-
return statusOK && pageOK
59-
})
49+
r := getRouter(true)
50+
r.GET("/messages", GetMessages)
51+
52+
req, _ := http.NewRequest("GET", "/messages", nil)
53+
testHTTPResponse(t, r, req, func(w *httptest.ResponseRecorder) bool {
54+
statusOK := w.Code == http.StatusOK
55+
56+
p, err := ioutil.ReadAll(w.Body)
57+
pageOK := err == nil && strings.Index(string(p), "<title>Message List</title>") > 0
58+
59+
return statusOK && pageOK
60+
})
61+
}
62+
63+
func TestCreateMessage(t *testing.T) {
64+
w := httptest.NewRecorder()
65+
r := getRouter(true)
66+
r.GET("/mesages/create", CreateMessage)
67+
68+
newMessage := getNewMessage()
69+
req, err := http.NewRequest("POST", "/messages/create", strings.NewReader(newMessage))
70+
if err != nil {
71+
t.Fail()
72+
}
73+
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
74+
req.Header.Add("Content-Length", strconv.Itoa(len(newMessage)))
75+
76+
r.ServeHTTP(w, req)
6077
}

0 commit comments

Comments
 (0)