Merge branch 'master' into printer_protocoin
This commit is contained in:
commit
159fe03cef
|
@ -221,7 +221,7 @@ class Usage(models.Model):
|
||||||
device = models.CharField(max_length=64)
|
device = models.CharField(max_length=64)
|
||||||
started_at = models.DateTimeField(auto_now_add=True)
|
started_at = models.DateTimeField(auto_now_add=True)
|
||||||
finished_at = models.DateTimeField(null=True)
|
finished_at = models.DateTimeField(null=True)
|
||||||
deleted_at = models.DateTimeField(null=True)
|
deleted_at = models.DateTimeField(null=True, blank=True)
|
||||||
|
|
||||||
num_seconds = models.IntegerField()
|
num_seconds = models.IntegerField()
|
||||||
num_reports = models.IntegerField()
|
num_reports = models.IntegerField()
|
||||||
|
@ -232,7 +232,7 @@ class Usage(models.Model):
|
||||||
|
|
||||||
MY_FIELDS = ['started_at', 'finished_at', 'user', 'num_seconds', 'should_bill']
|
MY_FIELDS = ['started_at', 'finished_at', 'user', 'num_seconds', 'should_bill']
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.started_at
|
return str(self.started_at)
|
||||||
|
|
||||||
class PinballScore(models.Model):
|
class PinballScore(models.Model):
|
||||||
user = models.ForeignKey(User, related_name='scores', blank=True, null=True, on_delete=models.SET_NULL)
|
user = models.ForeignKey(User, related_name='scores', blank=True, null=True, on_delete=models.SET_NULL)
|
||||||
|
|
|
@ -476,7 +476,10 @@ def gen_member_forms(member):
|
||||||
def custom_exception_handler(exc, context):
|
def custom_exception_handler(exc, context):
|
||||||
response = exception_handler(exc, context)
|
response = exception_handler(exc, context)
|
||||||
if response is not None:
|
if response is not None:
|
||||||
logging.warning('Response: %s', json.dumps(exc.detail))
|
if hasattr(exc, 'detail'):
|
||||||
|
logging.warning('Response: %s', json.dumps(exc.detail))
|
||||||
|
else:
|
||||||
|
logging.warning('Response: %s', exc)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def log_transaction(tx):
|
def log_transaction(tx):
|
||||||
|
|
|
@ -195,11 +195,29 @@ class MemberViewSet(Base, Retrieve, Update):
|
||||||
def unpause(self, request, pk=None):
|
def unpause(self, request, pk=None):
|
||||||
if not is_admin_director(self.request.user):
|
if not is_admin_director(self.request.user):
|
||||||
raise exceptions.PermissionDenied()
|
raise exceptions.PermissionDenied()
|
||||||
|
|
||||||
|
today = utils.today_alberta_tz()
|
||||||
member = self.get_object()
|
member = self.get_object()
|
||||||
member.current_start_date = utils.today_alberta_tz()
|
|
||||||
|
difference = utils.today_alberta_tz() - member.paused_date
|
||||||
|
if difference.days > 370: # give some leeway
|
||||||
|
logging.info('Member has been away for %s days (since %s), unvetting...', difference.days, member.paused_date)
|
||||||
|
member.vetted_date = None
|
||||||
|
member.orientation_date = None
|
||||||
|
member.lathe_cert_date = None
|
||||||
|
member.mill_cert_date = None
|
||||||
|
member.wood_cert_date = None
|
||||||
|
member.wood2_cert_date = None
|
||||||
|
member.tormach_cnc_cert_date = None
|
||||||
|
member.precix_cnc_cert_date = None
|
||||||
|
member.rabbit_cert_date = None
|
||||||
|
member.trotec_cert_date = None
|
||||||
|
|
||||||
|
member.current_start_date = today
|
||||||
member.paused_date = None
|
member.paused_date = None
|
||||||
if not member.monthly_fees:
|
if not member.monthly_fees:
|
||||||
member.monthly_fees = 55
|
member.monthly_fees = 55
|
||||||
|
|
||||||
member.save()
|
member.save()
|
||||||
utils.tally_membership_months(member)
|
utils.tally_membership_months(member)
|
||||||
utils.gen_member_forms(member)
|
utils.gen_member_forms(member)
|
||||||
|
@ -559,6 +577,7 @@ class DoorViewSet(viewsets.ViewSet, List):
|
||||||
for card in cards:
|
for card in cards:
|
||||||
member = card.user.member
|
member = card.user.member
|
||||||
if member.paused_date: continue
|
if member.paused_date: continue
|
||||||
|
if not member.vetted_date: continue
|
||||||
if not member.is_allowed_entry: continue
|
if not member.is_allowed_entry: continue
|
||||||
|
|
||||||
active_member_cards[card.card_number] = '{} ({})'.format(
|
active_member_cards[card.card_number] = '{} ({})'.format(
|
||||||
|
@ -760,7 +779,8 @@ class StatsViewSet(viewsets.ViewSet, List):
|
||||||
if should_count:
|
if should_count:
|
||||||
start_new_use = not last_use or last_use.finished_at or last_use.username != username
|
start_new_use = not last_use or last_use.finished_at or last_use.username != username
|
||||||
if start_new_use:
|
if start_new_use:
|
||||||
if username_isfrom_track and time.time() - track[device]['time'] > 20*60:
|
username_isexpired = time.time() - track[device]['time'] > 2*60*60 # two hours
|
||||||
|
if username_isfrom_track and username_isexpired:
|
||||||
msg = 'Usage tracker problem expired username {} for device: {}'.format(username, device)
|
msg = 'Usage tracker problem expired username {} for device: {}'.format(username, device)
|
||||||
utils.alert_tanner(msg)
|
utils.alert_tanner(msg)
|
||||||
logger.error(msg)
|
logger.error(msg)
|
||||||
|
@ -1428,6 +1448,21 @@ class PinballViewSet(Base):
|
||||||
|
|
||||||
return Response(200)
|
return Response(200)
|
||||||
|
|
||||||
|
@action(detail=True, methods=['get'])
|
||||||
|
def get_name(self, request, pk=None):
|
||||||
|
auth_token = request.META.get('HTTP_AUTHORIZATION', '')
|
||||||
|
if secrets.PINBALL_API_TOKEN and auth_token != 'Bearer ' + secrets.PINBALL_API_TOKEN:
|
||||||
|
raise exceptions.PermissionDenied()
|
||||||
|
|
||||||
|
card = get_object_or_404(models.Card, card_number=pk)
|
||||||
|
member = card.user.member
|
||||||
|
|
||||||
|
res = dict(
|
||||||
|
name=member.preferred_name + ' ' + member.last_name[0]
|
||||||
|
)
|
||||||
|
return Response(res)
|
||||||
|
|
||||||
|
|
||||||
class RegistrationView(RegisterView):
|
class RegistrationView(RegisterView):
|
||||||
serializer_class = serializers.MyRegisterSerializer
|
serializer_class = serializers.MyRegisterSerializer
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,7 @@ let prevAutoscan = '';
|
||||||
export function AdminMemberCards(props) {
|
export function AdminMemberCards(props) {
|
||||||
const { token, result, refreshResult } = props;
|
const { token, result, refreshResult } = props;
|
||||||
const cards = result.cards;
|
const cards = result.cards;
|
||||||
const startDimmed = Boolean((result.member.paused_date || !result.member.is_allowed_entry) && cards.length);
|
const startDimmed = Boolean((result.member.paused_date || !result.member.is_allowed_entry || !result.member.vetted_date) && cards.length);
|
||||||
const [dimmed, setDimmed] = useState(startDimmed);
|
const [dimmed, setDimmed] = useState(startDimmed);
|
||||||
const [input, setInput] = useState({ active_status: 'card_active' });
|
const [input, setInput] = useState({ active_status: 'card_active' });
|
||||||
const [error, setError] = useState(false);
|
const [error, setError] = useState(false);
|
||||||
|
@ -134,7 +134,7 @@ export function AdminMemberCards(props) {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const startDimmed = Boolean((result.member.paused_date || !result.member.is_allowed_entry) && cards.length);
|
const startDimmed = Boolean((result.member.paused_date || !result.member.is_allowed_entry || !result.member.vetted_date) && cards.length);
|
||||||
setDimmed(startDimmed);
|
setDimmed(startDimmed);
|
||||||
}, [result.member]);
|
}, [result.member]);
|
||||||
|
|
||||||
|
@ -298,7 +298,7 @@ export function AdminMemberCards(props) {
|
||||||
|
|
||||||
<Dimmer active={dimmed}>
|
<Dimmer active={dimmed}>
|
||||||
<p>
|
<p>
|
||||||
Member paused or not allowed entry, {cards.length} card{cards.length === 1 ? '' : 's'} ignored anyway.
|
Member paused, unvetted or not allowed entry. {cards.length} card{cards.length === 1 ? '' : 's'} ignored anyway.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<Button size='tiny' onClick={() => setDimmed(false)}>Close</Button>
|
<Button size='tiny' onClick={() => setDimmed(false)}>Close</Button>
|
||||||
|
@ -363,15 +363,45 @@ export function AdminMemberPause(props) {
|
||||||
<div>
|
<div>
|
||||||
<Header size='medium'>Pause / Unpause Membership</Header>
|
<Header size='medium'>Pause / Unpause Membership</Header>
|
||||||
|
|
||||||
<p>Pause members who are inactive, former, or on vacation.</p>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
{result.member.paused_date ?
|
{result.member.paused_date ?
|
||||||
<Button onClick={handleUnpause} loading={loading}>
|
result.member.vetted_date && moment().diff(moment(result.member.paused_date), 'days') > 370 ?
|
||||||
Unpause
|
<>
|
||||||
</Button>
|
<p>
|
||||||
|
{result.member.preferred_name} has been away for more than a year and will need to be re-vetted according to our
|
||||||
|
<a href='https://wiki.protospace.ca/Approved_policies/Membership' target='_blank' rel='noopener noreferrer'> policy</a>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<Form.Checkbox
|
||||||
|
name='told_subscriptions'
|
||||||
|
value={told1}
|
||||||
|
label='Told member to get re-vetted'
|
||||||
|
required
|
||||||
|
onChange={(e, v) => setTold1(v.checked)}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<Form.Checkbox
|
||||||
|
name='told_shelves'
|
||||||
|
value={told2}
|
||||||
|
label='Collected payment for member dues'
|
||||||
|
required
|
||||||
|
onChange={(e, v) => setTold2(v.checked)}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<Button onClick={handleUnpause} loading={loading} disabled={!told1 || !told2}>
|
||||||
|
Unpause
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
:
|
||||||
|
<Button onClick={handleUnpause} loading={loading}>
|
||||||
|
Unpause
|
||||||
|
</Button>
|
||||||
:
|
:
|
||||||
<>
|
<>
|
||||||
|
<p>Pause members who are inactive, former, or on vacation.</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<Form.Checkbox
|
<Form.Checkbox
|
||||||
name='told_subscriptions'
|
name='told_subscriptions'
|
||||||
|
|
Loading…
Reference in New Issue
Block a user