Development Update #1: My Steem TV Show and Movie AppsteemCreated with Sketch.

in #utopian-io6 years ago

Repository

https://github.com/jrawsthorne/review.app

New Features

  • User authentication system using SteemConnect (uh-oh)
  • Database to store ids of posts
  • Posts need to be displayed with the linked metadata
  • Custom API to allow for more complex querying of posts

#1 Database

The database needed to store a variety of information about a post including a way to reference each post. The common way to query the steemit api is by author and the permanent link so these fields were mandatory. On the front end I also wanted to be able to filter by the type of post, for example a review, or just a discussion. The database will also store the metadata relating to each post. For a review of a TV episode this would include the MovieDB ID, season number and episode number. To reduce the number of api requests to TheMovieDB I decided to also store the title, which would be the name of the show in this case, as well as the paths to relevant images. There will also be a rating field. In the future I will add this to a user model so all users can rate something.

This is the schema (GitHub Link)

const schema = new mongoose.Schema(
  {
    author: {
      type: String,
      required: true,
    },
    permlink: {
      type: String,
      required: true,
      unique: true,
    },
    postType: {
      type: String,
      required: true,
    },
    mediaType: {
      type: String,
      required: true,
    },
    tmdbid: {
      type: Number,
      required: true,
    },
    title: {
      type: String,
      required: true,
    },
    posterPath: {
      type: String,
    },
    backdropPath: {
      type: String,
    },
    episodePath: {
      type: String,
    },
    seasonPath: {
      type: String,
    },
    seasonNum: {
      type: Number,
    },
    episodeNum: {
      type: Number,
    },
    rating: {
      type: Number,
    },
  },
  {
    timestamps: true,
  },
);

#2 API routes

Retrieve post by author and permlink with related metadata (GitHub Link)

router.get('/@:author/:permlink', (req, res) => {
  const { author, permlink } = req.params;
  Post.findOne({ author, permlink })
    .then((post) => {
      if (!post) {
        return res.status(404).json({ error: "Post couldn't be found" });
      }
      return res.json(post);
    });
});

Front end makes the request and merges with the data from the steemit api (GitHub Link)

export const fetchPost = (author, permlink) => ({
  type: FETCH_POST,
  payload: axios.get(`/api/posts/@${author}/${permlink}`)
    .then(res => res.data)
    .then(post => steemAPI.getContentAsync(post.author, post.permlink)
      .then(steemPost => getPostData(steemPost, post)))
    .then(steemPost => steemPost.id !== 0 && steemPost),
  meta: {
    author,
    permlink,
    globalError: 'Sorry, there was an error fetching the post',
  },
});

Retrieve posts matching certain criteria (GitHub Link)

router.get('/', (req, res) => {
  const {
    postType = 'all', mediaType, tmdbid, seasonNum, episodeNum, rating, limit = 20,
  } = req.query;
  const query = {};
  if (mediaType) query.mediaType = mediaType;
  if (tmdbid) query.tmdbid = tmdbid;
  if (seasonNum) query.seasonNum = seasonNum;
  if (episodeNum) query.episodeNum = episodeNum;
  if (rating) query.rating = rating;
  if (postType !== 'all') {
    query.postType = postType;
  }
  Post.count(query)
    .then((count) => {
      Post.find(query).limit(limit)
        .then(posts => res.json({
          count,
          results: posts,
        }));
    });
});

Front end makes the request and calls the steemit api for every post it finds that isn't already stored locally (GitHub Link)

export const fetchPosts = (posts, {
  postType = 'all', mediaType = null, tmdbid = null, seasonNum = null, episodeNum = null, rating = null,
}) => ({
  type: FETCH_POSTS,
  payload: axios.get('/api/posts', {
    params: {
      postType: postType || 'all',
      mediaType: mediaType || undefined,
      tmdbid: tmdbid || undefined,
      seasonNum: seasonNum || undefined,
      episodeNum: seasonNum && episodeNum ? episodeNum : undefined,
      rating: rating || undefined,
    },
  })
    .then(res =>
      Promise.all(res.data.results.filter(post => !_.get(posts, `@${post.author}/${post.permlink}`)).map(post => steemAPI.getContentAsync(post.author, post.permlink)
        .then(steemPost => getPostData(steemPost, post))))
        .then(steemPosts => arrayToObject(steemPosts.filter(post => post.id !== 0), 'url'))),
  meta: {
    globalError: 'Sorry, there was an error fetching posts',
  },
});

Ability to update the metadata associated with a post if an image path changes for some reason (GitHub Link)

router.post('/update-metadata', (req, res) => {
  /* checking whether necessary values exist */
  return Post.findOne({
    author, permlink, postType, mediaType, tmdbid, seasonNum, episodeNum,
  })
    .then((post) => {
      if (!post) return res.status(404).json({ error: "Post couldn't be found" });
      if (mediaType === 'movie') {
        theMovieDBAPI.movieInfo(tmdbid)
          .then(movie => Post.findOneAndUpdate({
            author, permlink, postType, mediaType, tmdbid,
          }, { posterPath: movie.poster_path, backdropPath: movie.backdrop_path }, { new: true })
            .then(newPost => res.json(newPost)));
      }
      /* checking other media types */
      return post;
    });
});

#3 Display posts

Home page shows all posts, can filter by media type

Home page
Filtered home page

Every show/movie page shows the posts for it

Movie page
Show page
Episode page

Single post page shows metadata, post title and formatted body

Movie post
Show post
Episode post

#4 Mobile styling

Until I come up with a final design I added some mobile styling so content wouldn't expand out of the page. On the home page, a landscape image is shown to use the limited space better.

Post page
Home page

#5 Login with SteemConnect

I fixed the SteemConnect login redirecting to localhost and now when you login it shows your avatar in the top right. The access token is only stored client side so there is no possibility of a leak if the server is hacked. I also only request an online token and not an offline one which can be used to generate unlimited tokens. Logout revokes the token so it can't ever be used again.

Roadmap

  • Better filters for pages - store list of posts matching filter in redux store
  • Post formatting - youtube/dtube/more complex markdown/html
  • Ability to actually write new posts
  • Store all database info in JSON metadata of a post as backup
  • User profile pages
  • Allow all users to give star rating
  • User actions (like, comment)
  • Subscribe to certain show - get notifications when new episode airs
  • Subscribed page showing all posts from subscribed shows/movies

Proof of Work Done

https://github.com/jrawsthorne

Sort:  

Thanks for the contribution. It has been approved.


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Hey @jrawsthorne

We're already looking forward to your next contribution!

Contributing on Utopian

Learn how to contribute on our website or by watching this tutorial on Youtube.

Utopian Witness!

Vote for Utopian Witness! We are made of developers, system administrators, entrepreneurs, artists, content creators, thinkers. We embrace every nationality, mindset and belief.

Want to chat? Join us on Discord https://discord.gg/h52nFrV

Coin Marketplace

STEEM 0.30
TRX 0.12
JST 0.033
BTC 64420.25
ETH 3150.23
USDT 1.00
SBD 3.99