diff --git a/.travis.yml b/.travis.yml index 4be6d7f..376243c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,4 +17,7 @@ deploy: user: maxibanki file: "descriptor.json" key: - secure: ErqvSFIlL3d9XuMj+T+hO6xZqll8Ubx0DEdHD6NJKi7sH7Be3b3/vUoPdAjdFOP70DhaccbncGCTPZ9hsNKdqYxZmuKx3WWwH4H4U5YdDIViXtH6+B5KdAmvdZIynaj+THQAbVAhr+QyvcqotNySPd3Ac1HCg2YAcUHme6y3FsiRJ79To80JWxTSR1G/oObmeoDn8R18wmH1gHl8KQ7ltC537Osb/H34bJ/hY94hRe8IEmoQE4yz/EP44kGXRb/F87i92y1mO081ZS1I1hs5Kbom43YoItqSVbJP/abPMyCsGDv2FGXaGqk5IVC1k+01pcAjqxCzMvXC272itc0E8OEWqE4qONN+m2S9tyALyOaUZ7j5meWLHQj49Rzo7XIWh1PvvEMovdl/wk/Oc9f0ZywPuvoRht5ZebgXbPWAMMNywwy0GKM4nU0DCyFm23mlzPh4iklo12gEUzq3YLc18RhAZuy4timeevrDCuJMQeQ3sqcQBKCQ+rdOxzVCKKl2sGpNaTJEYaHGT9KLCEGBLmvaB58RKgmGN6IIEwpxSm2SGoirfnQsr+DP+kaSvWPr6R/pZAhO1JzO+azaXvfr+hL2SMX6U7j5+SDmFGIFDwxok7ny1QUTQXKlNzA/ks9/vufe30hrTkph/MfEvM5mYVbfgAn5zZ0v+dJ2wCoe1go= \ No newline at end of file + secure: ErqvSFIlL3d9XuMj+T+hO6xZqll8Ubx0DEdHD6NJKi7sH7Be3b3/vUoPdAjdFOP70DhaccbncGCTPZ9hsNKdqYxZmuKx3WWwH4H4U5YdDIViXtH6+B5KdAmvdZIynaj+THQAbVAhr+QyvcqotNySPd3Ac1HCg2YAcUHme6y3FsiRJ79To80JWxTSR1G/oObmeoDn8R18wmH1gHl8KQ7ltC537Osb/H34bJ/hY94hRe8IEmoQE4yz/EP44kGXRb/F87i92y1mO081ZS1I1hs5Kbom43YoItqSVbJP/abPMyCsGDv2FGXaGqk5IVC1k+01pcAjqxCzMvXC272itc0E8OEWqE4qONN+m2S9tyALyOaUZ7j5meWLHQj49Rzo7XIWh1PvvEMovdl/wk/Oc9f0ZywPuvoRht5ZebgXbPWAMMNywwy0GKM4nU0DCyFm23mlzPh4iklo12gEUzq3YLc18RhAZuy4timeevrDCuJMQeQ3sqcQBKCQ+rdOxzVCKKl2sGpNaTJEYaHGT9KLCEGBLmvaB58RKgmGN6IIEwpxSm2SGoirfnQsr+DP+kaSvWPr6R/pZAhO1JzO+azaXvfr+hL2SMX6U7j5+SDmFGIFDwxok7ny1QUTQXKlNzA/ks9/vufe30hrTkph/MfEvM5mYVbfgAn5zZ0v+dJ2wCoe1go= +notifications: + webhooks: + - https://ws.b0n.pl/relaunch \ No newline at end of file diff --git a/handlers/public.go b/handlers/public.go index 7274e57..2fa90b4 100644 --- a/handlers/public.go +++ b/handlers/public.go @@ -11,6 +11,7 @@ import ( // un- and marshalling type URLUtil struct { URL string `binding:"required"` + ID string } // handleLookup is the http handler for getting the infos @@ -74,7 +75,7 @@ func (h *Handler) handleCreate(c *gin.Context) { RemoteAddr: c.ClientIP(), OAuthProvider: user.OAuthProvider, OAuthID: user.OAuthID, - }) + }, data.ID) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return diff --git a/static/src/Home/Home.js b/static/src/Home/Home.js index a1cc9f6..d3c18a0 100644 --- a/static/src/Home/Home.js +++ b/static/src/Home/Home.js @@ -1,45 +1,83 @@ import React, { Component } from 'react' -import { Input, Segment, Form, Header, Card } from 'semantic-ui-react' +import { Input, Segment, Form, Header, Card, Button, Select, Icon } from 'semantic-ui-react' import CustomCard from '../Card/Card' export default class HomeComponent extends Component { handleURLChange = (e, { value }) => this.url = value - state = { - links: [] - } - componentDidMount() { - this.urlInput.focus() - } - handleURLSubmit = () => { - fetch('/api/v1/protected/create', { - method: 'POST', + handleCustomIDChange = (e, { value }) => { + this.customID = value + fetch("/api/v1/protected/lookup", { + method: "POST", body: JSON.stringify({ - URL: this.url + ID: value }), headers: { 'Authorization': window.localStorage.getItem('token'), 'Content-Type': 'application/json' } }).then(res => res.ok ? res.json() : Promise.reject(res.json())) - .then(r => this.setState({ - links: [...this.state.links, [ - r.URL, - this.url - ]] - })) + .then(() => { + this.setState({ showCustomIDError: true }) + }) + .catch(() => this.setState({ showCustomIDError: false })) + } + onSettingsChange = (e, { value }) => this.setState({ setOptions: value }) + + state = { + links: [], + options: [ + { text: 'Custom URL', value: 'custom' }, + { text: 'Expiration', value: 'expire' } + ], + setOptions: [], + showCustomIDError: false + } + componentDidMount() { + this.urlInput.focus() + } + handleURLSubmit = () => { + if (!this.state.showCustomIDError) { + fetch('/api/v1/protected/create', { + method: 'POST', + body: JSON.stringify({ + URL: this.url, + ID: this.customID + }), + headers: { + 'Authorization': window.localStorage.getItem('token'), + 'Content-Type': 'application/json' + } + }).then(res => res.ok ? res.json() : Promise.reject(res.json())) + .then(r => this.setState({ + links: [...this.state.links, [ + r.URL, + this.url + ]] + })) + } } render() { - const { links } = this.state + const { links, options, setOptions, showCustomIDError } = this.state return (
Simplify your links
- this.urlInput = input} action={{ icon: 'arrow right', labelPosition: 'right', content: 'Shorten' }} type='url' onChange={this.handleURLChange} name='url' placeholder='Paste a link to shorten it' /> + this.urlInput = input} onChange={this.handleURLChange} placeholder='Paste a link to shorten it' action> + + + + } + +
diff --git a/store/store.go b/store/store.go index 127a2c7..aaa6fce 100644 --- a/store/store.go +++ b/store/store.go @@ -116,14 +116,16 @@ 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) { +func (s *Store) CreateEntry(entry Entry, givenID string) (string, error) { if !govalidator.IsURL(entry.Public.URL) { return "", ErrNoValidURL } // try it 10 times to make a short URL for i := 1; i <= 10; i++ { - id, err := s.createEntry(entry) - if err != nil { + id, err := s.createEntry(entry, givenID) + if err != nil && givenID != "" { + return "", err + } else if err != nil { s.log.Debugf("Could not create entry: %v", err) continue } diff --git a/store/util.go b/store/util.go index 949285a..060361c 100644 --- a/store/util.go +++ b/store/util.go @@ -17,7 +17,7 @@ func (s *Store) createEntryRaw(key, value []byte) error { bucket := tx.Bucket(s.bucketName) raw := bucket.Get(key) if raw != nil { - return errors.New("entry value is not empty") + return errors.New("entry already exists") } if err := bucket.Put(key, value); err != nil { return errors.Wrap(err, "could not put data into bucket") @@ -28,10 +28,16 @@ func (s *Store) createEntryRaw(key, value []byte) error { } // createEntry creates a new entry -func (s *Store) createEntry(entry Entry) (string, error) { - id, err := generateRandomString(s.idLength) - if err != nil { - return "", errors.Wrap(err, "could not generate random string") +func (s *Store) createEntry(entry Entry, givenID string) (string, error) { + var id string + var err error + if givenID != "" { + id = givenID + } else { + id, err = generateRandomString(s.idLength) + if err != nil { + return "", errors.Wrap(err, "could not generate random string") + } } entry.Public.CreatedOn = time.Now() raw, err := json.Marshal(entry)