Add new "choir" calendar and add cascading functionality for calendars
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				Jenkins Production Deployment
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	Jenkins Production Deployment
				
			This commit is contained in:
		
							parent
							
								
									59fee19a76
								
							
						
					
					
						commit
						cb85e81d67
					
				| 
						 | 
					@ -29,6 +29,19 @@ export const checkMemberPrivileges = async (sessionId: string, sessionKey: strin
 | 
				
			||||||
	return password == process.env.MEMBER_CREDENTIAL;
 | 
						return password == process.env.MEMBER_CREDENTIAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Checks if the password gives choir view privileges
 | 
				
			||||||
 | 
					 * @param password
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const checkChoirPrivileges = async (sessionId: string, sessionKey: string, password: string, ip: string) => {
 | 
				
			||||||
 | 
						if(sessionId) {
 | 
				
			||||||
 | 
							let user = await UserService.checkSession(sessionId, sessionKey, ip);
 | 
				
			||||||
 | 
							return user.isActive;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return password == process.env.CHOIR_CREDENTIAL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Checks if the password gives management view privileges
 | 
					 * Checks if the password gives management view privileges
 | 
				
			||||||
 * @param password
 | 
					 * @param password
 | 
				
			||||||
| 
						 | 
					@ -48,6 +61,8 @@ export const hasAccess = async (calendarName: string, sessionId: string, session
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
		case 'members':
 | 
							case 'members':
 | 
				
			||||||
			return await checkMemberPrivileges(sessionId, sessionKey, password, ip);
 | 
								return await checkMemberPrivileges(sessionId, sessionKey, password, ip);
 | 
				
			||||||
 | 
							case 'choir':
 | 
				
			||||||
 | 
								return await checkChoirPrivileges(sessionId, sessionKey, password, ip);
 | 
				
			||||||
		case 'management':
 | 
							case 'management':
 | 
				
			||||||
			return await checkManagementPrivileges(sessionId, sessionKey, password, ip);
 | 
								return await checkManagementPrivileges(sessionId, sessionKey, password, ip);
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,7 @@ export const eventsRouter = express.Router();
 | 
				
			||||||
export const calendarNames = new Map<string, any>([
 | 
					export const calendarNames = new Map<string, any>([
 | 
				
			||||||
	['public', {id: 1, name: 'Nachklang_calendar'}],
 | 
						['public', {id: 1, name: 'Nachklang_calendar'}],
 | 
				
			||||||
	['members', {id: 2, name: 'Nachklang_internal_calendar'}],
 | 
						['members', {id: 2, name: 'Nachklang_internal_calendar'}],
 | 
				
			||||||
 | 
						['choir', {id: 4, name: 'Nachklang_choir_calendar'}],
 | 
				
			||||||
	['management', {id: 3, name: 'Nachklang_management_calendar'}]
 | 
						['management', {id: 3, name: 'Nachklang_management_calendar'}]
 | 
				
			||||||
]);
 | 
					]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,6 +56,7 @@ eventsRouter.get('/:calendar/json', async (req: Request, res: Response) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		let user = await UserService.checkSession(sessionId, sessionKey, ip);
 | 
							let user = await UserService.checkSession(sessionId, sessionKey, ip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// If no user was found, check if the password gives access to the calendar
 | 
				
			||||||
		if(user === null || !user.isActive) {
 | 
							if(user === null || !user.isActive) {
 | 
				
			||||||
			if (! await CredentialService.hasAccess(calendarName, sessionId, sessionKey, password, ip)) {
 | 
								if (! await CredentialService.hasAccess(calendarName, sessionId, sessionKey, password, ip)) {
 | 
				
			||||||
				res.status(403).send({'message': 'You do not have access to the specified calendar.'});
 | 
									res.status(403).send({'message': 'You do not have access to the specified calendar.'});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,14 @@ export const getAllEvents = async (calendarId: number): Promise<Event[]> => {
 | 
				
			||||||
	let conn = await NachklangCalendarDB.getConnection();
 | 
						let conn = await NachklangCalendarDB.getConnection();
 | 
				
			||||||
	let eventRows: Event[] = [];
 | 
						let eventRows: Event[] = [];
 | 
				
			||||||
	try {
 | 
						try {
 | 
				
			||||||
 | 
							const calendarQuery = 'SELECT calendar_id, includes_calendars FROM calendars WHERE calendar_id = ?';
 | 
				
			||||||
 | 
							const calendarRes = await conn.query(calendarQuery, calendarId);
 | 
				
			||||||
 | 
							let calendarsToFetch: number[] = [calendarId];
 | 
				
			||||||
 | 
							for(let row of calendarRes) {
 | 
				
			||||||
 | 
								let includes: number[] = JSON.parse(row.includes_calendars);
 | 
				
			||||||
 | 
								calendarsToFetch = [...calendarsToFetch, ...includes];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const eventsQuery = `
 | 
							const eventsQuery = `
 | 
				
			||||||
		SELECT e.calendar_id, e.uuid, e.created_date, e.created_by_id, u.full_name, v.* FROM events e
 | 
							SELECT e.calendar_id, e.uuid, e.created_date, e.created_by_id, u.full_name, v.* FROM events e
 | 
				
			||||||
			INNER JOIN (
 | 
								INNER JOIN (
 | 
				
			||||||
| 
						 | 
					@ -25,9 +33,9 @@ export const getAllEvents = async (calendarId: number): Promise<Event[]> => {
 | 
				
			||||||
			INNER JOIN event_versions v
 | 
								INNER JOIN event_versions v
 | 
				
			||||||
			ON v.event_id = latest_versions.event_id AND v.event_version_id = latest_versions.latest_version
 | 
								ON v.event_id = latest_versions.event_id AND v.event_version_id = latest_versions.latest_version
 | 
				
			||||||
			LEFT OUTER JOIN users u ON u.user_id = e.created_by_id
 | 
								LEFT OUTER JOIN users u ON u.user_id = e.created_by_id
 | 
				
			||||||
			WHERE e.calendar_id = ? AND v.status = 'PUBLIC'
 | 
								WHERE e.calendar_id IN (?) AND v.status = 'PUBLIC'
 | 
				
			||||||
			ORDER BY e.event_id`;
 | 
								ORDER BY e.event_id`;
 | 
				
			||||||
		const eventsRes = await conn.query(eventsQuery, calendarId);
 | 
							const eventsRes = await conn.query(eventsQuery, [calendarsToFetch]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (let row of eventsRes) {
 | 
							for (let row of eventsRes) {
 | 
				
			||||||
			eventRows.push({
 | 
								eventRows.push({
 | 
				
			||||||
| 
						 | 
					@ -56,6 +64,11 @@ export const getAllEvents = async (calendarId: number): Promise<Event[]> => {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Returns all events for the given calendar for the admin UI (therefore includes admin relevant information and
 | 
				
			||||||
 | 
					 * ignores the calendar includes
 | 
				
			||||||
 | 
					 * @param calendarId
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
export const getAllEventsAdmin = async (calendarId: number): Promise<Event[]> => {
 | 
					export const getAllEventsAdmin = async (calendarId: number): Promise<Event[]> => {
 | 
				
			||||||
	let conn = await NachklangCalendarDB.getConnection();
 | 
						let conn = await NachklangCalendarDB.getConnection();
 | 
				
			||||||
	let eventRows: Event[] = [];
 | 
						let eventRows: Event[] = [];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,9 @@
 | 
				
			||||||
import {Event} from './event.interface';
 | 
					import {Event} from './event.interface';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Interface to external classes - Turns the given events into an ical string
 | 
				
			||||||
 | 
					 * @param events
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
export const convertToIcal = async (events: Event[]): Promise<string> => {
 | 
					export const convertToIcal = async (events: Event[]): Promise<string> => {
 | 
				
			||||||
	try {
 | 
						try {
 | 
				
			||||||
		let ical: iCalFile = {body: []};
 | 
							let ical: iCalFile = {body: []};
 | 
				
			||||||
| 
						 | 
					@ -15,6 +19,10 @@ export const convertToIcal = async (events: Event[]): Promise<string> => {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Method to serialize an iCalFile object into an ical string
 | 
				
			||||||
 | 
					 * @param ical
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
const serializeIcalFile = (ical: iCalFile): string => {
 | 
					const serializeIcalFile = (ical: iCalFile): string => {
 | 
				
			||||||
	let returnString = '';
 | 
						let returnString = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +35,10 @@ const serializeIcalFile = (ical: iCalFile): string => {
 | 
				
			||||||
	return returnString;
 | 
						return returnString;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Method to serialize a single ical event into an ical event string
 | 
				
			||||||
 | 
					 * @param icalevent
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
const serializeIcalEvent = (icalevent: iCalEvent): string => {
 | 
					const serializeIcalEvent = (icalevent: iCalEvent): string => {
 | 
				
			||||||
	let returnString = '';
 | 
						let returnString = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -50,7 +62,10 @@ const serializeIcalEvent = (icalevent: iCalEvent): string => {
 | 
				
			||||||
	return returnString;
 | 
						return returnString;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Method to generate the ical header string
 | 
				
			||||||
 | 
					 * @param ical
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
const generateHeaderInfo = (ical: iCalFile) => {
 | 
					const generateHeaderInfo = (ical: iCalFile) => {
 | 
				
			||||||
	ical.header = 'BEGIN:VCALENDAR\n' +
 | 
						ical.header = 'BEGIN:VCALENDAR\n' +
 | 
				
			||||||
		'VERSION:2.0\n' +
 | 
							'VERSION:2.0\n' +
 | 
				
			||||||
| 
						 | 
					@ -78,14 +93,27 @@ const generateHeaderInfo = (ical: iCalFile) => {
 | 
				
			||||||
		'END:VTIMEZONE\n';
 | 
							'END:VTIMEZONE\n';
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Method to generate the ical footer info
 | 
				
			||||||
 | 
					 * @param ical
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
const generateFooterInfo = (ical: iCalFile) => {
 | 
					const generateFooterInfo = (ical: iCalFile) => {
 | 
				
			||||||
	ical.footer = 'END:VCALENDAR';
 | 
						ical.footer = 'END:VCALENDAR';
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Method to add events to the iCalFile object
 | 
				
			||||||
 | 
					 * @param ical
 | 
				
			||||||
 | 
					 * @param event
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
const addEventToFile = (ical: iCalFile, event: Event) => {
 | 
					const addEventToFile = (ical: iCalFile, event: Event) => {
 | 
				
			||||||
	ical.body.push(createIcalEvent(event));
 | 
						ical.body.push(createIcalEvent(event));
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Method to turn an event object into an iCalEvent object
 | 
				
			||||||
 | 
					 * @param event
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
const createIcalEvent = (event: Event): iCalEvent => {
 | 
					const createIcalEvent = (event: Event): iCalEvent => {
 | 
				
			||||||
	let description = event.description ? event.description + '\n' : '';
 | 
						let description = event.description ? event.description + '\n' : '';
 | 
				
			||||||
	let location = event.location ? event.location + '\n' : '';
 | 
						let location = event.location ? event.location + '\n' : '';
 | 
				
			||||||
| 
						 | 
					@ -107,6 +135,12 @@ const createIcalEvent = (event: Event): iCalEvent => {
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Helper method to format dates in a valid iCal format
 | 
				
			||||||
 | 
					 * @param date
 | 
				
			||||||
 | 
					 * @param wholeDayFormat
 | 
				
			||||||
 | 
					 * @param isEndDate
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
const formatDate = (date: Date, wholeDayFormat: boolean = false, isEndDate: boolean = false): string => {
 | 
					const formatDate = (date: Date, wholeDayFormat: boolean = false, isEndDate: boolean = false): string => {
 | 
				
			||||||
	let returnString = '';
 | 
						let returnString = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user