To many, the social media experience has become a stressful experience. Newsfeeds have become pinboards for sponsored content. Statuses, comments, and any online interactions expose users to restless keyboard warriors. Some might say that social media has become anything but social.
Now as the kingpins of social media continue to dither, this Launchpad App has tackled this issue head-on by creating its very own social media platform, Letus. The core value of this app is to provide users with a social media platform that promotes more natural and meaningful interactions between friends, family, and work colleagues.
From start to finish, this application relies on the power, speed and flexibility of RedisGraph. Let’s take a look at how this app was created.
But before we dive in, make sure to have a browse around the Redis Launchpad to discover a range of exciting applications for you to get involved in.
You’ll build a social media platform that shields users from trolls and liberates them from sponsored content. This mobile application will only display posts that are made by your friends, family, or whoever you connect with on Letus.
There won’t be any mysterious algorithm that exposes you to unwanted connections and advertisements. Instead, Letus will give you full control over the content you’ll see. Below we’ll go through A-Z of what actions you need to take to bring this application to life, along with the required components.
RedisGraph: used to sparse matrices to represent the adjacency matrix in graphs and linear algebra to query the graph.
Google Cloud Platform (GCP): used as a public cloud vendor that classifies text and analyzes sentiments in this project.
Azure Functions: used as a serverless solution to write less code, maintain infrastructure, and save on costs.
Google Identity: used as a customer identity and access management (CIAM) platform that authenticates users via web-based Oauth 2.0.
Expo: Used by Mobile developers to build apps
Firebase: Backend as a Service
$ git clone https://github.com/redis-developer/letus
$ cd LetusApp
$ npm install --global expo-cli
Node modules with config plugins can be added to the project’s Expo config automatically by using the expo install command
$ npm install
$ expo install
For local development, RedisGraph can be run using the redismod Docker container
$ docker run -d -p 6379:6379 redislabs/redismod
You can run just the Expo Go App locally to use, and develop, the react native app. By accessing existing (free) firebase auth and existing (free) Azure functions deployed for DEV only.
Developer tools running on http://localhost:19002 Opening developer tools in the browser… Starting Metro Bundler Metro waiting on exp://192.168.1.9:19000 |
Create a .env.local file to store your local configuration
Set the value of LETUS_API_URL to the location of your API (can use .env if local functions)
Set the value of GOOGLE_WEB_CLIENT_ID to use a Web OAUTH credential created in your Google Identity account.
Set value of firebase config in the .env or .env.local file
FIREBASE_API_KEY=
FIREBASE_AUTH_DOMAIN=
FIREBASE_PROJECT_ID=
FIREBASE_STORAGE_BUCKET=
FIREBASE_MEASSGE_SENDER_ID=
FIREBASE_APP_ID=
$ expo start
Press i to launch an iOS simulator or a for Android. (note: Android simulator requires Android Studio and sdk setup)
This project uses Azure Functions which can be accessed directly in your local development. If you wish to publish these functions to the cloud, you must create your own Azure account. Tip: There is a very useful VS Code Extension to help manage your azure projects and functions.
REDIS_HOST
REDIS_PORT
REDIS_PASS
REDIS_GRAPH
GCP_API_KEY
Click /try-free/ and setup Redis Enterprise cloud database with RedisGraph as shown below:
MATCH (me:Person {userid: $userid})
OPTIONAL MATCH (me)-[:ignores]->(ign:IgnoreSetting)
WITH me, ign
MATCH (poster:Person)-[:posted]->(post:Post)
WHERE (poster = me OR (poster)-[:friended]-(me))
AND (NOT (post)-[:inCategory]->(:Category {name:ign.category}) AND NOT (post)<-[:posted]-(:Person {userid:ign.poster}))
WITH post, poster, me
OPTIONAL MATCH (post)-[:hasComment]->(comment:Comment)<-[:commented]-(commenter:Person)
WHERE commenter = me OR (commenter)-[:friended]-(me)
WITH me, post, poster, collect(comment) as comments, collect(commenter) as commenters
ORDER BY post.created DESC
SKIP $skip
LIMIT $limit
RETURN post, poster, comments, commenters
MATCH (me:Person {userid:$userid}) ${categories
.map(
(cat, index) =>
'MERGE (cat' + index + ':Category {name: $cat' + index + '})'
)
.join(
' '
)}
MERGE (sentiment:Sentiment {name: $sentiment})
CREATE (me)-[:posted]->(post:Post {text:$text,created:$now})
MERGE (post)-[:hasSentiment]->(sentiment) ${categories
.map((cat, index) => 'MERGE (post)-[:inCategory]->(cat' + index + ')')
.join(' ')}
RETURN post
MATCH (me:Person), (post:Post)
WHERE me.userid = $userid
AND ID(post) = $onPost
CREATE (me)-[:commented]->(comment:Comment {text:$text,created:$now})
CREATE (post)-[:hasComment]->(comment)
RETURN post
Note: single-direction :friended relationships determine pending friend requests
MATCH (me:Person { userid: $userid })
MATCH (them:Person { userid: $themid })
MERGE (me)-[:friended]->(them)
RETURN me, them
MATCH (me:Person {userid: $userid})
WITH me
MATCH (them:Person)-[:friended]->(me)
WHERE NOT (me)-[:friended]->(them)
RETURN them
MATCH (me:Person { userid: $userid })
MERGE (me)-[:ignores]->(ignore:IgnoreSetting {poster:$themid, category: $category, sentiment: $sentiment})
RETURN me, ignore
MATCH (them:Person)
MATCH (me:Person {userid:$userid})
WHERE NOT them.userid = $userid
AND them.name STARTS WITH $name
AND NOT (me)-[:friended]->(them)
RETURN them
NLP Commands
Using the free tier of GCP Natural Language, we apply both sentiment analysis and text classification to all posts made in the system.
const sslCreds = getApiKeyCredentials();
const client = new language.LanguageServiceClient({ sslCreds });
const document = {
content: text,
type: 'PLAIN_TEXT',
};
const [result] = await client.analyzeSentiment({ document: document });
sentiment = mapSentiment(result.documentSentiment.score || 0);
// GCP requires 20 words
// we pad with prepositions if between 10-19 words for max coverage
if (len < 20) {
content = [...content.split(' '), ...preps.slice(0, 20 - len)].join(' ');
}
const sslCreds = getApiKeyCredentials();
const client = new language.LanguageServiceClient({ sslCreds });
const document = {
content,
type: 'PLAIN_TEXT',
};
const [result] = await client.classifyText({ document: document });
categories = result.categories || [];
As social media continues to intertwine itself into everyday life, trolling remains as pervasive as ever. Facebook, Twitter, Instagram, and even Linkedin have become hunting grounds for restless keyboard warriors.
Then you have the endless bombardment of sponsored content, whose interests are prioritized ahead of the user’s. But by using Redis, this marketplace app was able to create a social media platform for mobile users that removes both of these hazards.
The power and speed of RedisGraph was crucial to building Letus since it allowed the application to query data with maximum efficiency. From what began as just a simple idea, Redis was able to bring this application to life… but that’s not all.
Every day people are tapping into the wonders of Redis to create exciting applications that’s having an impact on everyday lives. How can you use Redis to help change society for the better?
For more inspiration, you can visit the Redis Launchpad where you’ll find a whole range of innovative apps. Likewise, you can also discover more about how this app was made by clicking here.
Matt Pileggi
Matt has over 20 years of experience in web development and is now the principal engineer for Games24x7.
Make sure to keep to date with all of Matt’s projects on Github by checking out his page here.