User's possibilities on site - php

I want to build a system on the website, that allows users to do some things depend on their rating. For example I have rule for rating value X:
1 post in 3 days
10 comments in 1 day
20 votes in 2 days
for rating value Y, rule may be following:
3 post in 1 day
50 comments in 1 day
30 votes in 1 day
Each night I recalculate users' ratings, so I know what each user is able to do.
Possibilities don't sum or reset on each rating's recalculation.
One more important thing is that admin can fill concrete user's possibilities at any time.
What is optimal database (MySQL) structure for desired?
I can count what concrete user has done:
SELECT COUNT(*) FROM posts WHERE UserID=XXX AND DateOfPost >= 'YYY'
SELECT COUNT(*) FROM comments WHERE UserID=XXX AND CommentOfPost >= 'YYY'
But how can I do admin filling possibilities in this case?

I would log the number of actions of each user each day and use that table to compare.
This table would contain the following fields:
date: the day when the action took place
count: the number of actions took that day
userId: who did this action
action: which action post/comment/vote/...
ignore: boolean, if this is set, admin has reset the values
Checking a rule: SELECT SUM(count) FROM log WHERE userId = XXX AND action = YYY AND ignore = 0 AND DATEDIFF(date, NOW()) <= DAYS
Resetting a rule: UPDATE ignore = 1 FROM log WHERE userId = XXX
If his rating changes the result is still valid (you'll just compare with on other total)
When you create a rules table:
action
limits
days
rating_min
rating_max
You can query for permissions like this:
SELECT action, IF(SUM(count) < MIN(limits), 1, 0) as can_do_action FROM log LEFT JOIN rules ON rules.action = log.action WHERE userId = XXX AND rating_min <= RATING AND rating_max >= RATING AND ignore = 0 AND DATEDIFF(date, NOW()) <= days
So you get a table loggin like this:
- comment => 1
- votes => 0
You do have to update this table every action (create a new row if first action of the day or update the count of the row)
The absence of a rule means no actions have been made, so we can ignore it.

If I understand you correctly you have a user that can post 1 blog, and comment 10 times. Now he/she has commented 5 times and posted a blog. You want the admin to click a button, and now the user can again post a blog and comment 10 times?
It might be a bit of a hack, but you could count the actions that are being reset/ignored, and substract that from the current actions?
e.g.: user has 1 blog and 5 comments. Admin presses "reset", and you save those values.
Now as the user posts another blog, and you check if that's allowed, you'll get
SELECT COUNT(*) FROM posts WHERE UserID=XXX AND DateOfPost >= 'YYY'
And you do something like this
SELECT changes FROM adminTable WHERE UserID=XXX AND type = 'post'
And if count - changes is ok, you're set.

What about having, in the user table, three columns called remainingPosts, remainingComments and remainingVotes? You'll decrease the columns when the user has performed a specific action, and in this way the admin can always "refill" those columns, even above the original limit.
===
Another option is to store the expiration of the permissions in those columns, so that you can reset the permissions just putting the expiry for a certain column to the day before. You can then use your queries to get the remaining number of posts/comments/votes for the user.

I suggest separating the two concerns entirely:
The process of enabling features/possibilities to users
The data model of user features
For example, you could have a simple many-to-many table representing user features:
user_features(
user_id
,feature_id
,source (admin|earned)
,primary key(user_id, feature_id)
);
This makes it really easy for an administrator to disable/enable parts or all of the feature set.
Your nightly job would query relevant tables and grant/revoke features by inserting/deleting from this table.
If you go with this approach, you can actually give the features either based on a rating or specific actions.
A rule such as "3 posts in 3 days", can be implemented like this:
when a user posts, check if the previous post was made within 24 hours.
if yes then
increment counter by 1
record current timestamp
if counter = 3 then
grant feature to user
else
reset counter to 1
record current timestamp
You would need two columns (post_count:int, last_post:date) in some table keyed by user_id.

Related

Good way to map table based on members and months in year

I need to make simple table like this
This table represents yearly membership status for each month, it's super simple there is no advanced stuff there, that membership status is updated manually by admin (when member pays, admin update status for that month).
From database standpoint i have 2 simple tables like this:
As you can see i have membership table with member_id and date, and when payment is made that table is being populated.
So my question is: what is good way to map data to match that table ?
i'm thinking something like this (for example i want all members data from 2017 year)
select m.*,
GROUP_CONCAT(MONTH(ms.date)) as dates
from members m
left join membership ms on m.id = ms.member_id
where ms.date >= 01-01-2018
and ms.date <= 12-31-2018
this query should return list of members with dates array(array of numbers, each number represents month), so on UI side i could maybe generate this table view based on that ? Any suggestions for this, anyone have better solution ?
Your query seems fine. You can then use it to determine whether or not a month exists in the array of dates by using the includes function on the date array.
For example, to check if there should be an X for February you would check dates.includes(2). If true, place an X, otherwise leave blank.

Limit number of profiles a free user can view?

Is there a way that will allow me to limit the amount of profiles a user can look at on my site per day. so for instance each user has an id 1, 2, 3 etc. and if the one user views 5 profiles all together in one day then it stops them viewing any more and redirects them to a sign up page to become a paid member where they can view unlimited profiles?
I'm quite new to php and sql but this is primarily what i am working in if there's a way to do it in that.
Thanks
At your database create 1 table called user_views with 3 fields
id (auto increament), user_id (the user who is visiting), visited_user_id (the user id who is visited)..
At your user_details page which users see other user, at the start of your code set 1 function which will add that view to this table , if user has already visited this user it must ignore it and if user has make all allowed visits this function will redirect him ...
And the db table must be truncate each day at 00:00:00..
I think a simple use of SESSION variables and a counting mechanism would suffice.
yes you can limit them in viewing,
you can save it in database and every time they view each profile then save it into ur database, you can make a table,
tbl_user_view
field: user_id, view_count
every profile view make an update function wich
UPDATE tble_user_view set view_count = view_count + 1 WHERE user_id = user_id
and here's some twist, if the user viewed the same profile twice you need to record it as 1,
so save the id of the profile that they viewed in COOKIES or if you do not care on database load you can save it there.
Yes. Each time the user views a profile, store that information (viewer, who they viewed, a time stamp).
Every time they go to view a profile, check how many profiles they have viewed today. If it's over the limit, redirect them.
There's other logic you may want to consider, for example, if they come back to the same profile 5 times, does it count each time?

Most viewed posts in the last 21 days

I'm trying to create a blog system with php and I need a way of counting the most viewed post during the last 21 days. Does anybody know of a good way of doing this?
I don't have much experience with php so i need someone to point me in the right direction. I have tried to look into google anlytics API but it seems a bit complicated. Would it be easier to just use cookies?
Since you are building your own blog system, here is the simplest way to do it:
I assume that this is anonymous counting of your blog post visits. If you want to have ip logged records you'll have to adjust the business logic.
Create a new table called visits.
Add an id (Primary key), a field called blogpostid ( that will store the id of the post being viewed) and a field called dtpost with timestamp or datetime properties that upon insert will automatically put the date/time.
Now you can query like this:
select visits.blogpostid, count(dtpost) as counted from posts
left join posts on posts.id = visits.blogpostid
where dtpost between (NOW() AND <-21 days interval function>)
order by counted DESC group by visits.blogpostid;
What you really do is storing the datetime of someone visiting your blog post. This automatically is a count so whatever interval you put the between will fetch the data *. Then the count() function does the counting.
One thing to know is that your own browser refresh will add up to the counting of the visits so you'll have to provide a way to block counting the refresh of the browser (usually a time limit or a cookie to say that you have already seen that page).
*Edit:
Since this is ambiguous, what I mean is that it will fetch your data within the time period that you want.
Create a table views with a foreign key to post ids and add an entry with the visitors information and the date. Then you can fetch the most viewed posts like this (untested):
SELECT p.*, COUNT(p.*) count FROM posts p
INNER JOIN views v ON v.post_id = p.id
WHERE DATE_SUB(CURDATE(), INTERVAL 21 DAY) <= p.date_viewed
ORDER BY count DESC
GROUP BY p.id;
To prevent the count from incrementing when viewed multiple times by the same user you can use the session meganism to prevent that from happening.
session_start();
if (!isset($_SESSION['posts_viewed'])) {
$_SESSION['posts_viewed'] = array();
}
// some logic to get to relevant post id here
// check that the post_id is not in the array
if (!in_array($post_id, $_SESSION['posts_viewed'])) {
// logic to increment a persistent counter (e.g. in mysql) here
// add post_id to array
array_push($_SESSION['posts_viewed'], $post_id);
}
// finally some logic that display the post here
session_close();

MySQL Table structure of thumb UP & DOWN for comments system?

i already created a table for comments but i want to add the feature of thumb Up and Down for comments like Digg and Youtube, i use php & mysql and i'm wondering What's the best table scheme to implement that so comments with many likes will be on the top.
This is my current comments table : comments(id,user,article,comment,stamp)
Note: Only registred will be able to vote so it should limit 1 vote to each user in a comment
Thanks
Keep a votes table. E.g. votes(comment_id, user_id, value, stamp) - value is -1 or +1.
This allows accountability, and you can do a UNIQUE index on (comment_id, user_id) to prevent duplicate voting. You can also remove a user and all of his votes easily, if he/she is spamming.
For sorting comments by score it is possible to do a JOIN between the comment and vote tables and use SUM/GROUP BY to get the total score. However, this can be slow. For speed, you might consider keeping a score field in the comments table as well. Every time a new row is added to the votes table, you add/subtract 1 from the comment's score.
Because you are storing every vote in a table, it is easy to recalculate the score on demand. Stack Overflow does something similar with reputation - the total reputation score for a user is cached and recalculated every so often.
You could add a score field and increment or decrement with each thumb action:
UPDATE comments SET score=score+1 Where id=123
Then when you select, order by score DESC.
Since a user should be registered to thumb up/down, I would store the user ID and the post ID to validate the up/downs.
2 tables will be appropriate for this task. Let me know if you need a design.

Querying data for a Facebook-like news feed

I have a social networking site where users update their moods, profiles and add photos.
I'm currently logging all updates in a table called "update_log" with the following structure:
update_id int (auto),
userid int,
update_type int (1=profile, 2=photo, 3=mood)
pictureid int
mood_a int
mood_b int
mood_c int
update_time int
Profile update record:
(auto), 1, 1, 0, 0, 0, 0, 1239003781
Photo update record:
(auto), 1, 2, 11544, 0, 0, 0, 1239003781
Mood update record:
(auto), 1, 3, 0, 1, 490, 70, 1239003781
For the photo record, there's a corresponding table userphotos which holds the caption and filename/location data
For moods, there is a mood lookup table that holds the mood descriptions (i.e., I'm lazy =\ )
What I need to do is query this data to show on a user's profile page, it will show this feed for any of their favorite users for the last x hours of activity.
The problem I'm running into is that if a user uploads five photos over the course of a half hour or something, I just want that to be one line in the feed, not an entry for each photo upload.
Same goes for profile updates.
I need to query the data so the user will see something like this:
user x updated their mood! (I'm tired) on Apr 4, 2009 10:35 pm
user y uploaded x new photos on April 4, 2009 10:20 pm
user x updated their profile on April 4, 2009 10:15 pm
How do I group the photo updates into one record returned in a query based on all records being within let's say an hour of each other?
Is there a way to do this with one query?
Thanks!
You want something like
SELECT * FROM update_log WHERE update_time > NOW() - 30 MINUTES;
With 30 minutes being the period of time you're looking back.
I'm assuming you just needed to know how to return in a single query the updates of the last 30 minutes.
If you're trying to group all of the photos together into 30 minute blocks, say for the last two days, you'd be better off changing your database structure and creating a photo_group table [containing a primary key, userid, and time of creation] and adding a group_id column to the update_log table.
When adding a new photo, check for an existing group created by that user in the last 30 minutes. SELECT * FROM photo_group WHERE user_id = XXX AND created > NOW () - 30 MINUTES;
If one does not exist, create it. Link the photos to the newest by adding the primary key of the photo_group table as the group_id in the update_log.
When you retrieve rows later, you can group them by group_id using your scripting language.
The disadvantage of this method is your grouping structure will be difficult to modify later, as previous entries will be grouped by their old groups when you change the rules for creating new groups.
If you want to do this without storing the groups, you'll have to handle the logic in your scripting language by grouping the photos together in a loop that checks the creation time of a photo, groups following photos in an array with it if they have been created within a specific time period, or restarts the loop, using the most recent photo that did not fit with the previous. This would be more overhead than adding a new table, but it would be easier to modify later.
Have you considered trying to do this with PHP rather than SQL queries? It might be less complex to query the results you need (All updates between these times) and then use PHP to compare the timestamps in order to determine how they should be grouped.

Categories