diff --git a/README.md b/README.md
index b1d5c72..834a3af 100644
--- a/README.md
+++ b/README.md
@@ -90,16 +90,6 @@ location ~* "^/[0-9a-z!?@_-]{1,99}$" {
proxy_set_header X-Real-IP $remote_addr;
rewrite ^/(.*)$ https://my-api-url.com/api/item/$1 redirect;
}
-location /status/ {
- auth_basic "Administrator Login";
- auth_basic_user_file /etc/nginx/.htpasswd;
- proxy_pass http://127.0.0.1:7000/status;
- proxy_set_header x-real-ip $remote_addr;
- # Upgrade for Websockets
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection "upgrade";
-}
location /socket.io {
proxy_pass http://127.0.0.1:7000;
proxy_set_header x-real-ip $remote_addr;
@@ -127,7 +117,13 @@ By default, the Yo backend API is open which would allow anyone who knew your AP
- Before leaving Auth0, create a user account for your application under User & Roles.
- When starting the Yo client, pass `REACT_APP_AUTH=true` as an ENV variable to enforce user logins.
- When starting the Yo server, pass `AUTH=true` as an ENV variable to enable authentication checks.
-- Navigate to Yo and login with the previously created user. If successful, you should be logged into the dashboard successfully.
+- Navigate to Yo and login with the previously created user. If successful, you should be logged into the dashboard successfully.
+
+By default, sign-ups via the Auth0 UI are disabled. If you would like to allow user-signup however, you can force this on by passing `REACT_APP_SIGNUPS=true` during Yo client startup.
+
+## Extras
+- If you're using PM2 to manage your node processes, you can use the included `yo-pm2.yaml` to start and deploy the app.
+- Yo can also be deployed via Docker using the included `docker-compose.yaml` file. Enter the Yo root directory and run `docker-compose up` to deploy the Yo client, backend and
## ☑ TODO
@@ -135,10 +131,11 @@ By default, the Yo backend API is open which would allow anyone who knew your AP
- [x] Client Dockerfile
- [x] Server Dockerfile
- [x] API Authentication
-- [ ] Better Error Handling when Navigating to Unset Names
+- [x] Edit/Delete Functionality
+- [ ] Build and Deploy App
+- [ ] Better Error Handling when Navigating to Unset Links
- [ ] Pass through for Query Parameters
- [ ] Swipeable Tabs
-- [ ] Edit/Delete Functionality
- [ ] Further refactor Home.js
## Contributers
diff --git a/client/package.json b/client/package.json
index 64d67f8..aaeffbf 100644
--- a/client/package.json
+++ b/client/package.json
@@ -21,6 +21,7 @@
"moment": "^2.24.0",
"querystringify": "^2.1.1",
"react": "^16.8.6",
+ "react-bootstrap-sweetalert": "^4.4.1",
"react-copy-to-clipboard": "^5.0.1",
"react-dom": "^16.8.6",
"react-router-dom": "^5.0.0",
diff --git a/client/src/components/home/Home.js b/client/src/components/home/Home.js
index c67a810..7a13dd6 100644
--- a/client/src/components/home/Home.js
+++ b/client/src/components/home/Home.js
@@ -8,6 +8,7 @@ import io from 'socket.io-client';
import {CopyToClipboard} from 'react-copy-to-clipboard';
import Auth0Lock from 'auth0-lock';
import axios from "axios";
+import SweetAlert from "react-bootstrap-sweetalert";
const socket = io(config.socketUrl);
@@ -49,12 +50,16 @@ class Home extends Component {
this.getLiveYos = this.getLiveYos.bind(this);
this.hideErrorDiags = this.hideErrorDiags.bind(this);
this.handleCopy = this.handleCopy.bind(this);
+ this.handleEdit = this.handleEdit.bind(this);
+ this.handleDelete = this.handleDelete.bind(this);
+ this.handleUpdate = this.handleUpdate.bind(this);
+ this.handleCancel = this.handleCancel.bind(this);
}
handleUserInput(e) {
const name = e.target.name;
const value = e.target.value;
- this.setState({ [name]: value });
+ this.setState({ [name]: value, editingOriginalUrl: value });
}
extractHostname(url) {
@@ -187,6 +192,91 @@ class Home extends Component {
});
}
+ handleUpdate() {
+ var accessToken = null;
+ try{ accessToken = localStorage.getItem("accessToken") }catch(e) { accessToken = null };
+ var updEndpoint = this.state.apiUrl + "update/" + this.state.editingLink;
+ var body = { originalUrl: this.state.editingOriginalUrl }
+ axios.post(updEndpoint, body, { 'headers' : {'Content-Type': 'application/json', 'Authorization': "Bearer " + accessToken} })
+ .then(
+ this.setState({
+ alert: (
+
+ This link was successfully updated.
+
+ )
+ }),
+ setTimeout(() => {
+ this.handleCancel()
+ }, 5000)
+ )
+ .catch(err =>
+ this.setState({
+ alert: (
+
+ There was an error while updating {this.state.editingLink}.
+
+ )
+ })
+ )
+ }
+
+ handleDelete() {
+ var accessToken = null;
+ try{ accessToken = localStorage.getItem("accessToken") }catch(e) { accessToken = null };
+ var delEndpoint = this.state.apiUrl + "delete/" + this.state.editingLink;
+ axios.post(delEndpoint, null, { 'headers' : {'Content-Type': 'application/json', 'Authorization': "Bearer " + accessToken} })
+ .then(
+ this.setState({
+ alert: (
+
+ This link was successfully deleted.
+
+ )
+ }),
+ setTimeout(() => {
+ this.handleCancel()
+ }, 5000)
+ )
+ .catch(err =>
+ this.setState({
+ alert: (
+
+ There was an error while deleting {this.state.editingLink}.
+
+ )
+ })
+ )
+ }
+
+ handleCancel() {
+ this.setState({alert: null});
+ }
+
renderButton() {
if (!this.state.showLoading) {
return (
@@ -249,7 +339,7 @@ class Home extends Component {
allowedConnections: ["Username-Password-Authentication"],
rememberLastLogin: false,
allowForgotPassword: false,
- allowSignUp: false,
+ allowSignUp: process.env.REACT_APP_SIGNUPS || false,
closable: false,
languageDictionary: {"title":"Yo - The URL Shortener"},
theme: {
@@ -465,7 +555,7 @@ class Home extends Component {
-
+
@@ -474,17 +564,62 @@ class Home extends Component {
href="#!"
style={{float: "left"}}
className="modal-close waves-effect waves-red red darken-2 btn"
- onClick={e =>
- window.confirm("Are you sure you want to permanently delete this link?") &&
- console.log("Deleted!")
- }
+ onClick={e =>
+ this.setState({
+ alert: (
+
+ Are you sure? This is permanent!
+
+ )
+ })
+ }
>
Delete
Cancel
- Update
+
+ this.setState({
+ alert: (
+
+ Do you want to update the current URL?
+
+ )
+ })
+ }
+ >
+ Update
+
+ {this.state.alert}
diff --git a/client/src/config/config.js.example b/client/src/config/config.js.example
index 6c7bf2f..52742c0 100644
--- a/client/src/config/config.js.example
+++ b/client/src/config/config.js.example
@@ -1,5 +1,5 @@
module.exports = {
- apiUrl: "https://yo-api.mysite.io/api/",
+ apiUrl: "https://yo-api.mysite.io/api/", // Include the trailing slash!
socketUrl: "https://yo-api.mysite.io",
baseUrl: "https://yo.mysite.io",
blockedNames: ['socket.io'], // Items listed here will be blocked as linkNames
diff --git a/client/yarn.lock b/client/yarn.lock
index e540ab2..df9e7a3 100644
--- a/client/yarn.lock
+++ b/client/yarn.lock
@@ -4391,17 +4391,7 @@ fstream-ignore@^1.0.5:
inherits "2"
minimatch "^3.0.0"
-fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
- version "1.0.12"
- resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
- integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==
- dependencies:
- graceful-fs "^4.1.2"
- inherits "~2.0.0"
- mkdirp ">=0.5 0"
- rimraf "2"
-
-fstream@^1.0.12:
+fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.12, fstream@^1.0.2:
version "1.0.12"
resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==
@@ -8264,6 +8254,13 @@ react-app-polyfill@^1.0.1:
regenerator-runtime "0.13.2"
whatwg-fetch "3.0.0"
+react-bootstrap-sweetalert@^4.4.1:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/react-bootstrap-sweetalert/-/react-bootstrap-sweetalert-4.4.1.tgz#94410a79c6d6a1e7ce4ede810904c90d08f6a01a"
+ integrity sha512-czUP6EPXb6GZopxxkixm+a5OaV+kbdxhFbsHaFNIF3l9jBypHCv29TrV8OOruAwrG+GpCmEd8LzzyYPZ0aL9TA==
+ dependencies:
+ object-assign "^4.1.0"
+
react-copy-to-clipboard@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.1.tgz#8eae107bb400be73132ed3b6a7b4fb156090208e"
diff --git a/images/architecture.png b/images/architecture.png
index 0054ec8..c95ae00 100644
Binary files a/images/architecture.png and b/images/architecture.png differ