Skip to content

Commit

Permalink
CUTYPE and X-NUM-GUESTS support (#244)
Browse files Browse the repository at this point in the history
* Add participation type for CUtype fields + support for x-num-guests

x-num-guests is a string for now to prevent its unnecessary inclusion

* Add xnum guests + cutype to schema

* Add additional fields to formatted attendee

+ format so that semicolon always ends first part and mailto always ends

* restrict sequence and make x-num-guests a number

* RSVP is not a required field

* typeof not needed for undefined check

---------

Co-authored-by: Adrian Curtin <[email protected]>
  • Loading branch information
jlapier and AdrianCurtin authored Aug 14, 2023
1 parent 4285364 commit e4784fd
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 31 deletions.
15 changes: 12 additions & 3 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ export type ParticipationRole =
| 'OPT-PARTICIPANT'
| 'NON-PARTICIPANT';

export type ParticipationType =
| 'INDIVIDUAL'
| 'GROUP'
| 'RESOURCE'
| 'ROOM'
| 'UNKNOWN';

export type Person = {
name?: string;
email?: string;
Expand All @@ -44,6 +51,8 @@ export type Attendee = Person & {
rsvp?: boolean;
partstat?: ParticipationStatus;
role?: ParticipationRole;
cutype?: ParticipationType;
xNumGuests?: number;
};

export type ActionType = 'audio' | 'display' | 'email' | 'procedure';
Expand Down Expand Up @@ -81,15 +90,15 @@ export type EventAttributes = {
url?: string;
status?: EventStatus;
busyStatus?: 'FREE' | 'BUSY' | 'TENTATIVE' | 'OOF';

organizer?: Person & {
sentBy?: string;
};
attendees?: Attendee[];

categories?: string[];
alarms?: Alarm[];

productId?: string;
uid?: string;
method?: string;
Expand Down
6 changes: 4 additions & 2 deletions src/schema/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ const contactSchema = yup.object().shape({
rsvp: yup.boolean(),
dir: yup.string().matches(urlRegex),
partstat: yup.string(),
role: yup.string()
role: yup.string(),
cutype: yup.string(),
xNumGuests: yup.number()
}).noUnknown()

const organizerSchema = yup.object().shape({
Expand Down Expand Up @@ -65,7 +67,7 @@ const schema = yup.object().shape({
productId: yup.string(),
method: yup.string(),
uid: yup.string().required(),
sequence: yup.number(),
sequence: yup.number().integer().max(2_147_483_647),
start: dateTimeSchema.required(),
duration: durationSchema,
startType: yup.string().matches(/utc|local/),
Expand Down
33 changes: 24 additions & 9 deletions src/utils/set-contact.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
export default function setContact({ name, email, rsvp, dir, partstat, role }) {
let formattedAttendee = ''
formattedAttendee += rsvp ? 'RSVP=TRUE;' : 'RSVP=FALSE;'
formattedAttendee += role ? `ROLE=${role};` : ''
formattedAttendee += partstat ? `PARTSTAT=${partstat};` : ''
formattedAttendee += dir ? `DIR=${dir};` : ''
formattedAttendee += 'CN='
formattedAttendee += name || 'Unnamed attendee'
formattedAttendee += email ? `:mailto:${email}` : ''
export default function setContact({ name, email, rsvp, dir, partstat, role, cutype, xNumGuests }) {
let formattedParts = [];

if(rsvp !== undefined){
formattedParts.push(rsvp ? 'RSVP=TRUE' : 'RSVP=FALSE');
}
if(cutype){
formattedParts.push("CUTYPE=".concat(cutype));
}
if(xNumGuests !== undefined){
formattedParts.push(`X-NUM-GUESTS=${xNumGuests}`);
}
if(role){
formattedParts.push("ROLE=".concat(role));
}
if(partstat){
formattedParts.push("PARTSTAT=".concat(partstat));
}
if(dir){
formattedParts.push("DIR=".concat(dir));
}
formattedParts.push('CN='.concat((name || 'Unnamed attendee')));

var formattedAttendee = formattedParts.join(';').concat(email ? ":mailto:".concat(email) : '');

return formattedAttendee
}
2 changes: 1 addition & 1 deletion test/pipeline/format.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ describe('pipeline.formatEvent', () => {
{name: 'Brittany Seaton', email: '[email protected]', rsvp: true }
]})
const formattedEvent = formatEvent(event)
expect(formattedEvent).to.contain('ATTENDEE;RSVP=FALSE;CN=Adam Gibbons:mailto:[email protected]')
expect(formattedEvent).to.contain('ATTENDEE;CN=Adam Gibbons:mailto:[email protected]')
expect(formattedEvent).to.contain('ATTENDEE;RSVP=TRUE;CN=Brittany Seaton:mailto:[email protected]')
})
it('writes a busystatus', () => {
Expand Down
9 changes: 9 additions & 0 deletions test/pipeline/validate.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ describe('pipeline.validate', () => {
expect(error).not.to.exist
expect(value.uid).to.equal('1')
})
it('returns an error if the sequence number is too long', () => {
const { error, value } = validateEvent({
uid: '1',
start: [1997, 10, 1, 22, 30],
duration: { hours: 1 },
sequence: 3_456_789_123, // bigger than 2,147,483,647
})
expect(error).to.exist
})
it('returns undefined when passed no event', () => {
const { error, value } = validateEvent()
expect(value).to.be.undefined
Expand Down
44 changes: 28 additions & 16 deletions test/utils/set-contact.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,24 @@ import { setContact } from '../../src/utils'
describe('utils.setContact', () => {
it('set a contact with role', () => {
const contact = { name: 'm-vinc', email: '[email protected]' }
expect(setContact(contact))
.to.equal(`CN=m-vinc:mailto:[email protected]`)

const contactChair = Object.assign({role: 'CHAIR'}, contact)
const contactRequired = Object.assign({role: 'REQ-PARTICIPANT' }, contact)
const contactOptional = Object.assign({role: 'OPT-PARTICIPANT' }, contact)
const contactNon = Object.assign({role: 'NON-PARTICIPANT' }, contact)
expect(setContact(contactChair))
.to.equal(`RSVP=FALSE;ROLE=CHAIR;CN=m-vinc:mailto:[email protected]`)
.to.equal(`ROLE=CHAIR;CN=m-vinc:mailto:[email protected]`)

const contactRequired = Object.assign({role: 'REQ-PARTICIPANT', rsvp: true }, contact)
expect(setContact(contactRequired))
.to.equal(`RSVP=FALSE;ROLE=REQ-PARTICIPANT;CN=m-vinc:mailto:[email protected]`)
.to.equal(`RSVP=TRUE;ROLE=REQ-PARTICIPANT;CN=m-vinc:mailto:[email protected]`)

const contactOptional = Object.assign({role: 'OPT-PARTICIPANT', rsvp: false }, contact)
expect(setContact(contactOptional))
.to.equal(`RSVP=FALSE;ROLE=OPT-PARTICIPANT;CN=m-vinc:mailto:[email protected]`)

const contactNon = Object.assign({role: 'NON-PARTICIPANT' }, contact)
expect(setContact(contactNon))
.to.equal(`RSVP=FALSE;ROLE=NON-PARTICIPANT;CN=m-vinc:mailto:[email protected]`)
expect(setContact(contact))
.to.equal(`RSVP=FALSE;CN=m-vinc:mailto:[email protected]`)
.to.equal(`ROLE=NON-PARTICIPANT;CN=m-vinc:mailto:[email protected]`)
})
it('set a contact with partstat', () => {
const contact = { name: 'm-vinc', email: '[email protected]' }
Expand All @@ -28,21 +32,21 @@ describe('utils.setContact', () => {
const contactTentative = Object.assign({contact, partstat: 'TENTATIVE'}, contact)

expect(setContact(contactUndefined))
.to.equal('RSVP=FALSE;CN=m-vinc:mailto:[email protected]')
.to.equal('CN=m-vinc:mailto:[email protected]')

expect(setContact(contactNeedsAction))
.to.equal('RSVP=FALSE;PARTSTAT=NEEDS-ACTION;CN=m-vinc:mailto:[email protected]')
.to.equal('PARTSTAT=NEEDS-ACTION;CN=m-vinc:mailto:[email protected]')

expect(setContact(contactDeclined))
.to.equal('RSVP=FALSE;PARTSTAT=DECLINED;CN=m-vinc:mailto:[email protected]')
.to.equal('PARTSTAT=DECLINED;CN=m-vinc:mailto:[email protected]')

expect(setContact(contactTentative))
.to.equal('RSVP=FALSE;PARTSTAT=TENTATIVE;CN=m-vinc:mailto:[email protected]')
.to.equal('PARTSTAT=TENTATIVE;CN=m-vinc:mailto:[email protected]')

expect(setContact(contactAccepted))
.to.equal('RSVP=FALSE;PARTSTAT=ACCEPTED;CN=m-vinc:mailto:[email protected]')
.to.equal('PARTSTAT=ACCEPTED;CN=m-vinc:mailto:[email protected]')
})
it('sets a contact and defaults RSVP to false', () => {
it('sets a contact and only sets RSVP if specified', () => {
const contact1 = {
name: 'Adam Gibbons',
email: '[email protected]'
Expand All @@ -56,9 +60,17 @@ describe('utils.setContact', () => {
}

expect(setContact(contact1))
.to.equal('RSVP=FALSE;CN=Adam Gibbons:mailto:[email protected]')
.to.equal('CN=Adam Gibbons:mailto:[email protected]')

expect(setContact(contact2))
.to.equal('RSVP=TRUE;DIR=https://example.com/contacts/adam;CN=Adam Gibbons:mailto:[email protected]')
})
it('set a contact with cutype and guests', () => {
const contact = { name: 'm-vinc', email: '[email protected]' }
const contactCuGuests = Object.assign({ cutype: 'INDIVIDUAL', xNumGuests: 0 }, contact)
const contactString = setContact(contactCuGuests)

expect(contactString).to.contain('CUTYPE=INDIVIDUAL')
expect(contactString).to.contain('X-NUM-GUESTS=0')
})
})

0 comments on commit e4784fd

Please sign in to comment.