mirror of https://github.com/acanas/swad-core.git
Version 20.70: May 07, 2021 New module swad_follow_database for database queries related to followin/followers.
This commit is contained in:
parent
4818af539d
commit
300662e301
2
Makefile
2
Makefile
|
@ -40,7 +40,7 @@ OBJS = swad_account.o swad_action.o swad_agenda.o swad_alert.o \
|
|||
swad_exam_set.o \
|
||||
swad_figure.o swad_figure_cache.o swad_file.o swad_file_browser.o \
|
||||
swad_file_extension.o swad_file_MIME.o swad_firewall.o swad_follow.o \
|
||||
swad_form.o swad_forum.o \
|
||||
swad_follow_database.o swad_form.o swad_forum.o \
|
||||
swad_game.o swad_global.o swad_group.o \
|
||||
swad_help.o swad_hierarchy.o swad_hierarchy_config.o swad_holiday.o \
|
||||
swad_HTML.o \
|
||||
|
|
|
@ -600,13 +600,14 @@ TODO: Salvador Romero Cort
|
|||
|
||||
TODO: FIX BUG, URGENT! En las fechas como parámetro Dat_WriteParamsIniEndDates(), por ejemplo al cambiar el color de la gráfica de accesos por día y hora, no se respeta la zona horaria.
|
||||
*/
|
||||
#define Log_PLATFORM_VERSION "SWAD 20.69.2 (2021-05-04)"
|
||||
#define Log_PLATFORM_VERSION "SWAD 20.70 (2021-05-07)"
|
||||
#define CSS_FILE "swad20.45.css"
|
||||
#define JS_FILE "swad20.69.1.js"
|
||||
/*
|
||||
TODO: Rename CENTRE to CENTER in help wiki.
|
||||
TODO: Rename ASSESSMENT.Announcements to ASSESSMENT.Calls_for_exams
|
||||
|
||||
Version 20.70: May 07, 2021 New module swad_follow_database for database queries related to followin/followers. (309943 lines)
|
||||
Version 20.69.2: May 04, 2021 Fixed bug in removal of timeline favs. (309778 lines)
|
||||
Version 20.69.1: Apr 30, 2021 Code refactoring in JavaScript (firstChild instead of childNodes[0]). (309775 lines)
|
||||
Version 20.69: Apr 30, 2021 Changes in timeline to not repeat notes in new activity. (309773 lines)
|
||||
|
|
422
swad_follow.c
422
swad_follow.c
|
@ -33,6 +33,7 @@
|
|||
#include "swad_error.h"
|
||||
#include "swad_figure.h"
|
||||
#include "swad_follow.h"
|
||||
#include "swad_follow_database.h"
|
||||
#include "swad_form.h"
|
||||
#include "swad_global.h"
|
||||
#include "swad_HTML.h"
|
||||
|
@ -58,12 +59,6 @@
|
|||
/******************************* Private types *******************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
Fol_SUGGEST_ONLY_USERS_WITH_PHOTO,
|
||||
Fol_SUGGEST_ANY_USER,
|
||||
} Fol_WhichUsersSuggestToFollowThem_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
/************** External global variables from others modules ****************/
|
||||
/*****************************************************************************/
|
||||
|
@ -78,10 +73,6 @@ extern struct Globals Gbl;
|
|||
/***************************** Private prototypes ****************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
static unsigned Fol_GetUsrsToFollow (unsigned MaxUsrsToShow,
|
||||
Fol_WhichUsersSuggestToFollowThem_t WhichUsersSuggestToFollowThem,
|
||||
MYSQL_RES **mysql_res);
|
||||
|
||||
static void Fol_PutIconsWhoToFollow (__attribute__((unused)) void *Args);
|
||||
static void Fol_PutIconToUpdateWhoToFollow (void);
|
||||
|
||||
|
@ -146,7 +137,7 @@ void Fol_SuggestUsrsToFollowMainZone (void)
|
|||
Mnu_ContextMenuEnd ();
|
||||
|
||||
/***** Get users *****/
|
||||
if ((NumUsrs = Fol_GetUsrsToFollow (Fol_MAX_USRS_TO_FOLLOW_MAIN_ZONE,
|
||||
if ((NumUsrs = Fol_DB_GetUsrsToFollow (Fol_MAX_USRS_TO_FOLLOW_MAIN_ZONE,
|
||||
Fol_SUGGEST_ANY_USER,
|
||||
&mysql_res)))
|
||||
{
|
||||
|
@ -211,7 +202,7 @@ void Fol_SuggestUsrsToFollowMainZoneOnRightColumn (void)
|
|||
struct UsrData UsrDat;
|
||||
|
||||
/***** Get users *****/
|
||||
if ((NumUsrs = Fol_GetUsrsToFollow (Fol_MAX_USRS_TO_FOLLOW_RIGHT_COLUMN,
|
||||
if ((NumUsrs = Fol_DB_GetUsrsToFollow (Fol_MAX_USRS_TO_FOLLOW_RIGHT_COLUMN,
|
||||
Fol_SUGGEST_ONLY_USERS_WITH_PHOTO,
|
||||
&mysql_res)))
|
||||
{
|
||||
|
@ -263,171 +254,6 @@ void Fol_SuggestUsrsToFollowMainZoneOnRightColumn (void)
|
|||
DB_FreeMySQLResult (&mysql_res);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*************************** Get users to follow *****************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
static unsigned Fol_GetUsrsToFollow (unsigned MaxUsrsToShow,
|
||||
Fol_WhichUsersSuggestToFollowThem_t WhichUsersSuggestToFollowThem,
|
||||
MYSQL_RES **mysql_res)
|
||||
{
|
||||
extern const char *Pri_VisibilityDB[Pri_NUM_OPTIONS_PRIVACY];
|
||||
char SubQuery1[256];
|
||||
char SubQuery2[256];
|
||||
char SubQuery3[256];
|
||||
char SubQuery4[256];
|
||||
|
||||
/***** Build subqueries related to photos *****/
|
||||
switch (WhichUsersSuggestToFollowThem)
|
||||
{
|
||||
case Fol_SUGGEST_ONLY_USERS_WITH_PHOTO:
|
||||
// Photo visibility should be >= profile visibility in every subquery
|
||||
sprintf (SubQuery1, // 1. Users followed by my followed
|
||||
" AND usr_data.PhotoVisibility IN ('%s','%s')"
|
||||
" AND usr_data.Photo<>''",
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_SYSTEM],
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_WORLD ]);
|
||||
sprintf (SubQuery2, // 2. Users who share any course with me
|
||||
" AND usr_data.PhotoVisibility IN ('%s','%s','%s')"
|
||||
" AND usr_data.Photo<>''",
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_COURSE],
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_SYSTEM],
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_WORLD ]);
|
||||
sprintf (SubQuery3, // 3. Users who share any course with me with another role
|
||||
" AND usr_data.PhotoVisibility IN ('%s','%s','%s','%s')"
|
||||
" AND usr_data.Photo<>''",
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_USER ],
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_COURSE],
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_SYSTEM],
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_WORLD ]);
|
||||
sprintf (SubQuery4, // 4. Add some likely unknown random users
|
||||
" AND usr_data.PhotoVisibility IN ('%s','%s')"
|
||||
" AND usr_data.Photo<>''",
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_SYSTEM],
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_WORLD ]);
|
||||
break;
|
||||
case Fol_SUGGEST_ANY_USER:
|
||||
SubQuery1[0] = '\0';
|
||||
SubQuery2[0] = '\0';
|
||||
SubQuery3[0] = '\0';
|
||||
SubQuery4[0] = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
/***** Build query to get users to follow *****/
|
||||
// Get only users with surname 1 and first name
|
||||
return (unsigned)
|
||||
DB_QuerySELECT (mysql_res,"can not get users to follow",
|
||||
"SELECT DISTINCT UsrCod FROM"
|
||||
" ("
|
||||
/***** Likely known users *****/
|
||||
"(SELECT DISTINCT UsrCod FROM"
|
||||
" ("
|
||||
// 1. Users followed by my followed
|
||||
"("
|
||||
"SELECT DISTINCT usr_follow.FollowedCod AS UsrCod"
|
||||
" FROM usr_follow,"
|
||||
"(SELECT FollowedCod"
|
||||
" FROM usr_follow"
|
||||
" WHERE FollowerCod=%ld) AS my_followed,"
|
||||
" usr_data"
|
||||
" WHERE usr_follow.FollowerCod=my_followed.FollowedCod"
|
||||
" AND usr_follow.FollowedCod<>%ld"
|
||||
" AND usr_follow.FollowedCod=usr_data.UsrCod"
|
||||
" AND usr_data.Surname1<>''" // Surname 1 not empty
|
||||
" AND usr_data.FirstName<>''" // First name not empty
|
||||
"%s" // SubQuery1
|
||||
")"
|
||||
" UNION "
|
||||
// 2. Users who share any course with me
|
||||
"("
|
||||
"SELECT DISTINCT crs_users.UsrCod"
|
||||
" FROM crs_users,"
|
||||
"(SELECT CrsCod"
|
||||
" FROM crs_users"
|
||||
" WHERE UsrCod=%ld) AS my_crs,"
|
||||
" usr_data"
|
||||
" WHERE crs_users.CrsCod=my_crs.CrsCod"
|
||||
" AND crs_users.UsrCod<>%ld"
|
||||
" AND crs_users.UsrCod=usr_data.UsrCod"
|
||||
" AND usr_data.Surname1<>''" // Surname 1 not empty
|
||||
" AND usr_data.FirstName<>''" // First name not empty
|
||||
"%s" // SubQuery2
|
||||
")"
|
||||
" UNION "
|
||||
// 3. Users who share any course with me with another role
|
||||
"("
|
||||
"SELECT DISTINCT crs_users.UsrCod"
|
||||
" FROM crs_users,"
|
||||
"(SELECT CrsCod,Role"
|
||||
" FROM crs_users"
|
||||
" WHERE UsrCod=%ld) AS my_crs_role,"
|
||||
" usr_data"
|
||||
" WHERE crs_users.CrsCod=my_crs_role.CrsCod"
|
||||
" AND crs_users.Role<>my_crs_role.Role"
|
||||
" AND crs_users.UsrCod=usr_data.UsrCod"
|
||||
" AND usr_data.Surname1<>''" // Surname 1 not empty
|
||||
" AND usr_data.FirstName<>''" // First name not empty
|
||||
"%s" // SubQuery3
|
||||
")"
|
||||
") AS LikelyKnownUsrsToFollow"
|
||||
// Do not select my followed
|
||||
" WHERE UsrCod NOT IN"
|
||||
" (SELECT FollowedCod FROM usr_follow"
|
||||
" WHERE FollowerCod=%ld)"
|
||||
// Get only MaxUsrsToShow * 3 users
|
||||
" ORDER BY RAND() LIMIT %u"
|
||||
")"
|
||||
" UNION "
|
||||
"("
|
||||
/***** Likely unknown userd *****/
|
||||
// 4. Add some likely unknown random user
|
||||
// Be careful with the method to get some random users
|
||||
// from the big table of users.
|
||||
// It's much faster getting a random code and then get the first users
|
||||
// with codes >= that random code
|
||||
// that getting all users and then ordering by rand.
|
||||
"SELECT usr_data.UsrCod"
|
||||
" FROM usr_data,"
|
||||
"(SELECT ROUND(RAND()*(SELECT MAX(UsrCod)"
|
||||
" FROM usr_data)) AS RandomUsrCod) AS random_usr" // a random user code
|
||||
" WHERE usr_data.UsrCod<>%ld"
|
||||
" AND usr_data.Surname1<>''" // Surname 1 not empty
|
||||
" AND usr_data.FirstName<>''" // First name not empty
|
||||
"%s" // SubQuery4
|
||||
// Do not select my followed
|
||||
" AND usr_data.UsrCod NOT IN"
|
||||
" (SELECT FollowedCod"
|
||||
" FROM usr_follow"
|
||||
" WHERE FollowerCod=%ld)"
|
||||
" AND usr_data.UsrCod>=random_usr.RandomUsrCod" // random user code could not exists in table of users
|
||||
// Get only MaxUsrsToShow users
|
||||
" LIMIT %u"
|
||||
")"
|
||||
") AS UsrsToFollow"
|
||||
// Get only MaxUsrsToShow users
|
||||
" ORDER BY RAND()"
|
||||
" LIMIT %u",
|
||||
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
SubQuery1,
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
SubQuery2,
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
SubQuery3,
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
MaxUsrsToShow * 2, // 2/3 likely known users
|
||||
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
SubQuery4,
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
MaxUsrsToShow, // 1/3 likely unknown users
|
||||
|
||||
MaxUsrsToShow);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************** Put contextual icons in "who to follow" ******************/
|
||||
/*****************************************************************************/
|
||||
|
@ -456,24 +282,6 @@ static void Fol_PutIconToUpdateWhoToFollow (void)
|
|||
Frm_EndForm ();
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*************** Check if a user is a follower of another user ***************/
|
||||
/*****************************************************************************/
|
||||
|
||||
bool Fol_CheckUsrIsFollowerOf (long FollowerCod,long FollowedCod)
|
||||
{
|
||||
if (FollowerCod == FollowedCod)
|
||||
return false;
|
||||
|
||||
/***** Check if a user is a follower of another user *****/
|
||||
return (DB_QueryCOUNT ("can not get if a user is a follower of another one",
|
||||
"SELECT COUNT(*)"
|
||||
" FROM usr_follow"
|
||||
" WHERE FollowerCod=%ld"
|
||||
" AND FollowedCod=%ld",
|
||||
FollowerCod,FollowedCod) != 0);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*************************** Get number of followed **************************/
|
||||
/*****************************************************************************/
|
||||
|
@ -505,18 +313,8 @@ void Fol_GetNumFollow (long UsrCod,
|
|||
|
||||
/***** 3. Slow check: Get number of following/followers from database *****/
|
||||
Gbl.Cache.Follow.UsrCod = UsrCod;
|
||||
*NumFollowing = Gbl.Cache.Follow.NumFollowing = (unsigned)
|
||||
DB_QueryCOUNT ("can not get number of followed",
|
||||
"SELECT COUNT(*)"
|
||||
" FROM usr_follow"
|
||||
" WHERE FollowerCod=%ld",
|
||||
UsrCod);
|
||||
*NumFollowers = Gbl.Cache.Follow.NumFollowers = (unsigned)
|
||||
DB_QueryCOUNT ("can not get number of followers",
|
||||
"SELECT COUNT(*)"
|
||||
" FROM usr_follow"
|
||||
" WHERE FollowedCod=%ld",
|
||||
UsrCod);
|
||||
*NumFollowing = Gbl.Cache.Follow.NumFollowing = Fol_DB_GetNumFollowing (UsrCod);
|
||||
*NumFollowers = Gbl.Cache.Follow.NumFollowers = Fol_DB_GetNumFollowers (UsrCod);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -690,14 +488,8 @@ static void Fol_ListFollowingUsr (struct UsrData *UsrDat)
|
|||
/***** Show user's profile *****/
|
||||
if (Prf_ShowUserProfile (UsrDat))
|
||||
{
|
||||
/***** Check if a user is a follower of another user *****/
|
||||
NumUsrs = (unsigned)
|
||||
DB_QuerySELECT (&mysql_res,"can not get followed users",
|
||||
"SELECT FollowedCod" // row[0]
|
||||
" FROM usr_follow"
|
||||
" WHERE FollowerCod=%ld"
|
||||
" ORDER BY FollowTime DESC",
|
||||
UsrDat->UsrCod);
|
||||
/***** Get list of following *****/
|
||||
NumUsrs = Fol_DB_GetListFollowing (UsrDat->UsrCod,&mysql_res);
|
||||
|
||||
if (NumUsrs)
|
||||
{
|
||||
|
@ -776,14 +568,8 @@ static void Fol_ListFollowersUsr (struct UsrData *UsrDat)
|
|||
/***** Show user's profile *****/
|
||||
if (Prf_ShowUserProfile (UsrDat))
|
||||
{
|
||||
/***** Check if a user is a follower of another user *****/
|
||||
NumUsrs = (unsigned)
|
||||
DB_QuerySELECT (&mysql_res,"can not get followers",
|
||||
"SELECT FollowerCod"
|
||||
" FROM usr_follow"
|
||||
" WHERE FollowedCod=%ld"
|
||||
" ORDER BY FollowTime DESC",
|
||||
UsrDat->UsrCod);
|
||||
/***** Get list of followers *****/
|
||||
NumUsrs = Fol_DB_GetListFollowers (UsrDat->UsrCod,&mysql_res);
|
||||
|
||||
if (NumUsrs)
|
||||
{
|
||||
|
@ -875,7 +661,8 @@ static void Fol_ShowFollowedOrFollower (struct UsrData *UsrDat)
|
|||
else // It's not me
|
||||
{
|
||||
/* Put form to follow / unfollow */
|
||||
if (Fol_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod,UsrDat->UsrCod)) // I follow user
|
||||
if (Fol_DB_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
UsrDat->UsrCod)) // I follow user
|
||||
/* Form to unfollow */
|
||||
Fol_PutIconToUnfollow (UsrDat);
|
||||
else if (Visible) // I do not follow this user and I can follow
|
||||
|
@ -930,7 +717,8 @@ static void Fol_WriteRowUsrToFollowOnRightColumn (struct UsrData *UsrDat)
|
|||
else // It's not me
|
||||
{
|
||||
/* Put form to follow / unfollow */
|
||||
if (Fol_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod,UsrDat->UsrCod)) // I follow user
|
||||
if (Fol_DB_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
UsrDat->UsrCod)) // I follow user
|
||||
/* Form to unfollow */
|
||||
Fol_PutIconToUnfollow (UsrDat);
|
||||
else if (Visible) // I do not follow this user and I can follow
|
||||
|
@ -998,7 +786,7 @@ void Fol_FollowUsr1 (void)
|
|||
if (Usr_GetParamOtherUsrCodEncryptedAndGetUsrData ())
|
||||
{
|
||||
// Follow only if I do not follow him/her
|
||||
if (!Fol_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
if (!Fol_DB_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
Gbl.Usrs.Other.UsrDat.UsrCod))
|
||||
Fol_FollowUsr (&Gbl.Usrs.Other.UsrDat);
|
||||
|
||||
|
@ -1033,7 +821,7 @@ void Fol_UnfollowUsr1 (void)
|
|||
if (Usr_GetParamOtherUsrCodEncryptedAndGetUsrData ())
|
||||
{
|
||||
// Unfollow only if I follow him/her
|
||||
if (Fol_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
if (Fol_DB_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
Gbl.Usrs.Other.UsrDat.UsrCod))
|
||||
Fol_UnfollowUsr (&Gbl.Usrs.Other.UsrDat);
|
||||
|
||||
|
@ -1167,7 +955,6 @@ static void Fol_GetFollowedFromSelectedUsrs (unsigned *NumFollowed,
|
|||
extern const char *Txt_Selected_users_X_Followed_Y_Not_followed_Z;
|
||||
struct UsrData UsrDat;
|
||||
const char *Ptr;
|
||||
bool IFollowUsr;
|
||||
unsigned NumUsrs = 0;
|
||||
|
||||
/***** Initialize structure with user's data *****/
|
||||
|
@ -1187,12 +974,9 @@ static void Fol_GetFollowedFromSelectedUsrs (unsigned *NumFollowed,
|
|||
Usr_DONT_GET_ROLE_IN_CURRENT_CRS)) // Get from the database the data of the student
|
||||
if (Usr_CheckIfUsrBelongsToCurrentCrs (&UsrDat))
|
||||
{
|
||||
/* Check if I follow this user */
|
||||
IFollowUsr = Fol_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
UsrDat.UsrCod);
|
||||
|
||||
/* Update number of users */
|
||||
if (IFollowUsr)
|
||||
/* Check if I follow this user, and update number of users */
|
||||
if (Fol_DB_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
UsrDat.UsrCod)) // I follow user
|
||||
(*NumFollowed)++;
|
||||
NumUsrs++;
|
||||
}
|
||||
|
@ -1238,7 +1022,7 @@ void Fol_FollowUsrs ()
|
|||
Usr_DONT_GET_ROLE_IN_CURRENT_CRS))
|
||||
if (Usr_CheckIfUsrBelongsToCurrentCrs (&UsrDat))
|
||||
/* If I don't follow this user ==> follow him/her */
|
||||
if (!Fol_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
if (!Fol_DB_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
UsrDat.UsrCod))
|
||||
{
|
||||
Fol_FollowUsr (&UsrDat);
|
||||
|
@ -1287,7 +1071,7 @@ void Fol_UnfollowUsrs (void)
|
|||
Usr_DONT_GET_ROLE_IN_CURRENT_CRS))
|
||||
if (Usr_CheckIfUsrBelongsToCurrentCrs (&UsrDat))
|
||||
/* If I follow this user ==> unfollow him/her */
|
||||
if (Fol_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
if (Fol_DB_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
UsrDat.UsrCod))
|
||||
{
|
||||
Fol_UnfollowUsr (&UsrDat);
|
||||
|
@ -1325,13 +1109,7 @@ static void Fol_FollowUsr (struct UsrData *UsrDat)
|
|||
return;
|
||||
|
||||
/***** Follow user in database *****/
|
||||
DB_QueryREPLACE ("can not follow user",
|
||||
"REPLACE INTO usr_follow"
|
||||
" (FollowerCod,FollowedCod,FollowTime)"
|
||||
" VALUES"
|
||||
" (%ld,%ld,NOW())",
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
UsrDat->UsrCod);
|
||||
Fol_DB_FollowUsr (UsrDat->UsrCod);
|
||||
|
||||
/***** Flush cache *****/
|
||||
Fol_FlushCacheFollow ();
|
||||
|
@ -1367,12 +1145,7 @@ static void Fol_UnfollowUsr (struct UsrData *UsrDat)
|
|||
return;
|
||||
|
||||
/***** Unfollow user in database *****/
|
||||
DB_QueryDELETE ("can not unfollow user",
|
||||
"DELETE FROM usr_follow"
|
||||
" WHERE FollowerCod=%ld"
|
||||
" AND FollowedCod=%ld",
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
UsrDat->UsrCod);
|
||||
Fol_DB_UnfollowUsr (UsrDat->UsrCod);
|
||||
|
||||
/***** Flush cache *****/
|
||||
Fol_FlushCacheFollow ();
|
||||
|
@ -1385,122 +1158,12 @@ static void Fol_UnfollowUsr (struct UsrData *UsrDat)
|
|||
void Fol_GetAndShowRankingFollowers (void)
|
||||
{
|
||||
MYSQL_RES *mysql_res;
|
||||
unsigned NumUsrs = 0; // Initialized to avoid warning
|
||||
unsigned NumUsrs;
|
||||
|
||||
/***** Get ranking from database *****/
|
||||
switch (Gbl.Scope.Current)
|
||||
{
|
||||
case Hie_Lvl_SYS:
|
||||
NumUsrs = (unsigned)
|
||||
DB_QuerySELECT (&mysql_res,"can not get ranking",
|
||||
"SELECT FollowedCod," // row[0]
|
||||
"COUNT(FollowerCod) AS N" // row[1]
|
||||
" FROM usr_follow"
|
||||
" GROUP BY FollowedCod"
|
||||
" ORDER BY N DESC,"
|
||||
"FollowedCod"
|
||||
" LIMIT 100");
|
||||
break;
|
||||
case Hie_Lvl_CTY:
|
||||
NumUsrs = (unsigned)
|
||||
DB_QuerySELECT (&mysql_res,"can not get ranking",
|
||||
"SELECT usr_follow.FollowedCod," // row[0]
|
||||
"COUNT(DISTINCT usr_follow.FollowerCod) AS N" // row[1]
|
||||
" FROM ins_instits,"
|
||||
"ctr_centers,"
|
||||
"deg_degrees,"
|
||||
"crs_courses,"
|
||||
"crs_users,"
|
||||
"usr_follow"
|
||||
" WHERE ins_instits.CtyCod=%ld"
|
||||
" AND ins_instits.InsCod=ctr_centers.InsCod"
|
||||
" AND ctr_centers.CtrCod=deg_degrees.CtrCod"
|
||||
" AND deg_degrees.DegCod=crs_courses.DegCod"
|
||||
" AND crs_courses.CrsCod=crs_users.CrsCod"
|
||||
" AND crs_users.UsrCod=usr_follow.FollowedCod"
|
||||
" GROUP BY usr_follow.FollowedCod"
|
||||
" ORDER BY N DESC,"
|
||||
"usr_follow.FollowedCod"
|
||||
" LIMIT 100",
|
||||
Gbl.Hierarchy.Cty.CtyCod);
|
||||
break;
|
||||
case Hie_Lvl_INS:
|
||||
NumUsrs = (unsigned)
|
||||
DB_QuerySELECT (&mysql_res,"can not get ranking",
|
||||
"SELECT usr_follow.FollowedCod," // row[0]
|
||||
"COUNT(DISTINCT usr_follow.FollowerCod) AS N" // row[1]
|
||||
" FROM ctr_centers,"
|
||||
"deg_degrees,"
|
||||
"crs_courses,"
|
||||
"crs_users,"
|
||||
"usr_follow"
|
||||
" WHERE ctr_centers.InsCod=%ld"
|
||||
" AND ctr_centers.CtrCod=deg_degrees.CtrCod"
|
||||
" AND deg_degrees.DegCod=crs_courses.DegCod"
|
||||
" AND crs_courses.CrsCod=crs_users.CrsCod"
|
||||
" AND crs_users.UsrCod=usr_follow.FollowedCod"
|
||||
" GROUP BY usr_follow.FollowedCod"
|
||||
" ORDER BY N DESC,"
|
||||
"usr_follow.FollowedCod"
|
||||
" LIMIT 100",
|
||||
Gbl.Hierarchy.Ins.InsCod);
|
||||
break;
|
||||
case Hie_Lvl_CTR:
|
||||
NumUsrs = (unsigned)
|
||||
DB_QuerySELECT (&mysql_res,"can not get ranking",
|
||||
"SELECT usr_follow.FollowedCod," // row[0]
|
||||
"COUNT(DISTINCT usr_follow.FollowerCod) AS N" // row[1]
|
||||
" FROM deg_degrees,"
|
||||
"crs_courses,"
|
||||
"crs_users,"
|
||||
"usr_follow"
|
||||
" WHERE deg_degrees.CtrCod=%ld"
|
||||
" AND deg_degrees.DegCod=crs_courses.DegCod"
|
||||
" AND crs_courses.CrsCod=crs_users.CrsCod"
|
||||
" AND crs_users.UsrCod=usr_follow.FollowedCod"
|
||||
" GROUP BY usr_follow.FollowedCod"
|
||||
" ORDER BY N DESC,"
|
||||
"usr_follow.FollowedCod"
|
||||
" LIMIT 100",
|
||||
Gbl.Hierarchy.Ctr.CtrCod);
|
||||
break;
|
||||
case Hie_Lvl_DEG:
|
||||
NumUsrs = (unsigned)
|
||||
DB_QuerySELECT (&mysql_res,"can not get ranking",
|
||||
"SELECT usr_follow.FollowedCod," // row[0]
|
||||
"COUNT(DISTINCT usr_follow.FollowerCod) AS N" // row[1]
|
||||
" FROM crs_courses,"
|
||||
"crs_users,"
|
||||
"usr_follow"
|
||||
" WHERE crs_courses.DegCod=%ld"
|
||||
" AND crs_courses.CrsCod=crs_users.CrsCod"
|
||||
" AND crs_users.UsrCod=usr_follow.FollowedCod"
|
||||
" GROUP BY usr_follow.FollowedCod"
|
||||
" ORDER BY N DESC,"
|
||||
"usr_follow.FollowedCod"
|
||||
" LIMIT 100",
|
||||
Gbl.Hierarchy.Deg.DegCod);
|
||||
break;
|
||||
case Hie_Lvl_CRS:
|
||||
NumUsrs = (unsigned)
|
||||
DB_QuerySELECT (&mysql_res,"can not get ranking",
|
||||
"SELECT usr_follow.FollowedCod," // row[0]
|
||||
"COUNT(DISTINCT usr_follow.FollowerCod) AS N" // row[1]
|
||||
" FROM crs_users,"
|
||||
"usr_follow"
|
||||
" WHERE crs_users.CrsCod=%ld"
|
||||
" AND crs_users.UsrCod=usr_follow.FollowedCod"
|
||||
" GROUP BY usr_follow.FollowedCod"
|
||||
" ORDER BY N DESC,"
|
||||
"usr_follow.FollowedCod"
|
||||
" LIMIT 100",
|
||||
Gbl.Hierarchy.Crs.CrsCod);
|
||||
break;
|
||||
default:
|
||||
Err_WrongScopeExit ();
|
||||
break;
|
||||
}
|
||||
NumUsrs = Fol_DB_GetRankingFollowers (&mysql_res);
|
||||
|
||||
/***** Show ranking *****/
|
||||
Prf_ShowRankingFigure (&mysql_res,NumUsrs);
|
||||
}
|
||||
|
||||
|
@ -1523,40 +1186,9 @@ void Fol_GetNotifFollower (char SummaryStr[Ntf_MAX_BYTES_SUMMARY + 1],
|
|||
|
||||
void Fol_RemoveUsrFromUsrFollow (long UsrCod)
|
||||
{
|
||||
DB_QueryDELETE ("can not remove user from followers and followed",
|
||||
"DELETE FROM usr_follow"
|
||||
" WHERE FollowerCod=%ld"
|
||||
" OR FollowedCod=%ld",
|
||||
UsrCod,UsrCod);
|
||||
/***** Remove user from followers and followed *****/
|
||||
Fol_DB_RemoveUsrFromUsrFollow (UsrCod);
|
||||
|
||||
/***** Flush cache *****/
|
||||
Fol_FlushCacheFollow ();
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/******* Create/drop temporary tables with me and the users I follow *********/
|
||||
/*****************************************************************************/
|
||||
|
||||
void Fol_CreateTmpTableMeAndUsrsIFollow (void)
|
||||
{
|
||||
/***** Create temporary table with me and the users I follow *****/
|
||||
DB_Query ("can not create temporary table",
|
||||
"CREATE TEMPORARY TABLE fol_tmp_me_and_followed "
|
||||
"(UsrCod INT NOT NULL,"
|
||||
"UNIQUE INDEX(UsrCod))"
|
||||
" ENGINE=MEMORY"
|
||||
" SELECT %ld AS UsrCod" // Me
|
||||
" UNION"
|
||||
" SELECT FollowedCod AS UsrCod" // Users I follow
|
||||
" FROM usr_follow"
|
||||
" WHERE FollowerCod=%ld",
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod);
|
||||
}
|
||||
|
||||
void Fol_DropTmpTableMeAndUsrsIFollow (void)
|
||||
{
|
||||
/***** Drop temporary table with me and the users I follow *****/
|
||||
DB_Query ("can not remove temporary table",
|
||||
"DROP TEMPORARY TABLE IF EXISTS fol_tmp_me_and_followed");
|
||||
}
|
||||
|
|
|
@ -27,10 +27,7 @@
|
|||
/********************************** Headers **********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <stdlib.h> // For malloc
|
||||
|
||||
#include "swad_notification.h"
|
||||
#include "swad_user.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************************** Public constants *****************************/
|
||||
|
@ -40,6 +37,12 @@
|
|||
/******************************** Public types *******************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
Fol_SUGGEST_ONLY_USERS_WITH_PHOTO,
|
||||
Fol_SUGGEST_ANY_USER,
|
||||
} Fol_WhichUsersSuggestToFollowThem_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************************** Public prototypes ****************************/
|
||||
/*****************************************************************************/
|
||||
|
@ -48,7 +51,6 @@ void Fol_PutLinkWhoToFollow (void);
|
|||
void Fol_SuggestUsrsToFollowMainZone (void);
|
||||
void Fol_SuggestUsrsToFollowMainZoneOnRightColumn (void);
|
||||
|
||||
bool Fol_CheckUsrIsFollowerOf (long FollowerCod,long FollowedCod);
|
||||
void Fol_FlushCacheFollow (void);
|
||||
void Fol_GetNumFollow (long UsrCod,
|
||||
unsigned *NumFollowing,unsigned *NumFollowers);
|
||||
|
@ -78,7 +80,7 @@ void Fol_GetNotifFollower (char SummaryStr[Ntf_MAX_BYTES_SUMMARY + 1],
|
|||
|
||||
void Fol_RemoveUsrFromUsrFollow (long UsrCod);
|
||||
|
||||
void Fol_CreateTmpTableMeAndUsrsIFollow (void);
|
||||
void Fol_DropTmpTableMeAndUsrsIFollow (void);
|
||||
void Fol_DB_CreateTmpTableMeAndUsrsIFollow (void);
|
||||
void Fol_DB_DropTmpTableMeAndUsrsIFollow (void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,513 @@
|
|||
// swad_follow_database.c: user's followers and followed operations with database
|
||||
|
||||
/*
|
||||
SWAD (Shared Workspace At a Distance),
|
||||
is a web platform developed at the University of Granada (Spain),
|
||||
and used to support university teaching.
|
||||
|
||||
This file is part of SWAD core.
|
||||
Copyright (C) 1999-2021 Antonio Cañas Vargas
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General 3 License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*****************************************************************************/
|
||||
/*********************************** Headers *********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
#include "swad_database.h"
|
||||
#include "swad_error.h"
|
||||
#include "swad_follow.h"
|
||||
#include "swad_follow_database.h"
|
||||
#include "swad_global.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************************** Public constants *****************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
/***************************** Private constants *****************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
/******************************* Private types *******************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
/************** External global variables from others modules ****************/
|
||||
/*****************************************************************************/
|
||||
|
||||
extern struct Globals Gbl;
|
||||
|
||||
/*****************************************************************************/
|
||||
/************************* Private global variables **************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
/***************************** Private prototypes ****************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
/*************************** Get users to follow *****************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
unsigned Fol_DB_GetUsrsToFollow (unsigned MaxUsrsToShow,
|
||||
Fol_WhichUsersSuggestToFollowThem_t WhichUsersSuggestToFollowThem,
|
||||
MYSQL_RES **mysql_res)
|
||||
{
|
||||
extern const char *Pri_VisibilityDB[Pri_NUM_OPTIONS_PRIVACY];
|
||||
char SubQuery1[256];
|
||||
char SubQuery2[256];
|
||||
char SubQuery3[256];
|
||||
char SubQuery4[256];
|
||||
|
||||
/***** Build subqueries related to photos *****/
|
||||
switch (WhichUsersSuggestToFollowThem)
|
||||
{
|
||||
case Fol_SUGGEST_ONLY_USERS_WITH_PHOTO:
|
||||
// Photo visibility should be >= profile visibility in every subquery
|
||||
sprintf (SubQuery1, // 1. Users followed by my followed
|
||||
" AND usr_data.PhotoVisibility IN ('%s','%s')"
|
||||
" AND usr_data.Photo<>''",
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_SYSTEM],
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_WORLD ]);
|
||||
sprintf (SubQuery2, // 2. Users who share any course with me
|
||||
" AND usr_data.PhotoVisibility IN ('%s','%s','%s')"
|
||||
" AND usr_data.Photo<>''",
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_COURSE],
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_SYSTEM],
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_WORLD ]);
|
||||
sprintf (SubQuery3, // 3. Users who share any course with me with another role
|
||||
" AND usr_data.PhotoVisibility IN ('%s','%s','%s','%s')"
|
||||
" AND usr_data.Photo<>''",
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_USER ],
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_COURSE],
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_SYSTEM],
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_WORLD ]);
|
||||
sprintf (SubQuery4, // 4. Add some likely unknown random users
|
||||
" AND usr_data.PhotoVisibility IN ('%s','%s')"
|
||||
" AND usr_data.Photo<>''",
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_SYSTEM],
|
||||
Pri_VisibilityDB[Pri_VISIBILITY_WORLD ]);
|
||||
break;
|
||||
case Fol_SUGGEST_ANY_USER:
|
||||
SubQuery1[0] = '\0';
|
||||
SubQuery2[0] = '\0';
|
||||
SubQuery3[0] = '\0';
|
||||
SubQuery4[0] = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
/***** Build query to get users to follow *****/
|
||||
// Get only users with surname 1 and first name
|
||||
return (unsigned)
|
||||
DB_QuerySELECT (mysql_res,"can not get users to follow",
|
||||
"SELECT DISTINCT UsrCod FROM"
|
||||
" ("
|
||||
/***** Likely known users *****/
|
||||
"(SELECT DISTINCT UsrCod FROM"
|
||||
" ("
|
||||
// 1. Users followed by my followed
|
||||
"("
|
||||
"SELECT DISTINCT usr_follow.FollowedCod AS UsrCod"
|
||||
" FROM usr_follow,"
|
||||
"(SELECT FollowedCod"
|
||||
" FROM usr_follow"
|
||||
" WHERE FollowerCod=%ld) AS my_followed,"
|
||||
" usr_data"
|
||||
" WHERE usr_follow.FollowerCod=my_followed.FollowedCod"
|
||||
" AND usr_follow.FollowedCod<>%ld"
|
||||
" AND usr_follow.FollowedCod=usr_data.UsrCod"
|
||||
" AND usr_data.Surname1<>''" // Surname 1 not empty
|
||||
" AND usr_data.FirstName<>''" // First name not empty
|
||||
"%s" // SubQuery1
|
||||
")"
|
||||
" UNION "
|
||||
// 2. Users who share any course with me
|
||||
"("
|
||||
"SELECT DISTINCT crs_users.UsrCod"
|
||||
" FROM crs_users,"
|
||||
"(SELECT CrsCod"
|
||||
" FROM crs_users"
|
||||
" WHERE UsrCod=%ld) AS my_crs,"
|
||||
" usr_data"
|
||||
" WHERE crs_users.CrsCod=my_crs.CrsCod"
|
||||
" AND crs_users.UsrCod<>%ld"
|
||||
" AND crs_users.UsrCod=usr_data.UsrCod"
|
||||
" AND usr_data.Surname1<>''" // Surname 1 not empty
|
||||
" AND usr_data.FirstName<>''" // First name not empty
|
||||
"%s" // SubQuery2
|
||||
")"
|
||||
" UNION "
|
||||
// 3. Users who share any course with me with another role
|
||||
"("
|
||||
"SELECT DISTINCT crs_users.UsrCod"
|
||||
" FROM crs_users,"
|
||||
"(SELECT CrsCod,Role"
|
||||
" FROM crs_users"
|
||||
" WHERE UsrCod=%ld) AS my_crs_role,"
|
||||
" usr_data"
|
||||
" WHERE crs_users.CrsCod=my_crs_role.CrsCod"
|
||||
" AND crs_users.Role<>my_crs_role.Role"
|
||||
" AND crs_users.UsrCod=usr_data.UsrCod"
|
||||
" AND usr_data.Surname1<>''" // Surname 1 not empty
|
||||
" AND usr_data.FirstName<>''" // First name not empty
|
||||
"%s" // SubQuery3
|
||||
")"
|
||||
") AS LikelyKnownUsrsToFollow"
|
||||
// Do not select my followed
|
||||
" WHERE UsrCod NOT IN"
|
||||
" (SELECT FollowedCod FROM usr_follow"
|
||||
" WHERE FollowerCod=%ld)"
|
||||
// Get only MaxUsrsToShow * 3 users
|
||||
" ORDER BY RAND() LIMIT %u"
|
||||
")"
|
||||
" UNION "
|
||||
"("
|
||||
/***** Likely unknown userd *****/
|
||||
// 4. Add some likely unknown random user
|
||||
// Be careful with the method to get some random users
|
||||
// from the big table of users.
|
||||
// It's much faster getting a random code and then get the first users
|
||||
// with codes >= that random code
|
||||
// that getting all users and then ordering by rand.
|
||||
"SELECT usr_data.UsrCod"
|
||||
" FROM usr_data,"
|
||||
"(SELECT ROUND(RAND()*(SELECT MAX(UsrCod)"
|
||||
" FROM usr_data)) AS RandomUsrCod) AS random_usr" // a random user code
|
||||
" WHERE usr_data.UsrCod<>%ld"
|
||||
" AND usr_data.Surname1<>''" // Surname 1 not empty
|
||||
" AND usr_data.FirstName<>''" // First name not empty
|
||||
"%s" // SubQuery4
|
||||
// Do not select my followed
|
||||
" AND usr_data.UsrCod NOT IN"
|
||||
" (SELECT FollowedCod"
|
||||
" FROM usr_follow"
|
||||
" WHERE FollowerCod=%ld)"
|
||||
" AND usr_data.UsrCod>=random_usr.RandomUsrCod" // random user code could not exists in table of users
|
||||
// Get only MaxUsrsToShow users
|
||||
" LIMIT %u"
|
||||
")"
|
||||
") AS UsrsToFollow"
|
||||
// Get only MaxUsrsToShow users
|
||||
" ORDER BY RAND()"
|
||||
" LIMIT %u",
|
||||
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
SubQuery1,
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
SubQuery2,
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
SubQuery3,
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
MaxUsrsToShow * 2, // 2/3 likely known users
|
||||
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
SubQuery4,
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
MaxUsrsToShow, // 1/3 likely unknown users
|
||||
|
||||
MaxUsrsToShow);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*************** Check if a user is a follower of another user ***************/
|
||||
/*****************************************************************************/
|
||||
|
||||
bool Fol_DB_CheckUsrIsFollowerOf (long FollowerCod,long FollowedCod)
|
||||
{
|
||||
if (FollowerCod == FollowedCod)
|
||||
return false;
|
||||
|
||||
/***** Check if a user is a follower of another user *****/
|
||||
return (DB_QueryCOUNT ("can not get if a user is a follower of another one",
|
||||
"SELECT COUNT(*)"
|
||||
" FROM usr_follow"
|
||||
" WHERE FollowerCod=%ld"
|
||||
" AND FollowedCod=%ld",
|
||||
FollowerCod,FollowedCod) != 0);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*************************** Get number of followed **************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
unsigned Fol_DB_GetNumFollowing (long UsrCod)
|
||||
{
|
||||
/***** Get number of following from database *****/
|
||||
return (unsigned)
|
||||
DB_QueryCOUNT ("can not get number of followed",
|
||||
"SELECT COUNT(*)"
|
||||
" FROM usr_follow"
|
||||
" WHERE FollowerCod=%ld",
|
||||
UsrCod);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*************************** Get number of followers *************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
unsigned Fol_DB_GetNumFollowers (long UsrCod)
|
||||
{
|
||||
/***** Get number of followers from database *****/
|
||||
return (unsigned)
|
||||
DB_QueryCOUNT ("can not get number of followers",
|
||||
"SELECT COUNT(*)"
|
||||
" FROM usr_follow"
|
||||
" WHERE FollowedCod=%ld",
|
||||
UsrCod);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/************************** Get list of following ****************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
unsigned Fol_DB_GetListFollowing (long UsrCod,MYSQL_RES **mysql_res)
|
||||
{
|
||||
/***** Trivial check: user code should be > 0 *****/
|
||||
if (UsrCod <= 0)
|
||||
return 0;
|
||||
|
||||
/***** Get followed users from database *****/
|
||||
return (unsigned)
|
||||
DB_QuerySELECT (mysql_res,"can not get following",
|
||||
"SELECT FollowedCod" // row[0]
|
||||
" FROM usr_follow"
|
||||
" WHERE FollowerCod=%ld"
|
||||
" ORDER BY FollowTime DESC",
|
||||
UsrCod);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/************************** Get list of followers ****************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
unsigned Fol_DB_GetListFollowers (long UsrCod,MYSQL_RES **mysql_res)
|
||||
{
|
||||
/***** Trivial check: user code should be > 0 *****/
|
||||
if (UsrCod <= 0)
|
||||
return 0;
|
||||
|
||||
/***** Get followed users from database *****/
|
||||
return (unsigned)
|
||||
DB_QuerySELECT (mysql_res,"can not get followers",
|
||||
"SELECT FollowerCod"
|
||||
" FROM usr_follow"
|
||||
" WHERE FollowedCod=%ld"
|
||||
" ORDER BY FollowTime DESC",
|
||||
UsrCod);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/******************************** Follow user ********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
void Fol_DB_FollowUsr (long UsrCod)
|
||||
{
|
||||
/***** Trivial check: user code should be > 0 *****/
|
||||
if (UsrCod <= 0)
|
||||
return;
|
||||
|
||||
/***** Follow user in database *****/
|
||||
DB_QueryREPLACE ("can not follow user",
|
||||
"REPLACE INTO usr_follow"
|
||||
" (FollowerCod,FollowedCod,FollowTime)"
|
||||
" VALUES"
|
||||
" (%ld,%ld,NOW())",
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
UsrCod);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/******************************* Unfollow user *******************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
void Fol_DB_UnfollowUsr (long UsrCod)
|
||||
{
|
||||
/***** Trivial check: user code should be > 0 *****/
|
||||
if (UsrCod <= 0)
|
||||
return;
|
||||
|
||||
/***** Unfollow user in database *****/
|
||||
DB_QueryDELETE ("can not unfollow user",
|
||||
"DELETE FROM usr_follow"
|
||||
" WHERE FollowerCod=%ld"
|
||||
" AND FollowedCod=%ld",
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
UsrCod);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*********** Get ranking of users attending to number of followers ***********/
|
||||
/*****************************************************************************/
|
||||
|
||||
unsigned Fol_DB_GetRankingFollowers (MYSQL_RES **mysql_res)
|
||||
{
|
||||
/***** Get ranking from database *****/
|
||||
switch (Gbl.Scope.Current)
|
||||
{
|
||||
case Hie_Lvl_SYS:
|
||||
return (unsigned)
|
||||
DB_QuerySELECT (mysql_res,"can not get ranking",
|
||||
"SELECT FollowedCod," // row[0]
|
||||
"COUNT(FollowerCod) AS N" // row[1]
|
||||
" FROM usr_follow"
|
||||
" GROUP BY FollowedCod"
|
||||
" ORDER BY N DESC,"
|
||||
"FollowedCod"
|
||||
" LIMIT 100");
|
||||
case Hie_Lvl_CTY:
|
||||
return (unsigned)
|
||||
DB_QuerySELECT (mysql_res,"can not get ranking",
|
||||
"SELECT usr_follow.FollowedCod," // row[0]
|
||||
"COUNT(DISTINCT usr_follow.FollowerCod) AS N" // row[1]
|
||||
" FROM ins_instits,"
|
||||
"ctr_centers,"
|
||||
"deg_degrees,"
|
||||
"crs_courses,"
|
||||
"crs_users,"
|
||||
"usr_follow"
|
||||
" WHERE ins_instits.CtyCod=%ld"
|
||||
" AND ins_instits.InsCod=ctr_centers.InsCod"
|
||||
" AND ctr_centers.CtrCod=deg_degrees.CtrCod"
|
||||
" AND deg_degrees.DegCod=crs_courses.DegCod"
|
||||
" AND crs_courses.CrsCod=crs_users.CrsCod"
|
||||
" AND crs_users.UsrCod=usr_follow.FollowedCod"
|
||||
" GROUP BY usr_follow.FollowedCod"
|
||||
" ORDER BY N DESC,"
|
||||
"usr_follow.FollowedCod"
|
||||
" LIMIT 100",
|
||||
Gbl.Hierarchy.Cty.CtyCod);
|
||||
case Hie_Lvl_INS:
|
||||
return (unsigned)
|
||||
DB_QuerySELECT (mysql_res,"can not get ranking",
|
||||
"SELECT usr_follow.FollowedCod," // row[0]
|
||||
"COUNT(DISTINCT usr_follow.FollowerCod) AS N" // row[1]
|
||||
" FROM ctr_centers,"
|
||||
"deg_degrees,"
|
||||
"crs_courses,"
|
||||
"crs_users,"
|
||||
"usr_follow"
|
||||
" WHERE ctr_centers.InsCod=%ld"
|
||||
" AND ctr_centers.CtrCod=deg_degrees.CtrCod"
|
||||
" AND deg_degrees.DegCod=crs_courses.DegCod"
|
||||
" AND crs_courses.CrsCod=crs_users.CrsCod"
|
||||
" AND crs_users.UsrCod=usr_follow.FollowedCod"
|
||||
" GROUP BY usr_follow.FollowedCod"
|
||||
" ORDER BY N DESC,"
|
||||
"usr_follow.FollowedCod"
|
||||
" LIMIT 100",
|
||||
Gbl.Hierarchy.Ins.InsCod);
|
||||
case Hie_Lvl_CTR:
|
||||
return (unsigned)
|
||||
DB_QuerySELECT (mysql_res,"can not get ranking",
|
||||
"SELECT usr_follow.FollowedCod," // row[0]
|
||||
"COUNT(DISTINCT usr_follow.FollowerCod) AS N" // row[1]
|
||||
" FROM deg_degrees,"
|
||||
"crs_courses,"
|
||||
"crs_users,"
|
||||
"usr_follow"
|
||||
" WHERE deg_degrees.CtrCod=%ld"
|
||||
" AND deg_degrees.DegCod=crs_courses.DegCod"
|
||||
" AND crs_courses.CrsCod=crs_users.CrsCod"
|
||||
" AND crs_users.UsrCod=usr_follow.FollowedCod"
|
||||
" GROUP BY usr_follow.FollowedCod"
|
||||
" ORDER BY N DESC,"
|
||||
"usr_follow.FollowedCod"
|
||||
" LIMIT 100",
|
||||
Gbl.Hierarchy.Ctr.CtrCod);
|
||||
case Hie_Lvl_DEG:
|
||||
return (unsigned)
|
||||
DB_QuerySELECT (mysql_res,"can not get ranking",
|
||||
"SELECT usr_follow.FollowedCod," // row[0]
|
||||
"COUNT(DISTINCT usr_follow.FollowerCod) AS N" // row[1]
|
||||
" FROM crs_courses,"
|
||||
"crs_users,"
|
||||
"usr_follow"
|
||||
" WHERE crs_courses.DegCod=%ld"
|
||||
" AND crs_courses.CrsCod=crs_users.CrsCod"
|
||||
" AND crs_users.UsrCod=usr_follow.FollowedCod"
|
||||
" GROUP BY usr_follow.FollowedCod"
|
||||
" ORDER BY N DESC,"
|
||||
"usr_follow.FollowedCod"
|
||||
" LIMIT 100",
|
||||
Gbl.Hierarchy.Deg.DegCod);
|
||||
case Hie_Lvl_CRS:
|
||||
return (unsigned)
|
||||
DB_QuerySELECT (mysql_res,"can not get ranking",
|
||||
"SELECT usr_follow.FollowedCod," // row[0]
|
||||
"COUNT(DISTINCT usr_follow.FollowerCod) AS N" // row[1]
|
||||
" FROM crs_users,"
|
||||
"usr_follow"
|
||||
" WHERE crs_users.CrsCod=%ld"
|
||||
" AND crs_users.UsrCod=usr_follow.FollowedCod"
|
||||
" GROUP BY usr_follow.FollowedCod"
|
||||
" ORDER BY N DESC,"
|
||||
"usr_follow.FollowedCod"
|
||||
" LIMIT 100",
|
||||
Gbl.Hierarchy.Crs.CrsCod);
|
||||
break;
|
||||
default:
|
||||
Err_WrongScopeExit ();
|
||||
return 0; // Not reached
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*********************** Remove user from user follow ************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
void Fol_DB_RemoveUsrFromUsrFollow (long UsrCod)
|
||||
{
|
||||
/***** Trivial check: user code should be > 0 *****/
|
||||
if (UsrCod <= 0)
|
||||
return;
|
||||
|
||||
/***** Remove user from followers and followed *****/
|
||||
DB_QueryDELETE ("can not remove user from followers and followed",
|
||||
"DELETE FROM usr_follow"
|
||||
" WHERE FollowerCod=%ld"
|
||||
" OR FollowedCod=%ld",
|
||||
UsrCod,
|
||||
UsrCod);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/******* Create/drop temporary tables with me and the users I follow *********/
|
||||
/*****************************************************************************/
|
||||
|
||||
void Fol_DB_CreateTmpTableMeAndUsrsIFollow (void)
|
||||
{
|
||||
/***** Create temporary table with me and the users I follow *****/
|
||||
DB_Query ("can not create temporary table",
|
||||
"CREATE TEMPORARY TABLE fol_tmp_me_and_followed "
|
||||
"(UsrCod INT NOT NULL,"
|
||||
"UNIQUE INDEX(UsrCod))"
|
||||
" ENGINE=MEMORY"
|
||||
" SELECT %ld AS UsrCod" // Me
|
||||
" UNION"
|
||||
" SELECT FollowedCod AS UsrCod" // Users I follow
|
||||
" FROM usr_follow"
|
||||
" WHERE FollowerCod=%ld",
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod);
|
||||
}
|
||||
|
||||
void Fol_DB_DropTmpTableMeAndUsrsIFollow (void)
|
||||
{
|
||||
/***** Drop temporary table with me and the users I follow *****/
|
||||
DB_Query ("can not remove temporary table",
|
||||
"DROP TEMPORARY TABLE IF EXISTS fol_tmp_me_and_followed");
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
// swad_follow_database.h: user's followers and followed operations with database
|
||||
|
||||
#ifndef _SWAD_FOL_DB
|
||||
#define _SWAD_FOL_DB
|
||||
/*
|
||||
SWAD (Shared Workspace At a Distance in Spanish),
|
||||
is a web platform developed at the University of Granada (Spain),
|
||||
and used to support university teaching.
|
||||
|
||||
This file is part of SWAD core.
|
||||
Copyright (C) 1999-2021 Antonio Cañas Vargas
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*****************************************************************************/
|
||||
/********************************** Headers **********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
#include "swad_follow.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************************** Public constants *****************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
/******************************** Public types *******************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************************** Public prototypes ****************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
unsigned Fol_DB_GetUsrsToFollow (unsigned MaxUsrsToShow,
|
||||
Fol_WhichUsersSuggestToFollowThem_t WhichUsersSuggestToFollowThem,
|
||||
MYSQL_RES **mysql_res);
|
||||
|
||||
bool Fol_DB_CheckUsrIsFollowerOf (long FollowerCod,long FollowedCod);
|
||||
|
||||
unsigned Fol_DB_GetNumFollowing (long UsrCod);
|
||||
unsigned Fol_DB_GetNumFollowers (long UsrCod);
|
||||
|
||||
unsigned Fol_DB_GetListFollowing (long UsrCod,MYSQL_RES **mysql_res);
|
||||
unsigned Fol_DB_GetListFollowers (long UsrCod,MYSQL_RES **mysql_res);
|
||||
|
||||
void Fol_DB_FollowUsr (long UsrCod);
|
||||
void Fol_DB_UnfollowUsr (long UsrCod);
|
||||
|
||||
unsigned Fol_DB_GetRankingFollowers (MYSQL_RES **mysql_res);
|
||||
|
||||
void Fol_DB_RemoveUsrFromUsrFollow (long UsrCod);
|
||||
|
||||
void Fol_DB_CreateTmpTableMeAndUsrsIFollow (void);
|
||||
void Fol_DB_DropTmpTableMeAndUsrsIFollow (void);
|
||||
|
||||
#endif
|
|
@ -35,7 +35,7 @@
|
|||
#include "swad_database.h"
|
||||
#include "swad_error.h"
|
||||
#include "swad_figure.h"
|
||||
#include "swad_follow.h"
|
||||
#include "swad_follow_database.h"
|
||||
#include "swad_form.h"
|
||||
#include "swad_forum.h"
|
||||
#include "swad_global.h"
|
||||
|
@ -335,11 +335,11 @@ bool Prf_ShowUserProfile (struct UsrData *UsrDat)
|
|||
Fol_GetNumFollow (UsrDat->UsrCod,&NumFollowing,&NumFollowers);
|
||||
UsrFollowsMe = false;
|
||||
if (NumFollowing)
|
||||
UsrFollowsMe = Fol_CheckUsrIsFollowerOf (UsrDat->UsrCod,
|
||||
UsrFollowsMe = Fol_DB_CheckUsrIsFollowerOf (UsrDat->UsrCod,
|
||||
Gbl.Usrs.Me.UsrDat.UsrCod);
|
||||
IFollowUsr = false;
|
||||
if (NumFollowers)
|
||||
IFollowUsr = Fol_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
IFollowUsr = Fol_DB_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
UsrDat->UsrCod);
|
||||
|
||||
/***** Show following and followers *****/
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
#include "swad_department.h"
|
||||
#include "swad_enrolment.h"
|
||||
#include "swad_error.h"
|
||||
#include "swad_follow.h"
|
||||
#include "swad_follow_database.h"
|
||||
#include "swad_form.h"
|
||||
#include "swad_global.h"
|
||||
#include "swad_HTML.h"
|
||||
|
@ -2630,7 +2630,7 @@ static void Rec_PutIconsCommands (__attribute__((unused)) void *Args)
|
|||
/***** Button to follow / unfollow *****/
|
||||
if (!ItsMe) // Not me
|
||||
{
|
||||
if (Fol_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
if (Fol_DB_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||
Gbl.Record.UsrDat->UsrCod))
|
||||
// I follow user
|
||||
Lay_PutContextualLinkOnlyIcon (ActUnfUsr,NULL,
|
||||
|
|
|
@ -733,7 +733,7 @@ void Tml_DB_CreateSubQueryPublishers (const struct Tml_Timeline *Timeline,
|
|||
Gbl.Usrs.Me.UsrDat.UsrCod);
|
||||
break;
|
||||
case Usr_WHO_FOLLOWED: // Show the timeline of the users I follow
|
||||
Fol_CreateTmpTableMeAndUsrsIFollow ();
|
||||
Fol_DB_CreateTmpTableMeAndUsrsIFollow ();
|
||||
SubQueries->TablePublishers = ",fol_tmp_me_and_followed";
|
||||
Str_Copy (SubQueries->Publishers,
|
||||
"tml_pubs.PublisherCod=fol_tmp_me_and_followed.UsrCod AND ",
|
||||
|
|
|
@ -193,7 +193,7 @@ void Tml_Pub_GetListPubsToShowInTimeline (struct Tml_Timeline *Timeline)
|
|||
/* Drop temporary table with me and users I follow */
|
||||
if (Timeline->UsrOrGbl == Tml_Usr_TIMELINE_GBL && // Show the global timeline
|
||||
Timeline->Who == Usr_WHO_FOLLOWED) // Show the timeline of the users I follow
|
||||
Fol_DropTmpTableMeAndUsrsIFollow ();
|
||||
Fol_DB_DropTmpTableMeAndUsrsIFollow ();
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
Loading…
Reference in New Issue