diff --git a/apiserver/apiserver/api/models.py b/apiserver/apiserver/api/models.py index 9cd5424..7f168ef 100644 --- a/apiserver/apiserver/api/models.py +++ b/apiserver/apiserver/api/models.py @@ -250,6 +250,19 @@ class PinballScore(models.Model): def __str__(self): return str(self.started_at) +class Hosting(models.Model): + user = models.ForeignKey(User, related_name='hosting', blank=True, null=True, on_delete=models.SET_NULL) + + started_at = models.DateTimeField(auto_now_add=True) + finished_at = models.DateTimeField() + hours = models.DecimalField(max_digits=5, decimal_places=2) + + # no history + + MY_FIELDS = ['started_at', 'hours', 'finished_at', 'user'] + def __str__(self): + return str(self.started_at) + class HistoryIndex(models.Model): content_type = models.ForeignKey(ContentType, null=True, on_delete=models.SET_NULL) object_id = models.PositiveIntegerField() diff --git a/apiserver/apiserver/api/utils_stats.py b/apiserver/apiserver/api/utils_stats.py index 021a722..f81c811 100644 --- a/apiserver/apiserver/api/utils_stats.py +++ b/apiserver/apiserver/api/utils_stats.py @@ -29,6 +29,7 @@ DEFAULTS = { 'link': '', 'autoscan': '', 'last_scan': {}, + 'closing': {}, } if secrets.MUMBLE: diff --git a/apiserver/apiserver/api/views.py b/apiserver/apiserver/api/views.py index a5905a3..1a15b25 100644 --- a/apiserver/apiserver/api/views.py +++ b/apiserver/apiserver/api/views.py @@ -631,6 +631,7 @@ class DoorViewSet(viewsets.ViewSet, List): last_scan = dict( time=time.time(), member_id=member.id, + first_name=member.preferred_name, ) cache.set('last_scan', last_scan) @@ -1541,6 +1542,72 @@ class PinballViewSet(Base): return Response(scores) +class HostingViewSet(Base): + @action(detail=False, methods=['post']) + def offer(self, request): + #auth_token = request.META.get('HTTP_AUTHORIZATION', '') + #if secrets.PINBALL_API_TOKEN and auth_token != 'Bearer ' + secrets.PINBALL_API_TOKEN: + # raise exceptions.PermissionDenied() + + try: + member_id = int(request.data['member_id']) + except KeyError: + raise exceptions.ValidationError(dict(game_id='This field is required.')) + except ValueError: + raise exceptions.ValidationError(dict(game_id='Invalid number.')) + + try: + hours = int(request.data['hours']) + except KeyError: + raise exceptions.ValidationError(dict(player='This field is required.')) + except ValueError: + raise exceptions.ValidationError(dict(player='Invalid number.')) + + hosting_member = get_object_or_404(models.Member, id=member_id) + hosting_user = hosting_member.user + + logging.info('Hosting offer from %s %s for %s hours', hosting_member.preferred_name, hosting_member.last_name, hours) + + try: + current_hosting = models.Hosting.objects.get(user=hosting_user, finished_at__gte=now()) + logging.info('Current hosting by member: %s', current_hosting) + new_end = now() + datetime.timedelta(hours=hours) + new_delta = new_end - current_hosting.started_at + new_hours = new_delta.seconds / 3600 + + logging.info( + 'Hosting %s from %s is still going, updating hours from %s to %s.', + current_hosting.id, + current_hosting.started_at, + current_hosting.hours, + new_hours + ) + + current_hosting.finished_at = new_end + current_hosting.hours = new_hours + current_hosting.save() + + except models.Hosting.DoesNotExist: + h = models.Hosting.objects.create( + user=hosting_user, + hours=hours, + finished_at=now() + datetime.timedelta(hours=hours), + ) + + logging.info('No current hosting for that user, new hosting #%s created.', h.id) + + # update "open until" time + hosting = models.Hosting.objects.order_by('-finished_at').first() + closing = dict( + time=hosting.finished_at.timestamp(), + time_str=hosting.finished_at.astimezone(utils.TIMEZONE_CALGARY).strftime('%-I:%M %p'), + first_name=hosting.user.member.preferred_name, + ) + cache.set('closing', closing) + + return Response(200) + + class RegistrationView(RegisterView): serializer_class = serializers.MyRegisterSerializer diff --git a/apiserver/apiserver/urls.py b/apiserver/apiserver/urls.py index fc13f9b..2e34671 100644 --- a/apiserver/apiserver/urls.py +++ b/apiserver/apiserver/urls.py @@ -20,6 +20,7 @@ router.register(r'courses', views.CourseViewSet, basename='course') router.register(r'history', views.HistoryViewSet, basename='history') router.register(r'vetting', views.VettingViewSet, basename='vetting') router.register(r'pinball', views.PinballViewSet, basename='pinball') +router.register(r'hosting', views.HostingViewSet, basename='hosting') router.register(r'sessions', views.SessionViewSet, basename='session') router.register(r'training', views.TrainingViewSet, basename='training') router.register(r'interest', views.InterestViewSet, basename='interest') diff --git a/webclient/src/Home.js b/webclient/src/Home.js index cd1398a..fbd9be4 100644 --- a/webclient/src/Home.js +++ b/webclient/src/Home.js @@ -242,6 +242,8 @@ export function Home(props) { //const doorOpenStat = () => alarmStat() === 'Disarmed' && stats.alarm['data'] > 360 ? ', door open' : ''; const doorOpenStat = () => ''; + const closedStat = (x) => stats && stats.closing ? moment().unix() > stats.closing['time'] ? 'Closed' : 'Open until ' + stats.closing['time_str'] : 'Unknown'; + const show_signup = stats?.at_protospace; return ( @@ -356,6 +358,8 @@ export function Home(props) {

{user &&

Alarm status: {alarmStat()}{doorOpenStat()}

} + + {user &&

Hosting status: {closedStat()}

}