DB schema for a resource-based messaging system - mysql

My laravel application has some services and products, for simplicity's sake, I will keep it as generic as possible and I am going to call an individual service/product a resource.
I will have to implement a messaging system in such a way, so that a client can send message to the admin (and vice versa) against a single resource.
For example, consider project as being one such resource. An admin can create a project, a client can send messages to the admin who created that project. A client cannot create a project.
This is how I designed the db schema:
Message Storing Part:
conversations(id, message_id, from, to, body, is_seen)
messages(id, resource_id, resource_name)
Resource Storing Part:
projects(id, admin_id, client_id, some_other_column)
another_resource(id, admin_id, client_id, some_other_column)
yet_another_resource(id, admin_id, client_id, some_other_column)
Notice the resource_id and resource_name in the messages table:
resource_id is the id from one of the resource tables (projects, another_resource, yet_another_resource).
resource_name is where my problem is. If I implement this schema, I would have to hardcode a tablename in this column. An entry in the messages table would look like this:
+----+---------------+-------------+---------------------+---------------------+
| id | resource_name | resource_id | created_at | updated_at |
+----+---------------+-------------+---------------------+---------------------+
| 1 | project | 1 | 2018-01-13 15:11:07 | 2018-01-13 15:11:07 |
+----+---------------+-------------+---------------------+---------------------+
As you can see, if some client had to send a message on an entry of another_resource I would have to store the string "another_resource" as the resource_name in messages table and the id of that row of another_resource as the resource_id
I admit that I am not a good db designer but I have a strong feeling that storing a tablename as a column value is not a good idea. There must be some dynamic way of handling it. How could I improve my schema? Any modification, suggestion or advice will be greatly appreciated.

Related

Mysql Database Column naming that will cause less problems with Sequelize ORM tool

What is the best practice for naming columns in MySql Database when the test team will be using an ORM tool together with cypress to inject and remove data? - test data will be in JSON while the current DB is in MySQL.
For example, let's say I have a software company that has logins for an admin system (Tech Support staff users), dealers, but I also have customers (Users).
In My Table I have the following columns:
1-dealer
first_name | last_name | address
2-staffuser
first_name | Last Name | address
3-customeruser
first_name | last_name | address
Is this the "sane way"? or should it be:
1-dealer
dealer_first_name | dealer_last_name | dealer_address
2-staffuser
staff_user_first_name | staff_user_last_name | staff_user_address
3-customeruser
customer_user_first_name | customer_last_name | customer_user_address
Your models will have specific names in your return JSON so there would be no confusion on the front end with duplicate property/column naming in diff objects... but also you can alias your columns in sequelize if you needed to... i kind of wonder why you don't just have a user table with a user type column that was equal to either staff/dealer/customer tho if the values are the same

Need database structure for private, group and public chat - MySQL

My basic idea is to build a web-based chat application. I have checked a lot of database structures over the internet for my requirements and the conclusion is that there are so many solutions for that.
So here is the database structure I thought (But I'm pretty sure that it is not 100% correct or at least it can be improved)
Table users:
id | username | email | created_at | updated_at
Table chat_rooms
id | room_type | created_at | updated_at
Table: room_members
id | room_id | user_ids (in serialized form)
Table: messages
id | room_id | sender_id | message | created_at | updated_at
Table: receivers
id | message_id | receiver_id | read_at
There are 3 types of chats:
i) Private chat - a chat between two users
A user will select another user to start to chat with him/her
ii) Group chat - a chat between group of users
A user will add other users into the room to start a group chat
iii) Public chat - a chat between all the users
An open chat room to which anyone can join and send messages
So here is how it will work:
I logged into the site, redirected to the dashboard page. On that page, I have 3 options to start a chat as described above.
Notes:
1) If there is a previous chat between the users it should be shown as soon as I start a chat (pretty similar to Facebook) - This applies to all the three types of chats
2) I want to have a feature which says that when a specific user read a message.
3) I want to keep it scalable as much as possible for the future enhancement
Thanks
Yes this DB structure is workable for make alpha version.
you can make some small changes according to your requirement.

Database issue - how do I set up user accounts/pswds so they can ONLY add/change THEIR data?

Okay... I am working to create a mobile app that allows two groups of users to do two different things.
Essentially, the goal of the project is this:
Group A users: create account/pswd and can enter THEIR data into the database and/or change THEIR existing data (but ONLY their data)
Group B users: can SEARCH the database for information that is inserted by Group A. Down the track I'd like to set it up so that they can create an user account so they can also SAVE key information to THEIR account for faster recall (so they don't have to look up the info they search for regularly) -- but that is down the track.
I have a relational database set up using the mySQL that is available with my web-hosting account (it seemed to be the easiest way to go).
I'm just trying to work out how to handle the user account creation/authentication bit, because each group should ONLY be able to CHANGE/INSERT data to their own account, but can search for information submitted by anyone else.
Thanks in advance.
Use mysql facilites to manage permissions: roles, users and privileges.
Navigate through mysql official documentation (i.e. http://dev.mysql.com/doc/workbench/en/wb-adding-roles.html).
You can create two roles: groupA that can INSERT/SELECT/UPDATE one set of tables, groupB that can do the same but in another set of tables.
You can assign INSERT privilege in just the table you want, but SELECT privileges on all the tables.
Hope this info brings you some light...
Firstly this sounds like a huge project, I am sure there are frameworks out there that can do this for you. However, if you are trying to do this on your own continue reading.
This can be done several ways. I will try to be as detailed as possible. This requires SQL as well as application development/Software engineering knowledge.
Step 1: Setup your database
You will need the following tables: All ids are primary keys auto incremented, the other fields can be varchar, except fields that have date in their name
sessions [id, uid, random_token, datecreated]
resourcescope [rid, name]
user [uid, first, last, email, username, salted_pwd]
user_type [id, name, description]
user_resourcescope [id, uid, rid] //lookup table between userid and resourcescope
I prefer using Java or python because you can use dependency injection or decorators. As a result, you don't have to write a lot of code when checking if a user has access.
Putting it all into practice.
1. When a user signs up, you save them into a user database. Depending on the user type, you give them different permissions. Next, you save the user permissions inside the user_resourcescope table.
You should now have the following.
User Table
UID | first | last | email | username | salted_pwd | usertype
1 | james | iri | example#isp.com | jiri1928 | klasdjf8$kljs | 1
UserType table
usetype_id | Name
1 | Basic users
2 | Searcher
ResourceScope Table
rid | Name
1 | FindContent
2 | CreateContent
3 | DeleteContent
User_Resourcescope
id | uid | rid
1 | 1 | 1
2 | 1 | 3
Session
id | uid | random_token | datecreated
1 | 1 | ldkjfald882u3u | 1391274870322
Each resource represents a request within the system. For example,
http://api.myapi.com/content/add - This would be associated with the ResourceScope CreateContent
http://api.myapi.com/content/delete- This would be associated with the ResourceScope CreateDelete
http://api.myapi.com/content/search - This would be associated with the ResourceScope SearchContent
When someone tries to create content, you check if their cred are correct by validating their session information and you check to see if they have the correct permission by checking the User_Resourcescope table.
To prevent users from deleting content that is not theirs. Inside the content table you can add a creator field and put the user id associated with the content. And if someone try to delete content you can check their user id against the creator field.

How to organize user credential in DB?

What would be the best approach to storing user credentials in MySQL database.
I mean structure, not the data (hash vs clean text).
I have site where we got
Root Admin (1)
Client Admin (1)
Client Sub-Admins (N)
Employer Admin (N)
Employer Sub-Admins (N)
Above users login at back end page
Users (N)
Users login at front end of the site
N - means unlimited
Guess my question is should i put all admins in same table? However employers are not so trusted as Client Admins.
If i put admins in different tables, how i do authentication in PHP? Take data from both tables and merge into array then look in array if user exists?
If you're only ever going to have a single root/client admin I would suggest simply storing their user_id values separately, possibly in a configuration file that is difficult to modify by something like SQL injection. Otherwise the following scheme should allow you a fair amount of flexibility to assign as many users to as many groups as you want.
TABLE users
user_id INT PK AUTO_INCREMENT
user_name VARCHAR
user_password VARCHAR
...
TABLE groups
group_id INT PK AUTO_INCREMENT
group_name VARCHAR
[possible permissions declarations,
or create a similar group_perms table]
...
TABLE user_group_map
user_id INT PK
group_id INT PK
One way to do it is to separate the authentication/user profile data from its possible array of roles. So, assign roles to your users. Hell, assign contexts to your roles. The way I see it, you have a 1-to-many relation between user and roles, in which the roles are assigned a context (Admin of Employers, Admin of Clients, General Admin...).
I would not use multiple tables just to separate users based on how much I trust them. After reading your question and comments in your case you would have to create individual tables for root admins, client admins, employer admins and regular users since your trust level is different for each group. Implementation / maintenance can become really ugly when you start coding even with only two tables...
You seem to be very determined to go with separate tables though and if you choose to do so there are techniques you can "hide" this, for example, create a view to merge these tables, use SQL union in your DAO, or read each table and merge the data programmatically, etc. Again, as you build your application you will most likely have issues with this design.
I would rather use a single table for users and introduce the concept of roles with a many-to-many relation between them. Upon user creation I would associate each user with a default role (eg. user root-admin has a role of root-admin, etc.) along with any other roles that they seem to fit (eg. user cleint-admin has an additional role of client-sub-admin, etc.) Based on the requirements there could be roles that do not relate to users directly, eg. guest, member, etc.
I would also introduce the concept of application contexts with an optional many-to-many relation to roles then initially associate the role root-admin with the application context all meaning that s/he has no restrictions. Additional contexts would be created based on business requirements (eg. role employer-admin is part of the context hire-employees, etc.)
When authorizing, a security manager component can grant / deny access based on the user and its associated roles / contexts with additional logic included if necessary (eg. user is disabled).
Your next concern was that you have additional data for certain users which does not apply to others. In order to resolve this I would introduce the profiles table with an optional one-to-one relation to the users table (not every user has a profile, eg. user root-admin does not).
Schema (draft):
__________________ __________________
|USERS | |ROLES |
|==================| |==================|
|id | |id |
|username | 1..* 1..* |name |
|password | -------------- |description |
|failedattempts | |... |
|disabled | | |
|... | | |
|__________________| |__________________|
| 1 | 0..*
| |
| |
| |
| 0..1 | 0..*
__________________ __________________
|PROFILES | |CONTEXTS |
|==================| |==================|
|id | |id |
|firstname | |name |
|lastname | |description |
|email | |... |
|dob | | |
|... | | |
|__________________| |__________________|
I've described a user and group permission system in this post (ignore the title -- the original question was poorly worded):
Applying column permissions for a table over a trigger

SQL Server table with dynamic columns?

I am wondering how to approach this problem.
We have a profile table in our database that will be populated by a process that reads
an uploaded excel document and then dumps the columns and the data in their rows into the
user's profile (the only thing common between all such excel spreadsheets is an email address).
Accordingly, we can't really predict what a given user's profile is going to look like.
How do I create my profile table(s)?
Sorry I have to create another answer, but comment wont let me create the ascii sketch
----------
| user |
----------
| id pk|
| name |
| ..... |
----------
----------------
| preference |
----------------
| user_id fk | <-- reference user.id
| header |
| value |
----------------
csv_row=1,churk,height,11,weight,500lb,width,22,...
OR csv_row=1,churk,height=11,wieght=500lb,width=22......
this will yield 1 row in user table, user.id = 1, user.name = Churk
at least 3 rows in preference. {[1,height,11],[1,weight,500lb],[1,width,22]}
So when you query the DB, all you need is
SELECT * FROM user JOIN preference on preference.user_id = user.id WHERE user.name = 'Churk';
If you have someway to process these data using a programming language, and not blinding doing mappings, the it should be pretty simple.
User_table with an ID, and some fix info such as name and what not.
Then you have a profile table that has a user_id foreign key, and key pair value, header / value
How will this data be queried later? As much as I hate the practice, this may be a case of needing to store csv data in a column.
Update:
This might be a good fit for an Entity Attribute Value schema. I'm not really a fan of EAV either, but at least it's less evil than csv data in a column.