django-link-shortener
Advanced tools
| # Generated by Django 2.2.1 on 2019-05-28 15:22 | ||
| from django.db import migrations, models | ||
| class Migration(migrations.Migration): | ||
| dependencies = [ | ||
| ('shortener', '0001_initial'), | ||
| ] | ||
| operations = [ | ||
| migrations.AlterField( | ||
| model_name='urlprofile', | ||
| name='default_lifespan', | ||
| field=models.IntegerField(blank=True, default=120, null=True), | ||
| ), | ||
| migrations.AlterField( | ||
| model_name='urlprofile', | ||
| name='default_max_uses', | ||
| field=models.IntegerField(blank=True, default=-1, null=True), | ||
| ), | ||
| migrations.AlterField( | ||
| model_name='urlprofile', | ||
| name='enabled', | ||
| field=models.NullBooleanField(default=True), | ||
| ), | ||
| migrations.AlterField( | ||
| model_name='urlprofile', | ||
| name='max_concurrent_urls', | ||
| field=models.IntegerField(blank=True, default=100, null=True), | ||
| ), | ||
| migrations.AlterField( | ||
| model_name='urlprofile', | ||
| name='max_urls', | ||
| field=models.IntegerField(blank=True, default=-1, null=True), | ||
| ), | ||
| ] |
| # Generated by Django 2.2.1 on 2019-05-28 15:58 | ||
| from django.db import migrations, models | ||
| class Migration(migrations.Migration): | ||
| dependencies = [ | ||
| ('shortener', '0002_auto_20190528_1522'), | ||
| ] | ||
| operations = [ | ||
| migrations.AlterField( | ||
| model_name='urlmap', | ||
| name='full_url', | ||
| field=models.TextField(), | ||
| ), | ||
| ] |
| Metadata-Version: 1.1 | ||
| Name: django-link-shortener | ||
| Version: 0.3 | ||
| Summary: A simple Django Link Shortener. | ||
| Version: 0.4 | ||
| Summary: A simple Django Url Shortener. | ||
| Home-page: https://github.com/ronaldgrn/django-link-shortener | ||
@@ -9,3 +9,2 @@ Author: Petronald Green | ||
| License: MIT License | ||
| Download-URL: https://github.com/ronaldgrn/django-link-shortener/archive/0.2.tar.gz | ||
| Description: ===================== | ||
@@ -26,2 +25,6 @@ django-link-shortener | ||
| .. image:: https://coveralls.io/repos/github/ronaldgrn/django-link-shortener/badge.svg?branch=master | ||
| :target: https://coveralls.io/github/ronaldgrn/django-link-shortener?branch=master | ||
| django-link-shortener is a simple time and usage sensitive url shortening app. | ||
@@ -144,2 +147,22 @@ | ||
| Changelog | ||
| --------- | ||
| **v0.4** | ||
| - Allow null values in UrlProfile; null fields will use global values | ||
| - str representation of UrlProfile in admin | ||
| - add user to str representation of UrlMap | ||
| - removed 256 char limit on full_url (Credit: Khaeshah) | ||
| Upgrade Instructions | ||
| -------------------- | ||
| **0.3 -> 0.4** | ||
| :: | ||
| pip install django-link-shortener==0.4 | ||
| python manage.py migrate | ||
| Keywords: url shortener,link shortener | ||
@@ -146,0 +169,0 @@ Platform: UNKNOWN |
@@ -18,2 +18,4 @@ LICENSE | ||
| shortener/migrations/0001_initial.py | ||
| shortener/migrations/0002_auto_20190528_1522.py | ||
| shortener/migrations/0003_auto_20190528_1558.py | ||
| shortener/migrations/__init__.py |
+2
-1
| include LICENSE | ||
| include README.rst | ||
| include README.rst | ||
| recursive-include shortener/migrations *.py |
+26
-3
| Metadata-Version: 1.1 | ||
| Name: django-link-shortener | ||
| Version: 0.3 | ||
| Summary: A simple Django Link Shortener. | ||
| Version: 0.4 | ||
| Summary: A simple Django Url Shortener. | ||
| Home-page: https://github.com/ronaldgrn/django-link-shortener | ||
@@ -9,3 +9,2 @@ Author: Petronald Green | ||
| License: MIT License | ||
| Download-URL: https://github.com/ronaldgrn/django-link-shortener/archive/0.2.tar.gz | ||
| Description: ===================== | ||
@@ -26,2 +25,6 @@ django-link-shortener | ||
| .. image:: https://coveralls.io/repos/github/ronaldgrn/django-link-shortener/badge.svg?branch=master | ||
| :target: https://coveralls.io/github/ronaldgrn/django-link-shortener?branch=master | ||
| django-link-shortener is a simple time and usage sensitive url shortening app. | ||
@@ -144,2 +147,22 @@ | ||
| Changelog | ||
| --------- | ||
| **v0.4** | ||
| - Allow null values in UrlProfile; null fields will use global values | ||
| - str representation of UrlProfile in admin | ||
| - add user to str representation of UrlMap | ||
| - removed 256 char limit on full_url (Credit: Khaeshah) | ||
| Upgrade Instructions | ||
| -------------------- | ||
| **0.3 -> 0.4** | ||
| :: | ||
| pip install django-link-shortener==0.4 | ||
| python manage.py migrate | ||
| Keywords: url shortener,link shortener | ||
@@ -146,0 +169,0 @@ Platform: UNKNOWN |
+25
-0
@@ -16,2 +16,6 @@ ===================== | ||
| .. image:: https://coveralls.io/repos/github/ronaldgrn/django-link-shortener/badge.svg?branch=master | ||
| :target: https://coveralls.io/github/ronaldgrn/django-link-shortener?branch=master | ||
| django-link-shortener is a simple time and usage sensitive url shortening app. | ||
@@ -133,1 +137,22 @@ | ||
| SHORTENER_MAX_USES = 1 | ||
| Changelog | ||
| --------- | ||
| **v0.4** | ||
| - Allow null values in UrlProfile; null fields will use global values | ||
| - str representation of UrlProfile in admin | ||
| - add user to str representation of UrlMap | ||
| - removed 256 char limit on full_url (Credit: Khaeshah) | ||
| Upgrade Instructions | ||
| -------------------- | ||
| **0.3 -> 0.4** | ||
| :: | ||
| pip install django-link-shortener==0.4 | ||
| python manage.py migrate |
+2
-3
@@ -12,10 +12,9 @@ import os | ||
| name='django-link-shortener', | ||
| version='0.3', | ||
| version='0.4', | ||
| packages=['shortener'], | ||
| include_package_data=True, | ||
| license='MIT License', | ||
| description='A simple Django Link Shortener.', | ||
| description='A simple Django Url Shortener.', | ||
| long_description=README, | ||
| url='https://github.com/ronaldgrn/django-link-shortener', | ||
| download_url='https://github.com/ronaldgrn/django-link-shortener/archive/0.2.tar.gz', | ||
| author='Petronald Green', | ||
@@ -22,0 +21,0 @@ author_email='petronaldgreen@gmail.com', |
@@ -9,3 +9,3 @@ from django.db import models | ||
| user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) | ||
| full_url = models.CharField(max_length=256) | ||
| full_url = models.TextField() | ||
| short_url = models.CharField(max_length=50, unique=True, db_index=True) | ||
@@ -19,3 +19,3 @@ usage_count = models.IntegerField(default=0) | ||
| def __str__(self): | ||
| return self.full_url | ||
| return '{} - {}'.format(self.user, self.full_url) | ||
@@ -25,8 +25,9 @@ | ||
| user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) | ||
| enabled = models.BooleanField(default=True) | ||
| max_urls = models.IntegerField(default=-1) | ||
| max_concurrent_urls = models.IntegerField(default=100) | ||
| enabled = models.NullBooleanField(default=True, null=True) | ||
| max_urls = models.IntegerField(default=-1, null=True, blank=True) | ||
| max_concurrent_urls = models.IntegerField(default=100, null=True, blank=True) | ||
| default_lifespan = models.IntegerField(default=120, null=True, blank=True) | ||
| default_max_uses = models.IntegerField(default=-1, null=True, blank=True) | ||
| # TODO: Lifespan from SETTINGS | ||
| default_lifespan = models.IntegerField(default=120) | ||
| default_max_uses = models.IntegerField(default=-1) | ||
| def __str__(self): | ||
| return '{}'.format(self.user) |
@@ -22,9 +22,9 @@ from shortener.models import UrlMap, UrlProfile | ||
| try: | ||
| # use user settings | ||
| # use user settings where set | ||
| p = UrlProfile.objects.get(user=user) | ||
| enabled = p.enabled | ||
| max_urls = p.max_urls | ||
| max_concurrent = p.max_concurrent_urls | ||
| lifespan = p.default_lifespan | ||
| max_uses = p.default_max_uses | ||
| enabled = p.enabled if p.enabled is not None else getattr(settings, 'SHORTENER_ENABLED', True) | ||
| max_urls = p.max_urls if p.max_urls is not None else getattr(settings, 'SHORTENER_MAX_URLS', -1) | ||
| max_concurrent = p.max_concurrent_urls if p.max_concurrent_urls is not None else getattr(settings, 'SHORTENER_MAX_CONCURRENT', -1) | ||
| lifespan = p.default_lifespan if p.default_lifespan is not None else getattr(settings, 'SHORTENER_LIFESPAN', -1) | ||
| max_uses = p.default_max_uses if p.default_max_uses is not None else getattr(settings, 'SHORTENER_MAX_USES', -1) | ||
@@ -31,0 +31,0 @@ except UrlProfile.DoesNotExist: |
+115
-1
| from django.test import TestCase | ||
| from shortener import shortener | ||
| from shortener.models import UrlProfile | ||
| from tests.testapp.models import CustomUser | ||
@@ -25,3 +26,3 @@ import time | ||
| with self.assertRaisesMessage(PermissionError, 'not authorized to create shortlinks'): | ||
| url = shortener.create(self.bob, "http://devget.net/") | ||
| shortener.create(self.bob, "http://devget.net/") | ||
@@ -59,1 +60,114 @@ def test_max_urls_setting(self): | ||
| class UrlProfileTestCase(TestCase): | ||
| """ | ||
| Test User overrides | ||
| """ | ||
| def setUp(self): | ||
| self.ronald = CustomUser.objects.create_user('ronald', 'ronald@ronald.com', 'ronaldpassword') | ||
| self.urlProfile, created = UrlProfile.objects.update_or_create( | ||
| user=self.ronald, | ||
| defaults={ | ||
| 'enabled': None, | ||
| 'max_urls': None, | ||
| 'max_concurrent_urls': None, | ||
| 'default_lifespan': None, | ||
| 'default_max_uses': None | ||
| }, | ||
| ) | ||
| # def tearDown(self): | ||
| # # Reset UrlProfile | ||
| # UrlProfile.objects.update_or_create( | ||
| # user=self.ronald, | ||
| # defaults={ | ||
| # 'enabled': None, | ||
| # 'max_urls': None, | ||
| # 'max_concurrent_urls': None, | ||
| # 'default_lifespan': None, | ||
| # 'default_max_uses': None | ||
| # }, | ||
| # ) | ||
| def test_shortener_enabled_setting(self): | ||
| with self.settings(SHORTENER_ENABLED=False): | ||
| with self.assertRaisesMessage(PermissionError, 'not authorized to create shortlinks'): | ||
| shortener.create(self.ronald, "http://devget.net/") | ||
| # Ensure we can override with UrlProfile | ||
| self.urlProfile.enabled = True | ||
| self.urlProfile.save() | ||
| shortener.create(self.ronald, "http://devget.net/") | ||
| # Ensure we can omit with UrlProfile | ||
| self.urlProfile.enabled = None | ||
| self.urlProfile.save() | ||
| with self.assertRaisesMessage(PermissionError, 'not authorized to create shortlinks'): | ||
| shortener.create(self.ronald, "http://devget.net/") | ||
| def test_max_urls_setting(self): | ||
| with self.settings(SHORTENER_MAX_URLS=0): | ||
| with self.assertRaisesMessage(PermissionError, 'url quota exceeded'): | ||
| shortener.create(self.ronald, "http://devget.net/") | ||
| # Ensure we can override with UrlProfile | ||
| self.urlProfile.max_urls = 2 | ||
| self.urlProfile.save() | ||
| shortener.create(self.ronald, "http://devget.net/") | ||
| shortener.create(self.ronald, "http://devget.net/") | ||
| with self.assertRaisesMessage(PermissionError, 'url quota exceeded'): | ||
| shortener.create(self.ronald, "http://devget.net/") | ||
| def test_max_concurrent_setting(self): | ||
| with self.settings(SHORTENER_MAX_CONCURRENT=2): | ||
| shortener.create(self.ronald, "http://devget.net/") | ||
| shortener.create(self.ronald, "http://devget.net/") | ||
| with self.assertRaisesMessage(PermissionError, 'concurrent quota exceeded'): | ||
| shortener.create(self.ronald, "http://devget.net/") | ||
| # Ensure we can override with UrlProfile | ||
| self.urlProfile.max_concurrent_urls = 3 | ||
| self.urlProfile.save() | ||
| shortener.create(self.ronald, "http://devget.net/") | ||
| with self.assertRaisesMessage(PermissionError, 'concurrent quota exceeded'): | ||
| shortener.create(self.ronald, "http://devget.net/") | ||
| def test_lifespan_setting(self): | ||
| with self.settings(SHORTENER_LIFESPAN=2): # 4 seconds | ||
| url = shortener.create(self.ronald, "http://blog.devget.net/") | ||
| self.assertEqual(shortener.expand(url), "http://blog.devget.net/") | ||
| time.sleep(3) | ||
| with self.assertRaisesMessage(PermissionError, 'shortlink expired'): | ||
| self.assertEqual(shortener.expand(url), "http://blog.devget.net/") | ||
| # Ensure we can override with UrlProfile | ||
| self.urlProfile.default_lifespan = 6 | ||
| self.urlProfile.save() | ||
| url = shortener.create(self.ronald, "http://blog.devget.net/") | ||
| self.assertEqual(shortener.expand(url), "http://blog.devget.net/") | ||
| time.sleep(4) | ||
| self.assertEqual(shortener.expand(url), "http://blog.devget.net/") | ||
| time.sleep(3) | ||
| with self.assertRaisesMessage(PermissionError, 'shortlink expired'): | ||
| self.assertEqual(shortener.expand(url), "http://blog.devget.net/") | ||
| def test_max_uses_setting(self): | ||
| with self.settings(SHORTENER_MAX_USES=0): | ||
| url = shortener.create(self.ronald, "http://blog.devget.net/") | ||
| with self.assertRaisesMessage(PermissionError, 'max usages for link reached'): | ||
| # Ensure error is raised when we hit limit | ||
| shortener.expand(url) | ||
| # Ensure we can override with UrlProfile | ||
| self.urlProfile.default_max_uses = 2 | ||
| self.urlProfile.save() | ||
| url = shortener.create(self.ronald, "http://blog.devget.net/") | ||
| self.assertEqual(shortener.expand(url), "http://blog.devget.net/") | ||
| self.assertEqual(shortener.expand(url), "http://blog.devget.net/") | ||
| with self.assertRaisesMessage(PermissionError, 'max usages for link reached'): | ||
| # Ensure error is raised when we hit limit | ||
| shortener.expand(url) |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
35412
34.7%22
10%386
58.2%