tags:

views:

56

answers:

1

What I am trying to achieve is a complex privacy routine, i have the following tables.

posts

posts_privacy

privacy_global

followerlist

We have a news feed sort of thing on our site, which gets the 10 latests posts from the people a user is following, there are 3 levels of privacy, first is privacy_global where the user can set a privacy options on his posts , 0 , 1 and 2 for "Only me", "Everyone", "followers only" respectively, then there is posts_privacy where the user can choose to list people he wants to show to or hide the post from before posting it, this setting overrides the privacy_global settings and posts_privacy instead if set.

now what my problem is that, when i apply privacy in the news feed using php I basically ask for the posts like this.

SELECT `post`.*,
  `users`.`fullname`,
  `users`.`username`,
  `posts_privacy`.`hide`,
  `posts_privacy`.`show`,
FROM `post`
  LEFT JOIN `posts_privacy` ON `post`.`id`=`posts_privacy`.`postid`
  INNER JOIN `users` ON `post`.`userid` = `users`.`id`
WHERE (`post`.`userid` IN (1,2,3,4,5,6) 
AND 12 NOT IN (
  SELECT `hide` FROM `posts_privacy` WHERE `postid`=`post`.`id`)
  OR `show`= 12
)

 GROUP BY `post`.`id`
 ORDER BY `time` DESC LIMIT 10"

I cant figure out how to apply all the other conditions, before this i was using another query and returning serialized arrays of people that the post needs to be hidden or shown to, then unserialized and proccessed it in php and removed that post from the array before being sent to the browser, that created a hole in the news feed, instead of loading 10 posts only 6 posts appear becasue php removed the 4 that had privacy before they made it to the browser, my goal here is to do EVERYTHING all the privacy conditions in SQL before the posts leave the database, so I dont have this issue with the counts of the posts in the newsfeed.

I tried looking into MySQL functions and procedures but i was told that they cant process queries or return tables.

any advice as to how to approach this issue?

EDIT: If it helps, the system i am trying to make is simlar to that on Facebook, where the user can set post specfic privacy, but also has global settings that get overridded when that is done.


Structure of tables:

followerslist:

id PRIMARY KEY BIGINT(20)
userid BIGINT(20) << id of the user who clicks the follow button
targetid BIGINT(20) << id of the user who gets followed

post:

id PRIMARY KEY BIGINT(20)
content TEXT
title VARCHAR(100)
time DATETIME
userid BIGINT(20)

posts_privacy:

id PRIMARY KEY BIGINT(20)
postid BIGINT(20)
hide BIGINT(20)
show BIGINT(20)

+1  A: 

The following is one way to get the results you are after. You will need to do some careful testing though, as I've run out of time to go any further with it. It is based on the perspective of the viewer - the user who is requesting the posts for which they have permission to view. It's not perfect, so please treat it as something from which to build.

Some of the fields that the query returns will not be needed in the final version, but they are handy for testing:

SET @viewerid := 5;
SELECT
  p.id AS post_id,
  owner.id AS owner_id,
  pg.privacy AS privacy_global,
  pp.hide AS hide_from,
  pp.show AS show_to,
  f.userid AS viewer,
  f.targetid AS following
FROM posts AS p
JOIN users AS owner ON owner.id = p.userid
JOIN privacy_global AS pg ON pg.postid = p.id
LEFT JOIN posts_privacy AS pp ON pp.postid = p.id
LEFT JOIN followerlist AS f ON f.userid = @viewerid
WHERE ((pg.privacy = 0 AND pp.show = @viewerid)
OR (pg.privacy = 1)
OR (pg.privacy = 2 AND f.targetid = p.userid))
AND ((pp.hide != @viewerid OR pp.hide IS NULL)
AND (p.userid != @viewerid))
GROUP BY p.id
LIMIT 10;

During testing, you might find it useful to break the query down. The following chunk lists the post ID, post owner, global privacy setting and the hide from / show to user IDs:

SELECT
  p.id AS post_id,
  owner.id AS owner_id,
  pg.privacy AS privacy_global,
  pp.hide AS hide_from,
  pp.show AS show_to
FROM posts AS p
JOIN users AS owner ON owner.id = p.userid
JOIN privacy_global AS pg ON pg.postid = p.id
LEFT JOIN posts_privacy AS pp ON pp.postid = p.id

Add the viewer user ID, and extra rows will be shown for each post where the owner of that post is being followed by the viewer:

SET @viewerid := 1;
SELECT
  p.id AS post_id,
  owner.id AS owner_id,
  pg.privacy AS privacy_global,
  pp.hide AS hide_from,
  pp.show AS show_to,
  f.userid AS viewer,
  f.targetid AS following
FROM posts AS p
JOIN users AS owner ON owner.id = p.userid
JOIN privacy_global AS pg ON pg.postid = p.id
LEFT JOIN posts_privacy AS pp ON pp.postid = p.id
LEFT JOIN followerlist AS f ON f.userid = @viewerid;

The WHERE clauses then go on to narrow down these results based on per-post and global privacy settings.

Mike
Thanks a lot :) i was really looking for something to build on, I will try on from here, you are really helpful thankyou :D.
Akay
I finished the task :D, everything works as expected =D.
Akay