Social Network Activity Feed + Groups - database

I'm working on an social network app and want to create an activity feed so people can keep up to date with all of their connections (classic facebook stream). I have a DB table called activity setup for this like so:
activity_id (int)
user_id (int) //who posted it
group_id (int) //the group of connections that have permission to view
type (enum) //the type of activity performed
time (datetime) //the time the activity was performed
I would then do a select * from activity where user_id in (connections) to get the latest news.
Here's the catch. User's activities do not always have visibility to the complete set of connections. Users can create groups of user ids to form smaller sets within their super set of connections. Its like how facebook allows you to specify who sees a particular post instead of allowing all friends to see it.
I have a separate groups table setup with the following schema:
group_id (int)
connection_id (user_id, int)
user_id (group creator)
I have a group_id in my activity table. The group_id is the link to the subset of connections that have permission to see the post.
My question is, what is the best way to do this type of feed, and is there an optimal single select statement that will get me the output desired (a list of my connections activities that I have been granted permission to see)?
Thanks.

If you're open to offloading your activity stream functionality to a service via an API, Collabinate (http://www.collabinate.com) may be useful to you.

Related

Database help, one table & multiple users, where CRUD permission depends on column value used

I'm developing a call ticketing system for a hospital, where multiple users from different branches do CRUD activity on one table. This table has relationship restricted value column called, let say [BranchId]. There are three different type of users,
A. Ticket Manager (where they can CRUD without restriction),
B. Ticket Issuer (where they can issue/view/delete tickets but they can't resolve)
C. Ticket Resolver (where they can view/resolve/delete tickets but they can't issue).
So for example,
A patient, who has an appointment with [BranchId] 1, calls to the hospital, and wants to cancel their appointment,
A Ticket Issuer answers the phone and adds this event onto the ticket table and assigns it to [BranchId]=1.
Then the colleagues who work on [BranchId]=1 (they can only see dataset with [BranchId]=1) views the data and resolves (sets the [IsResolved] column to 1)
The patient gets a phone call to notify that their appointment was cancelled.
Solutions so far I can think of
Table Triggers:-
The Ticket Manager adds all users into a table, let say called [BranchUsers] and this table as a column called [Username] where this is populated with Domain\Username, [IsIssuer], [IsResolver] and [BranchId]. The ticket table now has a CRUD trigger when it checks if SYSTEM_USER can issue/resolve and their branch. A separate View table would be used to select from the ticket table with INNER JOIN on [BranchId] for the SYSTEM_USER. However, the problem with this approach is that users can select data directly from the ticket table and so be able to read everything in the table and the [BranchUsers] table may be hard to maintain but that is ok.
Using Active Directory Group:-
So in the Windows Server AD Group, create a group called, let say [Branch1Users], [Branch2Users] etc..., and create multiple ticket tables... you see now it got complex as if one table need some changing such as renaming a column, then the .NET Core API references need too and going back to the Trigger approach above seems easier.
So what would you think be best, please advice anything even if you think it might not help as it may help create a light bulb ideas, I will start the trigger approach for now as this project has deadline soon :-)
Specs that might help:-
Microsoft SQL Server 2019
Windows Server 2019

Model datastore application

I am looking how to create an efficient model which will satisfy the requirements I put below. I have tried using gcloud-node but have noticed it has limitations with read consistencies, references, etc. I would prefer to write this is nodejs, but would be open to writing in java or python as long as it would improve my model. I am building around the new pricing model which will come July 1st.
My application consists of a closed email system. In essence what happens is users register to the site. These user's can make friends. Then they can send emails to each other.
Components of the app:
Users - Unlimited amount of users can join.
Friends - A User can have 200 confirmed friends and 100 pending friend requests. When a friendlist is retrieved it should show the name of the friend. (I will also need to receive the id of the friends so I can use it on my client side to create emails).
Emails - Users can send emails to their friends and they can receive emails from their friends. The user can then view all their sent emails independently(sentbox) and all their received emails independently(inbox).
They can also view the the emails sent between themselves and a friend order by newest. The emails should show the senders and receivers names. Once an email is read it needs to be marked as read.
My model looks something like this, but as you can see their are inefficiencies.
Datastore Kinds:
USER
-email (id) //The email doesn't need to be the id, but I need to be able to retrieve users by their email
-hash_password
-name
-account_status
-created_date
FRIEND
-id (auto-generated)
-friend1
-friend2
-status
EMAIL
-id (auto-generated)
-from
-to
-mutual_id
-message
-created_date
-has_seen
Procedures of the application:
Register - Get operation to see if a user with this email exists. If does not insert key.
Login - Get operation to get user based on email. If exists retrieve the hash_password from the entity and compare to user's input.
Send friend request - Friend data will be written twice for every relationship. Then using the index on friend1 and index on status I will query all the friends for a user and filter only those which are 'pending'. I will then count these friends and see if they are over X. Again I will do this for the other user. If they are both not over the pending limit, I will insert the friend request. This needs to run in a transaction.
Accept a friend request - Friend data will be written twice for every relationship. Then using the index on friend1 and index on status I will query all the friends for a user and filter only those which are pending. I will then count these friends and see if they are over X. Again I will do this for the other user. If they are both not over the pending limit, I will change both entities's status to accepted as a transaction.
Show confirmed friends - Friend data will be written twice for every relationship. Then using the index on friend1 and index on status I will query all the friends for a user and filter only those which are accepted. Not sure how I will show the friend's names (e.g what happens if a user changed their name this needs to be reflected in all friend relationships and emails!).
Show pending friends - Friend data will be written twice for every relationship. Then using the index on friend1 and index on status I will query all the friends for a user and filter only those which are pending. Not sure how I will show the friend's names (e.g what happens if a user changed their name this needs to be reflected in all friend relationships and emails!).
View sent emails - Using the index on the from property I would query to get all the sent emails from a user 5 at a time ordered by created_date (newest first). (e.g what happens if a user changed their name this needs to be reflected in all friend relationships and emails!).
View received emails - Using the index on the to property I would query to get all the received emails to a user 5 at a time ordered by created_date (newest first). When a emails is seen it will update that entities has_seen property to true. (e.g what happens if a user changed their name this needs to be reflected in all friend relationships and emails!).
View emails between 2 users - Using the index on mutual_id which is based on [lower_lexicographic_email]:[higher_lexicographic_email] to query the mutual emails. Ordered by newest, 5 at a time. (e.g what happens if a user changed their name this needs to be reflected in all friend relationships and emails!).
Create email - Using the friend1 and status index I will confirm the user's are friends. If they are friends, I will insert an email.

How to get "relationships" elements efficiently on datastore?

I'm developing a social login system using google datastore. I need to authenticate the user using its social identity and then return the information of all its identities. The client can login with multiple social accounts and also with an identity created on my site so it basically has multiple social identities plus my site identity. Currently I'm using running 3 queries (sequentially) which I feel it's a bit too much so I'm wondering if there is a better way to do this:
// get the username registered with my site(if is registered)
- userID = SELECT userID From social WHERE socialID == $socialID
// get the data of the user
- userData = SELECT * from MyData WHERE userID == userID
// get the data of any other identity it uses / has linked to the user id
- otherSocial = select * FROM social WHERE userID=userID and socialID != $socialID
You can get userData by its key, which is faster and cheaper than running a query. In order to be able to do that, you should use userId as an id for userData.
Your third query is probably needed only in some rare circumstances, e.g. when a user accesses account settings. In either case, I would not worry too much about these queries: they retrieve a small number of entities, which means that they execute very fast.
You can store some data in a session, so you don't have to retrieve it until the next session. I store a LoginOption entity, which is an equivalent of your userId and socialId. Thus, I can bypass the first query until a user logs out or a session expires.

Users, Customers, Tenants, Employees - All in the same table?

In this case let me be more specific about the problem
I've got a peoples table(with customer & supplier) and I've got a users table(for users who can login).
Currently I have this DB structure
Customers -> Organisations -> linked through rel_customer_addresses to address table.
(as 1 customer could have delivery_address, invoice address etc.)
Users -> Tenants -> linked through rel_users_addresses to the address table
(as 1 user could have delivery_address, invoice address etc.)
Now I've got in the invoice table customer_key. The problem is when the user himself is the customer and the invoice is from one of his customers. How do I indicate my web app to look up user and not the customer?
Since you're looking at 2 separate entities (customers and users), I would go ahead and use 2 separate tables and have them share a unique identifier (i.e., username, SID).
That way there's no chance of one seeing information from the other without the appropriate permissions.
There are several ways to control this, but the logic is something like this.
If userID exists in table user, do this.
If userID exists in table customer, do this.
If userID exists in table user AND table customer, do this.
That way you can control the situation completely either independently or together. In other words, you could grant special permissions to userID that is found in table customer, or just make it completely separate (similar to say, how facebook makes a separate 'identity' for pages vs the account it's registered to).
Hope that helps!

Granting access of specific user to specific (multiple) docs

I'm building a small project with database. I have a user table which has two columns, user_id and name, The second table stores the id and name of some documents: it also has two columns doc_id and doc_name. I want to grant access of specific user to specific (multiple) docs.
For example:
user1 can access doc_2 and doc_3 Only.
user2 can access doc_1 and doc_2 Only and so on.
Users and forms keep changing (eg. after some time i need to add a new doc, and add access to existing or new user to that new doc).
Do i need to change database design? (for example add a column in docs to store name of each user who can access it? ) If this is so, can you tell me what changes i should do?
OR
Is it possible to do by creating views? In this case, do i still need to change the database design? If this is the case, can you tell me an example view please? In this case, will i need to create view for each user? For example if there are 100 users, i will need to create 100 views?
You need a third table (I'll call it user_doc). You need 2 main columns; user_id and doc_id.
You then insert one row for each document and user combo that has access permissions.
If their user_id doesn't appear in the user_doc table with the relvelant doc_id, they don't have permission.
A sample query to get a list of all docs a specific user has access to:
SELECT doc_id FROM user_doc WHERE user_id = #UserId
or to find all users with access to a specific doc:
SELECT user_id FROM user_doc WHERE doc_id = #DocId
You need to have a PERMISSIONS table with relationship between Users & Documents. The columns could be PERMISSIONS_ID,USER_ID (Refer User), DOC_ID (Refer Document). Every time access has to be given to a user for a document this table needs to be populated.

Resources