// swad_announcement.c: Global announcement /* 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-2019 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_announcement.h" #include "swad_box.h" #include "swad_database.h" #include "swad_form.h" #include "swad_global.h" #include "swad_parameter.h" #include "swad_role.h" /*****************************************************************************/ /****************************** Public constants *****************************/ /*****************************************************************************/ /*****************************************************************************/ /***************************** Internal constants ****************************/ /*****************************************************************************/ /*****************************************************************************/ /****************************** Internal types *******************************/ /*****************************************************************************/ /*****************************************************************************/ /************** External global variables from others modules ****************/ /*****************************************************************************/ extern struct Globals Gbl; /*****************************************************************************/ /************************* Internal global variables *************************/ /*****************************************************************************/ /*****************************************************************************/ /***************************** Internal prototypes ***************************/ /*****************************************************************************/ static void Ann_PutIconToAddNewAnnouncement (void); static void Ann_PutButtonToAddNewAnnouncement (void); static void Ann_DrawAnAnnouncement (long AnnCod,Ann_Status_t Status, const char *Subject,const char *Content, unsigned Roles, bool ShowAllAnnouncements, bool ICanEdit); static void Ann_PutParams (void); static long Ann_GetParamAnnCod (void); static void Ann_PutSubjectMessage (const char *Field,const char *Label, unsigned Rows); static void Ann_CreateAnnouncement (unsigned Roles,const char *Subject,const char *Content); /*****************************************************************************/ /************************** Show global announcements ************************/ /*****************************************************************************/ void Ann_ShowAllAnnouncements (void) { extern const char *Hlp_MESSAGES_Announcements; extern const char *Txt_Announcements; extern const char *Txt_No_announcements; MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned NumAnnouncements; unsigned NumAnn; long AnnCod; unsigned Roles; char Subject[Cns_MAX_BYTES_SUBJECT + 1]; char Content[Cns_MAX_BYTES_TEXT + 1]; unsigned UnsignedNum; Ann_Status_t Status; bool ICanEdit = (Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM); /***** Get announcements from database *****/ if (ICanEdit) { /* Select all announcements */ NumAnnouncements = (unsigned) DB_QuerySELECT (&mysql_res,"can not get announcements", "SELECT AnnCod,Status,Roles,Subject,Content" " FROM announcements" " ORDER BY AnnCod DESC"); } else if (Gbl.Usrs.Me.Logged) { /* Select only announcements I can see */ Rol_GetRolesInAllCrssIfNotYetGot (&Gbl.Usrs.Me.UsrDat); NumAnnouncements = (unsigned) DB_QuerySELECT (&mysql_res,"can not get announcements", "SELECT AnnCod,Status,Roles,Subject,Content" " FROM announcements" " WHERE (Roles&%u)<>0 " " ORDER BY AnnCod DESC", (unsigned) Gbl.Usrs.Me.UsrDat.Roles.InCrss); // All my roles in different courses } else // No user logged { /* Select only active announcements for unknown users */ NumAnnouncements = (unsigned) DB_QuerySELECT (&mysql_res,"can not get announcements", "SELECT AnnCod,Status,Roles,Subject,Content" " FROM announcements" " WHERE Status=%u AND (Roles&%u)<>0 " " ORDER BY AnnCod DESC", (unsigned) Ann_ACTIVE_ANNOUNCEMENT, (unsigned) (1 << Rol_UNK)); } /***** Start box *****/ Box_StartBox ("550px",Txt_Announcements, ICanEdit ? Ann_PutIconToAddNewAnnouncement : NULL, Hlp_MESSAGES_Announcements,Box_NOT_CLOSABLE); if (!NumAnnouncements) Ale_ShowAlert (Ale_INFO,Txt_No_announcements); /***** Show the announcements *****/ for (NumAnn = 0; NumAnn < NumAnnouncements; NumAnn++) { row = mysql_fetch_row (mysql_res); /* Get announcement code (row[0]) */ if (sscanf (row[0],"%ld",&AnnCod) != 1) Lay_ShowErrorAndExit ("Wrong code of announcement."); /* Get status of the announcement (row[1]) */ Status = Ann_OBSOLETE_ANNOUNCEMENT; if (sscanf (row[1],"%u",&UnsignedNum) == 1) if (UnsignedNum < Ann_NUM_STATUS) Status = (Ann_Status_t) UnsignedNum; /* Get roles (row[2]) */ if (sscanf (row[2],"%u",&Roles) != 1) Lay_ShowErrorAndExit ("Error when reading roles of announcement."); /* Get the content (row[3]) */ Str_Copy (Subject,row[3], Cns_MAX_BYTES_SUBJECT); /* Get the content (row[4]) and insert links */ Str_Copy (Content,row[4], Cns_MAX_BYTES_TEXT); Str_InsertLinks (Content,Cns_MAX_BYTES_TEXT,50); /* Show the announcement */ Ann_DrawAnAnnouncement (AnnCod,Status,Subject,Content, Roles,true,ICanEdit); } /***** Button to add new announcement *****/ if (ICanEdit) Ann_PutButtonToAddNewAnnouncement (); /***** End box *****/ Box_EndBox (); /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); } /*****************************************************************************/ /******************** Put icon to add a new announcement *********************/ /*****************************************************************************/ static void Ann_PutIconToAddNewAnnouncement (void) { extern const char *Txt_New_announcement; Ico_PutContextualIconToAdd (ActWriAnn,NULL,NULL, Txt_New_announcement); } /*****************************************************************************/ /******************* Put button to add a new announcement ********************/ /*****************************************************************************/ static void Ann_PutButtonToAddNewAnnouncement (void) { extern const char *Txt_New_announcement; Frm_StartForm (ActWriAnn); Btn_PutConfirmButton (Txt_New_announcement); Frm_EndForm (); } /*****************************************************************************/ /************************** Show global announcements ************************/ /*****************************************************************************/ void Ann_ShowMyAnnouncementsNotMarkedAsSeen (void) { MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned NumAnnouncements; unsigned NumAnn; long AnnCod; char Subject[Cns_MAX_BYTES_SUBJECT + 1]; char Content[Cns_MAX_BYTES_TEXT + 1]; /***** Select announcements not seen *****/ Rol_GetRolesInAllCrssIfNotYetGot (&Gbl.Usrs.Me.UsrDat); NumAnnouncements = (unsigned) DB_QuerySELECT (&mysql_res,"can not get announcements", "SELECT AnnCod,Subject,Content FROM announcements" " WHERE Status=%u AND (Roles&%u)<>0 " " AND AnnCod NOT IN" " (SELECT AnnCod FROM ann_seen WHERE UsrCod=%ld)" " ORDER BY AnnCod DESC", // Newest first (unsigned) Ann_ACTIVE_ANNOUNCEMENT, (unsigned) Gbl.Usrs.Me.UsrDat.Roles.InCrss, // All my roles in different courses Gbl.Usrs.Me.UsrDat.UsrCod); /***** Show the announcements *****/ if (NumAnnouncements) { fprintf (Gbl.F.Out,"
"); for (NumAnn = 0; NumAnn < NumAnnouncements; NumAnn++) { row = mysql_fetch_row (mysql_res); /* Get announcement code (row[0]) */ if (sscanf (row[0],"%ld",&AnnCod) != 1) Lay_ShowErrorAndExit ("Wrong code of announcement."); /* Get the content (row[1]) */ Str_Copy (Subject,row[1], Cns_MAX_BYTES_SUBJECT); /* Get the content (row[2]) and insert links */ Str_Copy (Content,row[2], Cns_MAX_BYTES_TEXT); Str_InsertLinks (Content,Cns_MAX_BYTES_TEXT,50); /* Show the announcement */ Ann_DrawAnAnnouncement (AnnCod,Ann_ACTIVE_ANNOUNCEMENT,Subject,Content, 0,false,false); } fprintf (Gbl.F.Out,"
"); } } /*****************************************************************************/ /****************** Draw an announcement as a yellow note ********************/ /*****************************************************************************/ static void Ann_DrawAnAnnouncement (long AnnCod,Ann_Status_t Status, const char *Subject,const char *Content, unsigned Roles, bool ShowAllAnnouncements, bool ICanEdit) { extern const char *Txt_Users; extern const char *Txt_ROLES_PLURAL_abc[Rol_NUM_ROLES][Usr_NUM_SEXS]; extern const char *Txt_NOTICE_Active_Mark_as_obsolete; extern const char *Txt_NOTICE_Obsolete_Mark_as_active; extern const char *Txt_Do_not_show_again; static const char *ContainerClass[Ann_NUM_STATUS] = { "NOTICE_CONTAINER_ACTIVE", // Ann_ACTIVE_ANNOUNCEMENT "NOTICE_CONTAINER_OBSOLETE", // Ann_OBSOLETE_ANNOUNCEMENT }; static const char *SubjectClass[Ann_NUM_STATUS] = { "NOTICE_SUBJECT_ACTIVE", // Ann_ACTIVE_ANNOUNCEMENT "NOTICE_SUBJECT_OBSOLETE", // Ann_OBSOLETE_ANNOUNCEMENT }; static const char *ContentClass[Ann_NUM_STATUS] = { "NOTICE_TEXT_ACTIVE", // Ann_ACTIVE_ANNOUNCEMENT "NOTICE_TEXT_OBSOLETE", // Ann_OBSOLETE_ANNOUNCEMENT }; static const char *UsersClass[Ann_NUM_STATUS] = { "NOTICE_AUTHOR_ACTIVE", // Ann_ACTIVE_ANNOUNCEMENT "NOTICE_AUTHOR_OBSOLETE", // Ann_OBSOLETE_ANNOUNCEMENT }; Rol_Role_t Role; bool SomeRolesAreSelected; Gbl.Announcements.AnnCod = AnnCod; // Parameter for forms /***** Start yellow note *****/ fprintf (Gbl.F.Out,"
", ContainerClass[Status]); if (ICanEdit) { /***** Put form to remove announcement *****/ Ico_PutContextualIconToRemove (ActRemAnn,Ann_PutParams); /***** Put form to change the status of the announcement *****/ switch (Status) { case Ann_ACTIVE_ANNOUNCEMENT: Lay_PutContextualLinkOnlyIcon (ActHidAnn,NULL,Ann_PutParams, "eye.svg", Txt_NOTICE_Active_Mark_as_obsolete); break; case Ann_OBSOLETE_ANNOUNCEMENT: Lay_PutContextualLinkOnlyIcon (ActRevAnn,NULL,Ann_PutParams, "eye-slash.svg", Txt_NOTICE_Obsolete_Mark_as_active); break; } } /***** Write the subject of the announcement *****/ fprintf (Gbl.F.Out,"
%s
", SubjectClass[Status],Subject); /***** Write the content of the announcement *****/ fprintf (Gbl.F.Out,"
%s
", ContentClass[Status],Content); /***** Write form *****/ fprintf (Gbl.F.Out,"
"); if (ShowAllAnnouncements) { /* Users' roles who can view this announcement */ fprintf (Gbl.F.Out,"

%s:", UsersClass[Status],Txt_Users); for (Role = Rol_UNK, SomeRolesAreSelected = false; Role <= Rol_TCH; Role++) if (Roles & (1 << Role)) { if (SomeRolesAreSelected) fprintf (Gbl.F.Out,","); SomeRolesAreSelected = true; fprintf (Gbl.F.Out," %s",Txt_ROLES_PLURAL_abc[Role][Usr_SEX_UNKNOWN]); } fprintf (Gbl.F.Out,"

"); } else /***** Put form to mark announcement as seen *****/ Lay_PutContextualLinkIconText (ActAnnSee,NULL,Ann_PutParams, "close.svg", Txt_Do_not_show_again); fprintf (Gbl.F.Out,"
"); /***** End yellow note *****/ fprintf (Gbl.F.Out,"
"); } /*****************************************************************************/ /******************** Params used to edit an assignment **********************/ /*****************************************************************************/ static void Ann_PutParams (void) { Par_PutHiddenParamLong ("AnnCod",Gbl.Announcements.AnnCod); } /*****************************************************************************/ /************** Get parameter with the code of an announcement ***************/ /*****************************************************************************/ static long Ann_GetParamAnnCod (void) { long AnnCod; /***** Get announcement code *****/ if ((AnnCod = Par_GetParToLong ("AnnCod")) <= 0) Lay_ShowErrorAndExit ("Wrong code of announcement."); return AnnCod; } /*****************************************************************************/ /***************** Show form to create a new announcement ********************/ /*****************************************************************************/ void Ann_ShowFormAnnouncement (void) { extern const char *Hlp_MESSAGES_Announcements; extern const char *The_ClassFormInBox[The_NUM_THEMES]; extern const char *Txt_New_announcement; extern const char *Txt_MSG_Subject; extern const char *Txt_MSG_Content; extern const char *Txt_Users; extern const char *Txt_Create_announcement; /***** Start form *****/ Frm_StartForm (ActRcvAnn); /***** Start box and table *****/ Box_StartBoxTable (NULL,Txt_New_announcement,NULL, Hlp_MESSAGES_Announcements,Box_NOT_CLOSABLE,2); /***** Announcement subject and body *****/ Ann_PutSubjectMessage ("Subject",Txt_MSG_Subject, 2); Ann_PutSubjectMessage ("Content",Txt_MSG_Content,20); /***** Users' roles who can view the announcement *****/ fprintf (Gbl.F.Out,"" "" "%s: " "" "", The_ClassFormInBox[Gbl.Prefs.Theme], Txt_Users); Rol_WriteSelectorRoles (1 << Rol_UNK | 1 << Rol_GST | 1 << Rol_STD | 1 << Rol_NET | 1 << Rol_TCH, 1 << Rol_UNK | 1 << Rol_GST | 1 << Rol_STD | 1 << Rol_NET | 1 << Rol_TCH, false,false); fprintf (Gbl.F.Out,"" ""); /***** End table, send button and end box *****/ Box_EndBoxTableWithButton (Btn_CREATE_BUTTON,Txt_Create_announcement); /***** End form *****/ Frm_EndForm (); } /*****************************************************************************/ /*********** Put form field for message subject or message content ***********/ /*****************************************************************************/ static void Ann_PutSubjectMessage (const char *Field,const char *Label, unsigned Rows) { extern const char *The_ClassFormInBox[The_NUM_THEMES]; fprintf (Gbl.F.Out,"" "" "" "" "" "" "" "", Field,The_ClassFormInBox[Gbl.Prefs.Theme],Label, Field,Field,Rows); } /*****************************************************************************/ /****** Receive a new announcement from a form and store it in database ******/ /*****************************************************************************/ void Ann_ReceiveAnnouncement (void) { extern const char *Txt_Announcement_created; unsigned Roles; char Subject[Cns_MAX_BYTES_SUBJECT + 1]; char Content[Cns_MAX_BYTES_TEXT + 1]; /***** Get data from form *****/ /* Get the subject of the announcement */ Par_GetParToHTML ("Subject",Subject,Cns_MAX_BYTES_SUBJECT); /* Get the content of the announcement */ Par_GetParAndChangeFormat ("Content",Content,Cns_MAX_BYTES_TEXT, Str_TO_RIGOROUS_HTML,true); /* Get users who can view this announcement */ Roles = Rol_GetSelectedRoles (); /***** Create a new announcement in database *****/ Ann_CreateAnnouncement (Roles,Subject,Content); /***** Write message of success *****/ Ale_ShowAlert (Ale_SUCCESS,Txt_Announcement_created); /***** Refresh list of announcements *****/ Ann_ShowAllAnnouncements (); } /*****************************************************************************/ /************************ Create a new announcement **************************/ /*****************************************************************************/ static void Ann_CreateAnnouncement (unsigned Roles,const char *Subject,const char *Content) { /***** Select announcements not seen *****/ DB_QueryINSERT ("can not create announcement", "INSERT INTO announcements" " (Roles,Subject,Content)" " VALUES" " (%u,'%s','%s')", Roles,Subject,Content); } /*****************************************************************************/ /*********** Mark as hidden a global announcement that was active ************/ /*****************************************************************************/ void Ann_HideActiveAnnouncement (void) { long AnnCod; /***** Get the code of the global announcement to hide *****/ AnnCod = Ann_GetParamAnnCod (); /***** Set global announcement as hidden *****/ DB_QueryUPDATE ("can not hide announcement", "UPDATE announcements SET Status=%u" " WHERE AnnCod=%ld", (unsigned) Ann_OBSOLETE_ANNOUNCEMENT,AnnCod); } /*****************************************************************************/ /*********** Mark as active a global announcement that was hidden ************/ /*****************************************************************************/ void Ann_RevealHiddenAnnouncement (void) { long AnnCod; /***** Get the code of the global announcement to show *****/ AnnCod = Ann_GetParamAnnCod (); /***** Set global announcement as shown *****/ DB_QueryUPDATE ("can not reveal announcement", "UPDATE announcements SET Status=%u" " WHERE AnnCod=%ld", (unsigned) Ann_ACTIVE_ANNOUNCEMENT,AnnCod); } /*****************************************************************************/ /********************** Remove a global announcement *************************/ /*****************************************************************************/ void Ann_RemoveAnnouncement (void) { extern const char *Txt_Announcement_removed; long AnnCod; /***** Get the code of the global announcement *****/ AnnCod = Ann_GetParamAnnCod (); /***** Remove announcement *****/ DB_QueryDELETE ("can not remove announcement", "DELETE FROM announcements WHERE AnnCod=%ld", AnnCod); /***** Remove users who have seen the announcement *****/ DB_QueryDELETE ("can not remove announcement", "DELETE FROM ann_seen WHERE AnnCod=%ld", AnnCod); /***** Write message of success *****/ Ale_ShowAlert (Ale_SUCCESS,Txt_Announcement_removed); /***** Refresh list of announcements *****/ Ann_ShowAllAnnouncements (); } /*****************************************************************************/ /************************ Create a new announcement **************************/ /*****************************************************************************/ void Ann_MarkAnnouncementAsSeen (void) { long AnnCod; /***** Get the code of the global announcement *****/ AnnCod = Ann_GetParamAnnCod (); /***** Mark announcement as seen *****/ DB_QueryREPLACE ("can not mark announcement as seen", "REPLACE INTO ann_seen" " (AnnCod,UsrCod)" " VALUES" " (%ld,%ld)", AnnCod,Gbl.Usrs.Me.UsrDat.UsrCod); /***** Show other announcements again *****/ Ann_ShowMyAnnouncementsNotMarkedAsSeen (); } /*****************************************************************************/ /******************** Remove user from seen announcements ********************/ /*****************************************************************************/ void Ann_RemoveUsrFromSeenAnnouncements (long UsrCod) { /***** Remove user from seen announcements *****/ DB_QueryDELETE ("can not remove user from seen announcements", "DELETE FROM ann_seen WHERE UsrCod=%ld", UsrCod); }