Merge branch 'develop' into Django2.0

This commit is contained in:
Aarni Halinen
2018-07-17 20:57:58 +03:00
33 changed files with 1024 additions and 493 deletions
+6 -3
View File
@@ -1,8 +1,8 @@
"""File containing webapp app admin registers."""
from django.contrib import admin
from webapp.models import Official, Role
from webapp.models import Feed, Tag, BaseFeed, Event, Registration
from webapp.models import Official, Role, Committee
from webapp.models import Feed, Tag, BaseFeed, Event, Signup, SignupForm, TemplateQuestion
from modeltranslation.admin import TranslationAdmin
from django.contrib.auth.models import Permission
# this is needed so that the models get registered for translation
@@ -13,6 +13,9 @@ admin.site.register(Permission)
admin.site.register(Feed, TranslationAdmin)
admin.site.register(Tag, TranslationAdmin)
admin.site.register(Event, TranslationAdmin)
admin.site.register(Registration, TranslationAdmin)
admin.site.register(SignupForm, TranslationAdmin)
admin.site.register(Signup, TranslationAdmin)
admin.site.register(TemplateQuestion, TranslationAdmin)
admin.site.register(Official)
admin.site.register(Role)
admin.site.register(Committee)
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-03-01 18:11
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('webapp', '0035_auto_20171019_1413'),
]
operations = [
migrations.CreateModel(
name='Committee',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255)),
],
),
migrations.AddField(
model_name='role',
name='committee',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='roles', to='webapp.Committee'),
),
]
@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-03-01 19:11
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('webapp', '0036_auto_20180301_2011'),
]
operations = [
migrations.AlterModelOptions(
name='committee',
options={'verbose_name': 'Committee', 'verbose_name_plural': 'Committees'},
),
]
@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-05-16 18:08
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('webapp', '0037_auto_20180301_2111'),
]
operations = [
migrations.RemoveField(
model_name='baserole',
name='category',
),
migrations.RemoveField(
model_name='role',
name='committee',
),
migrations.AddField(
model_name='official',
name='committee',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='roles', to='webapp.Committee'),
),
migrations.AlterField(
model_name='role',
name='official',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='roles', to='webapp.Official'),
),
]
@@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-05-16 18:13
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('webapp', '0038_auto_20180516_2108'),
]
operations = [
migrations.RemoveField(
model_name='official',
name='committee',
),
migrations.RemoveField(
model_name='role',
name='official',
),
migrations.AddField(
model_name='official',
name='role',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='roles', to='webapp.Role'),
),
migrations.AddField(
model_name='role',
name='committee',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='roles', to='webapp.Committee'),
),
migrations.AlterField(
model_name='committee',
name='name',
field=models.CharField(max_length=255, verbose_name='Name'),
),
]
@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-05-16 18:24
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('webapp', '0039_auto_20180516_2113'),
]
operations = [
migrations.RemoveField(
model_name='official',
name='role',
),
migrations.AddField(
model_name='official',
name='role',
field=models.ManyToManyField(null=True, related_name='roles', to='webapp.Role'),
),
]
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-05-16 19:04
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('webapp', '0040_auto_20180516_2124'),
]
operations = [
migrations.AlterField(
model_name='official',
name='role',
field=models.ManyToManyField(related_name='official', to='webapp.Role'),
),
]
@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-05-16 19:49
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('webapp', '0041_auto_20180516_2204'),
('webapp', '0041_delete_ohlhafvchallenge'),
]
operations = [
]
@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-06-05 16:53
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('webapp', '0042_merge_20180516_2249'),
]
operations = [
migrations.RemoveField(
model_name='event',
name='basefeed_ptr',
),
migrations.RemoveField(
model_name='event',
name='registration',
),
migrations.DeleteModel(
name='Event',
),
migrations.DeleteModel(
name='Registration',
),
]
@@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-07-05 15:51
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('webapp', '0043_auto_20180605_1953'),
]
operations = [
migrations.CreateModel(
name='Event',
fields=[
('basefeed_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='webapp.BaseFeed')),
('start_time', models.DateTimeField(default=django.utils.timezone.now)),
('end_time', models.DateTimeField(default=django.utils.timezone.now)),
],
options={
'verbose_name': 'Event',
'verbose_name_plural': 'Events',
},
bases=('webapp.basefeed',),
),
migrations.CreateModel(
name='Signup',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('time', models.DateTimeField(default=django.utils.timezone.now)),
('answer', models.CharField(max_length=255)),
],
options={
'verbose_name': 'Sign-up',
'verbose_name_plural': 'Sign-ups',
},
),
migrations.CreateModel(
name='SignupForm',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('start', models.DateTimeField(default=django.utils.timezone.now)),
('end', models.DateTimeField(default=django.utils.timezone.now)),
('question', models.CharField(max_length=255)),
],
options={
'verbose_name': 'Signup form',
'verbose_name_plural': 'Signup forms',
},
),
migrations.CreateModel(
name='TemplateQuestion',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255)),
('question', models.CharField(max_length=255)),
],
options={
'verbose_name': 'Template question',
'verbose_name_plural': 'Template questions',
},
),
migrations.AddField(
model_name='signup',
name='signupForm',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='webapp.SignupForm'),
),
migrations.AddField(
model_name='event',
name='signupForm',
field=models.ManyToManyField(blank=True, to='webapp.SignupForm'),
),
]
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-07-10 16:01
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('webapp', '0044_auto_20180705_1851'),
]
operations = [
migrations.RenameField(
model_name='signupform',
old_name='question',
new_name='questions',
),
]
@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-07-10 17:41
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('webapp', '0045_auto_20180710_1901'),
]
operations = [
migrations.RemoveField(
model_name='event',
name='signupForm',
),
migrations.AddField(
model_name='event',
name='signupForm',
field=models.ForeignKey(blank=True, default=0, on_delete=django.db.models.deletion.CASCADE, to='webapp.SignupForm'),
preserve_default=False,
),
]
@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-07-10 18:10
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('webapp', '0046_auto_20180710_2041'),
]
operations = [
migrations.RemoveField(
model_name='event',
name='signupForm',
),
migrations.AddField(
model_name='event',
name='signupForm',
field=models.ManyToManyField(blank=True, to='webapp.SignupForm'),
),
]
+84 -32
View File
@@ -2,16 +2,16 @@
from django.db import models
from django.utils import timezone
from datetime import timedelta
# from datetime import timedelta
from django.contrib.auth.models import User
from webapp.utils import month_from_now
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User
# from django.contrib.auth.models import User
from auditlog.registry import auditlog
from phonenumber_field.modelfields import PhoneNumberField
from django.contrib.postgres.fields import JSONField
# from django.contrib.postgres.fields import JSONField
import logging
# import logging
VERBOSE_NAME = _('Webapp')
@@ -61,8 +61,8 @@ class Event(BaseFeed):
start_time = models.DateTimeField(default=timezone.now)
end_time = models.DateTimeField(default=timezone.now)
registration = models.ForeignKey(
'Registration', on_delete=models.CASCADE, null=True)
signupForm = models.ManyToManyField(
'SignupForm', blank=True)
def __str__(self):
return _('Event: {}').format(self.title)
@@ -72,44 +72,69 @@ class Event(BaseFeed):
verbose_name_plural = _('Events')
class Registration(models.Model):
"""Model for event registration."""
class TemplateQuestion(models.Model):
"""Stores template questions for signup forms as JSONB"""
# question = JSONField()
name = models.CharField(max_length=255)
email = models.EmailField()
options = JSONField()
question = models.CharField(max_length=255)
def __str__(self):
return _('Registration: {}').format(self.name)
return _('Template questions: {}').format(self.name)
class Meta:
verbose_name = _('Registration')
verbose_name_plural = _('Registrations')
verbose_name = _('Template question')
verbose_name_plural = _('Template questions')
class SignupForm(models.Model):
"""Model for event signup form. Stores questions in JSONB."""
start = models.DateTimeField(default=timezone.now)
end = models.DateTimeField(default=timezone.now)
# question = JSONField()
questions = models.CharField(max_length=255)
class Meta:
verbose_name = _('Signup form')
verbose_name_plural = _('Signup forms')
class Signup(models.Model):
signupForm = models.ForeignKey('SignupForm', on_delete=models.CASCADE)
time = models.DateTimeField(default=timezone.now)
answer = models.CharField(max_length=255)
def __str__(self):
return _('Sign-ups: {}').format(self.signupForm)
class Meta:
verbose_name = _('Sign-up')
verbose_name_plural = _('Sign-ups')
class BaseRole(models.Model):
"""Base model for occupations/roles."""
CATEGORIES = (
('corporate', _('Corporate affairs')),
('freshman', _('Freshmen')),
('international', _('International')),
('external', _('External affairs')),
('media', _('Media')),
('tech', _('Technology')),
('wellbeing', _('Wellbeing')),
('elepaja', _('Elepaja')),
('ceremonies', _('Ceremonies')),
('culture', _('Culture')),
('studies', _('Studies')),
('sosso', _('Sössö magazine')),
('alumni', _('Alumni relations')),
('others', _('Others')),
)
# CATEGORIES = (
# ('corporate', _('Corporate affairs')),
# ('freshman', _('Freshmen')),
# ('international', _('International')),
# ('external', _('External affairs')),
# ('media', _('Media')),
# ('tech', _('Technology')),
# ('wellbeing', _('Wellbeing')),
# ('elepaja', _('Elepaja')),
# ('ceremonies', _('Ceremonies')),
# ('culture', _('Culture')),
# ('studies', _('Studies')),
# ('sosso', _('Sössö magazine')),
# ('alumni', _('Alumni relations')),
# ('others', _('Others')),
# )
name = models.CharField(_('Name'), max_length=255)
is_board = models.BooleanField(_('Board member'))
category = models.CharField(_('Category'), choices=CATEGORIES, default='others', max_length=255)
# category = models.CharField(_('Category'), choices=CATEGORIES, default='others', max_length=255)
def __str__(self):
n = self.name.capitalize()
@@ -122,6 +147,28 @@ class PresetRole(BaseRole):
description = models.TextField(_('Description'))
class Committee(models.Model):
"""
Committee model
Has many Roles found under variable roles
"""
class Meta:
"""Meta class for Committee class."""
verbose_name = _('Committee')
verbose_name_plural = _('Committees')
def __str__(self):
return _('Committee: {}').format(self.name)
name = models.CharField(_("Name"), max_length=255)
@property
def current_roles(self):
return self.roles.all().filter(end_date__gte=timezone.now()).filter(start_date__lte=timezone.now())
class Role(PresetRole):
"""
Model for Role.
@@ -138,7 +185,7 @@ class Role(PresetRole):
start_date = models.DateField(_('Start date'))
end_date = models.DateField(_('End date'))
official = models.ForeignKey('Official', related_name='roles', on_delete=models.CASCADE)
committee = models.ForeignKey('Committee', related_name='roles', on_delete=models.SET_NULL, null=True)
class Official(User):
@@ -151,11 +198,16 @@ class Official(User):
verbose_name_plural = _('Officials')
phone_number = PhoneNumberField(_('Phone number'))
role = models.ManyToManyField('Role', related_name='official')
def __str__(self):
return '{} {}'.format(self.first_name, self.last_name)
auditlog.register(Tag)
auditlog.register(Feed)
auditlog.register(Event)
auditlog.register(Signup)
auditlog.register(PresetRole)
auditlog.register(Role)
auditlog.register(Official)
+42
View File
@@ -0,0 +1,42 @@
from rest_framework import serializers
from webapp.models import *
class SignupFormSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = SignupForm
fields = ('id', 'start', 'end', 'questions')
class EventSerializer(serializers.HyperlinkedModelSerializer):
signupForm = SignupFormSerializer(many=True, read_only=True, required=False)
signup_id = serializers.PrimaryKeyRelatedField(
many=True,
source="signupForm",
queryset=SignupForm.objects.all())
class Meta:
model = Event
fields = ('id', 'tags', 'visible', 'title', 'description',
'content', 'start_time', 'end_time', 'signup_id', 'signupForm')
depth = 1
def create(self, validated_data):
signupForms = validated_data.pop('signupForm')
event = Event.objects.create(**validated_data)
for signupForm in signupForms:
event.signupForm.add(signupForm)
event.save()
return event
class SignupSerializer(serializers.ModelSerializer):
class Meta:
model = Signup
fields = ('id', 'signupForm', 'answer')
extra_kwargs = {
'url': {
'view_name': 'signup-detail',
}
}
+6
View File
@@ -0,0 +1,6 @@
.role-container {
background-color: aqua;
width: 200px;
text-align: center;
}
+30 -27
View File
@@ -4,34 +4,37 @@
{% load i18n %}
<div class="contact_div">
<div class="container">
<div class="row">
<div class="col">
<h2>{% trans "Contact" %}</h2>
<div>
{% if kaikki %}
<table>
{% for teekkari in kaikki %}
{% load static %}
<tr>
<td>
{% load static %}
<link rel="stylesheet" href="{% static "css/contact.css" %}">
<h2>{% trans "Contact" %}</h2>
{% if committees %}
{% for committee in committees %}
<!--Committee title-->
<h4>{{ committee.name }}</h4>
{% for role in committee.current_roles %}
{% for official in role.official.all %}
<div class="role-container">
<div class="row">
<div class="col">
<img src="static/img/missing.png">
</td>
<td>
<p class="name">{{ teekkari.first_name }} {{ teekkari.last_name }}</p>
<p class="email">{{ teekkari.email }}</p>
<p class="puh">{{ teekkari.phone_number }}</p>
</td>
</tr>
{% endfor %}
</table>
{% else %}
<p>Ei henkilöitä</p>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col">
<h5>{{role.name}}</h5>
<p>{{official.first_name}}
{{official.last_name}}
{{official.email}}</p>
</div>
</div>
</div>
{% endfor %}
{% endfor %}
{% endfor %}
{% else%}
<p>Ei Toimikuntia</p>
{% endif %}
</div>
{% endblock %}
+25 -11
View File
@@ -1,7 +1,7 @@
"""Translation classes."""
from modeltranslation.translator import register, TranslationOptions
from webapp.models import BaseFeed, Feed, Tag, Event, Registration
from webapp.models import BaseFeed, Feed, Tag, Event, Signup, SignupForm, TemplateQuestion
from webapp.models import PresetRole, BaseRole
@@ -19,13 +19,6 @@ class FeedTranslationOptions(TranslationOptions):
fields = ()
@register(Event)
class EventTranslationOptions(TranslationOptions):
"""Class for event translation options."""
fields = ()
@register(Tag)
class TagTranslationOptions(TranslationOptions):
"""Class for tag translation options."""
@@ -33,11 +26,32 @@ class TagTranslationOptions(TranslationOptions):
fields = ('name',)
@register(Registration)
class RegistrationTranslationOptions(TranslationOptions):
@register(Event)
class EventTranslationOptions(TranslationOptions):
"""Class for event translation options."""
fields = ()
@register(Signup)
class SignupTranslationOptions(TranslationOptions):
"""Class for registration translation options."""
fields = ('name',)
fields = ()
@register(SignupForm)
class SignupFormTranslationOptions(TranslationOptions):
"""Class for registration translation options."""
fields = ()
@register(TemplateQuestion)
class TemplateQuestionTranslationOptions(TranslationOptions):
"""Class for registration translation options."""
fields = ()
@register(BaseRole)
+57 -32
View File
@@ -1,45 +1,70 @@
"""Webapp urls."""
from django.conf.urls import url
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.conf.urls import url, include
from rest_framework import routers
# from rest_framework.urlpatterns import format_suffix_patterns
# from django.conf import settings
# from django.utils.translation import ugettext_lazy as _
from webapp.views import main_index
# from webapp.views import main_index
from webapp.views import login_view
from webapp.views import logout_view
from webapp.views import about_view
from webapp.views import guild_view
from webapp.views import freshmen_view
from webapp.views import jobs_view
from webapp.views import event_calendar_view
from webapp.views import international_view
from webapp.views import sosso_view
from webapp.views import contact_view
# from webapp.views import about_view
# from webapp.views import guild_view
# from webapp.views import freshmen_view
# from webapp.views import jobs_view
# from webapp.views import event_calendar_view
# from webapp.views import international_view
# from webapp.views import sosso_view
# from webapp.views import contact_view
from webapp.views import EventViewSet, SignupFormViewSet, SignupViewSet
router = routers.DefaultRouter()
router.register(r'events', EventViewSet)
router.register(r'signupForm', SignupFormViewSet)
router.register(r'signup', SignupViewSet)
urlpatterns = [
# main
url(r'^$', main_index),
url(r'^', include(router.urls)),
# login stuff
url(r'^login$', login_view),
url(r'^logout$', logout_view),
# git revision
url(r'^about', about_view),
# pages
url(r'^guild', guild_view),
url(r'^freshmen', freshmen_view),
url(r'^event_calendar', event_calendar_view),
url(r'^international', international_view),
url(r'^sosso', sosso_view),
url(r'^contact', contact_view),
# corporate
url(r'^jobs', jobs_view),
]
# urlpatterns = [
# # main
# url(r'^$', main_index),
# url(r'^api/$', api_root),
# url(r'^api/events/$', EventList.as_view(), name='event-list'),
# url(r'^api/events/(?P<pk>[0-9]+)/$', EventDetail.as_view(), name='event-detail'),
# url(r'^api/signup/$', SignupFormList.as_view(), name='signupform-list'),
# url(r'^api/signup/(?P<pk>[0-9]+)/$', SignupFormDetail.as_view(), name='signup-detail'),
# url(r'^api/signup/create$', SignupFormCreate.as_view(), name='signupform-create'),
# # url(r'^signupform/$', SignupFormList.as_view(), name='signupform-list'),
# # url(r'^signupform/(?P<pk>[0-9]+)/$', SignupFormDetail.as_view(), name='signupform-detail'),
# # login stuff
# url(r'^login$', login_view),
# url(r'^logout$', logout_view),
# # git revision
# url(r'^about', about_view),
# # pages
# url(r'^guild', guild_view),
# url(r'^freshmen', freshmen_view),
# url(r'^event_calendar', event_calendar_view),
# url(r'^international', international_view),
# url(r'^sosso', sosso_view),
# url(r'^contact', contact_view),
# # corporate
# url(r'^jobs', jobs_view),
# ]
if settings.DEBUG:
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
urlpatterns += staticfiles_urlpatterns()
# if settings.DEBUG:
# from django.contrib.staticfiles.urls import staticfiles_urlpatterns
# urlpatterns += staticfiles_urlpatterns()
+43 -10
View File
@@ -1,21 +1,52 @@
"""Webapp views."""
from django.db.models import Count
# from django.db.models import Count
from django.shortcuts import render, redirect
from django.contrib.auth import login, logout, authenticate
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import ensure_csrf_cookie
from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth.decorators import permission_required, login_required
from django.conf import settings
# from django.views.decorators.csrf import ensure_csrf_cookie
# from django.http import HttpResponse, HttpResponseRedirect
# from django.contrib.auth.decorators import permission_required, login_required
# from django.conf import settings
# from django.utils import timezone
from rest_framework.decorators import api_view
from rest_framework import viewsets
# from rest_framework import permissions, authentication
from rest_framework.response import Response
from rest_framework.reverse import reverse
import logging
import requests
# import logging
# import requests
from dealer.git import git
from webapp.models import Official
from webapp.models import Event, SignupForm, Signup, Committee
from webapp.serializers import EventSerializer, SignupFormSerializer, SignupSerializer
from members.views.utils import *
# -- REST API -- #
@api_view(['GET'])
def api_root(request, format=None):
return Response({'events': reverse('event-list', request=request, format=format), })
class EventViewSet(viewsets.ModelViewSet):
queryset = Event.objects.all()
serializer_class = EventSerializer
class SignupFormViewSet(viewsets.ModelViewSet):
queryset = SignupForm.objects.all()
serializer_class = SignupFormSerializer
class SignupViewSet(viewsets.ModelViewSet):
queryset = Signup.objects.all()
serializer_class = SignupSerializer
# -- OLD CODEBASE -- #
@require_http_methods(["GET"])
def main_index(request, *args, **kwargs):
@@ -114,8 +145,10 @@ def sosso_view(request, *args, **kwargs):
@require_http_methods(["GET"])
def contact_view(request, *args, **kwargs):
"""Render "Contact" page."""
committees = Committee.objects.order_by('name')
kaikki = Official.objects.all()
context = {"kaikki": kaikki}
context = {
"committees": committees
}
return render(request, "contact.html", context)