From 300662e30198e6db2c54691deb3d42eb76a4a725 Mon Sep 17 00:00:00 2001 From: acanas Date: Fri, 7 May 2021 19:11:57 +0200 Subject: [PATCH] Version 20.70: May 07, 2021 New module swad_follow_database for database queries related to followin/followers. --- Makefile | 2 +- swad_changelog.h | 3 +- swad_follow.c | 438 +++--------------------------- swad_follow.h | 14 +- swad_follow_database.c | 513 ++++++++++++++++++++++++++++++++++++ swad_follow_database.h | 66 +++++ swad_profile.c | 10 +- swad_record.c | 6 +- swad_timeline_database.c | 2 +- swad_timeline_publication.c | 2 +- 10 files changed, 635 insertions(+), 421 deletions(-) create mode 100644 swad_follow_database.c create mode 100644 swad_follow_database.h diff --git a/Makefile b/Makefile index 5bf77ee1..831f88f2 100644 --- a/Makefile +++ b/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 \ diff --git a/swad_changelog.h b/swad_changelog.h index 16ecefbe..bb746cab 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -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) diff --git a/swad_follow.c b/swad_follow.c index 90968204..1f86aa09 100644 --- a/swad_follow.c +++ b/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,9 +137,9 @@ void Fol_SuggestUsrsToFollowMainZone (void) Mnu_ContextMenuEnd (); /***** Get users *****/ - if ((NumUsrs = Fol_GetUsrsToFollow (Fol_MAX_USRS_TO_FOLLOW_MAIN_ZONE, - Fol_SUGGEST_ANY_USER, - &mysql_res))) + if ((NumUsrs = Fol_DB_GetUsrsToFollow (Fol_MAX_USRS_TO_FOLLOW_MAIN_ZONE, + Fol_SUGGEST_ANY_USER, + &mysql_res))) { /***** Begin box and table *****/ Box_BoxTableBegin ("560px",Txt_Who_to_follow, @@ -211,9 +202,9 @@ void Fol_SuggestUsrsToFollowMainZoneOnRightColumn (void) struct UsrData UsrDat; /***** Get users *****/ - if ((NumUsrs = Fol_GetUsrsToFollow (Fol_MAX_USRS_TO_FOLLOW_RIGHT_COLUMN, - Fol_SUGGEST_ONLY_USERS_WITH_PHOTO, - &mysql_res))) + if ((NumUsrs = Fol_DB_GetUsrsToFollow (Fol_MAX_USRS_TO_FOLLOW_RIGHT_COLUMN, + Fol_SUGGEST_ONLY_USERS_WITH_PHOTO, + &mysql_res))) { /***** Begin container *****/ HTM_DIV_Begin ("class=\"CONNECTED\""); @@ -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,8 +786,8 @@ void Fol_FollowUsr1 (void) if (Usr_GetParamOtherUsrCodEncryptedAndGetUsrData ()) { // Follow only if I do not follow him/her - if (!Fol_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod, - Gbl.Usrs.Other.UsrDat.UsrCod)) + if (!Fol_DB_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod, + Gbl.Usrs.Other.UsrDat.UsrCod)) Fol_FollowUsr (&Gbl.Usrs.Other.UsrDat); Ale_CreateAlert (Ale_SUCCESS,NULL,""); // Txt not used @@ -1033,8 +821,8 @@ void Fol_UnfollowUsr1 (void) if (Usr_GetParamOtherUsrCodEncryptedAndGetUsrData ()) { // Unfollow only if I follow him/her - if (Fol_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod, - Gbl.Usrs.Other.UsrDat.UsrCod)) + if (Fol_DB_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod, + Gbl.Usrs.Other.UsrDat.UsrCod)) Fol_UnfollowUsr (&Gbl.Usrs.Other.UsrDat); Ale_CreateAlert (Ale_SUCCESS,NULL,""); // Txt not used @@ -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,8 +1022,8 @@ 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, - UsrDat.UsrCod)) + if (!Fol_DB_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod, + UsrDat.UsrCod)) { Fol_FollowUsr (&UsrDat); NumFollowed++; @@ -1287,8 +1071,8 @@ 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, - UsrDat.UsrCod)) + if (Fol_DB_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod, + UsrDat.UsrCod)) { Fol_UnfollowUsr (&UsrDat); NumUnfollowed++; @@ -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"); - } diff --git a/swad_follow.h b/swad_follow.h index f8f97369..4964505f 100644 --- a/swad_follow.h +++ b/swad_follow.h @@ -27,10 +27,7 @@ /********************************** Headers **********************************/ /*****************************************************************************/ -#include // 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 diff --git a/swad_follow_database.c b/swad_follow_database.c new file mode 100644 index 00000000..d9eeee08 --- /dev/null +++ b/swad_follow_database.c @@ -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 . +*/ +/*****************************************************************************/ +/*********************************** 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"); + } diff --git a/swad_follow_database.h b/swad_follow_database.h new file mode 100644 index 00000000..72476c4e --- /dev/null +++ b/swad_follow_database.h @@ -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 . +*/ +/*****************************************************************************/ +/********************************** 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 diff --git a/swad_profile.c b/swad_profile.c index 522a7507..3e526d4b 100644 --- a/swad_profile.c +++ b/swad_profile.c @@ -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,12 +335,12 @@ bool Prf_ShowUserProfile (struct UsrData *UsrDat) Fol_GetNumFollow (UsrDat->UsrCod,&NumFollowing,&NumFollowers); UsrFollowsMe = false; if (NumFollowing) - UsrFollowsMe = Fol_CheckUsrIsFollowerOf (UsrDat->UsrCod, - Gbl.Usrs.Me.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, - UsrDat->UsrCod); + IFollowUsr = Fol_DB_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod, + UsrDat->UsrCod); /***** Show following and followers *****/ Fol_ShowFollowingAndFollowers (UsrDat, diff --git a/swad_record.c b/swad_record.c index 6e6132a4..c919ba98 100644 --- a/swad_record.c +++ b/swad_record.c @@ -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,8 +2630,8 @@ static void Rec_PutIconsCommands (__attribute__((unused)) void *Args) /***** Button to follow / unfollow *****/ if (!ItsMe) // Not me { - if (Fol_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod, - Gbl.Record.UsrDat->UsrCod)) + if (Fol_DB_CheckUsrIsFollowerOf (Gbl.Usrs.Me.UsrDat.UsrCod, + Gbl.Record.UsrDat->UsrCod)) // I follow user Lay_PutContextualLinkOnlyIcon (ActUnfUsr,NULL, Rec_PutParamUsrCodEncrypted,NULL, diff --git a/swad_timeline_database.c b/swad_timeline_database.c index 7268c22b..be290ca2 100644 --- a/swad_timeline_database.c +++ b/swad_timeline_database.c @@ -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 ", diff --git a/swad_timeline_publication.c b/swad_timeline_publication.c index 95035fc4..d37ea7a3 100644 --- a/swad_timeline_publication.c +++ b/swad_timeline_publication.c @@ -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 (); } /*****************************************************************************/