You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

django-link-shortener

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

django-link-shortener - pypi Package Compare versions

Comparing version
0.5
to
1.0.0b0
+1
django_link_shortener.egg-info/dependency_links.txt
Metadata-Version: 2.4
Name: django-link-shortener
Version: 1.0.0b0
Summary: A simple Django Url Shortener.
Author-email: Petronald Green <petronaldgreen@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/ronaldgrn/django-link-shortener
Keywords: url shortener,link shortener
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 3.2
Classifier: Framework :: Django :: 4.2
Classifier: Framework :: Django :: 5.0
Classifier: Framework :: Django :: 5.1
Classifier: Framework :: Django :: 5.2
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: django>=3.2
Dynamic: license-file
# django-link-shortener
[![image](https://github.com/ronaldgrn/django-link-shortener/actions/workflows/django-tests.yml/badge.svg)](https://github.com/ronaldgrn/django-link-shortener/actions/workflows/django-tests.yml)
[![PyPI - License](https://img.shields.io/pypi/l/django-link-shortener.svg)](https://pypi.org/project/django-link-shortener/)
[![PyPI](https://img.shields.io/pypi/v/django-link-shortener.svg)](https://pypi.org/project/django-link-shortener/)
[![Codecov](https://img.shields.io/codecov/c/github/ronaldgrn/django-link-shortener?token=PQ19R9VGTP)](https://codecov.io/gh/ronaldgrn/django-link-shortener)
django-link-shortener is a Django app for creating time-limited and usage-capped short URLs.
## Features
* Generate short links for URLs.
* Time-sensitive links (configurable lifespan).
* Usage-limited links (configurable maximum uses).
* Per-user override of default settings via Django admin.
* Test endpoint for easy shortcode creation during development.
* Character set for shortcodes excludes I, i, 1.
## Usage
1. Install with `pip install django-link-shortener`
2. Add `shortener` to your INSTALLED_APPS setting:
```python
INSTALLED_APPS = [
...
'shortener',
]
```
3. Include `shortener.urls` in your project urls.py:
```python
path('s/', include('shortener.urls')),
```
4. Run `python manage.py migrate` to create the shortener models.
5. Use `shortener.create(user, link)` to generate a shortcode.
```python
from shortener import shortener
user = User.objects.first()
shortener.create(user, "https://example.com")
```
6. To expand the shortcode use `shortener.expand(shorlink_id)`,
or visit `http://127.0.0.1:8000/s/<shortcode>/`.
## Test Endpoint
1. To enable the test endpoint, add the following to settings:
```python
SHORTENER_ENABLE_TEST_PATH = True
```
2. Start the development server and visit
`http://127.0.0.1:8000/s/test/<my-url-here>` to create a test shortcode.
3. Visit `http://127.0.0.1:8000/s/<shortcode>/` to be redirected
## Configuration Options
Place in settings.py. Each setting can be overridden on a per-user basis
using the UrlProfile section in the Django admin.
**SHORTENER_ENABLED**
Default: `True`
Controls whether users without a shortener profile can create shortlinks.
**SHORTENER_MAX_URLS**
Default: `-1`
Controls the default maximum limit of generated urls per account.
-1 sets infinite.
**SHORTENER_MAX_CONCURRENT**
Default: `-1`
Controls the default maximum limit of *concurrent* (active)
generated urls per account. -1 sets infinite.
**SHORTENER_LIFESPAN**
Default: `-1`
Sets the default lifespan of links in seconds. -1 sets infinite.
**SHORTENER_MAX_USES**
Default: `-1`
Sets the default amount of times a link can be followed. -1 sets infinite.
**SHORTENER_LENGTH**
Default: `5`
Note: Omitted from UrlProfile.
Sets how many digits should be used for links. Tries up to three
times to generate a unique shortcode where Each failure will result
in length temporarily being increased by 1.
**SHORTENER_ENABLE_TEST_PATH**
Default: `False`
If true, creates shortlinks on authenticated requests to `s/test/<url>/`
and returns a shortcode.
## Common Use Cases
goo.gl type usage (default). Unlimited concurrent links for an unlimited
length of time
```python
SHORTENER_ENABLED = True
SHORTENER_MAX_URLS = -1
SHORTENER_MAX_CONCURRENT = -1
SHORTENER_LIFESPAN = -1
SHORTENER_MAX_USES = -1
```
Internal temporary link usage.
100 active links with a lifespan of 1 hour. 1 usage per link.
```python
SHORTENER_ENABLED = True
SHORTENER_MAX_URLS = -1
SHORTENER_MAX_CONCURRENT = 100
SHORTENER_LIFESPAN = 600
SHORTENER_MAX_USES = 1
```
## Changelog
**v0.5**
- Replaced NullBooleanField with BooleanField (Credit: sen-den)
- Replaced travis-ci with github actions
**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)
LICENSE
MANIFEST.in
README.md
pyproject.toml
django_link_shortener.egg-info/PKG-INFO
django_link_shortener.egg-info/SOURCES.txt
django_link_shortener.egg-info/dependency_links.txt
django_link_shortener.egg-info/requires.txt
django_link_shortener.egg-info/top_level.txt
shortener/__init__.py
shortener/admin.py
shortener/apps.py
shortener/models.py
shortener/shortener.py
shortener/urls.py
shortener/views.py
shortener/migrations/0001_initial.py
shortener/migrations/0002_auto_20190528_1522.py
shortener/migrations/0003_auto_20190528_1558.py
shortener/migrations/0004_alter_urlprofile_enabled.py
shortener/migrations/__init__.py
include LICENSE
include README.md
recursive-include shortener/migrations *.py
Metadata-Version: 2.4
Name: django-link-shortener
Version: 1.0.0b0
Summary: A simple Django Url Shortener.
Author-email: Petronald Green <petronaldgreen@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/ronaldgrn/django-link-shortener
Keywords: url shortener,link shortener
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 3.2
Classifier: Framework :: Django :: 4.2
Classifier: Framework :: Django :: 5.0
Classifier: Framework :: Django :: 5.1
Classifier: Framework :: Django :: 5.2
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: django>=3.2
Dynamic: license-file
# django-link-shortener
[![image](https://github.com/ronaldgrn/django-link-shortener/actions/workflows/django-tests.yml/badge.svg)](https://github.com/ronaldgrn/django-link-shortener/actions/workflows/django-tests.yml)
[![PyPI - License](https://img.shields.io/pypi/l/django-link-shortener.svg)](https://pypi.org/project/django-link-shortener/)
[![PyPI](https://img.shields.io/pypi/v/django-link-shortener.svg)](https://pypi.org/project/django-link-shortener/)
[![Codecov](https://img.shields.io/codecov/c/github/ronaldgrn/django-link-shortener?token=PQ19R9VGTP)](https://codecov.io/gh/ronaldgrn/django-link-shortener)
django-link-shortener is a Django app for creating time-limited and usage-capped short URLs.
## Features
* Generate short links for URLs.
* Time-sensitive links (configurable lifespan).
* Usage-limited links (configurable maximum uses).
* Per-user override of default settings via Django admin.
* Test endpoint for easy shortcode creation during development.
* Character set for shortcodes excludes I, i, 1.
## Usage
1. Install with `pip install django-link-shortener`
2. Add `shortener` to your INSTALLED_APPS setting:
```python
INSTALLED_APPS = [
...
'shortener',
]
```
3. Include `shortener.urls` in your project urls.py:
```python
path('s/', include('shortener.urls')),
```
4. Run `python manage.py migrate` to create the shortener models.
5. Use `shortener.create(user, link)` to generate a shortcode.
```python
from shortener import shortener
user = User.objects.first()
shortener.create(user, "https://example.com")
```
6. To expand the shortcode use `shortener.expand(shorlink_id)`,
or visit `http://127.0.0.1:8000/s/<shortcode>/`.
## Test Endpoint
1. To enable the test endpoint, add the following to settings:
```python
SHORTENER_ENABLE_TEST_PATH = True
```
2. Start the development server and visit
`http://127.0.0.1:8000/s/test/<my-url-here>` to create a test shortcode.
3. Visit `http://127.0.0.1:8000/s/<shortcode>/` to be redirected
## Configuration Options
Place in settings.py. Each setting can be overridden on a per-user basis
using the UrlProfile section in the Django admin.
**SHORTENER_ENABLED**
Default: `True`
Controls whether users without a shortener profile can create shortlinks.
**SHORTENER_MAX_URLS**
Default: `-1`
Controls the default maximum limit of generated urls per account.
-1 sets infinite.
**SHORTENER_MAX_CONCURRENT**
Default: `-1`
Controls the default maximum limit of *concurrent* (active)
generated urls per account. -1 sets infinite.
**SHORTENER_LIFESPAN**
Default: `-1`
Sets the default lifespan of links in seconds. -1 sets infinite.
**SHORTENER_MAX_USES**
Default: `-1`
Sets the default amount of times a link can be followed. -1 sets infinite.
**SHORTENER_LENGTH**
Default: `5`
Note: Omitted from UrlProfile.
Sets how many digits should be used for links. Tries up to three
times to generate a unique shortcode where Each failure will result
in length temporarily being increased by 1.
**SHORTENER_ENABLE_TEST_PATH**
Default: `False`
If true, creates shortlinks on authenticated requests to `s/test/<url>/`
and returns a shortcode.
## Common Use Cases
goo.gl type usage (default). Unlimited concurrent links for an unlimited
length of time
```python
SHORTENER_ENABLED = True
SHORTENER_MAX_URLS = -1
SHORTENER_MAX_CONCURRENT = -1
SHORTENER_LIFESPAN = -1
SHORTENER_MAX_USES = -1
```
Internal temporary link usage.
100 active links with a lifespan of 1 hour. 1 usage per link.
```python
SHORTENER_ENABLED = True
SHORTENER_MAX_URLS = -1
SHORTENER_MAX_CONCURRENT = 100
SHORTENER_LIFESPAN = 600
SHORTENER_MAX_USES = 1
```
## Changelog
**v0.5**
- Replaced NullBooleanField with BooleanField (Credit: sen-den)
- Replaced travis-ci with github actions
**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)
[build-system]
requires = ["setuptools>=69.3"]
build-backend = "setuptools.build_meta"
[project]
name = "django-link-shortener"
version = "1.0.0-beta"
dependencies = [
"django>=3.2",
]
description = "A simple Django Url Shortener."
readme = "README.md"
requires-python = ">= 3.8"
authors = [
{name = "Petronald Green", email = "petronaldgreen@gmail.com"},
]
keywords = ['url shortener', 'link shortener']
license = "MIT"
license-files = ["LICENSE"]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Web Environment",
"Framework :: Django",
"Framework :: Django :: 3.2",
"Framework :: Django :: 4.2",
"Framework :: Django :: 5.0",
"Framework :: Django :: 5.1",
"Framework :: Django :: 5.2",
"Intended Audience :: Developers",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
]
[project.urls]
Homepage = "https://github.com/ronaldgrn/django-link-shortener"
# django-link-shortener
[![image](https://github.com/ronaldgrn/django-link-shortener/actions/workflows/django-tests.yml/badge.svg)](https://github.com/ronaldgrn/django-link-shortener/actions/workflows/django-tests.yml)
[![PyPI - License](https://img.shields.io/pypi/l/django-link-shortener.svg)](https://pypi.org/project/django-link-shortener/)
[![PyPI](https://img.shields.io/pypi/v/django-link-shortener.svg)](https://pypi.org/project/django-link-shortener/)
[![Codecov](https://img.shields.io/codecov/c/github/ronaldgrn/django-link-shortener?token=PQ19R9VGTP)](https://codecov.io/gh/ronaldgrn/django-link-shortener)
django-link-shortener is a Django app for creating time-limited and usage-capped short URLs.
## Features
* Generate short links for URLs.
* Time-sensitive links (configurable lifespan).
* Usage-limited links (configurable maximum uses).
* Per-user override of default settings via Django admin.
* Test endpoint for easy shortcode creation during development.
* Character set for shortcodes excludes I, i, 1.
## Usage
1. Install with `pip install django-link-shortener`
2. Add `shortener` to your INSTALLED_APPS setting:
```python
INSTALLED_APPS = [
...
'shortener',
]
```
3. Include `shortener.urls` in your project urls.py:
```python
path('s/', include('shortener.urls')),
```
4. Run `python manage.py migrate` to create the shortener models.
5. Use `shortener.create(user, link)` to generate a shortcode.
```python
from shortener import shortener
user = User.objects.first()
shortener.create(user, "https://example.com")
```
6. To expand the shortcode use `shortener.expand(shorlink_id)`,
or visit `http://127.0.0.1:8000/s/<shortcode>/`.
## Test Endpoint
1. To enable the test endpoint, add the following to settings:
```python
SHORTENER_ENABLE_TEST_PATH = True
```
2. Start the development server and visit
`http://127.0.0.1:8000/s/test/<my-url-here>` to create a test shortcode.
3. Visit `http://127.0.0.1:8000/s/<shortcode>/` to be redirected
## Configuration Options
Place in settings.py. Each setting can be overridden on a per-user basis
using the UrlProfile section in the Django admin.
**SHORTENER_ENABLED**
Default: `True`
Controls whether users without a shortener profile can create shortlinks.
**SHORTENER_MAX_URLS**
Default: `-1`
Controls the default maximum limit of generated urls per account.
-1 sets infinite.
**SHORTENER_MAX_CONCURRENT**
Default: `-1`
Controls the default maximum limit of *concurrent* (active)
generated urls per account. -1 sets infinite.
**SHORTENER_LIFESPAN**
Default: `-1`
Sets the default lifespan of links in seconds. -1 sets infinite.
**SHORTENER_MAX_USES**
Default: `-1`
Sets the default amount of times a link can be followed. -1 sets infinite.
**SHORTENER_LENGTH**
Default: `5`
Note: Omitted from UrlProfile.
Sets how many digits should be used for links. Tries up to three
times to generate a unique shortcode where Each failure will result
in length temporarily being increased by 1.
**SHORTENER_ENABLE_TEST_PATH**
Default: `False`
If true, creates shortlinks on authenticated requests to `s/test/<url>/`
and returns a shortcode.
## Common Use Cases
goo.gl type usage (default). Unlimited concurrent links for an unlimited
length of time
```python
SHORTENER_ENABLED = True
SHORTENER_MAX_URLS = -1
SHORTENER_MAX_CONCURRENT = -1
SHORTENER_LIFESPAN = -1
SHORTENER_MAX_USES = -1
```
Internal temporary link usage.
100 active links with a lifespan of 1 hour. 1 usage per link.
```python
SHORTENER_ENABLED = True
SHORTENER_MAX_URLS = -1
SHORTENER_MAX_CONCURRENT = 100
SHORTENER_LIFESPAN = 600
SHORTENER_MAX_USES = 1
```
## Changelog
**v0.5**
- Replaced NullBooleanField with BooleanField (Credit: sen-den)
- Replaced travis-ci with github actions
**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)
[egg_info]
tag_build =
tag_date = 0
+46
-2
from django.contrib import admin
from .models import UrlMap, UrlProfile
class UrlMapAdmin(admin.ModelAdmin):
model = UrlMap
raw_id_fields = (
"user",
)
list_display = (
"short_url",
"user",
"usage_count",
"max_count",
"lifespan",
"date_created",
"date_expired",
"full_url",
)
search_fields = (
"short_url",
"full_url",
"user__username",
)
class UrlProfileAdmin(admin.ModelAdmin):
model = UrlProfile
raw_id_fields = (
"user",
)
list_display = (
"user",
"enabled",
"max_urls",
"max_concurrent_urls",
"default_lifespan",
"default_max_uses",
)
list_filter = (
"enabled",
)
search_fields = (
"user__username",
)
# Register your models here.
admin.site.register(UrlMap)
admin.site.register(UrlProfile)
admin.site.register(UrlMap, UrlMapAdmin)
admin.site.register(UrlProfile, UrlProfileAdmin)
+15
-4
from shortener.models import UrlMap, UrlProfile
from django.conf import settings
from django.db import IntegrityError
from datetime import timedelta
from django.db.models import F
from datetime import datetime, timedelta
from django.utils import timezone

@@ -46,3 +48,6 @@

else:
expiry_date = timezone.make_aware(timezone.datetime.max, timezone.get_default_timezone())
# Avoid using the absolute maximum date to avoid overflow issues
# when setting negative timezones
safe_max_date = datetime(datetime.max.year, 1, 1, tzinfo=timezone.get_default_timezone())
expiry_date = safe_max_date

@@ -90,5 +95,11 @@ # Ensure user has not met max_urls quota

url.usage_count += 1
url.save()
# Avoid a race condition by not using `+= 1` here, and using F() instead:
url.usage_count = F("usage_count") + 1
# Telling `save` to ONLY save changes to the counter. That's all we need
# to update, and so we'll save a bit of bandwidth by not sending ALL
# possible values back across the wire, just to update this field:
# See: https://docs.djangoproject.com/en/5.0/ref/models/instances/#specifying-which-fields-to-save
url.save(update_fields=["usage_count"])
return url.full_url

@@ -5,7 +5,8 @@ from django.urls import path

app_name = "shortener"
urlpatterns = [
path('<link>/', views.expand),
path('<link>/', views.expand, name="expand"),
]
if getattr(settings, 'SHORTENER_ENABLE_TEST_PATH', False):
urlpatterns.append(path('test/<path:link>', views.test))
urlpatterns.append(path('test/<path:link>', views.test, name="test"))
Metadata-Version: 2.1
Name: django-link-shortener
Version: 0.5
Summary: A simple Django Url Shortener.
Home-page: https://github.com/ronaldgrn/django-link-shortener
Author: Petronald Green
Author-email: petronaldgreen@gmail.com
License: MIT License
Keywords: url shortener,link shortener
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 2.2
Classifier: Framework :: Django :: 3.0
Classifier: Framework :: Django :: 3.1
Classifier: Framework :: Django :: 3.2
Classifier: Framework :: Django :: 4.0
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
License-File: LICENSE
=====================
django-link-shortener
=====================
.. image:: https://github.com/ronaldgrn/django-link-shortener/actions/workflows/django-tests.yml/badge.svg
:target: https://github.com/ronaldgrn/django-link-shortener/actions/workflows/django-tests.yml
.. image:: https://img.shields.io/pypi/l/django-link-shortener.svg
:alt: PyPI - License
:target: https://pypi.org/project/django-link-shortener/
.. image:: https://img.shields.io/pypi/v/django-link-shortener.svg
:alt: PyPI
:target: https://pypi.org/project/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.
Uses A-Za-z0-9 with the exception of I, i and 1.
Requires user to be logged in for link creation.
Usage
-----
1. pip install django-link-shortener
2. Add '`shortener'` to your INSTALLED_APPS setting::
INSTALLED_APPS = [
...
'shortener',
]
3. Include `shortener.urls` in your project urls.py::
path('s/', include('shortener.urls')),
4. Run `python manage.py migrate` to create the shortener models.
Testing
-------
1. Add the following to settings
```
SHORTENER_ENABLE_TEST_PATH = True
```
1. Start the development server and visit http://127.0.0.1:8000/s/test/<My-URL-HERE>
to create a test shortcode.
or
Use shortener.create(user, link) to generate a link via code. Use shortener.expand(link)
to revert
6. Visit http://127.0.0.1:8000/s/<shortcode>/ to be redirected
Configuration Options
---------------------
Place in settings.py. Each setting be overridden on a per-user basis using the admin UrlProfile section
SHORTENER_ENABLED
Default: True
Controls whether users without a shortener profile can create shortlinks.
SHORTENER_MAX_URLS
Default: -1
Controls the default maximum limit of generated urls per account.
-1 sets infinite.
SHORTENER_MAX_CONCURRENT
Default: -1
Controls the default maximum limit of *concurrent* (active) generated urls per account.
-1 sets infinite
SHORTENER_LIFESPAN
Default: -1
Sets the default lifespan of links in seconds
-1 sets infinite
SHORTENER_MAX_USES
Default: -1
Sets the default amount of times a link can be followed
-1 sets infinite
SHORTENER_LENGTH
Default: 5
Note: Omitted from UrlProfile
Sets how many digits should be used for links.
Tries up to three times to generate a unique shortcode where
Each failure will result in length temporarily being increased by 1.
SHORTENER_ENABLE_TEST_PATH
Default: False
If true, creates shortlinks for logged in users at s/test/<<url>>/
The response is the shortcode to use used at s/<<shortcode>>
Common Use Cases
----------------
goo.gl type usage (default). Unlimited concurrent links for an unlimited length of time
::
SHORTENER_ENABLED = True
SHORTENER_MAX_URLS = -1
SHORTENER_MAX_CONCURRENT = -1
SHORTENER_LIFESPAN = -1
SHORTENER_MAX_USES = -1
Internal temporary link usage (such as on nodeferret.com). 100 Temp links per minute. 1 usage per link.
::
SHORTENER_ENABLED = True
SHORTENER_MAX_URLS = -1
SHORTENER_MAX_CONCURRENT = 100 # To prevent spamming
SHORTENER_LIFESPAN = 600
SHORTENER_MAX_USES = 1
Changelog
---------
**v0.5**
- Replaced NullBooleanField with BooleanField (Credit: sen-den)
- Replaced travis-ci with github actions
**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 --> 0.5**
::
pip install django-link-shortener==0.5
python manage.py migrate
shortener/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
shortener/admin.py,sha256=4kvFNraIN6h6Lkc8UnlsNcGPWX5WuCHunX_rT7kxE_I,162
shortener/apps.py,sha256=AxHfGHS90aZkCOlb0ZWUL4MP94yGDiSgwtKAdtWafMM,93
shortener/models.py,sha256=2FHhEz5TtQYEMPQeTqESRsF7GjYSbAeQtTEYztejg8c,1226
shortener/shortener.py,sha256=eVD7UuphUBRFWaH4BuaqypNsOf5RXFwcB1KIUUQic2c,3510
shortener/tests.py,sha256=NciCsZndnGrA-PJPBLuE0qrOOLtP50S0UUP77jExO1c,7909
shortener/urls.py,sha256=A2JsKCazqhXrBOBx9Inq8IovhTpNGa-ii4r-rY9VBVc,265
shortener/views.py,sha256=OVcOnp7mCByewsLpt3IL2G6376MUQxovEo7-ZA8sT9I,531
shortener/migrations/0001_initial.py,sha256=Fe8Sexd3KlA-SRs-xr2M0kClThEwJwzyvoMHblTjojU,1851
shortener/migrations/0002_auto_20190528_1522.py,sha256=XZIBeAqIxKsg1i0ONB-ioV-H8lnsp6CHCl7gxTlQTuo,1145
shortener/migrations/0003_auto_20190528_1558.py,sha256=wZHHGCw9tW3r8cMIzb3_KwPm2dSHvnjZygFFyYWm1uU,377
shortener/migrations/0004_alter_urlprofile_enabled.py,sha256=sxzE66v3mEmD84rCmdpq-s9oc7oShK6Zt6AtWQcr9Ho,404
shortener/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
django_link_shortener-0.5.dist-info/LICENSE,sha256=llXuiNIWrY4yw0XfIHUND69bCw52JFPJN-3hECSEKmE,1071
django_link_shortener-0.5.dist-info/METADATA,sha256=E_y3EFc7ZszwHC_YDFSz10S1PWJy0WFvdsY5djQqtds,5111
django_link_shortener-0.5.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
django_link_shortener-0.5.dist-info/top_level.txt,sha256=8fVZ-e_NjbMpSyO0G89mqIAHW-uQ6GeoU9HPaEkWukw,10
django_link_shortener-0.5.dist-info/RECORD,,
from django.test import TestCase
from shortener import shortener
from shortener.models import UrlProfile
from tests.testapp.models import CustomUser
import time
class UrlMapTestCase(TestCase):
def setUp(self):
self.bob = CustomUser.objects.create_user('bob', 'bob@bob.com', 'bobpassword')
self.alice = CustomUser.objects.create_user('alice', 'alice@alice.com', 'alicepassword')
def test_url_creation(self):
url = shortener.create(self.bob, "http://devget.net/")
self.assertEqual(shortener.expand(url), "http://devget.net/")
def test_invalid_link(self):
url = shortener.create(self.bob, "http://devget.net/")
self.assertEqual(shortener.expand(url), "http://devget.net/") # good shortlink
with self.assertRaisesMessage(KeyError, 'invalid shortlink'):
self.assertEqual(shortener.expand('photosynthesis'), "http://devget.net/") # bad shortlink
def test_shortener_enabled_setting(self):
with self.settings(SHORTENER_ENABLED=False):
with self.assertRaisesMessage(PermissionError, 'not authorized to create shortlinks'):
shortener.create(self.bob, "http://devget.net/")
def test_max_urls_setting(self):
with self.settings(SHORTENER_MAX_URLS=2):
shortener.create(self.bob, "http://devget.net/")
shortener.create(self.bob, "http://devget.net/")
with self.assertRaisesMessage(PermissionError, 'url quota exceeded'):
shortener.create(self.bob, "http://devget.net/")
def test_max_concurrent_setting(self):
with self.settings(SHORTENER_MAX_CONCURRENT=2):
shortener.create(self.bob, "http://devget.net/")
shortener.create(self.bob, "http://devget.net/")
with self.assertRaisesMessage(PermissionError, 'concurrent quota exceeded'):
shortener.create(self.bob, "http://devget.net/")
def test_lifespan_setting(self):
with self.settings(SHORTENER_LIFESPAN=4): # 4 seconds
url = shortener.create(self.bob, "http://blog.devget.net/")
self.assertEqual(shortener.expand(url), "http://blog.devget.net/")
time.sleep(5)
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=2):
url = shortener.create(self.bob, "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)
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)
shortener
Wheel-Version: 1.0
Generator: bdist_wheel (0.37.1)
Root-Is-Purelib: true
Tag: py3-none-any