-
Notifications
You must be signed in to change notification settings - Fork 829
[Bug 1125536] Convert all rate limiting to a standard helper. #2363
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| from django.contrib import admin | ||
|
|
||
| from kitsune.journal.models import Record | ||
|
|
||
|
|
||
| class RecordAdmin(admin.ModelAdmin): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Love having this app. Is the admin the only way to look at the data for now? Is that good enough?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the admin is the only way to look at these. I think that is good enough for now. Do you think the model captures enough information? The Fjord one has a lot more details, but I didn't think we needed them.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this works. I am thinking that we could put a json string in the msg if we need to capture some sort of structured data. That can then be processed offline. |
||
| list_display = ( | ||
| 'id', | ||
| 'level', | ||
| 'src', | ||
| 'msg', | ||
| 'created', | ||
| ) | ||
| list_filter = ('src',) | ||
|
|
||
|
|
||
| admin.site.register(Record, RecordAdmin) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| # -*- coding: utf-8 -*- | ||
| import datetime | ||
| from south.db import db | ||
| from south.v2 import SchemaMigration | ||
| from django.db import models | ||
|
|
||
|
|
||
| class Migration(SchemaMigration): | ||
|
|
||
| def forwards(self, orm): | ||
| # Adding model 'Record' | ||
| db.create_table(u'journal_record', ( | ||
| (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), | ||
| ('level', self.gf('django.db.models.fields.CharField')(max_length=20)), | ||
| ('src', self.gf('django.db.models.fields.CharField')(max_length=50)), | ||
| ('msg', self.gf('django.db.models.fields.CharField')(max_length=255)), | ||
| ('created', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), | ||
| )) | ||
| db.send_create_signal(u'journal', ['Record']) | ||
|
|
||
|
|
||
| def backwards(self, orm): | ||
| # Deleting model 'Record' | ||
| db.delete_table(u'journal_record') | ||
|
|
||
|
|
||
| models = { | ||
| u'journal.record': { | ||
| 'Meta': {'object_name': 'Record'}, | ||
| 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
| u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
| 'level': ('django.db.models.fields.CharField', [], {'max_length': '20'}), | ||
| 'msg': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
| 'src': ('django.db.models.fields.CharField', [], {'max_length': '50'}) | ||
| } | ||
| } | ||
|
|
||
| complete_apps = ['journal'] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| from datetime import datetime | ||
|
|
||
| from django.db import models | ||
|
|
||
|
|
||
| RECORD_INFO = u'info' | ||
| RECORD_ERROR = u'error' | ||
|
|
||
|
|
||
| class RecordManager(models.Manager): | ||
| def log(self, level, src, msg, **kwargs): | ||
| msg = msg.format(**kwargs).encode('utf-8') | ||
| return Record.objects.create(level=RECORD_INFO, src=src, msg=msg) | ||
|
|
||
| def info(self, src, msg, **kwargs): | ||
| self.log(RECORD_INFO, src, msg, **kwargs) | ||
|
|
||
| def error(self, src, msg, **kwargs): | ||
| self.log(RECORD_ERROR, src, msg, **kwargs) | ||
|
|
||
|
|
||
| class Record(models.Model): | ||
| """Defines an audit record for something that happened in translations""" | ||
|
|
||
| TYPE_CHOICES = [ | ||
| (RECORD_INFO, RECORD_INFO), | ||
| (RECORD_ERROR, RECORD_ERROR), | ||
| ] | ||
|
|
||
| # The log level of this message (e.g. "info", "error", ...) | ||
| level = models.CharField(choices=TYPE_CHOICES, max_length=20) | ||
|
|
||
| # What component was running (e.g. "sumo.ratelimit", "questions.aaq") | ||
| src = models.CharField(max_length=50) | ||
|
|
||
| # The message details. (e.g. "user bob hit the ratelimit for questions.ask") | ||
| msg = models.CharField(max_length=255) | ||
|
|
||
| # When this log entry was created | ||
| created = models.DateTimeField(default=datetime.now) | ||
|
|
||
| objects = RecordManager() | ||
|
|
||
| def __unicode__(self): | ||
| return u'<Record {self.src} {self.msg}>'.format(self=self) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| # -*- coding: utf-8 -*- | ||
| import datetime | ||
| from south.db import db | ||
| from south.v2 import DataMigration | ||
| from django.db import models | ||
|
|
||
| class Migration(DataMigration): | ||
|
|
||
| def forwards(self, orm): | ||
| """Add a permission (and content type if needed) for bypassing ratelimits.""" | ||
| # First create a content type for these kind of permissions. | ||
| ContentType = orm['contenttypes.ContentType'] | ||
| global_permission_ct, created = ContentType.objects.get_or_create(name='global_permission', app_label='sumo') | ||
|
|
||
| # Then we create a permission attached to that content type. | ||
| Permission = orm['auth.Permission'] | ||
| view_perm = Permission.objects.create( | ||
| name='Bypass Ratelimits', | ||
| content_type=global_permission_ct, | ||
| codename='bypass_ratelimit') | ||
|
|
||
| def backwards(self, orm): | ||
| """Delete the bypass permission. """ | ||
| Permission = orm['auth.Permission'] | ||
| Permission.objects.get(codename='bypass_ratelimit').delete() | ||
|
|
||
| models = { | ||
| u'auth.group': { | ||
| 'Meta': {'object_name': 'Group'}, | ||
| u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
| 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), | ||
| 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) | ||
| }, | ||
| u'auth.permission': { | ||
| 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, | ||
| 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
| 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), | ||
| u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
| 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) | ||
| }, | ||
| u'auth.user': { | ||
| 'Meta': {'object_name': 'User'}, | ||
| 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
| 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), | ||
| 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
| 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), | ||
| u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
| 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), | ||
| 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
| 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
| 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
| 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
| 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), | ||
| 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), | ||
| 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) | ||
| }, | ||
| u'contenttypes.contenttype': { | ||
| 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, | ||
| 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
| u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
| 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
| 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) | ||
| } | ||
| } | ||
|
|
||
| complete_apps = ['auth', 'sumo'] | ||
| symmetrical = True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yay! so much cleaner