diff --git a/.gitignore b/.gitignore index 509ad63..a3e0552 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.pyc +*.log ENV lids/lids/local_settings.py *~ diff --git a/lids/lidapp/management/commands/bind.py b/lids/lidapp/management/commands/bind.py index 320c60f..cf08a22 100755 --- a/lids/lidapp/management/commands/bind.py +++ b/lids/lidapp/management/commands/bind.py @@ -1,6 +1,7 @@ from django.core.management.base import BaseCommand, CommandError from lidapp.models import ID from optparse import make_option +import logging class Command(BaseCommand): @@ -26,6 +27,7 @@ class Command(BaseCommand): ) def handle(self, *args, **options): + logger = logging.getLogger('lidapp.actions') identifier = args[0] try: id = ID.objects.get(identifier=identifier) @@ -38,4 +40,5 @@ def handle(self, *args, **options): kwargs[opt] = options[opt] id.bind(**kwargs) + logger.info('Action: bind IP: 127.0.0.1 ID: %s Result:SUCCESS. Data: %s' % (identifier, kwargs)) self.stdout.write(id.dump_string() + '\n') diff --git a/lids/lidapp/management/commands/lookup.py b/lids/lidapp/management/commands/lookup.py index 205f4fd..c7176cb 100755 --- a/lids/lidapp/management/commands/lookup.py +++ b/lids/lidapp/management/commands/lookup.py @@ -1,5 +1,6 @@ from django.core.management.base import BaseCommand, CommandError from lidapp.models import ID +import logging class Command(BaseCommand): @@ -7,10 +8,12 @@ class Command(BaseCommand): help = 'Get metadata for an identifier' def handle(self, *args, **options): + logger = logging.getLogger('lidapp.actions') identifier = args[0] try: id = ID.objects.get(identifier=identifier) except ID.DoesNotExist: raise CommandError('Identifier "%s" does not exist' % identifier) + logger.info('Action: lookup IP: 127.0.0.1 ID: %s Result:SUCCESS.' % identifier) self.stdout.write(id.dump_string() + '\n') diff --git a/lids/lidapp/management/commands/mint.py b/lids/lidapp/management/commands/mint.py index e24813a..6d1170c 100755 --- a/lids/lidapp/management/commands/mint.py +++ b/lids/lidapp/management/commands/mint.py @@ -2,6 +2,7 @@ from lidapp.models import ID, Minter, Requester from optparse import make_option from django.utils.timezone import now +import logging class Command(BaseCommand): args = '' @@ -22,21 +23,23 @@ class Command(BaseCommand): ) def handle(self, *args, **options): + logger = logging.getLogger('lidapp.actions') try: minter_name = args[0] + minter = Minter.objects.get(name=minter_name) + requester = Requester.objects.get(ip='127.0.0.1') except IndexError: raise CommandError('Please specify a minter') - try: - minter = Minter.objects.get(name=minter_name) except Minter.DoesNotExist: raise CommandError('Minter "%s" does not exist' % minter_name) - try: - requester = Requester.objects.get(name='CommandLine') except Requester.DoesNotExist: - requester = Requester.objects.create(name='CommandLine', date_created=now()) + requester = Requester.objects.create(name='Command Line', date_created=now(),admin=True, ip='127.0.0.1') ids = minter.mint(requester=requester, quantity=options['quantity']) + for x in range(options['quantity']): + logger.info('Action: mint %s of %s IP: 127.0.0.1 Result:SUCCESS. Minted %s' % (x+1, options['quantity'], ids[x].identifier)) + if not options['verbose']: output = '\n'.join([id.identifier for id in ids]) self.stdout.write(output+'\n') diff --git a/lids/lidapp/models.py b/lids/lidapp/models.py index bbdae78..0315add 100755 --- a/lids/lidapp/models.py +++ b/lids/lidapp/models.py @@ -7,8 +7,10 @@ class Requester(models.Model): name = models.CharField(max_length=63, unique=True) - organization = models.CharField(max_length=63) + organization = models.CharField(max_length=63, blank=True) + ip = models.IPAddressField(unique=True) date_created = models.DateTimeField() + admin = models.BooleanField(default=False) description = models.TextField(blank=True) def __unicode__(self): diff --git a/lids/lidapp/sql/requester.sql b/lids/lidapp/sql/requester.sql new file mode 100644 index 0000000..cd9a63b --- /dev/null +++ b/lids/lidapp/sql/requester.sql @@ -0,0 +1 @@ +INSERT INTO lidapp_requester (name, ip, date_created, admin) VALUES ('Command Line', '127.0.0.1', NOW(), TRUE); diff --git a/lids/lidapp/views.py b/lids/lidapp/views.py index ba0c3bf..a8fd47c 100755 --- a/lids/lidapp/views.py +++ b/lids/lidapp/views.py @@ -1,32 +1,76 @@ -from django.http import HttpResponse -from django.shortcuts import get_object_or_404, redirect +from django.http import HttpResponse, Http404, HttpResponseForbidden +from django.shortcuts import redirect +from django.utils.timezone import now from lidapp.models import ID, Minter, Requester +import logging import json +logger = logging.getLogger('lidapp.actions') + def _ids_to_json(ids): return json.dumps([id.dump_dict() for id in ids], indent=2) def mint(request, minter_name, quantity=1): - minter = get_object_or_404(Minter, name=minter_name) - requester = get_object_or_404(Requester, name=request.GET['requester']) + ip = request.META['REMOTE_ADDR'] + quantity = int(quantity) + try: + requester = Requester.objects.get(ip=ip) + minter = Minter.objects.get(name=minter_name) + except Requester.DoesNotExist: + logger.info('Action: mint %s IP: %s Result:FAILED. IP not recognized' %(quantity, ip)) + raise Http404('You are not permitted to mint IDs from IP address %s' % ip) + except Minter.DoesNotExist: + logger.info('Action: mint %s IP: %s Result:FAILED. Minter %s does not exist' % (quantity, ip, minter_name)) + raise Http404('Minter %s does not exist' % minter_name) ids = minter.mint(requester=requester, quantity=quantity) + for x in range(quantity): + logger.info('Action: mint %s of %s IP: %s Result:SUCCESS. Minted %s' % (x+1, quantity, ip, ids[x].identifier)) return HttpResponse(_ids_to_json(ids), content_type='application/json') def bind(request, identifier): - id = get_object_or_404(ID, identifier=identifier) + ip = request.META['REMOTE_ADDR'] + try: + requester = Requester.objects.get(ip=ip) + id = ID.objects.get(identifier=identifier) + except Requester.DoesNotExist: + logger.info('Action: bind IP: %s ID: %s Result:FAILED. IP not recognized' % (ip, identifier)) + raise Http404('You are not permitted to bind IDs from IP address %s' % ip) + except ID.DoesNotExist: + logger.info('Action: bind IP: %s ID: %s Result:FAILED. Identifier does not exist' % (ip, identifier)) + raise Http404('ID %s does not exist %s' % identifier) + if requester.admin == False and not id.requester.ip == requester.ip: + logger.info('Action: bind IP: %s ID: %s Result:FAILED. Requester not authorized to edit ID' % (ip, identifier)) + return HttpResponseForbidden('You are not authorized to bind data to ID %s from IP address %s' % (identifier, ip)) kwargs = {} for field in id.bindable_fields: if field in request.GET: kwargs[field] = request.GET[field] id.bind(**kwargs) + logger.info('Action: bind IP: %s ID: %s Result:SUCCESS. Data: %s' % (ip, identifier, kwargs)) return HttpResponse(_ids_to_json([id]), content_type='application/json') def lookup(request, identifier): - id = get_object_or_404(ID,identifier=identifier) + ip = request.META['REMOTE_ADDR'] + try: + id = ID.objects.get(identifier=identifier) + except ID.DoesNotExist: + logger.info('Action: lookup IP: %s ID: %s Result:FAILED. Identifier does not exist' % (ip, identifier)) + raise Http404('ID %s does not exist %s' % identifier) + logger.info('Action: lookup IP: %s ID: %s Result:SUCCESS.' % (ip, identifier)) return HttpResponse(_ids_to_json([id]), content_type='application/json') def resolve(request, identifier): - id = get_object_or_404(ID,identifier=identifier) + ip = request.META['REMOTE_ADDR'] + try: + id = ID.objects.get(identifier=identifier) + except ID.DoesNotExist: + logger.info('Action: resolve IP: %s ID: %s Result:FAILED. Identifier does not exist' % (ip, identifier)) + raise Http404('ID %s does not exist' % identifier) if id.object_url: - url = id.object_url if id.object_url.startswith('http://') else 'http://'+id.object_url + url = id.object_url if id.object_url.startswith('http') else 'http://'+id.object_url + logger.info('Action: resolve IP: %s ID: %s Result:SUCCESS.' % (ip, identifier)) return redirect(url) + else: + logger.info('Action: resolve IP: %s ID: %s Result:FAILED. Identifier has not been bound to a url' % (ip, identifier)) + raise Http404('ID %s has not been bound to a url' % identifier) + #TODO: provide a more graceful resolution error page diff --git a/lids/lids/settings.py b/lids/lids/settings.py index 6ad7f35..b0a1af6 100755 --- a/lids/lids/settings.py +++ b/lids/lids/settings.py @@ -127,34 +127,32 @@ 'lidapp', ) -# A sample logging configuration. The only tangible logging -# performed by this configuration is to send an email to -# the site admins on every HTTP 500 error when DEBUG=False. -# See http://docs.djangoproject.com/en/dev/topics/logging for -# more details on how to customize your logging configuration. LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'filters': { - 'require_debug_false': { - '()': 'django.utils.log.RequireDebugFalse' - } - }, - 'handlers': { - 'mail_admins': { - 'level': 'ERROR', - 'filters': ['require_debug_false'], - 'class': 'django.utils.log.AdminEmailHandler' - } - }, - 'loggers': { - 'django.request': { - 'handlers': ['mail_admins'], - 'level': 'ERROR', - 'propagate': True, - }, - } -} + 'version': 1, + 'disable_existing_loggers': True, + 'formatters': { + 'standard': { + 'format': '%(asctime)s %(levelname)s: %(message)s' + }, + }, + 'handlers': { + 'file': { + 'level': 'INFO', + 'class': 'logging.handlers.RotatingFileHandler', + 'filename': os.path.join(os.path.dirname(__file__), 'logs', 'actions.log'), + 'maxBytes': 1024*1024*5, + 'backupCount': 10, + 'formatter': 'standard' + }, + }, + 'loggers': { + 'lidapp.actions': { + 'handlers': ['file'], + 'level': 'INFO', + 'propogate': False, + }, + }, + } # Models settings OBJECT_TYPES = (