Răsfoiți Sursa

Add report endpoint and form

poeti8 7 ani în urmă
părinte
comite
8e3c9cfb32
4 a modificat fișierele cu 128 adăugiri și 13 ștergeri
  1. 106 13
      client/pages/report.js
  2. 5 0
      server/config.example.js
  3. 16 0
      server/controllers/urlController.js
  4. 1 0
      server/server.js

+ 106 - 13
client/pages/report.js

@@ -1,8 +1,11 @@
-import React from 'react';
+import React, { Component } from 'react';
 import styled from 'styled-components';
+import axios from 'axios';
 import BodyWrapper from '../components/BodyWrapper';
 import { authUser } from '../actions';
 import { REPORT_EMAIL } from '../config';
+import TextInput from '../components/TextInput';
+import Button from '../components/Button';
 
 const Wrapper = styled.div`
   width: 600px;
@@ -12,18 +15,108 @@ const Wrapper = styled.div`
   align-items: flex-start;
 `;
 
-const ReportPage = () => (
-  <BodyWrapper>
-    <Wrapper>
-      <h3>Report abuse</h3>
-      <p>
-        Report abuses, malware and phishing links to the below email address. We will take them down
-        within 12 hours.
-      </p>
-      <p>{REPORT_EMAIL}</p>
-    </Wrapper>
-  </BodyWrapper>
-);
+const Form = styled.form`
+  position: relative;
+  display: flex;
+`;
+
+const Message = styled.p`
+  position: absolute;
+  left: 0;
+  bottom: -48px;
+  font-size: 14px;
+  color: ${props => (props.type === 'error' ? 'red' : 'green')};
+
+  @media only screen and (max-width: 448px) {
+    bottom: -40px;
+    font-size: 12px;
+  }
+`;
+
+class ReportPage extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      loading: false,
+      message: {
+        text: '',
+        type: '',
+      },
+      url: '',
+    };
+    this.onChange = this.onChange.bind(this);
+    this.onSubmit = this.onSubmit.bind(this);
+  }
+
+  onChange(e) {
+    const url = e.target.value;
+    this.setState({ url });
+  }
+
+  async onSubmit(e) {
+    e.preventDefault();
+    this.setState({ loading: true });
+    try {
+      await axios.post('/api/url/report', { url: this.state.url });
+      this.setState({
+        loading: false,
+        message: {
+          type: 'success',
+          text: "Thanks for the report, we'll take actions shortly.",
+        },
+      });
+    } catch (error) {
+      this.setState({
+        loading: false,
+        message: {
+          type: 'error',
+          text: error.response.data.error,
+        },
+      });
+    }
+
+    setTimeout(() => {
+      this.setState({
+        message: {
+          type: '',
+          text: '',
+        },
+      });
+    }, 2000);
+  }
+
+  render() {
+    const { loading, message, url } = this.state;
+
+    return (
+      <BodyWrapper>
+        <Wrapper>
+          <h3>Report abuse</h3>
+          <p>
+            Report abuses, malware and phishing links to the below email address. We will take
+            actions shortly.
+          </p>
+          <p>{REPORT_EMAIL}</p>
+          <p>Or use the form below.</p>
+          <Form onSubmit={this.onSubmit}>
+            <TextInput
+              type="text"
+              placeholder="URL"
+              value={url}
+              onChange={this.onChange}
+              height={44}
+              small
+            />
+            <Button type="submit" icon={loading ? 'loader' : ''}>
+              Send report
+            </Button>
+            <Message type={message.type}>{message.text}</Message>
+          </Form>
+        </Wrapper>
+      </BodyWrapper>
+    );
+  }
+}
 
 ReportPage.getInitialProps = ({ req, reduxStore }) => {
   const token = req && req.cookies && req.cookies.token;

+ 5 - 0
server/config.example.js

@@ -42,4 +42,9 @@ module.exports = {
   MAIL_SECURE: false,
   MAIL_USER: '',
   MAIL_PASSWORD: '',
+
+  /*
+    The email address that will receive submitted reports.
+  */
+  REPORT_MAIL: '',
 };

+ 16 - 0
server/controllers/urlController.js

@@ -23,6 +23,7 @@ const {
   getBannedDomain,
   getBannedHost,
 } = require('../db/url');
+const transporter = require('../mail/mail');
 const redis = require('../redis');
 const { addProtocol, generateShortUrl } = require('../utils');
 const config = require('../config');
@@ -238,6 +239,21 @@ exports.getStats = async ({ query: { id, domain }, user }, res) => {
   return res.status(200).json(stats);
 };
 
+exports.reportUrl = async ({ body: { url } }, res) => {
+  if (!url) return res.status(400).json({ error: 'No URL has been provided.' });
+  const mail = await transporter.sendMail({
+    from: config.MAIL_USER,
+    to: config.REPORT_MAIL,
+    subject: '[REPORT]',
+    text: url,
+    html: url,
+  });
+  if (mail.accepted.length) {
+    return res.status(200).json({ message: "Thanks for the report, we'll take actions shortly." });
+  }
+  return res.status(400).json({ error: "Couldn't submit the report. Try again later." });
+};
+
 exports.ban = async ({ body }, res) => {
   if (!body.id) return res.status(400).json({ error: 'No id has been provided.' });
 

+ 1 - 0
server/server.js

@@ -112,6 +112,7 @@ app.prepare().then(() => {
   server.delete('/api/url/customdomain', auth.authJwt, catchErrors(url.deleteCustomDomain));
   server.get('/api/url/stats', auth.authApikey, auth.authJwt, catchErrors(url.getStats));
   server.post('/api/url/requesturl', catchErrors(url.goToUrl));
+  server.post('/api/url/report', catchErrors(url.reportUrl));
   server.post(
     '/api/url/admin/ban',
     auth.authApikey,