diff --git a/ReadmeVM.md b/ReadmeVM.md index ac2d958..166ed1f 100644 --- a/ReadmeVM.md +++ b/ReadmeVM.md @@ -70,12 +70,12 @@ To run this platform, your environment must meet the following prerequisites: - **Install Dependencies**: Install any required software dependencies using your package manager like npm install or pip install - **Configuration**: Set up necessary environment variables or configuration files for example the Marist SSO credentials. -- **Starting the application**: Use command npm start to start the application +- **Starting the application**: Use the command npm start to start the application ## Support - **If you encounter issues with the VM or SSO contact Marist IT and Services for help**: Email: HelpDesk@marist.edu, Phone: (845) 575-4357 -- For porject related issues, clone the repo using: git clone https://github.com/KaiCottle/electionCapping24.git +- For project-related issues, clone the repo using: git clone https://github.com/KaiCottle/electionCapping24.git ## Contributing diff --git a/db/ReadmeDB.md b/db/ReadmeDB.md new file mode 100644 index 0000000..439dfda --- /dev/null +++ b/db/ReadmeDB.md @@ -0,0 +1,258 @@ +## ELECTION CAPPING 24 + +# Manual Database Update Guide + +**This guide provides steps to manually update faculty information in the database, such as name changes due to marriage or other profile updates.** + +--- + +## Table of Contents + +1. [Overview](#overview) +2. [Database Access](#database-access) +3. [Backup the Database](#backup-the-database) +4. [Update Process](#update-process) +5. [Verification](#verification) +6. [Additional Notes](#additional-notes) +7. [Use Case Examples](#use-case-example:-last-name-change) + (#use-case-example:-updating-faculty-table) + +--- + +## Overview + +Faculty members log in using their Marist school email, which serves as a primary key. While most updates are automated through the platform, manual updates may be required for cases like: + +- Last name changes (e.g., due to marriage). +- Updating department or role information. +- Correcting typos in profile data. + +This guide ensures manual updates are executed safely and accurately. + +--- + +## Database Access + +To access the database, you will need the following: + +1. **PostgreSQL client** installed on your system. +2. **Database credentials** provided during project setup: + - **Host**: `localhost` or the server IP: `10.11.29.95` + - **Port**: `5432` (default for PostgreSQL) + - **Database Name**: `election_capping` + - **Username**: root@10.11.29.95 + - **Password**: MaristDev2024! + +### Connect to the Database: + +Run the following command in your terminal: + +```bash +psql -h 10.11.29.95 -U -d election_capping +``` + +--- + +### Backup the Database + +- Before making any changes make sure you create a backup to avoid any accidental data loss: pg_dump -h 10.11.29.103 -U -d election_capping -f backup.sql + +### Update Process + +**1.Query User Current Info** + +- To view the current profile information, use the following SQL query: + +```bash +SELECT * FROM people WHERE email = 'faculty_email@marist.edu'; +``` + +**2.Update Fields** + +- To update, for example, last name do: + +```bash +UPDATE people +SET lname = 'NewLastName' +WHERE email = 'faculty_email@marist.edu'; +``` + +- To update other information (e.g., department or preferred name): + +```bash +UPDATE faculty +SET prefname = 'NewPreferredName', schoolid = 2 +WHERE fid = ( + SELECT pid FROM people WHERE email = 'faculty_email@marist.edu' +); +``` + +**3.Commit Changes** + +- PostgreSQL automatically commits changes, but if using a transaction block, use: + +```bash +COMMIT; +``` + +--- + +### Verification + +- After updating, verify the changes by re-querying the database: + +```bash +SELECT * FROM people WHERE email = 'faculty_email@marist.edu'; +``` + +- Check if the updated information appears correctly. Ensure there are no discrepancies in dependent tables + +--- + +### Additional notes + +- **Consistency**: Ensure updates are consistent across all related tables, such as people, faculty, and committeeassignments. +- **Primary Key (Email)**: Since the email is a primary key, it must not change. If it needs to be updated, contact Marist IT for assistance. +- **Audit Log**: Keep a record of changes made for auditing purposes. Example: + +```bash +echo "Updated lname for faculty_email@marist.edu to NewLastName on $(date)" >> change_log.txt +``` + +- **Testing Environment**: Test updates in a staging environment before applying them to production. + +--- + +### Use Case Example: Last Name Change + +- If a faculty member get married or wants their name changed here are some steps to follow: + +**Step 1**: Query the current information + +```bash +SELECT * FROM people WHERE email = 'jane.doe@marist.edu'; +``` + +**Step 2**: Update the last name + +```bash +UPDATE people +SET lname = 'Smith' +WHERE email = 'jane.doe@marist.edu'; +``` + +**Step 3**: Update the email + +```bash +UPDATE people +SET lname = 'Smith' +WHERE email = 'jane.doe@marist.edu'; +``` + +**Step 4**: Verify Update + +- Re-query the database to ensure the changes were successful: + +```bash +SELECT * FROM people WHERE email = 'jane.smith@marist.edu'; +``` + +### Use Case Example: Updating faculty table (using FID) + +This guide outlines the steps to update records in the database for the `people` and `faculty` tables. + +- Use the **`PID`** to update records in the `people` table. +- Use the **`FID`** to update records in the `faculty` table. + +--- + +## Updating the `people` Table (Using `PID`) + +### Steps to Update Information + +1. **Query the Current Record** + To confirm the data for a specific `PID`: + ```sql + SELECT * FROM people WHERE pid = 101; + ``` +2. **Update the record** + Use the UPDATE statement with the WHERE pid = ... clause. + +- **Example: Changing Last Name** + Suppose John Doe's last name changes to Smith due to marriage: + ```sql + UPDATE people + SET lname = 'Smith' + WHERE pid = 101; + ``` + +3. **Verify Changes** + Run the query again to confirm the update: + +```sql +SELECT * FROM people WHERE pid = 101; +``` + +**Example Output:** + +```sql +pid | fname | lname | email +----+--------+--------+------------------- + 101 | John | Smith | john.smith@marist.edu +``` + +--- + +## Updating the `faculty` Table (Using `FID`) + +### Steps to Update Information + +1. **Query the Current Record** + To confirm the data for a specific `FID`: + ```sql + SELECT * FROM faculty WHERE fid = 201; + ``` + +- **Example Output:** + +```sql +fid | department | role +-----+------------------+----------- + 201 | Computer Science | Chair +``` + +2. **Update the Record** + Use the UPDATE statement with the WHERE fid = ... clause. + +- **Example: Changing Department** + If the faculty member's department changes: + +```sql +UPDATE faculty +SET department = 'Mathematics' +WHERE fid = 201; +``` + +- **Example: Changing Role** + If the faculty member steps down as Chair: + +```sql +UPDATE faculty +SET role = 'Professor' +WHERE fid = 201; +``` + +3. **Verify Changes** + Run the query again to confirm the update: + +```sql +SELECT * FROM faculty WHERE fid = 201; +``` + +**Example Output** + +```sql +fid | department | role +-----+--------------+----------- + 201 | Mathematics | Professor +``` diff --git a/db/sql/Test_Data_Revised_1.sql b/db/sql/Test_Data_Revised_1.sql index 3be621f..bec8cf5 100644 --- a/db/sql/Test_Data_Revised_1.sql +++ b/db/sql/Test_Data_Revised_1.sql @@ -109,86 +109,91 @@ INSERT INTO Committees (Cname) VALUES ('Various hiring/staffing search committees'), ('Veterans affair committee'), ('Any of the Middle States working committees'), + ('Retention Committee'), + ('Sustainability Action Planning Committee'), + ('Master Plan Steering Committee'), + ('Athletics Strategic Planning Committee'), + ('Marist + AI'), ('Any of the Strategic Planning committees'); INSERT INTO Faculty (FID, Email, SchoolID, IsHidden, PrefName, URL, TheStatement, LastUpdated) VALUES - (1, 'Chris.Algozzine@marist.edu', 2, false, 'Chris Algozzine', 'http://www.marist.edu/{school}/faculty/{fn-ln}', + (1, 'Chris.Algozzine@marist.edu', 2, false, 'Chris Algozzine', 'https://www.marist.edu/computer-science-math/faculty/chris-algozzine', 'I choose to serve our community any way I can for many reasons. It started when I was a Boy Scout, and was forged forever in my ethos after I arrived here as a Freshman in 1985 to work on my bachelor’s degree, where I also joined service clubs like campus ministry, and was taught about service to our community by the faculty and Marist brothers. I went on to have a career at IBM and took every chance to serve the communities in which IBM did business. I served for a brief time as the Senior Location Executive at the Poughkeepsie IBM Site, which is a position serving as the spokesperson to the community and working with community non-profits. I enjoyed this work, and when I joined the Marist faculty in 1995, was immediately drawn to the Center for Civic Engagement. Granted a fellowship to study community based learning (CBL) practices with Dr. Gaeke and a cohort of our colleagues, I put CBL into practice in my courses, especially the Capping experience course. I’m proud of the service I bring to the Marist community and feel that in 9 short years I’ve embedded myself into opportunities to give back to my colleagues, our students, the college, and the community at large. I would be honored to serve as Chair of the Faculty, and hope you will vote for me.', '2024-02-05 16:31:28'), - (2, 'Joe.Kirtland@marist.edu', 2, false, 'Joseph Kirtland', 'http://www.marist.edu/{school}/faculty/{fn-ln}', + (2, 'Joe.Kirtland@marist.edu', 2, false, 'Joseph Kirtland', 'https://www.marist.edu/computer-science-math/faculty/joseph-kirtland', 'I am a firm believer in faculty-driven shared governance guided by the Faculty Handbook. But for that to work, we need to have a strong faculty voice driven predominantly by dedicated service on faculty and other committees. Through working on elected and appointed faculty committees, the faculty can have a significant and meaningful impact on college academics, college policies, campus environment, and the general direction of the college.', '2024-03-19 07:34:25'), - (3, 'Bowu.Zhang@marist.edu', 2, false, 'Bowu Zhang', 'http://www.marist.edu/{school}/faculty/{fn-ln}', + (3, 'Bowu.Zhang@marist.edu', 2, false, 'Bowu Zhang', 'https://www.marist.edu/computer-science-math/faculty/bowu-zhang', 'I have been the faculty advisor for Women-In-Technology Club at Marist for years. I enjoyed working with colleague and students to promote women''s participation in Computer Science (CS) through various networking activities. I welcome any thoughts to attract more women to CS.', '2024-03-19 08:49:36'), - (4, 'Casimer.DeCusatis@marist.edu', 2, false, 'Casimer Decusatis', 'http://www.marist.edu/{school}/faculty/{fn-ln}', + (4, 'Casimer.DeCusatis@marist.edu', 2, false, 'Casimer Decusatis', 'https://www.marist.edu/computer-science-math/faculty/casimer-decusatis.html', 'Ive found that service is a great way to interact with people from other parts of the college, and get a different perspective on our shared issues and challenges. In addition to my past service on Academic Standards, Core and Liberal Studies, and the Institutional Review Board, I''ve previously served on the President''s Faculty Climate Committee and the Technology Committee Working Group on Data Center Strategy. I feel that these experiences have allowed me to make Marist a better place for students, faculty, and staff alike. I''m always interested in finding new ways to help serve our campus community, and would appreciate the opportunity to stay involved in whatever capacity is needed.', '2024-03-19 16:53:35'), - (5, 'Eitel.Lauria@marist.edu', 5, false, 'Eitel Lauria', 'http://example.com/eitel_lauria', + (5, 'Eitel.Lauria@marist.edu', 5, false, 'Eitel Lauria', 'https://www.marist.edu/computer-science-math/faculty/eitel-lauria', 'I have chaired the AAC and served as the Vice Chair of FAC during the pandemic. I currently chair the faculty search committee in my department. I served on the presidential search committee, the CIO''s search committee, the previous middle-states committee, and co-chaired one of the strategic plan working groups. I have helped hire and mentored most of the faculty in my department through tenure and promotion. I will be on sabbatical in Spring 2025.', '2024-03-19 17:12:37'), - (6, 'Luis.Espinasa@marist.edu', 6, false, 'Luis Espinasa', 'http://www.marist.edu/{school}/faculty/{fn-ln}', + (6, 'Luis.Espinasa@marist.edu', 6, false, 'Luis Espinasa', 'https://www.marist.edu/science/faculty/luis-espinasa', 'I have been in Marist for 18 years. Have served in the Rank and Tenure committee once, and in the Grievance Committee as its Chair for two years.', '2024-03-19 18:44:57'), - (7, 'Tracey.McGrail@marist.edu', 2, false, 'Tracey McGrail', 'http://www.marist.edu/{school}/faculty/{fn-ln}', + (7, 'Tracey.McGrail@marist.edu', 2, false, 'Tracey McGrail', 'https://www.marist.edu/computer-science-math/faculty/tracey-mcgrail', 'I believe that faculty service is very important to the function of the college. In particular, while membership on the Rank and Tenure Committee is a heavy commitment (I was on when there were 13 candidates for tenure!), this group plays a critical role in evaluating faculty. If elected I will serve.', '2024-03-21 15:12:53'), - (8, 'Megan.Dennis@marist.edu', 6, false, 'Megan Dennis', 'http://www.marist.edu/{school}/faculty/{fn-ln}', + (8, 'Megan.Dennis@marist.edu', 6, false, 'Megan Dennis', 'https://www.marist.edu/science/faculty/megan-dennis', 'I am not comfortable serving on Rank & Tenure at this point in my career. As a recently-tenured faculty member, I have not yet had the opportunity to serve on a peer committee for tenure evaluation, and feel that I lack the experience necessary to fairly assess candidates from across the college as a member of R&T.', '2024-03-27 13:22:33'), - (9, 'Jocelyn.Nadeau@marist.edu', 6, false, 'Jocelyn Nadeau', 'http://www.marist.edu/{school}/faculty/{fn-ln}', + (9, 'Jocelyn.Nadeau@marist.edu', 6, false, 'Jocelyn Nadeau', 'https://www.marist.edu/science/faculty/jocelyn-nadeau', 'Since I started in 2005, I have served on many campus wide, SoS, and departmental committees and spent considerable time devoted to service that is unique to laboratory science within my department. These service endeavors have all been rewarding and productive in their own way, but they have also negatively impacted my ability to advance my scholarship to where it needs to be to apply for promotion to full professor, especially in the past 5 years due to COVID-related and overall workload issues. So, I am asking for some consideration given that I have already served on two of the major elected committees since 2012. As soon as I was tenured and eligible after my probationary year, I was elected to the Rank and Tenure Committee in 2012 and served as its chair during the third year of my term (in only my 10th year at Marist). Right after my service sabbatical was over, I was elected to FAC where I served a 3-year term that spanned through summer 2020. I will be more than willing to serve on R&T again in the future, but I am asking for some mercy at this current time. Thank you.', '2024-03-29 14:33:05'), - (10, 'Andrei.Buckareff@marist.edu', 3, false, 'Andrei Buckareff', 'http://www.marist.edu/{school}/faculty/{fn-ln}', + (10, 'Andrei.Buckareff@marist.edu', 3, false, 'Andrei Buckareff', 'https://www.marist.edu/computer-science-math/faculty/robert-cannistra', 'I have enjoyed serving on Rank & Tenure, along with other committees. While it''s a lot of work, it is rewarding work. I am presently in my first year serving on the Faculty Research and Sabbaticals (which I have served on previously). I am presently chair of said committee. I am happy to serve on any committee.', '2024-03-29 17:23:01'), - (11, 'Joshua.Kotzin@marist.edu', 3, false, 'Joshua Kotzin', 'http://www.marist.edu/{school}/faculty/{fn-ln}', + (11, 'Joshua.Kotzin@marist.edu', 3, false, 'Joshua Kotzin', 'https://www.marist.edu/liberal-arts/faculty/joshua-kotzin', 'I believe service is an important way for faculty to help the college fulfill its mission. As the Chair of the English Department (in which role I''ve served for more than a year), I have learned a lot about the institution as a whole and the ways faculty work fits into that bigger picture.', '2024-03-29 18:36:28'), - (12, 'Annamaria.Maciocia@marist.edu', 3, false, 'Annamaria Maciocia', 'http://www.marist.edu/{school}/faculty/{fn-ln}', + (12, 'Annamaria.Maciocia@marist.edu', 3, false, 'Annamaria Maciocia', 'https://www.marist.edu/liberal-arts/faculty/annamaria-maciocia', 'I am honored to serve the faculty, School of Liberal Arts, and the Marist community in any capacity. If elected, I will contribute my time and best effort to participate on FAC or AAC. As a term faculty member at Marist College since 1995, I have witnessed the diligent, selfless dedication of tenured faculty in these roles. It is with profound gratitude and respect for their service that I am motivated to serve. Additionally both FAC and AAC are vital to the integrity of shared governance; therefore, service at this responsibility of every eligible faculty member.', '2024-03-29 23:45:04'), - (13, 'Brian.Loh@marist.edu', 3, false, 'Brian Loh', 'http://www.marist.edu/{school}/faculty/{fn-ln}', + (13, 'Brian.Loh@marist.edu', 3, false, 'Brian Loh', 'https://www.marist.edu/liberal-arts/faculty/brian-loh', 'I am currently serving as acting honors director, and I''m a member of the Marist Mindfulness Collective, the Global Studies Committee, and the Interfaith Committee. As of writing (3/30/24) I am not seeking election as I have a kid coming end of May and will be on parental leave in spring ''25. I am open to serving in the future, but please consider someone who will be a little less distracted this time around!', '2024-03-30 07:30:45'), - (14, 'Melissa.Gaeke@marist.edu', 3, false, 'Melissa Gaeke', 'http://www.marist.edu/{school}/faculty/{fn-ln}', + (14, 'Melissa.Gaeke@marist.edu', 3, false, 'Melissa Gaeke', 'https://www.marist.edu/liberal-arts/faculty/melissa-gaeke', 'I believe that service to a community is a vital component to a healthy system of governance and think that committees should reflect diverse and representative voices of the various constituencies that comprise the community. While full representation is not always possible, it is the responsibility of those who serve to make sure they are involved with those they represent so they are able to adequately represent their interests.', '2024-03-30 09:34:53'), - (15, 'Jennifer.Finn@marist.edu', 1, false, 'Jennifer Finn', 'http://www.marist.edu/{school}/faculty/{fn-ln}', + (15, 'Jennifer.Finn@marist.edu', 1, false, 'Jennifer Finn', 'https://www.marist.edu/communication-arts/faculty/jennifer-finn', 'For the last 5 years, I''ve served as Department Chair for the Fashion Design and Merchandising Program, where I''ve collaborated with faculty on several curriculum and assessment initiatives, served in an advisory role with faculty and administration members, and positioned myself as a leader & mentor to our part-time faculty members. I''m interested in serving as a member on the Faculty Affairs Committee because I believe the role of faculty shared governance is an extremely important one, and there are opportunities that exist for further defining roles, responsibilities, and development for Term faculty.', '2024-03-30 10:35:16'), - (16, 'Jeff.Bass@marist.edu', 1, false, 'Jeff Bass', 'http://www.marist.edu/{school}/faculty/{fn-ln}', + (16, 'Jeff.Bass@marist.edu', 1, false, 'Jeff Bass', 'https://foxweb.marist.edu/users/jeff.bass/?_gl=1*1dxoiwp*_gcl_au*MzIwMDc2ODgxLjE3MzM2OTU3MDk.*FPAU*MzIwMDc2ODgxLjE3MzM2OTU3MDk.*_ga*MTg2OTU2MzA1Ny4xNzMzNjk1NzEw*_ga_6WL3ZSKM4H*MTczMzcyMDQxMC4yLjEuMTczMzcyMTU0Mi4wLjAuMzQyMDI5MzM2*_fplc*bnJJMHNDZE1XbVpnSkVpNDdud212aUNjSVQwM01QcXQ5dm9IOTQ0V09GNHIlMkJ2Y0Jrdk5TS3FJMUhmRWtOSjhhSVdwMkhMMVFJRTJVZTE3d1ZjcCUyQno2SWE5NU80b0g2d2VJcTV5N0lHa0ZBSHJDa3VUcWNtZlVXemlzUVdEQSUzRCUzRA..', 'Hello colleagues, besides being eligible, I am ready, willing, and able to serve on the Faculty Affairs Committee. I am one of the longest-serving term faculty, and in 2018-19 I chaired a committee that was instrumental in making term faculty eligible for FAC and AAC. In the past year, I have gone through a series of disciplinary measures designed to make me a better employee, teacher, and human being. I feel more capable than ever to represent your interests on the FAC, and I am eager to work with the new group of dynamic administrators managing the faculty and the college. I hope I can count on your vote, I won''t let you down.', '2024-03-30 17:36:56'), - (17, 'Joseph.Campisi@marist.edu', 3, false, 'Joseph Campisi', 'http://www.marist.edu/{school}/faculty/{fn-ln}', + (17, 'Joseph.Campisi@marist.edu', 3, false, 'Joseph Campisi', 'https://www.marist.edu/liberal-arts/faculty/joseph-campisi', 'I have served on a number of committees during my time here at Marist and am currently the co-chair of CSAC and on the Fellowship Committee (which works with Pat Taylor and students applying for things like Fulbrights, etc.). I view service to students, the college, and my faculty colleagues as important, and would gladly serve on any committee if so elected.', '2024-03-31 11:42:26'), - (18, 'Elizabeth.Reid@marist.edu', 2, false, 'Elizabeth Reid', 'http://www.marist.edu/{school}/faculty/{fn-ln}', + (18, 'Elizabeth.Reid@marist.edu', 2, false, 'Elizabeth Reid', 'https://www.marist.edu/computer-science-math/faculty/elizabeth-reid', 'I enjoy working closely with students and faculty in clubs and committees. While serving on committees, I have formed professional relationships and collaborated with people across campus. Some committees I have been a member of include: the Campus Life Committee, the Celebration of Undergraduate Research, Scholarship & Creative Activity (CURSCA) Committee, and a committee charged with planning academic events around the inauguration of President Weinman. During the Middle States review, I served as a member of the Working Group on Standard VII: Governance, Leadership, and Administration for the reaccreditation of Marist College. I am also currently a Hearing Board Member. This year I have taken on the added responsibility of being a Co-Chair of the CURSCA committee. In this position, I work closely with faculty and staff to organize an event that provides a platform for students to showcase their work to the Marist community. Although I will be on sabbatical next Spring, I am looking forward to additional service opportunities in the future.', '2024-03-31 21:26:07'), - (19, 'Sally.Dwyer-McNulty@marist.edu', 3, false, 'Sally Dwyer-McNulty', 'http://www.marist.edu/{school}/faculty/{fn-ln}', + (19, 'Sally.Dwyer-McNulty@marist.edu', 3, false, 'Sally Dwyer-McNulty', 'https://www.marist.edu/liberal-arts/faculty/sally-dwyer-mcnulty', 'I value shared governance and working with faculty, students, staff, and administrators across campus.', '2024-04-01 10:00:28'), - (20, 'John.Morrison.Galbraith@marist.edu', 6, false, 'John Morrison Galbraith', 'http://www.marist.edu/{school}/faculty/{fn-ln}', + (20, 'John.Morrison.Galbraith@marist.edu', 6, false, 'John Morrison Galbraith', 'https://www.marist.edu/science/faculty/john-galbraith', 'I do not have a strong desire to be on committees. I do not think I am particularly good at it, and I feel my time and effort is better spent with teaching and research. However, I do believe in making Marist a better place, and I recognize the importance and value of faculty committees. Therefore, I have always served and will continue to serve, to the best of my ability on whatever committee I am on.', '2024-04-01 10:00:28'), @@ -232,19 +237,19 @@ INSERT INTO Faculty (FID, Email, SchoolID, IsHidden, PrefName, URL, TheStatement 'I study the role of self-transcendent emotions in human communication and wish to highlight my value in this line of research, as opposed to serving in FAC. I would advocate for thoughtful consideration of other candidates whose dedication to this role is matched by their enthusiasm and capability for it.', '2024-04-03 15:05:33'), - (31, 'Marina.Melita@marist.edu', 3, FALSE, 'M. Marina Melita', 'http://www.marist.edu/school/faculty/marina-melita', + (31, 'Marina.Melita@marist.edu', 3, FALSE, 'M. Marina Melita', 'https://www.marist.edu/liberal-arts/faculty/maureen-michele-melita', 'While I am usually happy to serve Marist in any way that I can, I do not think I can do so at this time, and also do a good job. Right now, I teach 8 courses per year, serve on the Global Studies Advising Committee, as well as the Queer Trans Sub-Committee of the Diversity Council. I run the Italian program at Marist and serve as the Chair of the World Film Program. Beyond Marist, I have a book project in the works, and was recently elected as the President of the academic association for Italian studies; The American Association of Teachers of Italian. I fear that adding one more responsibility will hinder my ability to perform my current duties at the level that my students, colleagues, and community members deserve and expect from me. In the future, when I have wrapped up some of my current duties, I would be happy to serve on one of the standing committees for Marist.', '2024-04-04 18:30:08'), - (32, 'Sasha.Biro@marist.edu', 3, FALSE, 'Sasha Biro', 'http://www.marist.edu/school/faculty/sasha-biro', + (32, 'Sasha.Biro@marist.edu', 3, FALSE, 'Sasha Biro', 'https://www.marist.edu/liberal-arts/faculty/sasha-biro', 'I am a Lecturer of Philosophy and Coordinator of the Diversity, Equity, Inclusion Workshop in First Year Seminar. I currently serve on the Retention Committee, and the Interfaith Committee. I am also a faculty advisor/editor to the Marist Undergraduate Philosophy Journal.', '2024-04-05 12:10:28'), - (33, 'Rebecca.Brown@marist.edu', 1, FALSE, 'Rebecca Brown', 'http://www.marist.edu/school/faculty/rebecca-brown', + (33, 'Rebecca.Brown@marist.edu', 1, FALSE, 'Rebecca Brown', 'https://www.marist.edu/communication-arts/faculty/rebecca-brown', 'As a senior professional lecturer of Fashion Merchandising and the Faculty Advisor of MPorium at Marist (student run live retail laboratory located in Steel Plant) I collaborate often with other schools and departments across campus on special projects. I work closely with advancement on giving campaigns, worked with middle states committee, the Dean of SCA and SOM bringing product ideas to life from concept to execution. I am on the Marist Bookstore committee, along with many fashion program and school committees. I believe in the importance of service and collaborating with others to be a part of the solution and not the problem.', '2024-04-06 08:53:37'), - (34, 'Robyn.Rosen@marist.edu', 1, FALSE, 'Robyn L. Rosen', 'http://www.marist.edu/school/faculty/robyn-rosen', + (34, 'Robyn.Rosen@marist.edu', 1, FALSE, 'Robyn L. Rosen', 'https://www.marist.edu/liberal-arts/faculty/robyn-rosen', 'As a senior professional lecturer of Fashion Merchandising and the Faculty Advisor of MPorium at Marist (student run live retail laboratory located in Steel Plant) I collaborate often with other schools and departments across campus on special projects. I work closely with advancement on giving campaigns, worked with middle states committee, the Dean of SCA and SOM bringing product ideas to life from concept to execution. I am on the Marist Bookstore committee, along with many fashion program and school committees. I believe in the importance of service and collaborating with others to be a part of the solution and not the problem.', '2024-04-06 19:58:22'), @@ -252,65 +257,84 @@ INSERT INTO Faculty (FID, Email, SchoolID, IsHidden, PrefName, URL, TheStatement 'While I would be happy to serve on campus-wide committees in the future as I have done in the past, I have just been appointed as the Academic Theatre Program Director and would like to be able to focus on the needs of the program, including restructuring some theatre processes & policies and mentoring a new hire in the program. I fully expect to continue to contribute to campus through numerous ongoing committees, but I would appreciate being passed over for this round of the major committees. And if you’d still like to vote for me, then thanks for the vote of confidence — I have been chair of English so I know that work intimately and work well (and happily) on logistics and editing. I am ultimately a theatre historian & designer at heart — I much prefer working & collaborating behind the scenes, digging into archives, and challenging audiences through art.', '2024-04-06 21:42:02'), - (36, 'Lisa.Neilson@marist.edu', 3, FALSE, 'Lisa R. Neilson', 'http://www.marist.edu/school/faculty/lisa-neilson', + (36, 'Lisa.Neilson@marist.edu', 3, FALSE, 'Lisa R. Neilson', 'https://www.marist.edu/liberal-arts/faculty/lisa-neilson', 'I believe that faculty service is very important to the function of the college. It strengthens our institution initiatives and can help foster a healthy and vibrant community. I have recently transitioned into a Lecturer position in the English Department. I am also the new Internship Director in our department with plans to extensively grow the internship program for English majors and minors. I look forward to settling into these positions in the upcoming academic year. Additionally, I am the Director of the Summer Pre-College Creative Writing Program.', '2024-04-07 11:07:19'), - (37, 'Thomas.Zurhellen@marist.edu', 3, FALSE, 'Tommy Zurhellen', 'http://www.marist.edu/school/faculty/tommy-zurhellen', + (37, 'Thomas.Zurhellen@marist.edu', 3, FALSE, 'Tommy Zurhellen', 'https://www.marist.edu/liberal-arts/faculty/tommy-zurhellen', 'Nobody does it better!', '2024-04-07 13:51:52'), - (38, 'Lea.Graham@marist.edu', 3, FALSE, 'Lea Graham', 'http://www.marist.edu/school/faculty/lea-graham', + (38, 'Lea.Graham@marist.edu', 3, FALSE, 'Lea Graham', 'https://www.marist.edu/liberal-arts/faculty/lea-graham', 'I do not wish to serve on campus-wide committees at this time. I am in the middle of several book projects and am busy supporting the new hires in the English Department and other department/school annual events. Thank you.', '2024-04-08 10:03:36'), - (39, 'Jamie.Perillo@marist.edu', 1, FALSE, 'Jamie Perillo', 'http://www.marist.edu/school/faculty/jamie-perillo', + (39, 'Jamie.Perillo@marist.edu', 1, FALSE, 'Jamie Perillo', 'https://www.marist.edu/communication-arts/faculty/jamie-perillo', 'This is my 15th year at Marist. I welcome the opportunity to serve on the FAC and represent the Fashion Program, School of Communication, and the Arts and all faculty. I have served on the following committees: the Fashion Design Curriculum Committee, the SCA Inventory Committee, the Fashion Gallery & Archive Committee, and the Fashion Department Diversity and Inclusion Committee. I have also served on and chaired several search and peer review committees.', '2024-04-09 16:23:57'), - (40, 'Stephanie.Conover@marist.edu', 1, FALSE, 'Stephanie Conover', 'http://www.marist.edu/school/faculty/stephanie-conover', + (40, 'Stephanie.Conover@marist.edu', 1, FALSE, 'Stephanie Conover', 'https://www.marist.edu/communication-arts/faculty/stephanie-conover', 'I would be happy to serve on FAC. After six years at Marist, I am interested in more opportunities to serve the broader college community beyond the Fashion Program and SCA. I enjoy collaborating with others across disciplines and think that the faculty governance committees are essential is moving Marist forward as we approach our 100th year.', '2024-04-09 17:51:15'), - (41, 'daria.hanssen@marist.edu', 7, FALSE, 'Daria Hanssen', 'http://www.marist.edu/school/faculty/daria-hanssen', + (41, 'daria.hanssen@marist.edu', 7, FALSE, 'Daria Hanssen', 'https://www.marist.edu/social-behavioral-science/faculty/daria-hanssen', 'I have been at Marist since 1996, starting as a part-time faculty in the Social Work/Sociology Department. As a tenured faculty member, I am committed to service and supporting the growth and development of students, in all ways.', '2024-04-09 17:51:15'), - (42, 'kavous.ardalan@marist.edu', 4, FALSE, 'Kavous Ardalan', 'http://www.marist.edu/school/faculty/kavous-ardalan', + (42, 'kavous.ardalan@marist.edu', 4, FALSE, 'Kavous Ardalan', 'https://www.marist.edu/management/faculty/kavous-ardalan', 'My experience at Marist College has been on the academic side, in the sense that I have felt most comfortable and most productive when I was a member of the rank and tenure committee. At the School of Management, I have felt most comfortable and most productive when I was a member of the peer review committee, a member of faculty search committee, or the departmental chairperson.', '2024-04-09 23:54:59'), - (43, 'julie.raines@marist.edu', 7, FALSE, 'Julie Raines', 'http://www.marist.edu/school/faculty/julie-raines', + (43, 'julie.raines@marist.edu', 7, FALSE, 'Julie Raines', 'https://www.marist.edu/social-behavioral-science/faculty/julie-raines', 'I would like to bring potential changes to the grievance process to a faculty plenary and working with current members will be the best way to develop improvements to our system. I started working on this while Chair of FAC with Beth Quinn so we have a good understanding of the areas of concern. Voting for me will give us the opportunity to make meaningful change to this process.', '2024-04-10 09:34:17'), - (44, 'jennifer.robinette@marist.edu', 6, FALSE, 'Jennifer Robinette', 'http://www.marist.edu/school/faculty/jennifer-robinette', + (44, 'jennifer.robinette@marist.edu', 6, FALSE, 'Jennifer Robinette', 'http://www.marist.edu/science/faculty/jennifer-robinette', 'I have been Public Speaking Across the Curriculum Coordinator on campus since 2015. I created and coordinate the Power Presenting Workshops for our First-Year Seminars. I teach COM 101-Public Presentation online during the Summer and COM 420-Advanced Public Presentation in the Fall. I am the faculty advisor for North Road Communications (NRC) - our student-run PR firm, which has grown to include 130 students and 25 Teams serving community clients. I handle the NRC one-credit experiential learning course and teach PR classes including COM 418-Campaign Management, COM 371-PR Cases, COM 333-Applied Research & Analytics, and COM 319-Crisis Communication. I also teach COM 211-Intro. to PR online during the Summer and Winter. Every semester, I teach an overload of courses out of necessity.', '2024-04-10 12:20:05'), - (45, 'jason.trent@marist.edu', 7, FALSE, 'Jason Trent', 'http://www.marist.edu/school/faculty/jason-trent', + (45, 'jason.trent@marist.edu', 7, FALSE, 'Jason Trent', 'https://www.marist.edu/social-behavioral-science/faculty/jason-trent', 'I just finished serving as the Secretary of the Faculty last semester (and I was on family leave for a portion of this current semester). I am open to serving on this committee.', '2024-04-10 12:54:22'), - (46, 'thomas.madden@marist.edu', 4, FALSE, 'Thomas M. Madden', 'http://www.marist.edu/school/faculty/thomas-madden', + (46, 'thomas.madden@marist.edu', 4, FALSE, 'Thomas M. Madden', 'https://www.marist.edu/management/faculty/thomas-madden', 'Not thrilled to serve on grievance as I already serve as a hearing officer in Title IX, Academic Integrity, and Student Conduct panels....but will if elected.', '2024-04-10 18:27:04'), - (47, 'kuangnen.cheng@marist.edu', 4, FALSE, 'Kuangnen Cheng', 'http://www.marist.edu/school/faculty/kuangnen-cheng', + (47, 'kuangnen.cheng@marist.edu', 4, FALSE, 'Kuangnen Cheng', 'https://www.marist.edu/management/faculty/kuangnen-hans-cheng', 'I have discovered that when a committee''s tasks and responsibilities do not align with my interests, my contribution tends to be minimal. My engagement is significantly higher in committees that develop recommendations to directly impact on student learning and life at Marist.', '2024-04-11 08:59:00'), - (48, 'byunghoon.jin@marist.edu', 4, FALSE, 'Byunghoon Jin', 'http://www.marist.edu/school/faculty/byunghoon-jin', + (48, 'byunghoon.jin@marist.edu', 4, FALSE, 'Byunghoon Jin', 'https://www.marist.edu/management/faculty/byunghoon-jin', 'I will be on sabbatical this fall (2024).', '2024-04-11 08:59:00'), - (49, 'ryan.kinlaw@marist.edu', 7, FALSE, 'Ryan Kinlaw', 'http://www.marist.edu/school/faculty/ryan-kinlaw', + (49, 'ryan.kinlaw@marist.edu', 7, FALSE, 'Ryan Kinlaw', 'https://www.marist.edu/social-behavioral-science/faculty/c-ryan-kinlaw', 'Having last year completed 6.5 years as department chair, I am currently willing to serve if elected to any committee. I feel this is an important element of the faculty role.', '2024-04-11 17:21:39'), - (50, 'yuwei.wang@marist.edu', 4, FALSE, 'Yuwei Wang', 'http://www.marist.edu/school/faculty/yuwei-wang', + (50, 'yuwei.wang@marist.edu', 4, FALSE, 'Yuwei Wang', 'https://www.marist.edu/management/faculty/yuwei-wang', 'I will be happy to serve on any committee if elected.', '2024-04-23 13:01:23'); -INSERT INTO Admins (aid, uname, thepassword, godmode) VALUES - (1, 'admin1', 'cd6357efdd966de8c0cb2f876cc89ec74ce35f0968e11743987084bd42fb8944', TRUE) +INSERT INTO Admins (aid, uname, thepassword, godmode) +VALUES (1, 'admin1', 'cd6357efdd966de8c0cb2f876cc89ec74ce35f0968e11743987084bd42fb8944', TRUE); + +-- Our own test data, comment this out when deploying +INSERT INTO People (Fname, Lname) +VALUES ('Aaron', 'Bonilla'); +INSERT INTO Faculty (FID, SchoolID, IsHidden, PrefName, Email, URL, TheStatement, LastUpdated) +VALUES (51, 3, FALSE, 'Bone', 'Aaron.Bonilla1@marist.edu', 'https://my.marist.edu', 'I love capping', CURRENT_TIMESTAMP); +INSERT INTO CommitteeAssignments (FID, CID) +VALUES + (51, 2), -- Assignment to CommitteeID 2 + (51, 15); -- Assignment to CommitteeID 15 + +INSERT INTO People (FName, LName) +VALUES ('Kai', 'Cottle'); +INSERT INTO Faculty (FID, SchoolID, IsHidden, PrefName, Email, URL, theStatement, LastUpdated) +VALUES (52, 4, FALSE, 'Kai', 'Kai.Cottle1@marist.edu', 'https://my.marist.edu', 'Im so awesome', CURRENT_TIMESTAMP); +INSERT INTO CommitteeAssignments (FID, CID) +VALUES +(52, 3), -- Assignment to CommitteeID 2 +(52, 11); -- Assignment to CommitteeID 15 diff --git a/db/sql/database_structure.sql b/db/sql/database_structure.sql index c9ba8bc..13f82bd 100644 --- a/db/sql/database_structure.sql +++ b/db/sql/database_structure.sql @@ -1,9 +1,9 @@ -drop table if exists CommitteeAssignments; -drop table if exists Committees; -drop table if exists Faculty; -drop table if exists Admins; -drop table if exists Schools; -drop table if exists People; +drop table if exists CommitteeAssignments cascade; +drop table if exists Committees cascade; +drop table if exists Faculty cascade; +drop table if exists Admins cascade; +drop table if exists Schools cascade; +drop table if exists People cascade; -- Creating tables @@ -40,6 +40,10 @@ create table Faculty ( primary key (FID) ); +-- Add the new column 'token' to the Faculty table (NOT GOING TO BE USED ANYMORE) +--alter table Faculty +--add token text; + create table Committees ( CID serial not null, Cname text not null, diff --git a/package-lock.json b/package-lock.json index 6413c76..4f1ed0f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,8 @@ "react-scripts": "5.0.1", "react-select": "^5.8.2", "typescript": "^4.9.5", - "web-vitals": "^2.1.4" + "web-vitals": "^2.1.4", + "ws": "^8.18.0" } }, "node_modules/@adobe/css-tools": { @@ -8600,7 +8601,6 @@ "version": "1.18.1", "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.1.tgz", "integrity": "sha512-a5mtTqEaZvBCL9A9aqkrtfz+3SMDhOVUnjafjo+s7A9Txkq+SVX2DLvSp1Zrv4uCXa3lMSK3viWnh9Gg07PBUA==", - "license": "MIT", "dependencies": { "cookie": "0.7.2", "cookie-signature": "1.0.7", @@ -8619,7 +8619,6 @@ "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -8627,14 +8626,12 @@ "node_modules/express-session/node_modules/cookie-signature": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", - "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", - "license": "MIT" + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==" }, "node_modules/express-session/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -8642,8 +8639,7 @@ "node_modules/express-session/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/express/node_modules/debug": { "version": "2.6.9", @@ -12586,6 +12582,27 @@ } } }, + "node_modules/jsdom/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -15336,7 +15353,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -17871,7 +17887,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", - "license": "MIT", "dependencies": { "random-bytes": "~1.0.0" }, @@ -18286,26 +18301,6 @@ } } }, - "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/webpack-manifest-plugin": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz", @@ -18952,15 +18947,16 @@ } }, "node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "license": "MIT", "engines": { - "node": ">=8.3.0" + "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -18980,7 +18976,6 @@ "version": "15.1.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", - "license": "MIT", "engines": { "node": ">=8.0" } @@ -27933,6 +27928,14 @@ "whatwg-url": "^8.5.0", "ws": "^7.4.6", "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "requires": {} + } } }, "jsesc": { @@ -31890,14 +31893,6 @@ "spdy": "^4.0.2", "webpack-dev-middleware": "^5.3.4", "ws": "^8.13.0" - }, - "dependencies": { - "ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "requires": {} - } } }, "webpack-manifest-plugin": { @@ -32403,9 +32398,9 @@ } }, "ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "requires": {} }, "xml-name-validator": { diff --git a/package.json b/package.json index e288273..d142fef 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,8 @@ "react-scripts": "5.0.1", "react-select": "^5.8.2", "typescript": "^4.9.5", - "web-vitals": "^2.1.4" + "web-vitals": "^2.1.4", + "ws": "^8.18.0" }, "scripts": { "start": "concurrently \"react-scripts start\" \"node server.js\"", diff --git a/server.js b/server.js index 9d82c27..756198a 100644 --- a/server.js +++ b/server.js @@ -11,7 +11,7 @@ const passport = require('passport'); const SamlStrategy = require('@node-saml/passport-saml').Strategy; const session = require('express-session'); const bodyParser = require("body-parser"); -const morgan = require('morgan'); +const morgan = require('morgan'); const httpPort = 80; const httpsPort = 443; @@ -36,7 +36,7 @@ app.use(session({ secret: 'your-secret-key', resave: false, saveUninitialized: true, - cookie: { secure: process.env.NODE_ENV === 'production' } // Ensure cookies are only used over HTTPS in production + cookie: { secure: process.env.NODE_ENV === 'production' } // Ensure cookies are only used over HTTPS in production })); // Function to hash passwords using SHA-256 @@ -92,15 +92,12 @@ app.post( failureFlash: true, }), function (req, res) { - // Access the authenticated user 'req.user' - console.log("req.user"); - console.log(req.user); res.redirect("/user-profile"); } ); // SSO login route -app.get('/sso/login', +app.get('/sso/login', passport.authenticate("saml", { failureRedirect: "/", failureFlash: true }), function (req, res) { res.redirect("/"); @@ -132,6 +129,263 @@ app.get('/schools', async (req, res) => { } ); +// Route to fetch committee names +app.get('/committees', async (req, res) => { + try { + const result = await client.query('SELECT Cname FROM Committees'); + console.log('Fetched committees:', result.rows); // Add this line to log the fetched data + res.json(result.rows); + } catch (err) { + console.error('Error fetching committees:', err); + res.status(500).json({ message: 'Server error' }); + } + } +); + +// Route to fetch school names +app.get('/schools', async (req, res) => { + try { + const result = await client.query('SELECT Sname FROM Schools'); + res.json(result.rows); + } catch (err) { + console.error('Error fetching schools:', err); + res.status(500).json({ message: 'Server error' }); + } + } +); + +// Middleware to ensure the user is authenticated +function ensureAuthenticated(req, res, next) { + if (req.isAuthenticated()) { + return next(); + } + res.status(401).json({ message: 'Unauthorized' }); +} + +app.get('/get-user-data', ensureAuthenticated, async (req, res) => { + try { + const email = req.user.email; // Get email from authenticated user + console.log('Querying Faculty table for email:', email); + + // Query the Faculty and People tables for the given email, including first and last names + const facultyResult = await client.query( + ` + SELECT + f.fid, + p.Fname AS firstName, + p.Lname AS lastName, + f.PrefName AS preferredName, + f.TheStatement AS serviceStatement, + f.SchoolID AS schoolid + FROM + Faculty f + JOIN + People p + ON + f.fid = p.pid + WHERE + f.Email = $1 + `, + [email] + ); + + if (facultyResult.rows.length === 0) { + console.error('Email not found:', email); + return res.status(404).json({ message: 'Email not found', found: false }); + } + + const faculty = facultyResult.rows[0]; + console.log('Faculty found:', faculty); + + // Query the Schools table for the school name + console.log('Querying Schools table for SchoolID:', faculty.schoolid); + const schoolResult = await client.query( + 'SELECT Sname FROM Schools WHERE SID = $1', + [faculty.schoolid] + ); + + const school = schoolResult.rows.length > 0 ? schoolResult.rows[0].sname : 'Unknown'; + console.log('School found:', school); + + // Query the CommitteeAssignments table for committee IDs + console.log('Querying CommitteeAssignments table for FID:', faculty.fid); + const committeeAssignmentsResult = await client.query( + 'SELECT CID FROM CommitteeAssignments WHERE FID = $1', + [faculty.fid] + ); + + const committeeIds = committeeAssignmentsResult.rows.map(row => row.cid); + console.log('Committee IDs found:', committeeIds); + + let committees = []; + if (committeeIds.length > 0) { + // Query the Committees table for committee names + console.log('Querying Committees table for Committee IDs:', committeeIds); + const committeesResult = await client.query( + 'SELECT Cname FROM Committees WHERE CID = ANY($1)', + [committeeIds] + ); + committees = committeesResult.rows.map(row => row.cname); + console.log('Committees found:', committees); + } + + // Respond with the required data + res.json({ + found: true, + firstName: faculty.firstname, + lastName: faculty.lastname, + preferredName: faculty.preferredname, + serviceStatement: faculty.servicestatement, + school: school, + committees: committees, + }); + } catch (error) { + console.error('Error in /get-user-data:', error); + res.status(500).json({ message: 'Server error', found: false }); + } +}); + +// Route to create a new faculty member +app.post('/create-faculty', ensureAuthenticated, async (req, res) => { + try { + const { firstName, lastName, preferredName, school, committees, serviceStatement } = req.body; + const email = req.user.email; // Get email from authenticated user + + // Insert into People table + const peopleResult = await client.query( + 'INSERT INTO People (Fname, Lname) VALUES ($1, $2) RETURNING PID', + [firstName, lastName] + ); + const pid = peopleResult.rows[0].pid; + + // Get School ID and School Name + const schoolResult = await client.query( + 'SELECT SID, Sname FROM Schools WHERE Sname = $1', + [school] + ); + const schoolID = schoolResult.rows[0].sid; + const schoolName = schoolResult.rows[0].sname; + + // Format the URL + const formattedSchoolName = schoolName.toLowerCase().replace(/\s+/g, '-'); + const formattedFirstName = firstName.toLowerCase().replace(/\s+/g, '-'); + const formattedLastName = lastName.toLowerCase().replace(/\s+/g, '-'); + const url = `http://www.marist.edu/${formattedSchoolName}/faculty/${formattedFirstName}-${formattedLastName}`; + + // Insert into Faculty table with the formatted URL + await client.query( + 'INSERT INTO Faculty (FID, Email, SchoolID, IsHidden, PrefName, URL, TheStatement, LastUpdated) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW())', + [ + pid, + email, + schoolID, + false, + preferredName, + url, + serviceStatement + ] + ); + + // Insert into CommitteeAssignments table + for (let committeeName of committees) { + // Get or create Committee ID + let cid; + const committeeResult = await client.query( + 'SELECT CID FROM Committees WHERE Cname = $1', + [committeeName] + ); + if (committeeResult.rows.length > 0) { + cid = committeeResult.rows[0].cid; + } else { + const newCommittee = await client.query( + 'INSERT INTO Committees (Cname) VALUES ($1) RETURNING CID', + [committeeName] + ); + cid = newCommittee.rows[0].cid; + } + + // Insert into CommitteeAssignments + await client.query( + 'INSERT INTO CommitteeAssignments (FID, CID) VALUES ($1, $2)', + [pid, cid] + ); + } + + res.status(200).json({ message: 'Profile created successfully' }); + } catch (error) { + console.error('Error in /create-faculty:', error); + res.status(500).json({ message: 'Server error' }); + } +}); + +// Route to edit an existing faculty member +app.put('/edit-faculty', ensureAuthenticated, async (req, res) => { + try { + const { firstName, lastName, preferredName, school, committees, serviceStatement } = req.body; + const email = req.user.email; // Get email from authenticated user + + // Get FID and PID + const facultyResult = await client.query( + 'SELECT FID FROM Faculty WHERE Email = $1', + [email] + ); + if (facultyResult.rows.length === 0) { + return res.status(404).json({ message: 'Faculty not found' }); + } + const fid = facultyResult.rows[0].fid; + + // Update People table + await client.query( + 'UPDATE People SET Fname = $1, Lname = $2 WHERE PID = $3', + [firstName, lastName, fid] + ); + + // Get School ID + const schoolResult = await client.query( + 'SELECT SID FROM Schools WHERE Sname = $1', + [school] + ); + const schoolID = schoolResult.rows[0].sid; + + // Update Faculty table + await client.query( + 'UPDATE Faculty SET PrefName = $1, SchoolID = $2, TheStatement = $3, LastUpdated = NOW() WHERE FID = $4', + [preferredName, schoolID, serviceStatement, fid] + ); + + // Update CommitteeAssignments + await client.query('DELETE FROM CommitteeAssignments WHERE FID = $1', [fid]); + for (let committeeName of committees) { + // Get or create Committee ID + let cid; + const committeeResult = await client.query( + 'SELECT CID FROM Committees WHERE Cname = $1', + [committeeName] + ); + if (committeeResult.rows.length > 0) { + cid = committeeResult.rows[0].cid; + } else { + const newCommittee = await client.query( + 'INSERT INTO Committees (Cname) VALUES ($1) RETURNING CID', + [committeeName] + ); + cid = newCommittee.rows[0].cid; + } + + // Insert into CommitteeAssignments + await client.query( + 'INSERT INTO CommitteeAssignments (FID, CID) VALUES ($1, $2)', + [fid, cid] + ); + } + + res.status(200).json({ message: 'Profile updated successfully' }); + } catch (error) { + console.error('Error in /edit-faculty:', error); + res.status(500).json({ message: 'Server error' }); + } +}); + // Route to handle admin login app.post('/admin-login', async (req, res) => { const { username, password } = req.body; // Capture username and password from request @@ -163,8 +417,8 @@ app.post('/admin-login', async (req, res) => { // Example existing route for fetching faculty data (unchanged) app.get('/faculty', async (req, res) => { try { - const result = await client.query(` - SELECT + const result = await client.query(` + SELECT faculty.fid, faculty.email, faculty.ishidden, diff --git a/src/AdminLogin.tsx b/src/AdminLogin.tsx index e74d3b5..68ee983 100644 --- a/src/AdminLogin.tsx +++ b/src/AdminLogin.tsx @@ -84,4 +84,4 @@ const AdminLogin: React.FC = () => { ); } -export default AdminLogin; +export default AdminLogin; \ No newline at end of file diff --git a/src/AdminView.tsx b/src/AdminView.tsx index e6d6d95..688d6f7 100644 --- a/src/AdminView.tsx +++ b/src/AdminView.tsx @@ -125,4 +125,4 @@ const App: React.FC = () => { ); }; -export default App; +export default App; \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index 41444ae..1e18643 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,12 +1,11 @@ import React, { useEffect } from 'react'; import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'; -import Login from './Login'; // Login component +import Login from './Login'; // Login component import AdminLogin from './AdminLogin'; // Admin login component import AdminView from './AdminView'; // Admin view component import UserProfile from './UserProfile'; // User profile component import { AuthProvider, useAuth } from './AuthContext'; // Adjust the path as necessary import { useNavigate } from 'react-router-dom'; -import UserLogin from './User-Login'; function App() { return ( @@ -19,18 +18,15 @@ function App() { {/* Other route for the login page */} } /> - {/* Route for the admin login page */} - } /> + {/* Route for the admin login page */} + } /> - {/* Protected route for the admin view page */} - } /> + {/* Protected route for the admin view page */} + } /> {/* Route for the user profile page */} } /> - {/* Route for the User Login */} - } /> - @@ -41,12 +37,10 @@ function App() { const ProtectedAdminRoute = () => { const { isAuthenticated, isAdmin } = useAuth(); - return ( - isAuthenticated && isAdmin ? ( - - ) : ( - - ) + return isAuthenticated && isAdmin ? ( + + ) : ( + ); }; diff --git a/src/Login.tsx b/src/Login.tsx index fe0dbec..fbb5756 100644 --- a/src/Login.tsx +++ b/src/Login.tsx @@ -25,4 +25,4 @@ function Login() { ); } -export default Login; +export default Login; \ No newline at end of file diff --git a/src/User-Login.css b/src/User-Login.css deleted file mode 100644 index b3f0446..0000000 --- a/src/User-Login.css +++ /dev/null @@ -1,69 +0,0 @@ -/* Login.css */ -.login-box { - position: relative; - background: rgba(255, 255, 255, 0.15); - padding: 15px 120px; - border-radius: 15px; - box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37); - backdrop-filter: blur(4px); - z-index: 2; - text-align: center; - border: 2px solid rgba(255, 255, 255, 0.9); - } - - .input-field { - margin-bottom: 15px; - text-align: left; - } - - .input-field label { - font-size: 16px; - font-weight: bold; - margin-bottom: 5px; - display: block; - } - - .input-field input { - width: 100%; - padding: 10px; - border: 1px solid #ccc; - border-radius: 10px; - font-size: 16px; - box-sizing: border-box; - } - - .input:focus{ - outline: none; - background-color: rgb(244, 244, 244); - } - - - - - .submit-button { - width: 100%; - padding: 10px; - background-color: #b80e0e; - color: white; - font-size: 25px; - font-weight: 600; - border: 2px solid #b80e0e; - border-radius: 15px; - cursor: pointer; - margin-top: 30px; - margin-bottom: 30px; - transition-duration: 0.4s; - } - - .submit-button:hover { - background-color: #921010; - font-size: 25.5px; - border: 2px solid rgb(203, 44, 44); - color: #dddddd; - box-shadow: 0 12px 16px 0 rgba(0,0,0,0.19),0 17px 50px 0 rgba(0,0,0,0.19); - } - - label{ - color: white; - } - diff --git a/src/User-Login.tsx b/src/User-Login.tsx deleted file mode 100644 index 38877ba..0000000 --- a/src/User-Login.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import React, { useState, FormEvent } from 'react'; -import { useNavigate } from 'react-router-dom'; -import { useAuth } from './AuthContext'; // Adjust the path as necessary -import './Login.css'; -import './AdminLogin.css'; -import backgroundImage from './assets/background.jpg'; -import logoImage from './assets/logo.png'; -import Footer from './components/footer/footer'; - -const UserLogin: React.FC = () => { - const [username, setUsername] = useState(''); - const [password, setPassword] = useState(''); - const [error, setError] = useState(''); - const navigate = useNavigate(); - const { login } = useAuth(); // Get the login function from context - - const handleSubmit = async (e: FormEvent) => { - e.preventDefault(); - console.log('Submitting login form'); // Log form submission - try { - const response = await fetch('https://facelect.capping.ecrl.marist.edu/admin-login', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ username, password }), - }); - - const data = await response.json(); - - if (response.ok) { - // Call the login function from the Auth context, marking the user as an admin - login(true); // Pass true to indicate admin login - - // Redirect to admin view if login is successful - navigate('/admin-view'); - } else { - setError(data.message); // Show error message if login fails - } - } catch (error) { - console.error('Error logging in:', error); - setError('Something went wrong. Please try again.'); - } - }; - - return ( -
- Background - Marist Election Profile Logo -
-

User Login:

- {error &&

{error}

} -
-
- - setUsername(e.target.value)} - required - /> -
-
- - setPassword(e.target.value)} - required - /> -
- -
-
-
- ); -} - -export default UserLogin; diff --git a/src/UserProfile.css b/src/UserProfile.css index a68645d..f228f12 100644 --- a/src/UserProfile.css +++ b/src/UserProfile.css @@ -3,9 +3,13 @@ * { font-family: "Inter", serif; } +.container{ + background-color: white; +} + .profile-form-container { - background-color: #f8f8f8; + background-color: white; border-radius: 20px; padding: 50px; max-width: 500px; @@ -14,7 +18,7 @@ } h1 { - font-size: 24px; + font-size: 30px; color: #b21e2d; text-align: center; } @@ -28,8 +32,23 @@ h1 { .form-group { margin-bottom: 30px; width: 95%; + padding-top: 10px; + transition: border 0.3s, box-shadow 0.3s; } +#inputBox { + border: 2px solid #5a5a5a; + border-radius: 5px; + outline: none; + margin-top: 10px; + transition: border 0.3s, box-shadow 0.3s; + } + +#inputBox:focus { + border-color: #B80E0E; + box-shadow: 0 0 8px rgba(184, 14, 14, 0.5); + } + .form-group label { font-size: 14px; color: #333; @@ -58,7 +77,9 @@ textarea::placeholder { /*The next 4 are supposed to style the committee dropdown, but I don't think it did anything */ -select, +input[type="text"], +textarea, +select, /* Added select to match the styling */ .css-yk16xz-control { width: 100%; padding: 10px; @@ -68,6 +89,7 @@ select, background-color: white; } + .css-1pahdxg-control { border-color: #b21e2d !important; box-shadow: none !important; @@ -99,6 +121,11 @@ select, margin: auto; transition-duration: 0.4s; color: white; + padding: 10px; + font-size: large; + border-radius: 15px; + margin-top: 30px; + margin-bottom: -10px; } .save-button:hover { @@ -109,5 +136,169 @@ select, width: 30px; } +.profile-view{ + font-size: larger; +} + +.edit-button{ + background-color: #b21e2d; + border: 2px solid #fe6978; + cursor: pointer; + display: flex; + justify-content: flex-end; + margin: auto; + transition-duration: 0.4s; + color: white; + padding: 10px; + font-size: large; + border-radius: 15px; + margin-top: 30px; + margin-bottom: -10px; +} + +.edit-button:hover { + background-color: #831b25; +} +.container { + background-color: white; + } + .profile-form-container { + background-color: white; + border-radius: 20px; + padding: 50px; + max-width: 500px; + margin: auto; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); + } + + .email-check-container { + margin-top: 30px; + text-align: center; + } + + .email-check-toggle { + background-color: #b21e2d; + color: white; + padding: 10px 20px; + border-radius: 10px; + border: none; + cursor: pointer; + font-size: 16px; + transition: 0.3s; + } + + .email-check-toggle:hover { + background-color: #831b25; + } + + .email-check { + margin-top: 20px; + text-align: center; + } + + .email-check label { + display: block; + font-size: 16px; + margin-bottom: 10px; + } + + .email-check input { + padding: 10px; + width: 300px; + border: 2px solid #b21e2d; + border-radius: 8px; + margin-bottom: 10px; + } + + .check-button { + background-color: #b21e2d; + color: white; + padding: 10px 20px; + border-radius: 10px; + border: none; + cursor: pointer; + font-size: 16px; + transition: 0.3s; + } + + .check-button:hover { + background-color: #831b25; + } + + .error { + color: red; + margin-top: 10px; + } + + .service-statement { + word-wrap: break-word; /* Break long words onto the next line */ + word-break: break-word; /* Ensure any overly long word breaks */ + white-space: pre-wrap; /* Keep line breaks and spacing while wrapping text */ + max-width: 100%; /* Make sure it fits within the container */ + } + + + .editing-header { + position: relative; + margin-bottom: 20px; /* Adds space between the header and the form content */ +} + +.go-back-button { + position: absolute; /* Places the button relative to the `editing-header` container */ + top: -20px; /* Adjusts the button's position above the form content */ + left: -10px; /* Adjusts the button's position to the left of the container padding */ + display: flex; + align-items: center; + background: none; + border: none; + color: #b21e2d; + font-size: 16px; + cursor: pointer; + transition: color 0.3s; +} + +.go-back-button:hover { + color: #831b25; +} + +.go-back-button:hover .tooltip { + visibility: visible; + opacity: 1; + } + + .tooltip { + visibility: hidden; + opacity: 0; + background-color: rgba(0, 0, 0, 0.7); + color: #fff; + text-align: center; + border-radius: 5px; + padding: 5px; + position: absolute; + top: -40px; + left: 50%; + transform: translateX(-50%); + z-index: 10; + transition: opacity 0.3s ease; + font-size: 12px; + white-space: nowrap; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); + } + +.back-arrow { + width: 18px; + height: 18px; + margin-right: 8px; + transition-duration: 0.4s +} + +.back-arrow:hover > .overlay { + width:100%; + height:100%; + position:absolute; + background-color:#000; + opacity:0.5; + border-radius:30px; +} diff --git a/src/UserProfile.tsx b/src/UserProfile.tsx index e79f6cc..62c36d7 100644 --- a/src/UserProfile.tsx +++ b/src/UserProfile.tsx @@ -2,8 +2,10 @@ import React, { useState, useEffect } from 'react'; import './UserProfile.css'; import Navbar from './components/navbar/Navbar'; import saveIcon from './assets/save-icon.png'; +import arrowIcon from './assets/arrow-icon.png'; import CreatableSelect from 'react-select/creatable'; import Select from 'react-select'; +import Footer from './components/footer/footer'; const UserProfile: React.FC = () => { const [isEditing, setIsEditing] = useState(false); @@ -15,6 +17,19 @@ const UserProfile: React.FC = () => { const [serviceStatement, setServiceStatement] = useState(''); const [committeeOptions, setCommitteeOptions] = useState<{ value: string, label: string }[]>([]); const [schoolOptions, setSchoolOptions] = useState<{ value: string, label: string }[]>([]); + const [profileExists, setProfileExists] = useState(false); + const [email, setEmail] = useState(''); + const [error, setError] = useState(''); + + // State to keep track of the original values + const [originalState, setOriginalState] = useState({ + firstName: '', + lastName: '', + preferredName: '', + school: '', + committees: [] as string[], + serviceStatement: '', + }); useEffect(() => { const fetchCommitteeNames = async () => { @@ -61,96 +76,114 @@ const UserProfile: React.FC = () => { } }; + const fetchUserData = async () => { + try { + const response = await fetch('/get-user-data', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }); + if (!response.ok) { + throw new Error(`Error fetching user data: ${response.statusText}`); + } + const data = await response.json(); + + if (data.found) { + setFirstName(data.firstName); + setLastName(data.lastName); + setPreferredName(data.preferredName); + setSchool(data.school); + setCommittees(data.committees); + setServiceStatement(data.serviceStatement); + setProfileExists(true); + setError(''); + + // Save original values + setOriginalState({ + firstName: data.firstName, + lastName: data.lastName, + preferredName: data.preferredName, + school: data.school, + committees: data.committees, + serviceStatement: data.serviceStatement, + }); + } else { + setProfileExists(false); + setError('Profile not found. Click "Edit Profile" to create a new profile.'); + } + } catch (err) { + console.error('Error fetching user data:', err); + setError('An error occurred. Please try again.'); + } + }; + fetchCommitteeNames(); fetchSchoolNames(); + fetchUserData(); }, []); const handleCommitteeChange = (selectedOptions: any) => { setCommittees(selectedOptions ? selectedOptions.map((option: any) => option.value) : []); }; - const handleSave = () => { - setIsEditing(false); - // Trigger save to the database here - }; - return ( -
+
-

Your Election Profile

+

Your Election Profile

- {isEditing ? ( - // Edit State -
-
- - setFirstName(e.target.value)} - placeholder="Your First Name Here" - /> - - setLastName(e.target.value)} - placeholder="Your Last Name Here" - /> -
-
- - setPreferredName(e.target.value)} - placeholder="Your Preferred Name Here" - /> -
-
- -