initial commit

This commit is contained in:
Franzi 2025-06-15 11:27:37 +02:00
commit ce809235e5
Signed by: kunsi
GPG key ID: 12E3D2136B818350
34 changed files with 736 additions and 0 deletions

0
settings/__init__.py Normal file
View file

30
settings/admin.py Normal file
View file

@ -0,0 +1,30 @@
from django.contrib import admin
from .models import SIPAccount, SnomPhone, SnomPhoneType, SnomFunctionKey
class SnomFunctionKeyInline(admin.TabularInline):
model = SnomFunctionKey
@admin.display(description="SIP Account")
def sip_username_ip(obj):
return f"{obj.username}@{obj.ip}"
@admin.register(SIPAccount)
class SIPAccountAdmin(admin.ModelAdmin):
list_display = (sip_username_ip, 'display_name', 'tone_scheme')
list_filter = ('ip', 'tone_scheme')
@admin.register(SnomPhone)
class SnomPhoneAdmin(admin.ModelAdmin):
list_display = ('phone_name', 'mac_address', 'sip_account')
@admin.register(SnomPhoneType)
class SnomPhoneTypeAdmin(admin.ModelAdmin):
inlines = [
SnomFunctionKeyInline
]

6
settings/apps.py Normal file
View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class SettingsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'settings'

View file

@ -0,0 +1,37 @@
# Generated by Django 5.2.3 on 2025-06-15 08:00
import django.core.validators
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='SIPAccount',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ip', models.GenericIPAddressField()),
('username', models.CharField(max_length=255)),
('password', models.CharField(max_length=255)),
('display_name', models.CharField(max_length=255)),
('tone_scheme', models.CharField(max_length=10)),
],
),
migrations.CreateModel(
name='SnomPhone',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('mac_address', models.CharField(max_length=12, unique=True, validators=[django.core.validators.RegexValidator('^[0-9A-F]{12}$')])),
('phone_name', models.CharField(max_length=255)),
('admin_password', models.CharField(max_length=255)),
('sip_account', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='settings.sipaccount')),
],
),
]

View file

@ -0,0 +1,36 @@
# Generated by Django 5.2.3 on 2025-06-15 08:16
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('settings', '0001_initial'),
]
operations = [
migrations.AlterModelOptions(
name='sipaccount',
options={'ordering': ['display_name'], 'verbose_name': 'SIP Account', 'verbose_name_plural': 'SIP Accounts'},
),
migrations.AlterModelOptions(
name='snomphone',
options={'ordering': ['phone_name'], 'verbose_name': 'Snom Phone', 'verbose_name_plural': 'Snom Phones'},
),
migrations.RemoveField(
model_name='snomphone',
name='id',
),
migrations.AddField(
model_name='snomphone',
name='timezone',
field=models.CharField(default='GBR-0', help_text='https://service.snom.com/display/wiki/timezone', max_length=10),
),
migrations.AlterField(
model_name='snomphone',
name='mac_address',
field=models.CharField(max_length=12, primary_key=True, serialize=False, validators=[django.core.validators.RegexValidator('^[0-9A-F]{12}$')]),
),
]

View file

@ -0,0 +1,35 @@
# Generated by Django 5.2.3 on 2025-06-15 08:43
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('settings', '0002_alter_sipaccount_options_alter_snomphone_options_and_more'),
]
operations = [
migrations.CreateModel(
name='SnomPhoneType',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('model', models.CharField(max_length=255)),
],
),
migrations.CreateModel(
name='SnomFunctionKey',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('key_id', models.IntegerField()),
('label', models.CharField(max_length=255)),
('value', models.CharField(max_length=255)),
('phone_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='settings.snomphonetype')),
],
options={
'ordering': ['phone_type', 'key_id'],
'constraints': [models.UniqueConstraint(fields=('phone_type', 'key_id'), name='phone_type_key_id_unique')],
},
),
]

View file

@ -0,0 +1,20 @@
# Generated by Django 5.2.3 on 2025-06-15 08:50
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('settings', '0003_snomphonetype_snomfunctionkey'),
]
operations = [
migrations.AddField(
model_name='snomphone',
name='phone_type',
field=models.ForeignKey(default=0, on_delete=django.db.models.deletion.PROTECT, to='settings.snomphonetype'),
preserve_default=False,
),
]

View file

@ -0,0 +1,18 @@
# Generated by Django 5.2.3 on 2025-06-15 09:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('settings', '0004_snomphone_phone_type'),
]
operations = [
migrations.AddField(
model_name='snomphonetype',
name='phonebook_function_key',
field=models.IntegerField(default=-1, help_text='if set to anything >+0, phonebook will be provisioned on this key'),
),
]

View file

64
settings/models.py Normal file
View file

@ -0,0 +1,64 @@
from django.db import models
from django.core.validators import RegexValidator
class SIPAccount(models.Model):
ip = models.GenericIPAddressField()
username = models.CharField(max_length=255)
password = models.CharField(max_length=255)
display_name = models.CharField(max_length=255)
tone_scheme = models.CharField(max_length=10)
def __str__(self):
return f'{self.username}@{self.ip}'
class Meta:
verbose_name = "SIP Account"
verbose_name_plural = "SIP Accounts"
ordering = ['display_name']
class SnomPhoneType(models.Model):
model = models.CharField(max_length=255)
phonebook_function_key = models.IntegerField(default=-1, help_text='if set to anything >+0, phonebook will be provisioned on this key')
def __str__(self):
return self.model
class SnomFunctionKey(models.Model):
phone_type = models.ForeignKey(SnomPhoneType, on_delete=models.CASCADE)
key_id = models.IntegerField()
label = models.CharField(max_length=255)
value = models.CharField(max_length=255)
def __str__(self):
return f'{self.phone_type.model}:{self.key_id}'
class Meta:
ordering = ['phone_type', 'key_id']
constraints = [
models.UniqueConstraint(fields=['phone_type', 'key_id'], name='phone_type_key_id_unique')
]
class SnomPhone(models.Model):
mac_address = models.CharField(max_length=12, validators=[RegexValidator('^[0-9A-F]{12}$')], primary_key=True)
phone_name = models.CharField(max_length=255)
admin_password = models.CharField(max_length=255)
timezone = models.CharField(max_length=10, help_text="https://service.snom.com/display/wiki/timezone", default="GBR-0")
sip_account = models.ForeignKey(SIPAccount, on_delete=models.PROTECT)
phone_type = models.ForeignKey(SnomPhoneType, on_delete=models.PROTECT)
def __str__(self):
return self.phone_name
class Meta:
verbose_name = "Snom Phone"
verbose_name_plural = "Snom Phones"
ordering = ['phone_name']

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<settings>
<phone-settings>
<update_policy perm="R">auto_update</update_policy>
<phone_name perm="R">{{ settings.phone_name }}</phone_name>
<language perm="">English</language>
<web_language perm="">English</web_language>
<date_us_format perm="R">off</date_us_format>
<dialnumber_us_format perm="R">off</dialnumber_us_format>
<timezone>{{ settings.timezone }}</timezone>
<time_server perm="R">pool.ntp.org</time_server>
<tone_scheme perm="R">{{ settings.sip_account.tone_scheme }}</tone_scheme>
<user_name idx="1" perm="R">{{ settings.sip_account.username }}</user_name>
<user_pass idx="1" perm="R">{{ settings.sip_account.password }}</user_pass>
<user_host idx="1" perm="R">{{ settings.sip_account.ip }}</user_host>
<user_realname idx="1" perm="R">{{ settings.sip_account.display_name }}</user_realname>
<user_active idx="1" perm="R">on</user_active>
<functionKeys e="2">
{% for key in function_keys.all %}
{% if settings.phone_type.phonebook_function_key != key.key_id %}
<fkey idx="{{ key.key_id }}" context="active" label="{{ key.label}}" lp="on" default_text="$name" perm="R">{{ key.value }}</fkey>
{% endif %}
{% endfor %}
{% if settings.phone_type.phonebook_function_key >= 0 %}
<fkey idx="{{ settings.phone_type.phonebook_function_key }}" context="active" label="Phonebook" lp="on" default_text="$name" perm="R">url {{ phonebook_url }}</fkey>
{% endif %}
</functionKeys>
<admin_mode_password perm="R">{{ settings.admin_password }}</admin_mode_password>
<http_user perm="R">snom</http_user>
<http_pass perm="R">{{ settings.admin_password }}</http_pass>
</phone-settings>
</settings>

3
settings/tests.py Normal file
View file

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

7
settings/urls.py Normal file
View file

@ -0,0 +1,7 @@
from django.urls import path
from . import views
urlpatterns = [
path("settings-<str:mac_address>.xml", views.mac_settings, name="mac_settings"),
]

17
settings/views.py Normal file
View file

@ -0,0 +1,17 @@
from django.shortcuts import get_object_or_404, render
from settings.models import SnomPhone, SnomFunctionKey
from django.urls import reverse
def mac_settings(request, mac_address):
settings = get_object_or_404(SnomPhone, mac_address=mac_address)
function_keys = SnomFunctionKey.objects.filter(phone_type=settings.phone_type)
phonebook_url = request.build_absolute_uri(reverse("phonebook_index"))
context = {
"settings": settings,
"function_keys": function_keys,
"phonebook_url": phonebook_url,
}
return render(request, "settings/settings.xml", context, content_type="text/xml")