diff --git a/handlers/handlers.go b/handlers/handlers.go
index 6f462c1..c446817 100644
--- a/handlers/handlers.go
+++ b/handlers/handlers.go
@@ -90,7 +90,7 @@ func (h *Handler) setHandlers() error {
protected := h.engine.Group("/api/v1/protected")
protected.Use(h.authMiddleware)
protected.POST("/create", h.handleCreate)
- protected.POST("/info", h.handleInfo)
+ protected.POST("/lookup", h.handleLookup)
h.engine.NoRoute(h.handleAccess, gin.WrapH(http.FileServer(FS(false))))
return nil
diff --git a/handlers/public.go b/handlers/public.go
index 8e53a3a..7274e57 100644
--- a/handlers/public.go
+++ b/handlers/public.go
@@ -13,8 +13,8 @@ type URLUtil struct {
URL string `binding:"required"`
}
-// handleInfo is the http handler for getting the infos
-func (h *Handler) handleInfo(c *gin.Context) {
+// handleLookup is the http handler for getting the infos
+func (h *Handler) handleLookup(c *gin.Context) {
var data struct {
ID string `binding:"required"`
}
@@ -30,11 +30,13 @@ func (h *Handler) handleInfo(c *gin.Context) {
user := c.MustGet("user").(*jwtClaims)
if entry.OAuthID != user.OAuthID || entry.OAuthProvider != user.OAuthProvider {
c.JSON(http.StatusOK, store.Entry{
- URL: entry.URL,
+ Public: store.EntryPublicData{
+ URL: entry.Public.URL,
+ },
})
return
}
- c.JSON(http.StatusOK, entry)
+ c.JSON(http.StatusOK, entry.Public)
}
// handleAccess handles the access for incoming requests
@@ -54,7 +56,7 @@ func (h *Handler) handleAccess(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
- c.Redirect(http.StatusTemporaryRedirect, entry.URL)
+ c.Redirect(http.StatusTemporaryRedirect, entry.Public.URL)
}
// handleCreate handles requests to create an entry
@@ -66,7 +68,9 @@ func (h *Handler) handleCreate(c *gin.Context) {
}
user := c.MustGet("user").(*jwtClaims)
id, err := h.store.CreateEntry(store.Entry{
- URL: data.URL,
+ Public: store.EntryPublicData{
+ URL: data.URL,
+ },
RemoteAddr: c.ClientIP(),
OAuthProvider: user.OAuthProvider,
OAuthID: user.OAuthID,
diff --git a/handlers/public_test.go b/handlers/public_test.go
index 5daf02c..6138e2d 100644
--- a/handlers/public_test.go
+++ b/handlers/public_test.go
@@ -90,8 +90,8 @@ func TestCreateEntry(t *testing.T) {
func TestHandleInfo(t *testing.T) {
t.Run("check existing entry", func(t *testing.T) {
- reqBody, err := json.Marshal(store.Entry{
- URL: testURL,
+ reqBody, err := json.Marshal(gin.H{
+ "URL": testURL,
})
if err != nil {
t.Fatalf("could not marshal json: %v", err)
@@ -109,7 +109,7 @@ func TestHandleInfo(t *testing.T) {
if err != nil {
t.Fatalf("could not marshal the body: %v", err)
}
- req, err := http.NewRequest("POST", server.URL+"/api/v1/protected/info", bytes.NewBuffer(body))
+ req, err := http.NewRequest("POST", server.URL+"/api/v1/protected/lookup", bytes.NewBuffer(body))
if err != nil {
t.Fatalf("could not create request %v", err)
}
@@ -122,7 +122,7 @@ func TestHandleInfo(t *testing.T) {
if resp.StatusCode != http.StatusOK {
t.Errorf("expected status %d; got %d", http.StatusOK, resp.StatusCode)
}
- var entry store.Entry
+ var entry store.EntryPublicData
if err = json.NewDecoder(resp.Body).Decode(&entry); err != nil {
t.Fatalf("could not unmarshal data: %v", err)
}
@@ -131,7 +131,7 @@ func TestHandleInfo(t *testing.T) {
}
})
t.Run("invalid body", func(t *testing.T) {
- req, err := http.NewRequest("POST", server.URL+"/api/v1/protected/info", bytes.NewBuffer(nil))
+ req, err := http.NewRequest("POST", server.URL+"/api/v1/protected/lookup", bytes.NewBuffer(nil))
if err != nil {
t.Fatalf("could not create request %v", err)
}
@@ -157,7 +157,7 @@ func TestHandleInfo(t *testing.T) {
}
})
t.Run("no ID provided", func(t *testing.T) {
- req, err := http.NewRequest("POST", server.URL+"/api/v1/protected/info", bytes.NewBufferString("{}"))
+ req, err := http.NewRequest("POST", server.URL+"/api/v1/protected/lookup", bytes.NewBufferString("{}"))
if err != nil {
t.Fatalf("could not create request %v", err)
}
diff --git a/static/src/Card/Card.js b/static/src/Card/Card.js
new file mode 100644
index 0000000..d2d3572
--- /dev/null
+++ b/static/src/Card/Card.js
@@ -0,0 +1,41 @@
+import React, { Component } from 'react'
+import { Card, Icon, Button, Modal } from 'semantic-ui-react'
+import { QRCode } from 'react-qr-svg';
+import Clipboard from 'react-clipboard.js';
+
+export default class CardComponent extends Component {
+ render() {
+ return (
+
+
+ {this.props.header}
+
+
+ {this.props.metaHeader}
+
+
+ {this.props.description}
+
+
+
+ {!this.props.showInfoURL ?
+
}>
+
{this.props.description}
+
+
+
+
+
+
+
+ Copy to Clipboard
+
+
+
:
+
+
+
}
+
+ )
+ }
+};
\ No newline at end of file
diff --git a/static/src/Home/Home.js b/static/src/Home/Home.js
index 0f31ef0..a1cc9f6 100644
--- a/static/src/Home/Home.js
+++ b/static/src/Home/Home.js
@@ -1,7 +1,7 @@
import React, { Component } from 'react'
-import { Input, Segment, Form, Header, Card, Icon, Image, Button, Modal } from 'semantic-ui-react'
-import { QRCode } from 'react-qr-svg';
-import Clipboard from 'react-clipboard.js';
+import { Input, Segment, Form, Header, Card } from 'semantic-ui-react'
+
+import CustomCard from '../Card/Card'
export default class HomeComponent extends Component {
handleURLChange = (e, { value }) => this.url = value
@@ -43,33 +43,7 @@ export default class HomeComponent extends Component {
- {links.map((link, i) =>
-
-
- {new URL(link[1]).hostname}
-
-
- {link[1]}
-
-
- {link[0]}
-
-
-
-
- }>
- {link[0]}
-
-
-
-
-
-
- Copy to Clipboard
-
-
-
- )}
+ {links.map((link, i) => )}
)
diff --git a/static/src/Lookup/Lookup.js b/static/src/Lookup/Lookup.js
index 50a033f..6366e7f 100644
--- a/static/src/Lookup/Lookup.js
+++ b/static/src/Lookup/Lookup.js
@@ -1,17 +1,51 @@
import React, { Component } from 'react'
-import { Segment, Header, Form, Input } from 'semantic-ui-react'
+import { Segment, Header, Form, Input, Card } from 'semantic-ui-react'
+
+import CustomCard from '../Card/Card'
export default class LookupComponent extends Component {
+ state = {
+ links: []
+ }
+ handleURLChange = (e, { value }) => this.url = value
+ handleURLSubmit = () => {
+ let id = this.url.replace(window.location.origin + "/", "")
+ fetch("/api/v1/protected/lookup", {
+ method: "POST",
+ body: JSON.stringify({
+ ID: id
+ }),
+ headers: {
+ 'Authorization': window.localStorage.getItem('token'),
+ 'Content-Type': 'application/json'
+ }
+ }).then(res => res.ok ? res.json() : Promise.reject(res.json()))
+ .then(res => this.setState({
+ links: [...this.state.links, [
+ res.URL,
+ this.url,
+ this.VisitCount,
+ res.CratedOn,
+ res.LastVisit
+ ]]
+ }))
+ }
render() {
+ const { links } = this.state
return (
-
-
-
- this.urlInput = input} action={{ icon: 'arrow right', labelPosition: 'right', content: 'Lookup' }} type='url' onChange={this.handleURLChange} name='url' placeholder={window.location.origin+"/..."} />
-
-
-
+
+
+
+
+ this.urlInput = input} action={{ icon: 'arrow right', labelPosition: 'right', content: 'Lookup' }} type='url' onChange={this.handleURLChange} name='url' placeholder={window.location.origin + "/..."} />
+
+
+
+
+ {links.map((link, i) => )}
+
+
)
}
};
diff --git a/store/store.go b/store/store.go
index b353867..127a2c7 100644
--- a/store/store.go
+++ b/store/store.go
@@ -23,10 +23,15 @@ type Store struct {
// Entry is the data set which is stored in the DB as JSON
type Entry struct {
- URL, OAuthProvider, OAuthID string
- VisitCount int
- RemoteAddr string `json:",omitempty"`
- CreatedOn, LastVisit time.Time
+ OAuthProvider, OAuthID string
+ RemoteAddr string `json:",omitempty"`
+ Public EntryPublicData
+}
+
+type EntryPublicData struct {
+ CreatedOn, LastVisit time.Time
+ VisitCount int
+ URL string
}
// ErrNoEntryFound is returned when no entry to a id is found
@@ -82,8 +87,8 @@ func (s *Store) IncreaseVisitCounter(id string) error {
if err != nil {
return errors.Wrap(err, "could not get entry by ID")
}
- entry.VisitCount++
- entry.LastVisit = time.Now()
+ entry.Public.VisitCount++
+ entry.Public.LastVisit = time.Now()
raw, err := json.Marshal(entry)
if err != nil {
return err
@@ -112,7 +117,7 @@ func (s *Store) GetEntryByIDRaw(id string) ([]byte, error) {
// CreateEntry creates a new record and returns his short id
func (s *Store) CreateEntry(entry Entry) (string, error) {
- if !govalidator.IsURL(entry.URL) {
+ if !govalidator.IsURL(entry.Public.URL) {
return "", ErrNoValidURL
}
// try it 10 times to make a short URL
diff --git a/store/store_test.go b/store/store_test.go
index f158c50..8868333 100644
--- a/store/store_test.go
+++ b/store/store_test.go
@@ -74,7 +74,11 @@ func TestCreateEntry(t *testing.T) {
t.Fatalf("unexpected error: %v", err)
}
for i := 1; i <= 100; i++ {
- _, err := store.CreateEntry(Entry{URL: "https://golang.org/"})
+ _, err := store.CreateEntry(Entry{
+ Public: EntryPublicData{
+ URL: "https://golang.org/",
+ },
+ })
if err != nil && err != ErrGeneratingIDFailed {
t.Fatalf("unexpected error during creating entry: %v", err)
}
@@ -103,7 +107,11 @@ func TestIncreaseVisitCounter(t *testing.T) {
t.Fatalf("could not create store: %v", err)
}
defer cleanup(store)
- id, err := store.CreateEntry(Entry{URL: "https://golang.org/"})
+ id, err := store.CreateEntry(Entry{
+ Public: EntryPublicData{
+ URL: "https://golang.org/",
+ },
+ })
if err != nil {
t.Fatalf("could not create entry: %v", err)
}
@@ -118,7 +126,7 @@ func TestIncreaseVisitCounter(t *testing.T) {
if err != nil {
t.Fatalf("could not get entry by id: %v", err)
}
- if entryBeforeInc.VisitCount+1 != entryAfterInc.VisitCount {
+ if entryBeforeInc.Public.VisitCount+1 != entryAfterInc.Public.VisitCount {
t.Fatalf("the increasement was not successful, the visit count is not correct")
}
errIDIsEmpty := "could not get entry by ID: the given ID is empty"
diff --git a/store/util.go b/store/util.go
index b2daa4b..949285a 100644
--- a/store/util.go
+++ b/store/util.go
@@ -33,7 +33,7 @@ func (s *Store) createEntry(entry Entry) (string, error) {
if err != nil {
return "", errors.Wrap(err, "could not generate random string")
}
- entry.CreatedOn = time.Now()
+ entry.Public.CreatedOn = time.Now()
raw, err := json.Marshal(entry)
if err != nil {
return "", err