Git Product home page Git Product logo

react-news's Introduction

React-News

About

Note: Due to the popularity of this project, I am bumping up against the limits of my Firebase account. If it's unresponsive, that's probably why. If you fork the project, please sign up for a free Firebase account and update the URL in util/constants.js!

This is a real-time Hacker News clone written using React, RefluxJS, and a Firebase backend.

Demo

React-News

Demo available here.

Test User Login:
email: [email protected]
password: henleyedition1

Development and Build Process

To start the development server, run npm i && npm start and have at the src/. Files are served from /build.

Command Description
npm start Starts development server with hot reloading.
npm run build Runs development build. Outputs files to /build.
npm run dist Runs production build. Outputs files to /dist.
npm run lint Runs eslint on the /src folder.
npm test Runs test suite once.
npm run test:watch Runs test server.

Testing

Note: tests are a work in progress.

The test suite is run using npm test and npm run test:watch. Individual unit tests live in __tests__ directories throughout src/. Tests are built with Karma (test runner), Mocha (test environment), PhantomJS (test browser), Chai (assertions), and Sinon (spies/mocks). Jest was ruled out for reasons.

Firebase Structure

$ are Firebase-generated unique IDs.

├── comments
│   └── $commentId
│       ├── creator (username)
│       ├── creatorUID ($userId)
│       ├── postId ($postId)
│       ├── postTitle
│       ├── text
│       ├── time
│       └── upvotes
├── posts
│   └── $postId
│       ├── commentCount
│       ├── creator (username)
│       ├── creatorUID ($userId)
│       ├── time
│       ├── title
│       ├── upvotes
│       └── url
└── users
    └── $userId
        ├── md5hash
        ├── upvoted
        │   └── $itemId ($postId or $commentId)
        └── username

Firebase Security Rules

{
  "rules": {

    "posts": {
      // anyone can view posts
      ".read": true,
      ".indexOn": ["upvotes", "creatorUID", "commentCount", "time"],

      "$id": {
        // auth can't be null to make/edit post
        // if the post exists, auth.uid must match creatorUID
        ".write": "(auth != null && !data.exists()) || data.child('creatorUID').val() === auth.uid",

        // make sure all 5 fields are present before saving a new post
        // leave 'isDeleted' when deleting a post
        ".validate": "newData.hasChildren(['title', 'url', 'creator', 'creatorUID', 'time']) ||
                      newData.hasChildren(['isDeleted'])",

        // title must be a string with length>0
        "title": {
          ".validate": "newData.isString() && newData.val().length > 0"
        },
        "url": {
          ".validate": "newData.isString()"
        },
        "creator": {
          ".validate": "newData.isString()"
        },
        "creatorUID": {
          ".validate": "auth.uid === newData.val() && root.child('users/' + newData.val()).exists()"
        },
        "commentCount": {
          // commentCount must be writable by anyone logged in
          ".write": "auth != null",
          // 1st line: initial write
          // 2nd line: only alterable by 1
          // 3rd line: if deleted
          ".validate": "(!data.exists() && newData.val() === 1) ||
                        (newData.val() - data.val() === 1 || newData.val() - data.val() === -1) ||
                        !newData.exists()"
        },
        "upvotes": {
          // upvotes must be writable by anyone logged in
          ".write": "auth != null",
          // 1st line: initial write
          // 2nd line: cannot go below 0 and only alterable by 1
          ".validate": "(!data.exists() && newData.val() === 1) ||
                        (newData.val() >= 0 && (newData.val() - data.val() === 1 || newData.val() - data.val() === -1))"
        }
      }
    },

    "comments": {
      ".read": true,
      ".indexOn": ["postId","creatorUID","time"],

      "$comment_id": {
        ".write": "auth != null && (!data.exists() || data.child('creatorUID').val() === auth.uid)",
        ".validate": "newData.hasChildren(['postId', 'text', 'creator', 'creatorUID', 'time']) &&
                      (newData.child('text').isString() && newData.child('text').val() != '')",

        "upvotes": {
          // upvotes must be writable by anyone logged in
          ".write": "auth != null",
          // 1st line: initial write
          // 2nd line: cannot go below 0 and only alterable by 1
          ".validate": "(!data.exists() && newData.val() === 1) ||
                        (newData.val() - data.val() === 1 || newData.val() - data.val() === -1)"
        }
      }
    },

    "users": {
      ".read": true,
      ".indexOn": ["username"],

      "$uid": {
        // user not authenticated until after profile is created
        ".write": "!data.exists()",
        ".validate": "newData.hasChildren(['username', 'md5hash']) &&
                      newData.child('username').isString() &&
                      newData.child('md5hash').isString()",
        "upvoted": {
          "$itemId": {
            ".write": "auth.uid === $uid"
          }
        },
        "submitted": {
          "$itemId": {
            ".write": "auth.uid === $uid"
          }
        }
      }
    },

    // Don't let users post to other fields
    "$other": { ".validate": false }

  }
}

Firebase Authentication

To set up users, from your Firebase dashboard:

  1. Click Auth
  2. Click users
  3. Enable Email/password sign-in method

react-news's People

Contributors

aherriot avatar echenley avatar juniorbird avatar pandaiolo avatar wescravens avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-news's Issues

Database Initialization

When I use the firebase instance that you provided, it works. After setting up my own firebase instance, and putting the security rules in from the readme file, I get an error when I launch the app.

Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op.

Is there anything I should do to initialize the database?

Gulp build error

I'm trying to run the example but getting:

[01:11:37] gulp-notify: [Compile Error] Cannot find module 'react-router/lib/HashHistory' from '{path}/src/js'

hostnameFromUrl

gulp-notify: [Compile Error] Cannot find module '../mixins/hostnameFromUrl' from '/home/guillaume/tmp/react-news/src/scripts/components'

(archlinux 64bits)

post.jsx is expecting a file named ../mixins/hostnameFromUrl (line 14) but the real mixin is named hostNameFromUrl.js

Can't create new users when using set-up described in Readme

I've tried following the instructions in the README, and am not successfully getting react-news to create new users after setting up my own Firebase DB.

I'm not familiar with Firebase and am probably missing something simple!

Steps to repro:

  1. Create a new Firebase DB
  2. Copy-and-paste Firebase config from README to Security & Rules in Firebase DB
  3. Set Firebase url in constants.js to a new Firebase DB
  4. Register as new user
  5. Get "Something went wrong" error

    screen shot 2016-05-07 at 4 36 45 pm
  6. Try what I think is the update format in the Simulator and get "No .write rule allowed the operation"

    screen shot 2016-05-07 at 4 35 58 pm

Is there another step? If so, I'm happy to screenshot doing that and submit a pull request for the README.

Update rules to make it secure

Currently, when the user logs in, they can write anything to $uid because there is no check to ensure they can write to only their own $uid bucket.
I think we should add: ".write": "auth !== null && auth.uid === $uid" instead of !data.exists()

  "users": {
      ".read": true,
      ".indexOn": ["username"],

      "$uid": {
        // user not authenticated until after profile is created
       // ".write": "!data.exists()",
        "write":  "auth !== null && auth.uid === $uid"
        "upvoted": {
          "$itemId": {
            ".write": "auth.uid === $uid"
          }
        },
        "submitted": {
          "$itemId": {
            ".write": "auth.uid === $uid"
          }
        }
      }

Cannot find module 'react-router/lib/HashHistory'

I have an issue with HashHistory, when i run gulp get:

gulp-notify: [Compile Error] Cannot find module 'react-router/lib/HashHistory' from '/www/react/react-news/src/js'

I find one issue post at react-router.

It look's like we need update the file '/src/js/routes.jsx'.

provide firebase configuration

Can you provide firebase security rules and any other configuration needed for migrating to another firebase account? I'm getting an error when trying to create an account after changing firebase url.

Thanks for this great example!

Payload size can be decreased by replacing crypto by MD5

I am playing with react-news and it's great, but the bundle is pretty big

Some things are unavoidable, like react or firebase, obviously

However, FYI I could reduce the package by importing MD5 (caps) package, which is 9k, instead of crypto which is like 250k. Function usage is just md5(string) and returns the md5 hash.

Is crypto only used for generating md5 gravatar hash?

Use async actions instead of preEmit

First of all thanks for publishing this project, it helped me a lot in understanding more of the refluxjs concept!

When I looked at your actions file I was a bit surprised to find all the preEmit hooks there instead of using async actions. Did you do that on purpose, and if so then why?

Firebase Structure

This might be a stupid question but what exactly is the "Firebase Structure" part in the README.md?
Sorry for my ignorance, it's the first time I'm using Firebase. I was able to deploy the App but now stuck.

I assume it is the database structure?

Cheers, Martin.

Add user's posts/comments to profile

This was an oversight in the original Firebase design, and this change will allow for greater flexibility in the future. For instance, it is currently impossible to know whether a user's comment was successful without looping through the entire list of comments for a given post.

Hacker News seems like a good example to follow: https://github.com/HackerNews/API#users

UserStore throws JS Expn when signing up

Looks like there is a change to react-addons-update module. It now directly returns 'update' module.

Currently, it is doing:
import {update} from 'react-addons-update';

It should be doing:
import update from 'react-addons-update';

Can't browse the app

Hello,
I was trying to build the app and added my firebase url, but I got the error:-
TypeError: Path must be a string. Received undefined
any idea what is this about?

Thanks.

Tests with Jest

Hi @echenley
Thanks for this example app in reflux!
I would like to know if you plan to cover it with tests Jest\Jasmine? That would be a really great addition to fulfil the gap in this area since it's not covered in reflux docs.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.