Skip to content

Commit

Permalink
Merge pull request #1362 from NicoleRauch/master
Browse files Browse the repository at this point in the history
Meetup-Events können nun in die Softwerkskammer gespiegelt werden
  • Loading branch information
leider authored Aug 3, 2018
2 parents 8d95010 + 648a500 commit 95ed54e
Show file tree
Hide file tree
Showing 20 changed files with 283 additions and 66 deletions.
16 changes: 8 additions & 8 deletions commonComponents/pug/formComponents.pug
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ mixin currency(name, label, value, tooltip, placeholder, readonly)
mixin textareaPure(name, label, value, placeholder)
+textareaInternal('form-control', '4', name, label, value, null, placeholder)

mixin textarea(name, label, value, tooltip, placeholder)
+textareaInternal('md-textarea', '7', name, label, value, tooltip, placeholder)
mixin textarea(name, label, value, tooltip, placeholder, readonly)
+textareaInternal('md-textarea', '7', name, label, value, tooltip, placeholder, readonly)

mixin hightextarea(name, label, value, tooltip, placeholder)
+textareaInternal('md-textarea', '15', name, label, value, tooltip, placeholder)
Expand Down Expand Up @@ -99,15 +99,15 @@ mixin memberSubmitButtons(submitText)
mixin hidden(name, value)
input(type='hidden', name=name, value=value)

mixin date(name, label, value, tooltip)
mixin date(name, label, value, tooltip, readonly)
.form-group
+controlLabel(name, label, tooltip)
input.form-control.datepicker(id=name, type='text', name=name, value=value)
input.form-control.datepicker(id=name, type='text', name=name, value=value, disabled=readonly)

mixin time(name, value)
mixin time(name, value, readonly)
.form-group
label.control-label(for=name)  
input.form-control.timepicker(id=name, type='text', name=name, value=value)
input.form-control.timepicker(id=name, type='text', name=name, value=value, disabled=readonly)

mixin colorPicker(name, value)
.form-group
Expand All @@ -134,10 +134,10 @@ mixin controlLabel(name, label, tooltip)
-else
| #{label}:

mixin textareaInternal(classname, rowCount, name, label, value, tooltip, placeholder)
mixin textareaInternal(classname, rowCount, name, label, value, tooltip, placeholder, readonly)
.form-group
+controlLabel(name, label, tooltip)
textarea(class=classname, id=name, rows=rowCount, type='text', name=name, placeholder=placeholder) #{value}
textarea(class=classname, id=name, rows=rowCount, type='text', name=name, placeholder=placeholder, disabled=readonly) #{value}

mixin reallyDeleteModalPost(header, options, extraclasses)
+reallyDeleteModalOnly(header, options)
Expand Down
1 change: 1 addition & 0 deletions config/beans.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"calendarService": {"module": "./softwerkskammer/lib/activities/calendarService"},
"dashboardService": {"module": "./softwerkskammer/lib/dashboard/dashboardService"},
"groupsService": {"module": "./softwerkskammer/lib/groups/groupsService"},
"meetupActivitiesService": {"module": "./softwerkskammer/lib/meetupActivities/meetupActivitiesService"},
"groupsAndMembersService": {"module": "./softwerkskammer/lib/groupsAndMembers/groupsAndMembersService"},
"icalService": {"module": "./softwerkskammer/lib/activities/icalService"},
"galleryService": {"module": "./softwerkskammer/lib/gallery/galleryService"},
Expand Down
5 changes: 5 additions & 0 deletions locales/translation-de.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
"already_registered": "SoCraTes only",
"billing_address": "Rechnungsanschrift",
"blog_entry": "Blogartikel zur Aktivität",
"cloned_from_meetup_text": "Diese Aktivität wurde von Meetup kopiert. Einige Informationen kannst Du daher nur auf Meetup bearbeiten. Deine Änderungen werden zeitnah hierhin übertragen.",
"count": "Anzahl",
"count_participants_interval": "(0){Bislang gibt es keine Teilnahmezusagen.};(1){Bislang hat ein Mitglied seine Teilnahme zugesagt.};(2-inf){Bislang haben {{count}} Mitglieder ihre Teilnahme zugesagt.}",
"count_participants_meetup_interval": "(0){Woanders gibt es keine Anmeldungen.};(1){Woanders gibt es eine Anmeldung.};(2-inf){Woanders gibt es {{count}} Anmeldungen.}",
"create": "Aktivität anlegen",
"created_by": "Angelegt von",
"delete": "Aktivität löschen",
Expand Down Expand Up @@ -252,6 +254,8 @@
"join": "Gruppe beitreten",
"leave": "Gruppe verlassen",
"map_label": "Label in Karte",
"meetup_clone_title": "Kopiert existierende Events von Meetup.",
"meetupURL_label": "Meetup-URL (falls für diese Gruppe erforderlich)",
"more": "mehr lesen…",
"new": "Neue Gruppe",
"other": "Andere",
Expand All @@ -262,6 +266,7 @@
"email_prefix": "steht innerhalb [] vor dem Subject in gesendeten E-Mails",
"gotogroup": "Zur Gruppenseite.",
"map_label": "Label, das in der Karte angezeigt wird",
"meetupURL_label": "Manche Gruppen kommen leider nicht ohne eine Präsenz auf Meetup aus. Sollte das auch für diese Gruppe gelten, kann hier die Meetup-URL der Gruppe eingetragen werden. Dadurch werden die Meetup-Events der Gruppe automatisch in die Softwerkskammer übernommen.",
"name": "Die Adresse, unter der die Gruppe \"@softwerkskammer.org\" erreichbar ist.",
"title": "Anzeigetext innerhalb der Site, ist auch Realname für E-Mails",
"x_coord": "Waagerechte Position auf der Karte",
Expand Down
3 changes: 2 additions & 1 deletion softwerkskammer/frontendtests/fixtures/locals.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ module.exports = {
canUnsubscribe: function () { return ''; },
hasWaitinglist: function () { return ''; }
};
}
},
clonedFromMeetup: function () { return false; }
},
groups: [],
group: {},
Expand Down
21 changes: 16 additions & 5 deletions softwerkskammer/lib/activities/activity.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ class Activity {
return this.state.editorIds || [];
}

clonedFromMeetup() {
return !!this.state.clonedFromMeetup;
}

meetupRSVPCount() {
return this.state.meetupRSVPCount || 0;
}

fillFromUI(object, editorIds) {
this.state.url = object.url;

Expand All @@ -83,6 +91,9 @@ class Activity {
this.state.startUnix = fieldHelpers.parseToUnixUsingDefaultTimezone(object.startDate, object.startTime);
this.state.endUnix = fieldHelpers.parseToUnixUsingDefaultTimezone(object.endDate, object.endTime);

this.state.clonedFromMeetup = object.clonedFromMeetup;
this.state.meetupRSVPCount = object.meetupRSVPCount;

if (!this.id() || this.id() === 'undefined') {
this.state.id = fieldHelpers.createLinkFrom([this.assignedGroup(), this.title(), this.startMoment()]);
}
Expand Down Expand Up @@ -236,11 +247,11 @@ class Activity {
const resource = this.resourceNamed(resourceName);
const memberIds = resource.registeredMembers();
return this.participants
.filter(participant => memberIds.some(memberId => memberId === participant.id()))
.map(member => {
member.registeredAt = resource.registrationDateOf(member.id());
return member;
});
.filter(participant => memberIds.some(memberId => memberId === participant.id()))
.map(member => {
member.registeredAt = resource.registrationDateOf(member.id());
return member;
});
}
}

Expand Down
10 changes: 10 additions & 0 deletions softwerkskammer/lib/activities/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const icalService = beans.get('icalService');
const groupsService = beans.get('groupsService');
const activitystore = beans.get('activitystore');
const memberstore = beans.get('memberstore');
const meetupActivitiesService = beans.get('meetupActivitiesService');

const Activity = beans.get('activity');
const Group = beans.get('group');
Expand Down Expand Up @@ -91,6 +92,7 @@ function renderGdcrFor(gdcrDay, res, next) {
});
});
}

app.get('/gdcr2013', (req, res, next) => renderGdcrFor('2013-12-14', res, next));

app.get('/gdcr2014', (req, res, next) => renderGdcrFor('2014-11-15', res, next));
Expand Down Expand Up @@ -228,6 +230,13 @@ app.post('/submit', (req, res, next) => {
);
});

app.post('/clone-from-meetup', (req, res, next) => {
meetupActivitiesService.cloneActivitiesFromMeetup((err) => {
if (err) { return next(err); }
res.redirect('/activities');
});
});

app.get('/checkurl', (req, res) => misc.validate(req.query.url, req.query.previousUrl, R.partial(activitiesService.isValidUrl, [reservedURLs]), res.end));

app.get('/:url', (req, res, next) => {
Expand Down Expand Up @@ -265,6 +274,7 @@ function subscribe(body, req, res, next) {
res.redirect('/activities/' + encodeURIComponent(activityUrl));
});
}

app.post('/subscribe', (req, res, next) => subscribe(req.body, req, res, next));

app.get('/subscribe', (req, res, next) => {
Expand Down
27 changes: 15 additions & 12 deletions softwerkskammer/lib/activities/views/activities-forms.pug
Original file line number Diff line number Diff line change
Expand Up @@ -15,36 +15,39 @@ mixin activityform(activity, groups, editorNames, participantNames)
| #{t('activities.edit')}
else
| #{t('activities.create')}
p #{t('activities.helptext')}
a(href='/wiki/hilfe/activities-hilfe') #{t('activities.helplink')}
if (activity.clonedFromMeetup())
p #{t('activities.cloned_from_meetup_text')}
else
p #{t('activities.helptext')}
a(href='/wiki/hilfe/activities-hilfe') #{t('activities.helplink')}
.row
.col-md-6
+text('title', t('activities.title'), activity.title(), t('activities.tooltip.title'))
+text('title', t('activities.title'), activity.title(), t('activities.tooltip.title'), '', activity.clonedFromMeetup())
.row
.col-xs-6(style='padding-right:5px')
.col-xs-6(style='padding-left:0px;padding-right:3px')
+date('startDate', t('activities.start'), activity.startMoment().locale(language).format('L'), t('activities.tooltip.start'))
+date('startDate', t('activities.start'), activity.startMoment().locale(language).format('L'), t('activities.tooltip.start'), activity.clonedFromMeetup())
.col-xs-6(style='padding-left:3px;padding-right:0px')
+time('startTime', activity.startMoment().locale(language).format('LT'))
+time('startTime', activity.startMoment().locale(language).format('LT'), activity.clonedFromMeetup())
.col-xs-6(style='padding-left:5px')
.col-xs-6(style='padding-left:0px;padding-right:3px')
+date('endDate', t('activities.end'), activity.endMoment().locale(language).format('L'), t('activities.tooltip.end'))
+date('endDate', t('activities.end'), activity.endMoment().locale(language).format('L'), t('activities.tooltip.end'), activity.clonedFromMeetup())
#dates.col-xs-6(style='padding-left:3px;padding-right:0px')
+time('endTime', activity.endMoment().locale(language).format('LT'))
+textarea('description', t('general.description'), activity.description())
+textarea('direction', t('activities.directions'), activity.direction())
+time('endTime', activity.endMoment().locale(language).format('LT'), activity.clonedFromMeetup())
+textarea('description', t('general.description'), activity.description(), '', '', activity.clonedFromMeetup())
+textarea('direction', t('activities.directions'), activity.direction(), '', '', activity.clonedFromMeetup())
+editableMultiselect('editorIds', t('activities.editors'), editorNames, participantNames)
.col-md-6
.form-group
+controlLabel('url', t('activities.address_suffix'), t('activities.tooltip.address_suffix'))
input.form-control#url(type='text', name='url', value=activity.url())
+text('location', t('activities.location'), activity.location())
input.form-control#url(type='text', name='url', value=activity.url(), disabled=activity.clonedFromMeetup())
+text('location', t('activities.location'), activity.location(), '', '', activity.clonedFromMeetup())
.form-group
+controlLabel('preview', 'Preview')
#map.hidden-print(style='width: ' + '100%' + '; height: ' + '420px')
.form-group
label.control-label(for='assignedGroup') #{t('groups.group')}:
select#assignedGroup.form-control.enhance(name='assignedGroup')
select#assignedGroup.form-control.enhance(name='assignedGroup', disabled=activity.clonedFromMeetup())
for group in groups
option(value=group.id, selected = (activity.assignedGroup() != undefined && activity.assignedGroup() == group.id)) #{group.longName}
.row
Expand Down
2 changes: 2 additions & 0 deletions softwerkskammer/lib/activities/views/get.pug
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ block content
.hidden-print
if (allowsRegistration)
p #{t('activities.count_participants_interval', { postProcess: 'interval', count: activity.participants.length })}
if (activity.clonedFromMeetup())
p (#{t('activities.count_participants_meetup_interval', {postProcess: 'interval', count: activity.meetupRSVPCount()})})
+subscriptionButtons(activity, resourceRegistrationRenderer)
if (accessrights.isRegistered() && activity.participants.length > 0)
h4 #{t('activities.accepted_by')}:
Expand Down
31 changes: 18 additions & 13 deletions softwerkskammer/lib/activities/views/index.pug
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
extends ../../../views/layout
include ../../../../commonComponents/pug/formComponents
include activities-mixins

block title
Expand All @@ -8,18 +9,22 @@ block content
.row
.col-md-12
.page-header
.btn-group.pull-right
.btn-group
a.btn.btn-default.dropdown-toggle(data-toggle='dropdown')
| #{range}  
span.caret
ul.dropdown-menu
li: a(href='/activities/upcoming') #{t('activities.upcoming')}
li: a(href='/activities/past') #{t('activities.past')}
li: a(href='/activities') #{t('general.all')}
li: a(href='/activities/gdcr') #{t('general.gdcr_activities')}
a.btn.btn-default(href=webcalURL, title=t('activities.export_subscribe')): i.fa.fa-calendar.fa-fw
if (accessrights.canCreateActivity())
a.btn.btn-default(href='new/', title=t('activities.new')): i.fa.fa-file-o.fa-fw
form(role='form', method='POST', action='clone-from-meetup/')
+csrf
.btn-group.pull-right
.btn-group
a.btn.btn-default.dropdown-toggle(data-toggle='dropdown')
| #{range}  
span.caret
ul.dropdown-menu
li: a(href='/activities/upcoming') #{t('activities.upcoming')}
li: a(href='/activities/past') #{t('activities.past')}
li: a(href='/activities') #{t('general.all')}
li: a(href='/activities/gdcr') #{t('general.gdcr_activities')}
a.btn.btn-default(href=webcalURL, title=t('activities.export_subscribe')): i.fa.fa-calendar.fa-fw
if (accessrights.isSuperuser())
button.btn.btn-default(type='submit'): i.fa.fa-meetup.fa-fw
if (accessrights.canCreateActivity())
a.btn.btn-default(href='new/', title=t('activities.new')): i.fa.fa-file-o.fa-fw
h2 #{t('activities.activities')}
+activityList(activities)
17 changes: 13 additions & 4 deletions softwerkskammer/lib/commons/fieldHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,6 @@ module.exports = {
return text;
},

readableDate: function readableDate(unixtimestamp) {
return moment.unix(unixtimestamp).utc().format('DD.MM.YYYY');
},

parseToUnixUsingDefaultTimezone: function parseToUnixUsingDefaultTimezone(dateString, timeString) {
const result = this.parseToMomentUsingDefaultTimezone(dateString, timeString);
return result ? result.unix() : undefined;
Expand All @@ -87,6 +83,19 @@ module.exports = {
return undefined;
},

meetupDateToActivityTimes: function meetupDateToActivityTimes(meetupStartDate, meetupStartTime, durationInMillis) {
const startPoint = moment.tz(meetupStartDate + ' ' + meetupStartTime, 'YYYY-MM-DD H:m', this.defaultTimezone());
const endPoint = startPoint.clone(); // moment is mutable, clone it first!
endPoint.add(durationInMillis, 'milliseconds');

return {
startDate: startPoint.format('DD.MM.YYYY'),
startTime: startPoint.format('HH:mm'),
endDate: endPoint.format('DD.MM.YYYY'),
endTime: endPoint.format('HH:mm')
};
},

defaultTimezone: function defaultTimezone() {
return 'Europe/Berlin';
},
Expand Down
4 changes: 4 additions & 0 deletions softwerkskammer/lib/commons/misc.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ module.exports = {

startsWith: function startsWith(string, start) {
return string.indexOf(start) === 0;
},

stripTrailingSlash: function stripTrailingSlash(str) {
return str.substr(-1) === '/' ? str.substr(0, str.length - 1) : str;
}
};

10 changes: 10 additions & 0 deletions softwerkskammer/lib/groups/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class Group {
this.description = object.description;
this.type = object.type;
this.emailPrefix = object.emailPrefix;
this.meetupURL = object.meetupURL;
this.color = object.color;
this.organizers = misc.toArray(object.organizers);
this.mapX = object.mapX;
Expand Down Expand Up @@ -55,6 +56,15 @@ class Group {
return this.longName + ' [' + this.emailPrefix + '] - ' + this.id;
}

meetupUrlName() {
if (this.meetupURL) {
const strippedURL = misc.stripTrailingSlash(this.meetupURL);
return strippedURL.substr(strippedURL.lastIndexOf('/') + 1);
} else {
return null;
}
}

// Helper functions (static) -> look for a better place to implement
static regionalsFrom(groups) {
return groups.filter(group => group.type === regionalgruppe);
Expand Down
8 changes: 8 additions & 0 deletions softwerkskammer/lib/groups/groupstore.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ module.exports = {
persistence.getByField({emailPrefix: misc.toLowerCaseRegExp(prefix)}, R.partial(toGroup, [callback]));
},

getGroupsWithMeetupURL: function getGroupsWithMeetupURL(callback) {
persistence.listByField(
{meetupURL: {$exists: true, $nin: ['', null, undefined]}},
{},
R.partial(toGroupList, [callback])
);
},

saveGroup: function saveGroup(group, callback) {
delete group.members; // we do not want to persist the group members
persistence.save(group, callback);
Expand Down
12 changes: 12 additions & 0 deletions softwerkskammer/lib/groups/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const groupstore = beans.get('groupstore');
const wikiService = beans.get('wikiService');
const Group = beans.get('group');
const groupsAndMembers = beans.get('groupsAndMembersService');
const meetupActivitiesService = beans.get('meetupActivitiesService');
const activitystore = beans.get('activitystore');
const statusmessage = beans.get('statusmessage');

Expand Down Expand Up @@ -80,6 +81,17 @@ app.get('/edit/:groupname', (req, res, next) => {
});
});

app.post('/clone-from-meetup-for-group', (req, res, next) => {
groupstore.getGroup(req.body.groupname, (err, group) => {
if (err || !group) { return next(err); }
meetupActivitiesService.cloneActivitiesFromMeetupForGroup(group, (err2) => {
if (err2) { return next(err2); }
res.redirect('/groups/' + req.body.groupname);
});
});

});

app.get('/checkgroupname', (req, res) => {
misc.validate(req.query.id, null, groupsService.isGroupNameAvailable, res.end);
});
Expand Down
Loading

0 comments on commit 95ed54e

Please sign in to comment.