Compare commits
	
		
			17 Commits
		
	
	
		
			07f3881dde
			...
			306eb20257
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 306eb20257 | |||
| 5ae85083a5 | |||
| 1ac83f1066 | |||
| 7e0e6e9652 | |||
| ab1b152a46 | |||
| 8821cd86c6 | |||
| 4ea93c9eff | |||
| 40ca2064d9 | |||
| e840fbabac | |||
| ff2a8ff6d4 | |||
| d33256edb8 | |||
| 10b9e9280f | |||
| ee7f301f44 | |||
| 64984d69d5 | |||
| 4f856c0705 | |||
| 8b4da52760 | |||
| aa171375e5 | 
							
								
								
									
										4
									
								
								aircox/context_processors/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								aircox/context_processors/__init__.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
			
		||||
def station(request):
 | 
			
		||||
    station = request.station
 | 
			
		||||
    audio_streams = station.streams if station else None
 | 
			
		||||
    return {"station": station, "audio_streams": audio_streams}
 | 
			
		||||
@ -1,7 +1,12 @@
 | 
			
		||||
from django import forms
 | 
			
		||||
from django.forms import ModelForm
 | 
			
		||||
from django.forms import ModelForm, ImageField, FileField
 | 
			
		||||
 | 
			
		||||
from .models import Comment
 | 
			
		||||
from ckeditor.fields import RichTextField
 | 
			
		||||
from filer.models.imagemodels import Image
 | 
			
		||||
from filer.models.filemodels import File
 | 
			
		||||
 | 
			
		||||
from aircox.models import Comment, Episode, Program
 | 
			
		||||
from aircox.controllers.sound_file import SoundFile
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CommentForm(ModelForm):
 | 
			
		||||
@ -16,3 +21,38 @@ class CommentForm(ModelForm):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Comment
 | 
			
		||||
        fields = ["nickname", "email", "content"]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProgramForm(ModelForm):
 | 
			
		||||
    content = RichTextField()
 | 
			
		||||
    new_cover = ImageField(required=False)
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Program
 | 
			
		||||
        fields = ["content"]
 | 
			
		||||
 | 
			
		||||
    def save(self, commit=True):
 | 
			
		||||
        file_obj = self.cleaned_data["new_cover"]
 | 
			
		||||
        if file_obj:
 | 
			
		||||
            obj, _ = Image.objects.get_or_create(original_filename=file_obj.name, file=file_obj)
 | 
			
		||||
            self.instance.cover = obj
 | 
			
		||||
        super().save(commit=commit)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EpisodeForm(ModelForm):
 | 
			
		||||
    content = RichTextField()
 | 
			
		||||
    new_podcast = FileField(required=False)
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Episode
 | 
			
		||||
        fields = ["content"]
 | 
			
		||||
 | 
			
		||||
    def save(self, commit=True):
 | 
			
		||||
        file_obj = self.cleaned_data["new_podcast"]
 | 
			
		||||
        if file_obj:
 | 
			
		||||
            obj, _ = File.objects.get_or_create(original_filename=file_obj.name, file=file_obj)
 | 
			
		||||
            sound_file = SoundFile(obj.path)
 | 
			
		||||
            sound_file.sync(
 | 
			
		||||
                program=self.instance.program, episode=self.instance, type=0, is_public=True, is_downloadable=True
 | 
			
		||||
            )
 | 
			
		||||
        super().save(commit=commit)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										12
									
								
								aircox/migrations/0019_merge_20240119_1022.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								aircox/migrations/0019_merge_20240119_1022.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
# Generated by Django 4.2.7 on 2024-01-19 09:22
 | 
			
		||||
 | 
			
		||||
from django.db import migrations
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ("aircox", "0015_program_editors"),
 | 
			
		||||
        ("aircox", "0018_alter_staticpage_attach_to"),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = []
 | 
			
		||||
							
								
								
									
										12
									
								
								aircox/migrations/0020_merge_20240205_1027.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								aircox/migrations/0020_merge_20240205_1027.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
# Generated by Django 4.2.7 on 2024-02-05 09:27
 | 
			
		||||
 | 
			
		||||
from django.db import migrations
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ("aircox", "0019_merge_20240119_1022"),
 | 
			
		||||
        ("aircox", "0019_station_program_streams_title_and_more"),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = []
 | 
			
		||||
							
								
								
									
										623
									
								
								aircox/migrations/0021_alter_schedule_timezone.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										623
									
								
								aircox/migrations/0021_alter_schedule_timezone.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,623 @@
 | 
			
		||||
# Generated by Django 4.2.7 on 2024-02-06 08:13
 | 
			
		||||
 | 
			
		||||
import aircox.models.schedule
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ("aircox", "0020_merge_20240205_1027"),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name="schedule",
 | 
			
		||||
            name="timezone",
 | 
			
		||||
            field=models.CharField(
 | 
			
		||||
                choices=[
 | 
			
		||||
                    ("Africa/Abidjan", "Africa/Abidjan"),
 | 
			
		||||
                    ("Africa/Accra", "Africa/Accra"),
 | 
			
		||||
                    ("Africa/Addis_Ababa", "Africa/Addis_Ababa"),
 | 
			
		||||
                    ("Africa/Algiers", "Africa/Algiers"),
 | 
			
		||||
                    ("Africa/Asmara", "Africa/Asmara"),
 | 
			
		||||
                    ("Africa/Asmera", "Africa/Asmera"),
 | 
			
		||||
                    ("Africa/Bamako", "Africa/Bamako"),
 | 
			
		||||
                    ("Africa/Bangui", "Africa/Bangui"),
 | 
			
		||||
                    ("Africa/Banjul", "Africa/Banjul"),
 | 
			
		||||
                    ("Africa/Bissau", "Africa/Bissau"),
 | 
			
		||||
                    ("Africa/Blantyre", "Africa/Blantyre"),
 | 
			
		||||
                    ("Africa/Brazzaville", "Africa/Brazzaville"),
 | 
			
		||||
                    ("Africa/Bujumbura", "Africa/Bujumbura"),
 | 
			
		||||
                    ("Africa/Cairo", "Africa/Cairo"),
 | 
			
		||||
                    ("Africa/Casablanca", "Africa/Casablanca"),
 | 
			
		||||
                    ("Africa/Ceuta", "Africa/Ceuta"),
 | 
			
		||||
                    ("Africa/Conakry", "Africa/Conakry"),
 | 
			
		||||
                    ("Africa/Dakar", "Africa/Dakar"),
 | 
			
		||||
                    ("Africa/Dar_es_Salaam", "Africa/Dar_es_Salaam"),
 | 
			
		||||
                    ("Africa/Djibouti", "Africa/Djibouti"),
 | 
			
		||||
                    ("Africa/Douala", "Africa/Douala"),
 | 
			
		||||
                    ("Africa/El_Aaiun", "Africa/El_Aaiun"),
 | 
			
		||||
                    ("Africa/Freetown", "Africa/Freetown"),
 | 
			
		||||
                    ("Africa/Gaborone", "Africa/Gaborone"),
 | 
			
		||||
                    ("Africa/Harare", "Africa/Harare"),
 | 
			
		||||
                    ("Africa/Johannesburg", "Africa/Johannesburg"),
 | 
			
		||||
                    ("Africa/Juba", "Africa/Juba"),
 | 
			
		||||
                    ("Africa/Kampala", "Africa/Kampala"),
 | 
			
		||||
                    ("Africa/Khartoum", "Africa/Khartoum"),
 | 
			
		||||
                    ("Africa/Kigali", "Africa/Kigali"),
 | 
			
		||||
                    ("Africa/Kinshasa", "Africa/Kinshasa"),
 | 
			
		||||
                    ("Africa/Lagos", "Africa/Lagos"),
 | 
			
		||||
                    ("Africa/Libreville", "Africa/Libreville"),
 | 
			
		||||
                    ("Africa/Lome", "Africa/Lome"),
 | 
			
		||||
                    ("Africa/Luanda", "Africa/Luanda"),
 | 
			
		||||
                    ("Africa/Lubumbashi", "Africa/Lubumbashi"),
 | 
			
		||||
                    ("Africa/Lusaka", "Africa/Lusaka"),
 | 
			
		||||
                    ("Africa/Malabo", "Africa/Malabo"),
 | 
			
		||||
                    ("Africa/Maputo", "Africa/Maputo"),
 | 
			
		||||
                    ("Africa/Maseru", "Africa/Maseru"),
 | 
			
		||||
                    ("Africa/Mbabane", "Africa/Mbabane"),
 | 
			
		||||
                    ("Africa/Mogadishu", "Africa/Mogadishu"),
 | 
			
		||||
                    ("Africa/Monrovia", "Africa/Monrovia"),
 | 
			
		||||
                    ("Africa/Nairobi", "Africa/Nairobi"),
 | 
			
		||||
                    ("Africa/Ndjamena", "Africa/Ndjamena"),
 | 
			
		||||
                    ("Africa/Niamey", "Africa/Niamey"),
 | 
			
		||||
                    ("Africa/Nouakchott", "Africa/Nouakchott"),
 | 
			
		||||
                    ("Africa/Ouagadougou", "Africa/Ouagadougou"),
 | 
			
		||||
                    ("Africa/Porto-Novo", "Africa/Porto-Novo"),
 | 
			
		||||
                    ("Africa/Sao_Tome", "Africa/Sao_Tome"),
 | 
			
		||||
                    ("Africa/Timbuktu", "Africa/Timbuktu"),
 | 
			
		||||
                    ("Africa/Tripoli", "Africa/Tripoli"),
 | 
			
		||||
                    ("Africa/Tunis", "Africa/Tunis"),
 | 
			
		||||
                    ("Africa/Windhoek", "Africa/Windhoek"),
 | 
			
		||||
                    ("America/Adak", "America/Adak"),
 | 
			
		||||
                    ("America/Anchorage", "America/Anchorage"),
 | 
			
		||||
                    ("America/Anguilla", "America/Anguilla"),
 | 
			
		||||
                    ("America/Antigua", "America/Antigua"),
 | 
			
		||||
                    ("America/Araguaina", "America/Araguaina"),
 | 
			
		||||
                    ("America/Argentina/Buenos_Aires", "America/Argentina/Buenos_Aires"),
 | 
			
		||||
                    ("America/Argentina/Catamarca", "America/Argentina/Catamarca"),
 | 
			
		||||
                    ("America/Argentina/ComodRivadavia", "America/Argentina/ComodRivadavia"),
 | 
			
		||||
                    ("America/Argentina/Cordoba", "America/Argentina/Cordoba"),
 | 
			
		||||
                    ("America/Argentina/Jujuy", "America/Argentina/Jujuy"),
 | 
			
		||||
                    ("America/Argentina/La_Rioja", "America/Argentina/La_Rioja"),
 | 
			
		||||
                    ("America/Argentina/Mendoza", "America/Argentina/Mendoza"),
 | 
			
		||||
                    ("America/Argentina/Rio_Gallegos", "America/Argentina/Rio_Gallegos"),
 | 
			
		||||
                    ("America/Argentina/Salta", "America/Argentina/Salta"),
 | 
			
		||||
                    ("America/Argentina/San_Juan", "America/Argentina/San_Juan"),
 | 
			
		||||
                    ("America/Argentina/San_Luis", "America/Argentina/San_Luis"),
 | 
			
		||||
                    ("America/Argentina/Tucuman", "America/Argentina/Tucuman"),
 | 
			
		||||
                    ("America/Argentina/Ushuaia", "America/Argentina/Ushuaia"),
 | 
			
		||||
                    ("America/Aruba", "America/Aruba"),
 | 
			
		||||
                    ("America/Asuncion", "America/Asuncion"),
 | 
			
		||||
                    ("America/Atikokan", "America/Atikokan"),
 | 
			
		||||
                    ("America/Atka", "America/Atka"),
 | 
			
		||||
                    ("America/Bahia", "America/Bahia"),
 | 
			
		||||
                    ("America/Bahia_Banderas", "America/Bahia_Banderas"),
 | 
			
		||||
                    ("America/Barbados", "America/Barbados"),
 | 
			
		||||
                    ("America/Belem", "America/Belem"),
 | 
			
		||||
                    ("America/Belize", "America/Belize"),
 | 
			
		||||
                    ("America/Blanc-Sablon", "America/Blanc-Sablon"),
 | 
			
		||||
                    ("America/Boa_Vista", "America/Boa_Vista"),
 | 
			
		||||
                    ("America/Bogota", "America/Bogota"),
 | 
			
		||||
                    ("America/Boise", "America/Boise"),
 | 
			
		||||
                    ("America/Buenos_Aires", "America/Buenos_Aires"),
 | 
			
		||||
                    ("America/Cambridge_Bay", "America/Cambridge_Bay"),
 | 
			
		||||
                    ("America/Campo_Grande", "America/Campo_Grande"),
 | 
			
		||||
                    ("America/Cancun", "America/Cancun"),
 | 
			
		||||
                    ("America/Caracas", "America/Caracas"),
 | 
			
		||||
                    ("America/Catamarca", "America/Catamarca"),
 | 
			
		||||
                    ("America/Cayenne", "America/Cayenne"),
 | 
			
		||||
                    ("America/Cayman", "America/Cayman"),
 | 
			
		||||
                    ("America/Chicago", "America/Chicago"),
 | 
			
		||||
                    ("America/Chihuahua", "America/Chihuahua"),
 | 
			
		||||
                    ("America/Ciudad_Juarez", "America/Ciudad_Juarez"),
 | 
			
		||||
                    ("America/Coral_Harbour", "America/Coral_Harbour"),
 | 
			
		||||
                    ("America/Cordoba", "America/Cordoba"),
 | 
			
		||||
                    ("America/Costa_Rica", "America/Costa_Rica"),
 | 
			
		||||
                    ("America/Creston", "America/Creston"),
 | 
			
		||||
                    ("America/Cuiaba", "America/Cuiaba"),
 | 
			
		||||
                    ("America/Curacao", "America/Curacao"),
 | 
			
		||||
                    ("America/Danmarkshavn", "America/Danmarkshavn"),
 | 
			
		||||
                    ("America/Dawson", "America/Dawson"),
 | 
			
		||||
                    ("America/Dawson_Creek", "America/Dawson_Creek"),
 | 
			
		||||
                    ("America/Denver", "America/Denver"),
 | 
			
		||||
                    ("America/Detroit", "America/Detroit"),
 | 
			
		||||
                    ("America/Dominica", "America/Dominica"),
 | 
			
		||||
                    ("America/Edmonton", "America/Edmonton"),
 | 
			
		||||
                    ("America/Eirunepe", "America/Eirunepe"),
 | 
			
		||||
                    ("America/El_Salvador", "America/El_Salvador"),
 | 
			
		||||
                    ("America/Ensenada", "America/Ensenada"),
 | 
			
		||||
                    ("America/Fort_Nelson", "America/Fort_Nelson"),
 | 
			
		||||
                    ("America/Fort_Wayne", "America/Fort_Wayne"),
 | 
			
		||||
                    ("America/Fortaleza", "America/Fortaleza"),
 | 
			
		||||
                    ("America/Glace_Bay", "America/Glace_Bay"),
 | 
			
		||||
                    ("America/Godthab", "America/Godthab"),
 | 
			
		||||
                    ("America/Goose_Bay", "America/Goose_Bay"),
 | 
			
		||||
                    ("America/Grand_Turk", "America/Grand_Turk"),
 | 
			
		||||
                    ("America/Grenada", "America/Grenada"),
 | 
			
		||||
                    ("America/Guadeloupe", "America/Guadeloupe"),
 | 
			
		||||
                    ("America/Guatemala", "America/Guatemala"),
 | 
			
		||||
                    ("America/Guayaquil", "America/Guayaquil"),
 | 
			
		||||
                    ("America/Guyana", "America/Guyana"),
 | 
			
		||||
                    ("America/Halifax", "America/Halifax"),
 | 
			
		||||
                    ("America/Havana", "America/Havana"),
 | 
			
		||||
                    ("America/Hermosillo", "America/Hermosillo"),
 | 
			
		||||
                    ("America/Indiana/Indianapolis", "America/Indiana/Indianapolis"),
 | 
			
		||||
                    ("America/Indiana/Knox", "America/Indiana/Knox"),
 | 
			
		||||
                    ("America/Indiana/Marengo", "America/Indiana/Marengo"),
 | 
			
		||||
                    ("America/Indiana/Petersburg", "America/Indiana/Petersburg"),
 | 
			
		||||
                    ("America/Indiana/Tell_City", "America/Indiana/Tell_City"),
 | 
			
		||||
                    ("America/Indiana/Vevay", "America/Indiana/Vevay"),
 | 
			
		||||
                    ("America/Indiana/Vincennes", "America/Indiana/Vincennes"),
 | 
			
		||||
                    ("America/Indiana/Winamac", "America/Indiana/Winamac"),
 | 
			
		||||
                    ("America/Indianapolis", "America/Indianapolis"),
 | 
			
		||||
                    ("America/Inuvik", "America/Inuvik"),
 | 
			
		||||
                    ("America/Iqaluit", "America/Iqaluit"),
 | 
			
		||||
                    ("America/Jamaica", "America/Jamaica"),
 | 
			
		||||
                    ("America/Jujuy", "America/Jujuy"),
 | 
			
		||||
                    ("America/Juneau", "America/Juneau"),
 | 
			
		||||
                    ("America/Kentucky/Louisville", "America/Kentucky/Louisville"),
 | 
			
		||||
                    ("America/Kentucky/Monticello", "America/Kentucky/Monticello"),
 | 
			
		||||
                    ("America/Knox_IN", "America/Knox_IN"),
 | 
			
		||||
                    ("America/Kralendijk", "America/Kralendijk"),
 | 
			
		||||
                    ("America/La_Paz", "America/La_Paz"),
 | 
			
		||||
                    ("America/Lima", "America/Lima"),
 | 
			
		||||
                    ("America/Los_Angeles", "America/Los_Angeles"),
 | 
			
		||||
                    ("America/Louisville", "America/Louisville"),
 | 
			
		||||
                    ("America/Lower_Princes", "America/Lower_Princes"),
 | 
			
		||||
                    ("America/Maceio", "America/Maceio"),
 | 
			
		||||
                    ("America/Managua", "America/Managua"),
 | 
			
		||||
                    ("America/Manaus", "America/Manaus"),
 | 
			
		||||
                    ("America/Marigot", "America/Marigot"),
 | 
			
		||||
                    ("America/Martinique", "America/Martinique"),
 | 
			
		||||
                    ("America/Matamoros", "America/Matamoros"),
 | 
			
		||||
                    ("America/Mazatlan", "America/Mazatlan"),
 | 
			
		||||
                    ("America/Mendoza", "America/Mendoza"),
 | 
			
		||||
                    ("America/Menominee", "America/Menominee"),
 | 
			
		||||
                    ("America/Merida", "America/Merida"),
 | 
			
		||||
                    ("America/Metlakatla", "America/Metlakatla"),
 | 
			
		||||
                    ("America/Mexico_City", "America/Mexico_City"),
 | 
			
		||||
                    ("America/Miquelon", "America/Miquelon"),
 | 
			
		||||
                    ("America/Moncton", "America/Moncton"),
 | 
			
		||||
                    ("America/Monterrey", "America/Monterrey"),
 | 
			
		||||
                    ("America/Montevideo", "America/Montevideo"),
 | 
			
		||||
                    ("America/Montreal", "America/Montreal"),
 | 
			
		||||
                    ("America/Montserrat", "America/Montserrat"),
 | 
			
		||||
                    ("America/Nassau", "America/Nassau"),
 | 
			
		||||
                    ("America/New_York", "America/New_York"),
 | 
			
		||||
                    ("America/Nipigon", "America/Nipigon"),
 | 
			
		||||
                    ("America/Nome", "America/Nome"),
 | 
			
		||||
                    ("America/Noronha", "America/Noronha"),
 | 
			
		||||
                    ("America/North_Dakota/Beulah", "America/North_Dakota/Beulah"),
 | 
			
		||||
                    ("America/North_Dakota/Center", "America/North_Dakota/Center"),
 | 
			
		||||
                    ("America/North_Dakota/New_Salem", "America/North_Dakota/New_Salem"),
 | 
			
		||||
                    ("America/Nuuk", "America/Nuuk"),
 | 
			
		||||
                    ("America/Ojinaga", "America/Ojinaga"),
 | 
			
		||||
                    ("America/Panama", "America/Panama"),
 | 
			
		||||
                    ("America/Pangnirtung", "America/Pangnirtung"),
 | 
			
		||||
                    ("America/Paramaribo", "America/Paramaribo"),
 | 
			
		||||
                    ("America/Phoenix", "America/Phoenix"),
 | 
			
		||||
                    ("America/Port-au-Prince", "America/Port-au-Prince"),
 | 
			
		||||
                    ("America/Port_of_Spain", "America/Port_of_Spain"),
 | 
			
		||||
                    ("America/Porto_Acre", "America/Porto_Acre"),
 | 
			
		||||
                    ("America/Porto_Velho", "America/Porto_Velho"),
 | 
			
		||||
                    ("America/Puerto_Rico", "America/Puerto_Rico"),
 | 
			
		||||
                    ("America/Punta_Arenas", "America/Punta_Arenas"),
 | 
			
		||||
                    ("America/Rainy_River", "America/Rainy_River"),
 | 
			
		||||
                    ("America/Rankin_Inlet", "America/Rankin_Inlet"),
 | 
			
		||||
                    ("America/Recife", "America/Recife"),
 | 
			
		||||
                    ("America/Regina", "America/Regina"),
 | 
			
		||||
                    ("America/Resolute", "America/Resolute"),
 | 
			
		||||
                    ("America/Rio_Branco", "America/Rio_Branco"),
 | 
			
		||||
                    ("America/Rosario", "America/Rosario"),
 | 
			
		||||
                    ("America/Santa_Isabel", "America/Santa_Isabel"),
 | 
			
		||||
                    ("America/Santarem", "America/Santarem"),
 | 
			
		||||
                    ("America/Santiago", "America/Santiago"),
 | 
			
		||||
                    ("America/Santo_Domingo", "America/Santo_Domingo"),
 | 
			
		||||
                    ("America/Sao_Paulo", "America/Sao_Paulo"),
 | 
			
		||||
                    ("America/Scoresbysund", "America/Scoresbysund"),
 | 
			
		||||
                    ("America/Shiprock", "America/Shiprock"),
 | 
			
		||||
                    ("America/Sitka", "America/Sitka"),
 | 
			
		||||
                    ("America/St_Barthelemy", "America/St_Barthelemy"),
 | 
			
		||||
                    ("America/St_Johns", "America/St_Johns"),
 | 
			
		||||
                    ("America/St_Kitts", "America/St_Kitts"),
 | 
			
		||||
                    ("America/St_Lucia", "America/St_Lucia"),
 | 
			
		||||
                    ("America/St_Thomas", "America/St_Thomas"),
 | 
			
		||||
                    ("America/St_Vincent", "America/St_Vincent"),
 | 
			
		||||
                    ("America/Swift_Current", "America/Swift_Current"),
 | 
			
		||||
                    ("America/Tegucigalpa", "America/Tegucigalpa"),
 | 
			
		||||
                    ("America/Thule", "America/Thule"),
 | 
			
		||||
                    ("America/Thunder_Bay", "America/Thunder_Bay"),
 | 
			
		||||
                    ("America/Tijuana", "America/Tijuana"),
 | 
			
		||||
                    ("America/Toronto", "America/Toronto"),
 | 
			
		||||
                    ("America/Tortola", "America/Tortola"),
 | 
			
		||||
                    ("America/Vancouver", "America/Vancouver"),
 | 
			
		||||
                    ("America/Virgin", "America/Virgin"),
 | 
			
		||||
                    ("America/Whitehorse", "America/Whitehorse"),
 | 
			
		||||
                    ("America/Winnipeg", "America/Winnipeg"),
 | 
			
		||||
                    ("America/Yakutat", "America/Yakutat"),
 | 
			
		||||
                    ("America/Yellowknife", "America/Yellowknife"),
 | 
			
		||||
                    ("Antarctica/Casey", "Antarctica/Casey"),
 | 
			
		||||
                    ("Antarctica/Davis", "Antarctica/Davis"),
 | 
			
		||||
                    ("Antarctica/DumontDUrville", "Antarctica/DumontDUrville"),
 | 
			
		||||
                    ("Antarctica/Macquarie", "Antarctica/Macquarie"),
 | 
			
		||||
                    ("Antarctica/Mawson", "Antarctica/Mawson"),
 | 
			
		||||
                    ("Antarctica/McMurdo", "Antarctica/McMurdo"),
 | 
			
		||||
                    ("Antarctica/Palmer", "Antarctica/Palmer"),
 | 
			
		||||
                    ("Antarctica/Rothera", "Antarctica/Rothera"),
 | 
			
		||||
                    ("Antarctica/South_Pole", "Antarctica/South_Pole"),
 | 
			
		||||
                    ("Antarctica/Syowa", "Antarctica/Syowa"),
 | 
			
		||||
                    ("Antarctica/Troll", "Antarctica/Troll"),
 | 
			
		||||
                    ("Antarctica/Vostok", "Antarctica/Vostok"),
 | 
			
		||||
                    ("Arctic/Longyearbyen", "Arctic/Longyearbyen"),
 | 
			
		||||
                    ("Asia/Aden", "Asia/Aden"),
 | 
			
		||||
                    ("Asia/Almaty", "Asia/Almaty"),
 | 
			
		||||
                    ("Asia/Amman", "Asia/Amman"),
 | 
			
		||||
                    ("Asia/Anadyr", "Asia/Anadyr"),
 | 
			
		||||
                    ("Asia/Aqtau", "Asia/Aqtau"),
 | 
			
		||||
                    ("Asia/Aqtobe", "Asia/Aqtobe"),
 | 
			
		||||
                    ("Asia/Ashgabat", "Asia/Ashgabat"),
 | 
			
		||||
                    ("Asia/Ashkhabad", "Asia/Ashkhabad"),
 | 
			
		||||
                    ("Asia/Atyrau", "Asia/Atyrau"),
 | 
			
		||||
                    ("Asia/Baghdad", "Asia/Baghdad"),
 | 
			
		||||
                    ("Asia/Bahrain", "Asia/Bahrain"),
 | 
			
		||||
                    ("Asia/Baku", "Asia/Baku"),
 | 
			
		||||
                    ("Asia/Bangkok", "Asia/Bangkok"),
 | 
			
		||||
                    ("Asia/Barnaul", "Asia/Barnaul"),
 | 
			
		||||
                    ("Asia/Beirut", "Asia/Beirut"),
 | 
			
		||||
                    ("Asia/Bishkek", "Asia/Bishkek"),
 | 
			
		||||
                    ("Asia/Brunei", "Asia/Brunei"),
 | 
			
		||||
                    ("Asia/Calcutta", "Asia/Calcutta"),
 | 
			
		||||
                    ("Asia/Chita", "Asia/Chita"),
 | 
			
		||||
                    ("Asia/Choibalsan", "Asia/Choibalsan"),
 | 
			
		||||
                    ("Asia/Chongqing", "Asia/Chongqing"),
 | 
			
		||||
                    ("Asia/Chungking", "Asia/Chungking"),
 | 
			
		||||
                    ("Asia/Colombo", "Asia/Colombo"),
 | 
			
		||||
                    ("Asia/Dacca", "Asia/Dacca"),
 | 
			
		||||
                    ("Asia/Damascus", "Asia/Damascus"),
 | 
			
		||||
                    ("Asia/Dhaka", "Asia/Dhaka"),
 | 
			
		||||
                    ("Asia/Dili", "Asia/Dili"),
 | 
			
		||||
                    ("Asia/Dubai", "Asia/Dubai"),
 | 
			
		||||
                    ("Asia/Dushanbe", "Asia/Dushanbe"),
 | 
			
		||||
                    ("Asia/Famagusta", "Asia/Famagusta"),
 | 
			
		||||
                    ("Asia/Gaza", "Asia/Gaza"),
 | 
			
		||||
                    ("Asia/Harbin", "Asia/Harbin"),
 | 
			
		||||
                    ("Asia/Hebron", "Asia/Hebron"),
 | 
			
		||||
                    ("Asia/Ho_Chi_Minh", "Asia/Ho_Chi_Minh"),
 | 
			
		||||
                    ("Asia/Hong_Kong", "Asia/Hong_Kong"),
 | 
			
		||||
                    ("Asia/Hovd", "Asia/Hovd"),
 | 
			
		||||
                    ("Asia/Irkutsk", "Asia/Irkutsk"),
 | 
			
		||||
                    ("Asia/Istanbul", "Asia/Istanbul"),
 | 
			
		||||
                    ("Asia/Jakarta", "Asia/Jakarta"),
 | 
			
		||||
                    ("Asia/Jayapura", "Asia/Jayapura"),
 | 
			
		||||
                    ("Asia/Jerusalem", "Asia/Jerusalem"),
 | 
			
		||||
                    ("Asia/Kabul", "Asia/Kabul"),
 | 
			
		||||
                    ("Asia/Kamchatka", "Asia/Kamchatka"),
 | 
			
		||||
                    ("Asia/Karachi", "Asia/Karachi"),
 | 
			
		||||
                    ("Asia/Kashgar", "Asia/Kashgar"),
 | 
			
		||||
                    ("Asia/Kathmandu", "Asia/Kathmandu"),
 | 
			
		||||
                    ("Asia/Katmandu", "Asia/Katmandu"),
 | 
			
		||||
                    ("Asia/Khandyga", "Asia/Khandyga"),
 | 
			
		||||
                    ("Asia/Kolkata", "Asia/Kolkata"),
 | 
			
		||||
                    ("Asia/Krasnoyarsk", "Asia/Krasnoyarsk"),
 | 
			
		||||
                    ("Asia/Kuala_Lumpur", "Asia/Kuala_Lumpur"),
 | 
			
		||||
                    ("Asia/Kuching", "Asia/Kuching"),
 | 
			
		||||
                    ("Asia/Kuwait", "Asia/Kuwait"),
 | 
			
		||||
                    ("Asia/Macao", "Asia/Macao"),
 | 
			
		||||
                    ("Asia/Macau", "Asia/Macau"),
 | 
			
		||||
                    ("Asia/Magadan", "Asia/Magadan"),
 | 
			
		||||
                    ("Asia/Makassar", "Asia/Makassar"),
 | 
			
		||||
                    ("Asia/Manila", "Asia/Manila"),
 | 
			
		||||
                    ("Asia/Muscat", "Asia/Muscat"),
 | 
			
		||||
                    ("Asia/Nicosia", "Asia/Nicosia"),
 | 
			
		||||
                    ("Asia/Novokuznetsk", "Asia/Novokuznetsk"),
 | 
			
		||||
                    ("Asia/Novosibirsk", "Asia/Novosibirsk"),
 | 
			
		||||
                    ("Asia/Omsk", "Asia/Omsk"),
 | 
			
		||||
                    ("Asia/Oral", "Asia/Oral"),
 | 
			
		||||
                    ("Asia/Phnom_Penh", "Asia/Phnom_Penh"),
 | 
			
		||||
                    ("Asia/Pontianak", "Asia/Pontianak"),
 | 
			
		||||
                    ("Asia/Pyongyang", "Asia/Pyongyang"),
 | 
			
		||||
                    ("Asia/Qatar", "Asia/Qatar"),
 | 
			
		||||
                    ("Asia/Qostanay", "Asia/Qostanay"),
 | 
			
		||||
                    ("Asia/Qyzylorda", "Asia/Qyzylorda"),
 | 
			
		||||
                    ("Asia/Rangoon", "Asia/Rangoon"),
 | 
			
		||||
                    ("Asia/Riyadh", "Asia/Riyadh"),
 | 
			
		||||
                    ("Asia/Saigon", "Asia/Saigon"),
 | 
			
		||||
                    ("Asia/Sakhalin", "Asia/Sakhalin"),
 | 
			
		||||
                    ("Asia/Samarkand", "Asia/Samarkand"),
 | 
			
		||||
                    ("Asia/Seoul", "Asia/Seoul"),
 | 
			
		||||
                    ("Asia/Shanghai", "Asia/Shanghai"),
 | 
			
		||||
                    ("Asia/Singapore", "Asia/Singapore"),
 | 
			
		||||
                    ("Asia/Srednekolymsk", "Asia/Srednekolymsk"),
 | 
			
		||||
                    ("Asia/Taipei", "Asia/Taipei"),
 | 
			
		||||
                    ("Asia/Tashkent", "Asia/Tashkent"),
 | 
			
		||||
                    ("Asia/Tbilisi", "Asia/Tbilisi"),
 | 
			
		||||
                    ("Asia/Tehran", "Asia/Tehran"),
 | 
			
		||||
                    ("Asia/Tel_Aviv", "Asia/Tel_Aviv"),
 | 
			
		||||
                    ("Asia/Thimbu", "Asia/Thimbu"),
 | 
			
		||||
                    ("Asia/Thimphu", "Asia/Thimphu"),
 | 
			
		||||
                    ("Asia/Tokyo", "Asia/Tokyo"),
 | 
			
		||||
                    ("Asia/Tomsk", "Asia/Tomsk"),
 | 
			
		||||
                    ("Asia/Ujung_Pandang", "Asia/Ujung_Pandang"),
 | 
			
		||||
                    ("Asia/Ulaanbaatar", "Asia/Ulaanbaatar"),
 | 
			
		||||
                    ("Asia/Ulan_Bator", "Asia/Ulan_Bator"),
 | 
			
		||||
                    ("Asia/Urumqi", "Asia/Urumqi"),
 | 
			
		||||
                    ("Asia/Ust-Nera", "Asia/Ust-Nera"),
 | 
			
		||||
                    ("Asia/Vientiane", "Asia/Vientiane"),
 | 
			
		||||
                    ("Asia/Vladivostok", "Asia/Vladivostok"),
 | 
			
		||||
                    ("Asia/Yakutsk", "Asia/Yakutsk"),
 | 
			
		||||
                    ("Asia/Yangon", "Asia/Yangon"),
 | 
			
		||||
                    ("Asia/Yekaterinburg", "Asia/Yekaterinburg"),
 | 
			
		||||
                    ("Asia/Yerevan", "Asia/Yerevan"),
 | 
			
		||||
                    ("Atlantic/Azores", "Atlantic/Azores"),
 | 
			
		||||
                    ("Atlantic/Bermuda", "Atlantic/Bermuda"),
 | 
			
		||||
                    ("Atlantic/Canary", "Atlantic/Canary"),
 | 
			
		||||
                    ("Atlantic/Cape_Verde", "Atlantic/Cape_Verde"),
 | 
			
		||||
                    ("Atlantic/Faeroe", "Atlantic/Faeroe"),
 | 
			
		||||
                    ("Atlantic/Faroe", "Atlantic/Faroe"),
 | 
			
		||||
                    ("Atlantic/Jan_Mayen", "Atlantic/Jan_Mayen"),
 | 
			
		||||
                    ("Atlantic/Madeira", "Atlantic/Madeira"),
 | 
			
		||||
                    ("Atlantic/Reykjavik", "Atlantic/Reykjavik"),
 | 
			
		||||
                    ("Atlantic/South_Georgia", "Atlantic/South_Georgia"),
 | 
			
		||||
                    ("Atlantic/St_Helena", "Atlantic/St_Helena"),
 | 
			
		||||
                    ("Atlantic/Stanley", "Atlantic/Stanley"),
 | 
			
		||||
                    ("Australia/ACT", "Australia/ACT"),
 | 
			
		||||
                    ("Australia/Adelaide", "Australia/Adelaide"),
 | 
			
		||||
                    ("Australia/Brisbane", "Australia/Brisbane"),
 | 
			
		||||
                    ("Australia/Broken_Hill", "Australia/Broken_Hill"),
 | 
			
		||||
                    ("Australia/Canberra", "Australia/Canberra"),
 | 
			
		||||
                    ("Australia/Currie", "Australia/Currie"),
 | 
			
		||||
                    ("Australia/Darwin", "Australia/Darwin"),
 | 
			
		||||
                    ("Australia/Eucla", "Australia/Eucla"),
 | 
			
		||||
                    ("Australia/Hobart", "Australia/Hobart"),
 | 
			
		||||
                    ("Australia/LHI", "Australia/LHI"),
 | 
			
		||||
                    ("Australia/Lindeman", "Australia/Lindeman"),
 | 
			
		||||
                    ("Australia/Lord_Howe", "Australia/Lord_Howe"),
 | 
			
		||||
                    ("Australia/Melbourne", "Australia/Melbourne"),
 | 
			
		||||
                    ("Australia/NSW", "Australia/NSW"),
 | 
			
		||||
                    ("Australia/North", "Australia/North"),
 | 
			
		||||
                    ("Australia/Perth", "Australia/Perth"),
 | 
			
		||||
                    ("Australia/Queensland", "Australia/Queensland"),
 | 
			
		||||
                    ("Australia/South", "Australia/South"),
 | 
			
		||||
                    ("Australia/Sydney", "Australia/Sydney"),
 | 
			
		||||
                    ("Australia/Tasmania", "Australia/Tasmania"),
 | 
			
		||||
                    ("Australia/Victoria", "Australia/Victoria"),
 | 
			
		||||
                    ("Australia/West", "Australia/West"),
 | 
			
		||||
                    ("Australia/Yancowinna", "Australia/Yancowinna"),
 | 
			
		||||
                    ("Brazil/Acre", "Brazil/Acre"),
 | 
			
		||||
                    ("Brazil/DeNoronha", "Brazil/DeNoronha"),
 | 
			
		||||
                    ("Brazil/East", "Brazil/East"),
 | 
			
		||||
                    ("Brazil/West", "Brazil/West"),
 | 
			
		||||
                    ("CET", "CET"),
 | 
			
		||||
                    ("CST6CDT", "CST6CDT"),
 | 
			
		||||
                    ("Canada/Atlantic", "Canada/Atlantic"),
 | 
			
		||||
                    ("Canada/Central", "Canada/Central"),
 | 
			
		||||
                    ("Canada/Eastern", "Canada/Eastern"),
 | 
			
		||||
                    ("Canada/Mountain", "Canada/Mountain"),
 | 
			
		||||
                    ("Canada/Newfoundland", "Canada/Newfoundland"),
 | 
			
		||||
                    ("Canada/Pacific", "Canada/Pacific"),
 | 
			
		||||
                    ("Canada/Saskatchewan", "Canada/Saskatchewan"),
 | 
			
		||||
                    ("Canada/Yukon", "Canada/Yukon"),
 | 
			
		||||
                    ("Chile/Continental", "Chile/Continental"),
 | 
			
		||||
                    ("Chile/EasterIsland", "Chile/EasterIsland"),
 | 
			
		||||
                    ("Cuba", "Cuba"),
 | 
			
		||||
                    ("EET", "EET"),
 | 
			
		||||
                    ("EST", "EST"),
 | 
			
		||||
                    ("EST5EDT", "EST5EDT"),
 | 
			
		||||
                    ("Egypt", "Egypt"),
 | 
			
		||||
                    ("Eire", "Eire"),
 | 
			
		||||
                    ("Etc/GMT", "Etc/GMT"),
 | 
			
		||||
                    ("Etc/GMT+0", "Etc/GMT+0"),
 | 
			
		||||
                    ("Etc/GMT+1", "Etc/GMT+1"),
 | 
			
		||||
                    ("Etc/GMT+10", "Etc/GMT+10"),
 | 
			
		||||
                    ("Etc/GMT+11", "Etc/GMT+11"),
 | 
			
		||||
                    ("Etc/GMT+12", "Etc/GMT+12"),
 | 
			
		||||
                    ("Etc/GMT+2", "Etc/GMT+2"),
 | 
			
		||||
                    ("Etc/GMT+3", "Etc/GMT+3"),
 | 
			
		||||
                    ("Etc/GMT+4", "Etc/GMT+4"),
 | 
			
		||||
                    ("Etc/GMT+5", "Etc/GMT+5"),
 | 
			
		||||
                    ("Etc/GMT+6", "Etc/GMT+6"),
 | 
			
		||||
                    ("Etc/GMT+7", "Etc/GMT+7"),
 | 
			
		||||
                    ("Etc/GMT+8", "Etc/GMT+8"),
 | 
			
		||||
                    ("Etc/GMT+9", "Etc/GMT+9"),
 | 
			
		||||
                    ("Etc/GMT-0", "Etc/GMT-0"),
 | 
			
		||||
                    ("Etc/GMT-1", "Etc/GMT-1"),
 | 
			
		||||
                    ("Etc/GMT-10", "Etc/GMT-10"),
 | 
			
		||||
                    ("Etc/GMT-11", "Etc/GMT-11"),
 | 
			
		||||
                    ("Etc/GMT-12", "Etc/GMT-12"),
 | 
			
		||||
                    ("Etc/GMT-13", "Etc/GMT-13"),
 | 
			
		||||
                    ("Etc/GMT-14", "Etc/GMT-14"),
 | 
			
		||||
                    ("Etc/GMT-2", "Etc/GMT-2"),
 | 
			
		||||
                    ("Etc/GMT-3", "Etc/GMT-3"),
 | 
			
		||||
                    ("Etc/GMT-4", "Etc/GMT-4"),
 | 
			
		||||
                    ("Etc/GMT-5", "Etc/GMT-5"),
 | 
			
		||||
                    ("Etc/GMT-6", "Etc/GMT-6"),
 | 
			
		||||
                    ("Etc/GMT-7", "Etc/GMT-7"),
 | 
			
		||||
                    ("Etc/GMT-8", "Etc/GMT-8"),
 | 
			
		||||
                    ("Etc/GMT-9", "Etc/GMT-9"),
 | 
			
		||||
                    ("Etc/GMT0", "Etc/GMT0"),
 | 
			
		||||
                    ("Etc/Greenwich", "Etc/Greenwich"),
 | 
			
		||||
                    ("Etc/UCT", "Etc/UCT"),
 | 
			
		||||
                    ("Etc/UTC", "Etc/UTC"),
 | 
			
		||||
                    ("Etc/Universal", "Etc/Universal"),
 | 
			
		||||
                    ("Etc/Zulu", "Etc/Zulu"),
 | 
			
		||||
                    ("Europe/Amsterdam", "Europe/Amsterdam"),
 | 
			
		||||
                    ("Europe/Andorra", "Europe/Andorra"),
 | 
			
		||||
                    ("Europe/Astrakhan", "Europe/Astrakhan"),
 | 
			
		||||
                    ("Europe/Athens", "Europe/Athens"),
 | 
			
		||||
                    ("Europe/Belfast", "Europe/Belfast"),
 | 
			
		||||
                    ("Europe/Belgrade", "Europe/Belgrade"),
 | 
			
		||||
                    ("Europe/Berlin", "Europe/Berlin"),
 | 
			
		||||
                    ("Europe/Bratislava", "Europe/Bratislava"),
 | 
			
		||||
                    ("Europe/Brussels", "Europe/Brussels"),
 | 
			
		||||
                    ("Europe/Bucharest", "Europe/Bucharest"),
 | 
			
		||||
                    ("Europe/Budapest", "Europe/Budapest"),
 | 
			
		||||
                    ("Europe/Busingen", "Europe/Busingen"),
 | 
			
		||||
                    ("Europe/Chisinau", "Europe/Chisinau"),
 | 
			
		||||
                    ("Europe/Copenhagen", "Europe/Copenhagen"),
 | 
			
		||||
                    ("Europe/Dublin", "Europe/Dublin"),
 | 
			
		||||
                    ("Europe/Gibraltar", "Europe/Gibraltar"),
 | 
			
		||||
                    ("Europe/Guernsey", "Europe/Guernsey"),
 | 
			
		||||
                    ("Europe/Helsinki", "Europe/Helsinki"),
 | 
			
		||||
                    ("Europe/Isle_of_Man", "Europe/Isle_of_Man"),
 | 
			
		||||
                    ("Europe/Istanbul", "Europe/Istanbul"),
 | 
			
		||||
                    ("Europe/Jersey", "Europe/Jersey"),
 | 
			
		||||
                    ("Europe/Kaliningrad", "Europe/Kaliningrad"),
 | 
			
		||||
                    ("Europe/Kiev", "Europe/Kiev"),
 | 
			
		||||
                    ("Europe/Kirov", "Europe/Kirov"),
 | 
			
		||||
                    ("Europe/Kyiv", "Europe/Kyiv"),
 | 
			
		||||
                    ("Europe/Lisbon", "Europe/Lisbon"),
 | 
			
		||||
                    ("Europe/Ljubljana", "Europe/Ljubljana"),
 | 
			
		||||
                    ("Europe/London", "Europe/London"),
 | 
			
		||||
                    ("Europe/Luxembourg", "Europe/Luxembourg"),
 | 
			
		||||
                    ("Europe/Madrid", "Europe/Madrid"),
 | 
			
		||||
                    ("Europe/Malta", "Europe/Malta"),
 | 
			
		||||
                    ("Europe/Mariehamn", "Europe/Mariehamn"),
 | 
			
		||||
                    ("Europe/Minsk", "Europe/Minsk"),
 | 
			
		||||
                    ("Europe/Monaco", "Europe/Monaco"),
 | 
			
		||||
                    ("Europe/Moscow", "Europe/Moscow"),
 | 
			
		||||
                    ("Europe/Nicosia", "Europe/Nicosia"),
 | 
			
		||||
                    ("Europe/Oslo", "Europe/Oslo"),
 | 
			
		||||
                    ("Europe/Paris", "Europe/Paris"),
 | 
			
		||||
                    ("Europe/Podgorica", "Europe/Podgorica"),
 | 
			
		||||
                    ("Europe/Prague", "Europe/Prague"),
 | 
			
		||||
                    ("Europe/Riga", "Europe/Riga"),
 | 
			
		||||
                    ("Europe/Rome", "Europe/Rome"),
 | 
			
		||||
                    ("Europe/Samara", "Europe/Samara"),
 | 
			
		||||
                    ("Europe/San_Marino", "Europe/San_Marino"),
 | 
			
		||||
                    ("Europe/Sarajevo", "Europe/Sarajevo"),
 | 
			
		||||
                    ("Europe/Saratov", "Europe/Saratov"),
 | 
			
		||||
                    ("Europe/Simferopol", "Europe/Simferopol"),
 | 
			
		||||
                    ("Europe/Skopje", "Europe/Skopje"),
 | 
			
		||||
                    ("Europe/Sofia", "Europe/Sofia"),
 | 
			
		||||
                    ("Europe/Stockholm", "Europe/Stockholm"),
 | 
			
		||||
                    ("Europe/Tallinn", "Europe/Tallinn"),
 | 
			
		||||
                    ("Europe/Tirane", "Europe/Tirane"),
 | 
			
		||||
                    ("Europe/Tiraspol", "Europe/Tiraspol"),
 | 
			
		||||
                    ("Europe/Ulyanovsk", "Europe/Ulyanovsk"),
 | 
			
		||||
                    ("Europe/Uzhgorod", "Europe/Uzhgorod"),
 | 
			
		||||
                    ("Europe/Vaduz", "Europe/Vaduz"),
 | 
			
		||||
                    ("Europe/Vatican", "Europe/Vatican"),
 | 
			
		||||
                    ("Europe/Vienna", "Europe/Vienna"),
 | 
			
		||||
                    ("Europe/Vilnius", "Europe/Vilnius"),
 | 
			
		||||
                    ("Europe/Volgograd", "Europe/Volgograd"),
 | 
			
		||||
                    ("Europe/Warsaw", "Europe/Warsaw"),
 | 
			
		||||
                    ("Europe/Zagreb", "Europe/Zagreb"),
 | 
			
		||||
                    ("Europe/Zaporozhye", "Europe/Zaporozhye"),
 | 
			
		||||
                    ("Europe/Zurich", "Europe/Zurich"),
 | 
			
		||||
                    ("Factory", "Factory"),
 | 
			
		||||
                    ("GB", "GB"),
 | 
			
		||||
                    ("GB-Eire", "GB-Eire"),
 | 
			
		||||
                    ("GMT", "GMT"),
 | 
			
		||||
                    ("GMT+0", "GMT+0"),
 | 
			
		||||
                    ("GMT-0", "GMT-0"),
 | 
			
		||||
                    ("GMT0", "GMT0"),
 | 
			
		||||
                    ("Greenwich", "Greenwich"),
 | 
			
		||||
                    ("HST", "HST"),
 | 
			
		||||
                    ("Hongkong", "Hongkong"),
 | 
			
		||||
                    ("Iceland", "Iceland"),
 | 
			
		||||
                    ("Indian/Antananarivo", "Indian/Antananarivo"),
 | 
			
		||||
                    ("Indian/Chagos", "Indian/Chagos"),
 | 
			
		||||
                    ("Indian/Christmas", "Indian/Christmas"),
 | 
			
		||||
                    ("Indian/Cocos", "Indian/Cocos"),
 | 
			
		||||
                    ("Indian/Comoro", "Indian/Comoro"),
 | 
			
		||||
                    ("Indian/Kerguelen", "Indian/Kerguelen"),
 | 
			
		||||
                    ("Indian/Mahe", "Indian/Mahe"),
 | 
			
		||||
                    ("Indian/Maldives", "Indian/Maldives"),
 | 
			
		||||
                    ("Indian/Mauritius", "Indian/Mauritius"),
 | 
			
		||||
                    ("Indian/Mayotte", "Indian/Mayotte"),
 | 
			
		||||
                    ("Indian/Reunion", "Indian/Reunion"),
 | 
			
		||||
                    ("Iran", "Iran"),
 | 
			
		||||
                    ("Israel", "Israel"),
 | 
			
		||||
                    ("Jamaica", "Jamaica"),
 | 
			
		||||
                    ("Japan", "Japan"),
 | 
			
		||||
                    ("Kwajalein", "Kwajalein"),
 | 
			
		||||
                    ("Libya", "Libya"),
 | 
			
		||||
                    ("MET", "MET"),
 | 
			
		||||
                    ("MST", "MST"),
 | 
			
		||||
                    ("MST7MDT", "MST7MDT"),
 | 
			
		||||
                    ("Mexico/BajaNorte", "Mexico/BajaNorte"),
 | 
			
		||||
                    ("Mexico/BajaSur", "Mexico/BajaSur"),
 | 
			
		||||
                    ("Mexico/General", "Mexico/General"),
 | 
			
		||||
                    ("NZ", "NZ"),
 | 
			
		||||
                    ("NZ-CHAT", "NZ-CHAT"),
 | 
			
		||||
                    ("Navajo", "Navajo"),
 | 
			
		||||
                    ("PRC", "PRC"),
 | 
			
		||||
                    ("PST8PDT", "PST8PDT"),
 | 
			
		||||
                    ("Pacific/Apia", "Pacific/Apia"),
 | 
			
		||||
                    ("Pacific/Auckland", "Pacific/Auckland"),
 | 
			
		||||
                    ("Pacific/Bougainville", "Pacific/Bougainville"),
 | 
			
		||||
                    ("Pacific/Chatham", "Pacific/Chatham"),
 | 
			
		||||
                    ("Pacific/Chuuk", "Pacific/Chuuk"),
 | 
			
		||||
                    ("Pacific/Easter", "Pacific/Easter"),
 | 
			
		||||
                    ("Pacific/Efate", "Pacific/Efate"),
 | 
			
		||||
                    ("Pacific/Enderbury", "Pacific/Enderbury"),
 | 
			
		||||
                    ("Pacific/Fakaofo", "Pacific/Fakaofo"),
 | 
			
		||||
                    ("Pacific/Fiji", "Pacific/Fiji"),
 | 
			
		||||
                    ("Pacific/Funafuti", "Pacific/Funafuti"),
 | 
			
		||||
                    ("Pacific/Galapagos", "Pacific/Galapagos"),
 | 
			
		||||
                    ("Pacific/Gambier", "Pacific/Gambier"),
 | 
			
		||||
                    ("Pacific/Guadalcanal", "Pacific/Guadalcanal"),
 | 
			
		||||
                    ("Pacific/Guam", "Pacific/Guam"),
 | 
			
		||||
                    ("Pacific/Honolulu", "Pacific/Honolulu"),
 | 
			
		||||
                    ("Pacific/Johnston", "Pacific/Johnston"),
 | 
			
		||||
                    ("Pacific/Kanton", "Pacific/Kanton"),
 | 
			
		||||
                    ("Pacific/Kiritimati", "Pacific/Kiritimati"),
 | 
			
		||||
                    ("Pacific/Kosrae", "Pacific/Kosrae"),
 | 
			
		||||
                    ("Pacific/Kwajalein", "Pacific/Kwajalein"),
 | 
			
		||||
                    ("Pacific/Majuro", "Pacific/Majuro"),
 | 
			
		||||
                    ("Pacific/Marquesas", "Pacific/Marquesas"),
 | 
			
		||||
                    ("Pacific/Midway", "Pacific/Midway"),
 | 
			
		||||
                    ("Pacific/Nauru", "Pacific/Nauru"),
 | 
			
		||||
                    ("Pacific/Niue", "Pacific/Niue"),
 | 
			
		||||
                    ("Pacific/Norfolk", "Pacific/Norfolk"),
 | 
			
		||||
                    ("Pacific/Noumea", "Pacific/Noumea"),
 | 
			
		||||
                    ("Pacific/Pago_Pago", "Pacific/Pago_Pago"),
 | 
			
		||||
                    ("Pacific/Palau", "Pacific/Palau"),
 | 
			
		||||
                    ("Pacific/Pitcairn", "Pacific/Pitcairn"),
 | 
			
		||||
                    ("Pacific/Pohnpei", "Pacific/Pohnpei"),
 | 
			
		||||
                    ("Pacific/Ponape", "Pacific/Ponape"),
 | 
			
		||||
                    ("Pacific/Port_Moresby", "Pacific/Port_Moresby"),
 | 
			
		||||
                    ("Pacific/Rarotonga", "Pacific/Rarotonga"),
 | 
			
		||||
                    ("Pacific/Saipan", "Pacific/Saipan"),
 | 
			
		||||
                    ("Pacific/Samoa", "Pacific/Samoa"),
 | 
			
		||||
                    ("Pacific/Tahiti", "Pacific/Tahiti"),
 | 
			
		||||
                    ("Pacific/Tarawa", "Pacific/Tarawa"),
 | 
			
		||||
                    ("Pacific/Tongatapu", "Pacific/Tongatapu"),
 | 
			
		||||
                    ("Pacific/Truk", "Pacific/Truk"),
 | 
			
		||||
                    ("Pacific/Wake", "Pacific/Wake"),
 | 
			
		||||
                    ("Pacific/Wallis", "Pacific/Wallis"),
 | 
			
		||||
                    ("Pacific/Yap", "Pacific/Yap"),
 | 
			
		||||
                    ("Poland", "Poland"),
 | 
			
		||||
                    ("Portugal", "Portugal"),
 | 
			
		||||
                    ("ROC", "ROC"),
 | 
			
		||||
                    ("ROK", "ROK"),
 | 
			
		||||
                    ("Singapore", "Singapore"),
 | 
			
		||||
                    ("Turkey", "Turkey"),
 | 
			
		||||
                    ("UCT", "UCT"),
 | 
			
		||||
                    ("US/Alaska", "US/Alaska"),
 | 
			
		||||
                    ("US/Aleutian", "US/Aleutian"),
 | 
			
		||||
                    ("US/Arizona", "US/Arizona"),
 | 
			
		||||
                    ("US/Central", "US/Central"),
 | 
			
		||||
                    ("US/East-Indiana", "US/East-Indiana"),
 | 
			
		||||
                    ("US/Eastern", "US/Eastern"),
 | 
			
		||||
                    ("US/Hawaii", "US/Hawaii"),
 | 
			
		||||
                    ("US/Indiana-Starke", "US/Indiana-Starke"),
 | 
			
		||||
                    ("US/Michigan", "US/Michigan"),
 | 
			
		||||
                    ("US/Mountain", "US/Mountain"),
 | 
			
		||||
                    ("US/Pacific", "US/Pacific"),
 | 
			
		||||
                    ("US/Samoa", "US/Samoa"),
 | 
			
		||||
                    ("UTC", "UTC"),
 | 
			
		||||
                    ("Universal", "Universal"),
 | 
			
		||||
                    ("W-SU", "W-SU"),
 | 
			
		||||
                    ("WET", "WET"),
 | 
			
		||||
                    ("Zulu", "Zulu"),
 | 
			
		||||
                    ("localtime", "localtime"),
 | 
			
		||||
                ],
 | 
			
		||||
                default=aircox.models.schedule.current_timezone_key,
 | 
			
		||||
                help_text="timezone used for the date",
 | 
			
		||||
                max_length=100,
 | 
			
		||||
                verbose_name="timezone",
 | 
			
		||||
            ),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
							
								
								
									
										18
									
								
								aircox/migrations/0022_set_group_ownership.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								aircox/migrations/0022_set_group_ownership.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
from django.db import migrations
 | 
			
		||||
 | 
			
		||||
from aircox.models import Program
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def set_group_ownership(*args):
 | 
			
		||||
    for program in Program.objects.all():
 | 
			
		||||
        program.set_group_ownership()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ("aircox", "0021_alter_schedule_timezone"),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.RunPython(set_group_ownership),
 | 
			
		||||
    ]
 | 
			
		||||
@ -41,8 +41,7 @@ def user_default_groups(sender, instance, created, *args, **kwargs):
 | 
			
		||||
 | 
			
		||||
@receiver(signals.post_save, sender=Page)
 | 
			
		||||
def page_post_save(sender, instance, created, *args, **kwargs):
 | 
			
		||||
    return
 | 
			
		||||
    if not created and instance.cover:
 | 
			
		||||
    if not created and instance.cover and "raw" not in kwargs:
 | 
			
		||||
        Page.objects.filter(parent=instance, cover__isnull=True).update(cover=instance.cover)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -60,8 +59,7 @@ def program_post_save(sender, instance, created, *args, **kwargs):
 | 
			
		||||
 | 
			
		||||
@receiver(signals.pre_save, sender=Schedule)
 | 
			
		||||
def schedule_pre_save(sender, instance, *args, **kwargs):
 | 
			
		||||
    return
 | 
			
		||||
    if getattr(instance, "pk") is not None:
 | 
			
		||||
    if getattr(instance, "pk") is not None and "raw" not in kwargs:
 | 
			
		||||
        instance._initial = Schedule.objects.get(pk=instance.pk)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										29
									
								
								aircox/static/aircox/js/ckeditor-init.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								aircox/static/aircox/js/ckeditor-init.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
/* global CKEDITOR, django */
 | 
			
		||||
/* Modified in order to be manually loaded after vue.js */
 | 
			
		||||
 | 
			
		||||
  function initialiseCKEditor() {
 | 
			
		||||
    var textareas = Array.prototype.slice.call(
 | 
			
		||||
      document.querySelectorAll("textarea[data-type=ckeditortype]"),
 | 
			
		||||
    )
 | 
			
		||||
    for (var i = 0; i < textareas.length; ++i) {
 | 
			
		||||
      var t = textareas[i]
 | 
			
		||||
      if (
 | 
			
		||||
        t.getAttribute("data-processed") == "0" &&
 | 
			
		||||
        t.id.indexOf("__prefix__") == -1
 | 
			
		||||
      ) {
 | 
			
		||||
        t.setAttribute("data-processed", "1")
 | 
			
		||||
        var ext = JSON.parse(t.getAttribute("data-external-plugin-resources"))
 | 
			
		||||
        for (var j = 0; j < ext.length; ++j) {
 | 
			
		||||
          CKEDITOR.plugins.addExternal(ext[j][0], ext[j][1], ext[j][2])
 | 
			
		||||
        }
 | 
			
		||||
        CKEDITOR.replace(t.id, JSON.parse(t.getAttribute("data-config")))
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function initialiseCKEditorInInlinedForms() {
 | 
			
		||||
    if (typeof django === "object" && django.jQuery) {
 | 
			
		||||
      django.jQuery(document).on("formset:added", initialiseCKEditor)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
//})()
 | 
			
		||||
							
								
								
									
										34
									
								
								aircox/templates/accounts/profile.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								aircox/templates/accounts/profile.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
			
		||||
{% extends "aircox/base.html" %}
 | 
			
		||||
{% load i18n aircox %}
 | 
			
		||||
 | 
			
		||||
{% block head_title %}
 | 
			
		||||
    {% block title %}{{ user.username }}{% endblock %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block content-container %}
 | 
			
		||||
<div class="container content page-content">
 | 
			
		||||
  <h2 class="subtitle">Mon Profil</h2>
 | 
			
		||||
  {% translate "Username" %} : {{ user.username|title }}<br/>
 | 
			
		||||
  <!-- Connexion: {{ user.last_login }} -->
 | 
			
		||||
 | 
			
		||||
  <h2 class="subtitle is-1">Mes émissions</h2>
 | 
			
		||||
  {% if programs|length %}
 | 
			
		||||
  <ul>
 | 
			
		||||
  {% for p in programs %}
 | 
			
		||||
  <li>{{ p.title }} :
 | 
			
		||||
       
 | 
			
		||||
      <a href="{% url 'program-detail' slug=p.slug %}">
 | 
			
		||||
          <span title="{% translate 'View' %} {{ page }}">{% translate 'View' %}</span>
 | 
			
		||||
      </a>
 | 
			
		||||
       
 | 
			
		||||
      <a href="{% url 'program-edit' pk=p.pk %}">
 | 
			
		||||
          <span title="{% translate 'Edit' %} {{ page }}">{% translate 'Edit' %} </span>
 | 
			
		||||
      </a>
 | 
			
		||||
  </li>
 | 
			
		||||
  {% endfor %}
 | 
			
		||||
  </ul>
 | 
			
		||||
  {% else %}
 | 
			
		||||
  {% trans 'You are not listed as a program editor yet' %}
 | 
			
		||||
  {% endif %}
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
@ -1,3 +1,4 @@
 | 
			
		||||
{% load static i18n thumbnail aircox %}<!doctype html>
 | 
			
		||||
{% comment %}
 | 
			
		||||
Base website template. It displays various elements depending on context
 | 
			
		||||
variables.
 | 
			
		||||
@ -10,8 +11,6 @@ Usefull context:
 | 
			
		||||
- sidebar_url_name: url name sidebar item complete list
 | 
			
		||||
- sidebar_url_parent: parent page for sidebar items complete list
 | 
			
		||||
{% endcomment %}
 | 
			
		||||
{% load static i18n thumbnail aircox %}
 | 
			
		||||
 | 
			
		||||
<html>
 | 
			
		||||
    <head>
 | 
			
		||||
        <meta charset="utf-8" />
 | 
			
		||||
@ -71,12 +70,22 @@ Usefull context:
 | 
			
		||||
                            {% translate "Admin" %}
 | 
			
		||||
                        </a>
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                        {% if user.is_authenticated %}
 | 
			
		||||
                        <a class="nav-item" href="{% url "profile" %}" target="new">
 | 
			
		||||
                            {% translate "Profile" %}
 | 
			
		||||
                        </a>
 | 
			
		||||
                        <a class="nav-item" href="{% url "logout" %}" title="{% translate "Disconnect" %}"
 | 
			
		||||
                            aria-label="{% translate "Disconnect" %}">
 | 
			
		||||
                            <i class="fa fa-power-off"></i>
 | 
			
		||||
                        </a>
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                        {% endblock %}
 | 
			
		||||
                    </div>
 | 
			
		||||
                    {% endblock %}
 | 
			
		||||
                </nav>
 | 
			
		||||
                {% endblock %}
 | 
			
		||||
 | 
			
		||||
                {% block secondary-nav %}{% endblock %}
 | 
			
		||||
                {% endblock %}
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            {% block main-container %}
 | 
			
		||||
@ -90,6 +99,8 @@ Usefull context:
 | 
			
		||||
                {% endblock %}
 | 
			
		||||
                {% endspaceless %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                {% block header-container %}
 | 
			
		||||
                {% if page or cover or title %}
 | 
			
		||||
                <header class="container header preview preview-header {% if cover %}has-cover{% endif %}">
 | 
			
		||||
@ -103,6 +114,7 @@ Usefull context:
 | 
			
		||||
                    {% block headings %}
 | 
			
		||||
                    <div>
 | 
			
		||||
                        <h1 class="title is-1 {% block title-class %}{% endblock %}">{% block title %}{{ title|default:"" }}{% endblock %}</h1>
 | 
			
		||||
                        {% include "aircox/edit-link.html" %}
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div>
 | 
			
		||||
                        {% spaceless %}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								aircox/templates/aircox/edit-link.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								aircox/templates/aircox/edit-link.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
{% load aircox i18n %}
 | 
			
		||||
{% block user-actions-container %}
 | 
			
		||||
{% has_perm page page.program.change_permission_codename simple=True as can_edit %}
 | 
			
		||||
{% if user.is_authenticated and can_edit %}
 | 
			
		||||
{% with request.resolver_match.view_name as view_name %}
 | 
			
		||||
   
 | 
			
		||||
  {% if view_name in 'program-edit,bla' %}
 | 
			
		||||
  <!--
 | 
			
		||||
  <a href="{% url 'program-detail' page.slug %}" target="_self">
 | 
			
		||||
      <span title="{% translate 'View' %} {{ page }}">{% translate 'View' %} 👁 </span>
 | 
			
		||||
  </a>
 | 
			
		||||
  -->
 | 
			
		||||
  {% else %}
 | 
			
		||||
  <a href="{% url view_name|edit_view page.pk %}" target="_self">
 | 
			
		||||
      <span title="{% translate 'Edit' %} {{ page }}">{% translate 'Edit' %} 🖉  </span>
 | 
			
		||||
  </a>
 | 
			
		||||
  {% endif %}
 | 
			
		||||
{% endwith %}
 | 
			
		||||
{% endif %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
							
								
								
									
										36
									
								
								aircox/templates/aircox/episode_form.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								aircox/templates/aircox/episode_form.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
			
		||||
{% extends "aircox/basepage_detail.html" %}
 | 
			
		||||
{% load static i18n humanize honeypot aircox %}
 | 
			
		||||
 | 
			
		||||
{% block head_extra %}
 | 
			
		||||
  <script type="text/javascript" src="{% static "aircox/js/admin.js" %}"></script>
 | 
			
		||||
  <script type="text/javascript" src="{% static "aircox/js/ckeditor-init.js" %}"></script>
 | 
			
		||||
  <!-- <script type="text/javascript" src="{% static "ckeditor/ckeditor-init.js" %}"></script> -->
 | 
			
		||||
  <script type="text/javascript" src="{% static "ckeditor/ckeditor/ckeditor.js" %}"></script>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block init-scripts %}
 | 
			
		||||
    aircox.init(null, {hotReload:false, initPlayer:false, initApp:true})
 | 
			
		||||
    initialiseCKEditor()
 | 
			
		||||
    initialiseCKEditorInInlinedForms()
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block comments %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block content-container %}
 | 
			
		||||
<section class="container">
 | 
			
		||||
<form method="post" enctype="multipart/form-data">{% csrf_token %}
 | 
			
		||||
    <table>
 | 
			
		||||
        {{ form.as_table }}
 | 
			
		||||
        {% render_honeypot_field "website" %}
 | 
			
		||||
    </table>
 | 
			
		||||
    <br/>
 | 
			
		||||
    <input type="submit" value="Update" class="button is-success">
 | 
			
		||||
 | 
			
		||||
    {% include "aircox/playlist_inline.html" %}
 | 
			
		||||
 | 
			
		||||
    <input type="submit" value="Update" class="button is-success">
 | 
			
		||||
</form>
 | 
			
		||||
 | 
			
		||||
</section>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
@ -18,7 +18,7 @@
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
{% block content-container %}
 | 
			
		||||
<article class="message is-danger">
 | 
			
		||||
    <div class="message-header">
 | 
			
		||||
        <p>{% block error_title %}{% trans "An error occurred" %}{% endblock %}</p>
 | 
			
		||||
 | 
			
		||||
@ -10,21 +10,6 @@ Context:
 | 
			
		||||
- related_url: url to the full list of related_objects
 | 
			
		||||
{% endcomment %}
 | 
			
		||||
 | 
			
		||||
{% block top-nav-tools %}
 | 
			
		||||
{% has_perm page "change" as can_edit %}
 | 
			
		||||
{% if can_edit %}
 | 
			
		||||
<a class="navbar-item" href="{{ page|admin_url:'change' }}"
 | 
			
		||||
    target="new">
 | 
			
		||||
    <span class="icon is-small">
 | 
			
		||||
        <i class="fa fa-pen"></i>
 | 
			
		||||
    </span> 
 | 
			
		||||
    <span>{% translate "Edit" %}</span>
 | 
			
		||||
</a>
 | 
			
		||||
{% endif %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{% block breadcrumbs %}
 | 
			
		||||
{% if parent %}
 | 
			
		||||
    {% include "./widgets/breadcrumbs.html" with page=parent %}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										70
									
								
								aircox/templates/aircox/playlist_inline.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								aircox/templates/aircox/playlist_inline.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,70 @@
 | 
			
		||||
{% comment %}Inline block to edit playlists{% endcomment %}
 | 
			
		||||
{% load aircox aircox_admin static i18n %}
 | 
			
		||||
 | 
			
		||||
<div id="inline-tracks" class="box mb-5">
 | 
			
		||||
    {{ formset.non_form_errors }}
 | 
			
		||||
    <!-- formset.management_form -->
 | 
			
		||||
 | 
			
		||||
    <a-playlist-editor
 | 
			
		||||
            :labels="{% track_inline_labels %}"
 | 
			
		||||
            :init-data="{% track_inline_data formset=formset %}"
 | 
			
		||||
            settings-url="{% url "api:user-settings" %}"
 | 
			
		||||
            data-prefix="{{ formset.prefix }}-">
 | 
			
		||||
        <template #title>
 | 
			
		||||
            <h5 class="title is-4">{% trans "Playlist" %}</h5>
 | 
			
		||||
        </template>
 | 
			
		||||
        <template #top="{items}">
 | 
			
		||||
            <input type="hidden" name="{{ formset.prefix }}-TOTAL_FORMS"
 | 
			
		||||
                :value="items.length || 0"/>
 | 
			
		||||
            <input type="hidden" name="{{ formset.prefix }}-INITIAL_FORMS"
 | 
			
		||||
                value="{{ formset.initial_form_count }}"/>
 | 
			
		||||
            <input type="hidden" name="{{ formset.prefix }}-MIN_NUM_FORMS"
 | 
			
		||||
                value="{{ formset.min_num }}"/>
 | 
			
		||||
            <input type="hidden" name="{{ formset.prefix }}-MAX_NUM_FORMS"
 | 
			
		||||
                value="{{ formset.max_num }}"/>
 | 
			
		||||
        </template>
 | 
			
		||||
        <template #rows-header-head>
 | 
			
		||||
            <th style="max-width:2em" title="{% trans "Track Position" %}"
 | 
			
		||||
                    aria-description="{% trans "Track Position" %}">
 | 
			
		||||
                <span class="icon">
 | 
			
		||||
                    <i class="fa fa-arrow-down-1-9"></i>
 | 
			
		||||
                </span>
 | 
			
		||||
            </th>
 | 
			
		||||
        </template>
 | 
			
		||||
        <template v-slot:row-head="{item,row}">
 | 
			
		||||
            <td>
 | 
			
		||||
                [[ row+1 ]]
 | 
			
		||||
                <input type="hidden"
 | 
			
		||||
                    :name="'{{ formset.prefix }}-' + row + '-position'"
 | 
			
		||||
                    :value="row"/>
 | 
			
		||||
                <input t-if="item.data.id" type="hidden"
 | 
			
		||||
                    :name="'{{ formset.prefix }}-' + row + '-id'"
 | 
			
		||||
                    :value="item.data.id || item.id"/>
 | 
			
		||||
 | 
			
		||||
                {% for field in fields %}
 | 
			
		||||
                {% if field != 'position' %}
 | 
			
		||||
                <input type="hidden"
 | 
			
		||||
                    :name="'{{ formset.prefix }}-' + row + '-{{ field.name }}'"
 | 
			
		||||
                    v-model="item.data[attr]"/>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
                {% endfor %}
 | 
			
		||||
            </td>
 | 
			
		||||
        </template>
 | 
			
		||||
        {% for field in fields %}
 | 
			
		||||
        <template v-slot:row-{{ field }}="{item,cell,value,attr,emit}">
 | 
			
		||||
            <div class="field">
 | 
			
		||||
                <a-autocomplete
 | 
			
		||||
                        :input-class="['input', item.error(attr) ? 'is-danger' : 'half-field']"
 | 
			
		||||
                        url="{% url 'api:track-autocomplete' %}?{{ field }}=${query}&field={{ field }}"
 | 
			
		||||
                        :name="'{{ formset.prefix }}-' + cell.row + '-{{ field }}'"
 | 
			
		||||
                        v-model="item.data[attr]"
 | 
			
		||||
                        title="{{ field }}"
 | 
			
		||||
                        @change="emit('change', col)"/>
 | 
			
		||||
                <p v-for="error in item.error(attr)" class="help is-danger">
 | 
			
		||||
                    [[ error ]] !
 | 
			
		||||
                </p>
 | 
			
		||||
            </div>
 | 
			
		||||
        </template>
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
    </a-playlist-editor>
 | 
			
		||||
</div>
 | 
			
		||||
@ -2,6 +2,18 @@
 | 
			
		||||
{% comment %}Detail page of a show{% endcomment %}
 | 
			
		||||
{% load i18n aircox %}
 | 
			
		||||
 | 
			
		||||
{% block top-nav-tools %}
 | 
			
		||||
{% has_perm page page.change_permission_codename simple=True as can_edit %}
 | 
			
		||||
{% if can_edit %}
 | 
			
		||||
<a class="navbar-item" href="{% url 'program-edit' page.pk %}" target="_self">
 | 
			
		||||
    <span class="icon is-small">
 | 
			
		||||
        <i class="fa fa-pen"></i>
 | 
			
		||||
    </span> 
 | 
			
		||||
    <span>{% translate "Edit" %}</span>
 | 
			
		||||
</a>
 | 
			
		||||
{% endif %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block content-container %}
 | 
			
		||||
{% with schedules=program.schedule_set.all %}
 | 
			
		||||
{% if schedules %}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										39
									
								
								aircox/templates/aircox/program_form.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								aircox/templates/aircox/program_form.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
			
		||||
{% extends "aircox/page_detail.html" %}
 | 
			
		||||
{% load static i18n humanize honeypot aircox %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{% block head_extra %}
 | 
			
		||||
  {{ form.media }}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block init-scripts %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block comments %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block content-container %}
 | 
			
		||||
<section class="container">
 | 
			
		||||
<div>
 | 
			
		||||
<form method="post" enctype="multipart/form-data">{% csrf_token %}
 | 
			
		||||
    {% csrf_token %}
 | 
			
		||||
    {% for field in form %}
 | 
			
		||||
    <div class="field is-horizontal">
 | 
			
		||||
        <label class="label">{{ field.label }}</label>
 | 
			
		||||
        <div class="control">{{ field }}</div>
 | 
			
		||||
    </div>
 | 
			
		||||
    {% if field.errors %}
 | 
			
		||||
    <p class="help is-danger">{{ field.errors }}</p>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
    {% if field.help_text %}
 | 
			
		||||
    <p class="help">{{ field.help_text|safe }}</p>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
 | 
			
		||||
    <div class="has-text-right">
 | 
			
		||||
        <button type="submit" class="button">{% translate "Update" %}</button>
 | 
			
		||||
    </div>
 | 
			
		||||
</form>
 | 
			
		||||
</div>
 | 
			
		||||
</section>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
@ -25,12 +25,31 @@
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
{% if not object.content %}
 | 
			
		||||
    {% with object.parent.content as content %}
 | 
			
		||||
    {{ block.super }}
 | 
			
		||||
    {% endwith %}
 | 
			
		||||
{% else %}
 | 
			
		||||
    {{ block.super }}
 | 
			
		||||
{% block actions %}
 | 
			
		||||
{% if object.sound_set.public.count %}
 | 
			
		||||
<button class="button" @click="player.playButtonClick($event)"
 | 
			
		||||
        data-sounds="{{ object.podcasts|json }}">
 | 
			
		||||
    <span class="icon is-small">
 | 
			
		||||
        <span class="fas fa-play"></span>
 | 
			
		||||
    </span>
 | 
			
		||||
</button>
 | 
			
		||||
{% endif %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block actions %}
 | 
			
		||||
{% has_perm page object.program.change_permission_codename simple=True as can_edit %}
 | 
			
		||||
{% if can_edit %}
 | 
			
		||||
  <a class="button" href="{% url 'episode-edit' object.pk %}" target="_self">
 | 
			
		||||
    <span class="icon is-small"><i class="fas fa-pen" alt="{% trans 'edit' %}"></i></span>
 | 
			
		||||
  </a>
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
{% if object.sound_set.public.count %}
 | 
			
		||||
<button class="button" @click="player.playButtonClick($event)"
 | 
			
		||||
        data-sounds="{{ object.podcasts|json }}">
 | 
			
		||||
    <span class="icon is-small">
 | 
			
		||||
        <span class="fas fa-play"></span>
 | 
			
		||||
    </span>
 | 
			
		||||
</button>
 | 
			
		||||
{% endif %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										18
									
								
								aircox/templates/registration/login.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								aircox/templates/registration/login.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
{% extends "aircox/base.html" %}
 | 
			
		||||
{% load i18n aircox %}
 | 
			
		||||
 | 
			
		||||
{% block content-container %}
 | 
			
		||||
<div class="container content page-content">
 | 
			
		||||
<h2>{% trans "Log in" %}</h2>
 | 
			
		||||
<br/>
 | 
			
		||||
<form method="post" action="{% url 'login' %}">
 | 
			
		||||
  {% csrf_token %}
 | 
			
		||||
  <table>
 | 
			
		||||
  {{ form.as_table }}
 | 
			
		||||
  </table>
 | 
			
		||||
  <br/>
 | 
			
		||||
  <button class="button" type="submit">{% trans "Log in" %}</button>
 | 
			
		||||
  <input type="hidden" name="next" value="{{ next }}">
 | 
			
		||||
</form>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
@ -62,7 +62,7 @@ def do_has_perm(context, obj, perm, user=None, simple=False):
 | 
			
		||||
    if user is None:
 | 
			
		||||
        user = context["request"].user
 | 
			
		||||
    if simple:
 | 
			
		||||
        return user.has_perm("aircox.{}".format(perm))
 | 
			
		||||
        return user.has_perm("aircox.{}".format(perm)) or user.is_superuser
 | 
			
		||||
    else:
 | 
			
		||||
        return user.has_perm("{}.{}_{}".format(obj._meta.app_label, perm, obj._meta.model_name))
 | 
			
		||||
 | 
			
		||||
@ -134,3 +134,8 @@ def do_verbose_name(obj, plural=False):
 | 
			
		||||
    if isinstance(obj, str):
 | 
			
		||||
        return obj
 | 
			
		||||
    return obj._meta.verbose_name_plural if plural else obj._meta.verbose_name
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@register.filter(name="edit_view")
 | 
			
		||||
def do_edit_view(obj):
 | 
			
		||||
    return "%s-edit" % obj.split("-")[0]
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
from datetime import time, timedelta
 | 
			
		||||
import itertools
 | 
			
		||||
import logging
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.contrib.auth.models import User
 | 
			
		||||
@ -162,3 +163,10 @@ def tracks(episode, sound):
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def user():
 | 
			
		||||
    return User.objects.create_user(username="user1", password="bar")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def png_content():
 | 
			
		||||
    image_file = "{}/image.png".format(os.path.dirname(__file__))
 | 
			
		||||
    with open(image_file, "rb") as fh:
 | 
			
		||||
        return fh.read()
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								aircox/tests/image.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								aircox/tests/image.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 69 B  | 
@ -1,5 +1,6 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from django.contrib.auth.models import User, Group
 | 
			
		||||
from django.urls import reverse
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.django_db()
 | 
			
		||||
@ -23,3 +24,23 @@ def test_group_can_change_program(user, client, program):
 | 
			
		||||
    user = User.objects.get(pk=user.pk)  # reload user in order to have permissions set
 | 
			
		||||
    assert program.editors in user.groups.all()
 | 
			
		||||
    assert user.has_perm("aircox.%s" % program.change_permission_codename)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.django_db()
 | 
			
		||||
def test_group_change_program(user, client, program):
 | 
			
		||||
    client.force_login(user)
 | 
			
		||||
    response = client.get(reverse("program-edit", kwargs={"pk": program.pk}))
 | 
			
		||||
    assert response.status_code == 403
 | 
			
		||||
    user.groups.add(program.editors)
 | 
			
		||||
    response = client.get(reverse("program-edit", kwargs={"pk": program.pk}))
 | 
			
		||||
    assert response.status_code == 200
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.django_db()
 | 
			
		||||
def test_group_change_episode(user, client, program, episode):
 | 
			
		||||
    client.force_login(user)
 | 
			
		||||
    response = client.get(reverse("episode-edit", kwargs={"pk": episode.pk}))
 | 
			
		||||
    assert response.status_code == 403
 | 
			
		||||
    user.groups.add(program.editors)
 | 
			
		||||
    response = client.get(reverse("episode-edit", kwargs={"pk": episode.pk}))
 | 
			
		||||
    assert response.status_code == 200
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										22
									
								
								aircox/tests/test_profile.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								aircox/tests/test_profile.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from django.urls import reverse
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.django_db()
 | 
			
		||||
def test_authenticate(user, client, program):
 | 
			
		||||
    r = client.get(reverse("login"))
 | 
			
		||||
    assert r.status_code == 200
 | 
			
		||||
    assert b"id_username" in r.content
 | 
			
		||||
    r = client.post(reverse("login"), kwargs={"username": "foo", "password": "bar"})
 | 
			
		||||
    assert b"errorlist" in r.content
 | 
			
		||||
    assert client.login(username="user1", password="bar")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.django_db()
 | 
			
		||||
def test_profile_programs(user, client, program):
 | 
			
		||||
    client.force_login(user)
 | 
			
		||||
    r = client.get(reverse("profile"))
 | 
			
		||||
    assert program.title not in r.content.decode("utf-8")
 | 
			
		||||
    user.groups.add(program.editors)
 | 
			
		||||
    r = client.get(reverse("profile"))
 | 
			
		||||
    assert program.title in r.content.decode("utf-8")
 | 
			
		||||
							
								
								
									
										67
									
								
								aircox/tests/test_program.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								aircox/tests/test_program.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,67 @@
 | 
			
		||||
from itertools import chain
 | 
			
		||||
import json
 | 
			
		||||
import pytest
 | 
			
		||||
from django.urls import reverse
 | 
			
		||||
from django.core.files.uploadedfile import SimpleUploadedFile
 | 
			
		||||
 | 
			
		||||
from aircox.models import Program
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.django_db()
 | 
			
		||||
def test_edit_program(user, client, program):
 | 
			
		||||
    client.force_login(user)
 | 
			
		||||
    response = client.get(reverse("program-detail", kwargs={"slug": program.slug}))
 | 
			
		||||
    assert response.status_code == 200
 | 
			
		||||
    assert "🖉 ".encode() not in response.content
 | 
			
		||||
    user.groups.add(program.editors)
 | 
			
		||||
    response = client.get(reverse("program-detail", kwargs={"slug": program.slug}))
 | 
			
		||||
    assert "🖉 ".encode() in response.content
 | 
			
		||||
    assert b"foobar" not in response.content
 | 
			
		||||
    response = client.post(reverse("program-edit", kwargs={"pk": program.pk}), {"content": "foobar"})
 | 
			
		||||
    response = client.get(reverse("program-detail", kwargs={"slug": program.slug}))
 | 
			
		||||
    assert b"foobar" in response.content
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.django_db()
 | 
			
		||||
def test_add_cover(user, client, program, png_content):
 | 
			
		||||
    assert program.cover is None
 | 
			
		||||
    user.groups.add(program.editors)
 | 
			
		||||
    client.force_login(user)
 | 
			
		||||
    cover = SimpleUploadedFile("cover1.png", png_content, content_type="image/png")
 | 
			
		||||
    r = client.post(
 | 
			
		||||
        reverse("program-edit", kwargs={"pk": program.pk}), {"content": "foobar", "new_cover": cover}, follow=True
 | 
			
		||||
    )
 | 
			
		||||
    assert r.status_code == 200
 | 
			
		||||
    p = Program.objects.get(pk=program.pk)
 | 
			
		||||
    assert "cover1.png" in p.cover.url
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.django_db()
 | 
			
		||||
def test_edit_tracklist(user, client, program, episode, tracks):
 | 
			
		||||
    user.groups.add(program.editors)
 | 
			
		||||
    client.force_login(user)
 | 
			
		||||
    episode.status = 0x10  # published
 | 
			
		||||
    episode.save()
 | 
			
		||||
    r = client.get(reverse("program-detail", kwargs={"slug": episode.program.slug}))
 | 
			
		||||
    assert r.status_code == 200
 | 
			
		||||
    r = client.get(reverse("episode-detail", kwargs={"slug": episode.slug}))
 | 
			
		||||
    assert r.status_code == 200
 | 
			
		||||
    r2 = client.get(reverse("episode-edit", kwargs={"pk": episode.pk}))
 | 
			
		||||
    assert r2.status_code == 200
 | 
			
		||||
 | 
			
		||||
    tracklist = [t.id for t in episode.track_set.all().order_by("position")]
 | 
			
		||||
    tracklist_details_reversed = [(t.id, t.artist, t.title) for t in episode.track_set.all().order_by("-position")]
 | 
			
		||||
    tracklist_details_reversed = list(chain(*tracklist_details_reversed))
 | 
			
		||||
    data = """{{"website": [""], "content": ["foobar"], "new_podcast": [""], "form-TOTAL_FORMS": ["3"],
 | 
			
		||||
    "form-INITIAL_FORMS": ["3"], "form-MIN_NUM_FORMS": ["0"], "form-MAX_NUM_FORMS": ["1000"], "form-0-position": ["0"],
 | 
			
		||||
    "form-0-id": ["{}"], "form-0-": ["", "", "", "", "", ""], "form-0-artist": ["{}"], "form-0-title": ["{}"],
 | 
			
		||||
    "form-0-tags": [""], "form-0-album": [""], "form-0-year": [""], "form-1-position": ["1"], "form-1-id": ["{}"],
 | 
			
		||||
    "form-1-": ["", "", "", "", "", ""], "form-1-artist": ["{}"], "form-1-title": ["{}"], "form-1-tags": [""],
 | 
			
		||||
    "form-1-album": [""], "form-1-year": [""], "form-2-position": ["2"], "form-2-id": ["{}"], "form-2-": ["", "", "",
 | 
			
		||||
    "", "", ""], "form-2-artist": ["{}"], "form-2-title": ["{}"], "form-2-tags": [""], "form-2-album": [""],
 | 
			
		||||
    "form-2-year": [""]}}""".format(
 | 
			
		||||
        *tracklist_details_reversed
 | 
			
		||||
    )
 | 
			
		||||
    r = client.post(reverse("episode-edit", kwargs={"pk": episode.pk}), json.loads(data), follow=True)
 | 
			
		||||
    assert r.status_code == 200
 | 
			
		||||
    assert set(episode.track_set.all().values_list("id", flat=True)) == set(tracklist)
 | 
			
		||||
@ -114,12 +114,24 @@ urls = [
 | 
			
		||||
        views.EpisodeDetailView.as_view(),
 | 
			
		||||
        name="episode-detail",
 | 
			
		||||
    ),
 | 
			
		||||
    path(
 | 
			
		||||
        _("programs/episodes/<pk>/edit/"),
 | 
			
		||||
        views.EpisodeUpdateView.as_view(),
 | 
			
		||||
        name="episode-edit",
 | 
			
		||||
    ),
 | 
			
		||||
    path(_("podcasts/"), views.PodcastListView.as_view(), name="podcast-list"),
 | 
			
		||||
    path(_("podcasts/c/<slug:category_slug>/"), views.PodcastListView.as_view(), name="podcast-list"),
 | 
			
		||||
    # ---- others
 | 
			
		||||
    path(
 | 
			
		||||
        _("program/<pk>/edit/"),
 | 
			
		||||
        views.ProgramUpdateView.as_view(),
 | 
			
		||||
        name="program-edit",
 | 
			
		||||
    ),
 | 
			
		||||
    path(
 | 
			
		||||
        "errors/no-station",
 | 
			
		||||
        views.errors.NoStationErrorView.as_view(),
 | 
			
		||||
        name="errors-no-station",
 | 
			
		||||
    ),
 | 
			
		||||
    path("gestion/", views.ProfileView.as_view(), name="profile"),
 | 
			
		||||
    path("accounts/profile/", views.ProfileView.as_view(), name="profile"),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ from . import admin, errors
 | 
			
		||||
from .article import ArticleDetailView, ArticleListView
 | 
			
		||||
from .base import BaseAPIView, BaseView
 | 
			
		||||
from .diffusion import DiffusionListView, TimeTableView
 | 
			
		||||
from .episode import EpisodeDetailView, EpisodeListView, PodcastListView
 | 
			
		||||
from .episode import EpisodeDetailView, EpisodeListView, PodcastListView, EpisodeUpdateView
 | 
			
		||||
from .home import HomeView
 | 
			
		||||
from .log import LogListAPIView, LogListView
 | 
			
		||||
from .page import (
 | 
			
		||||
@ -11,11 +11,13 @@ from .page import (
 | 
			
		||||
    PageDetailView,
 | 
			
		||||
    PageListView,
 | 
			
		||||
)
 | 
			
		||||
from .profile import ProfileView
 | 
			
		||||
from .program import (
 | 
			
		||||
    ProgramDetailView,
 | 
			
		||||
    ProgramListView,
 | 
			
		||||
    ProgramPageDetailView,
 | 
			
		||||
    ProgramPageListView,
 | 
			
		||||
    ProgramUpdateView,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
__all__ = (
 | 
			
		||||
@ -30,6 +32,7 @@ __all__ = (
 | 
			
		||||
    "EpisodeDetailView",
 | 
			
		||||
    "EpisodeListView",
 | 
			
		||||
    "PodcastListView",
 | 
			
		||||
    "EpisodeUpdateView",
 | 
			
		||||
    "HomeView",
 | 
			
		||||
    "LogListAPIView",
 | 
			
		||||
    "LogListView",
 | 
			
		||||
@ -37,10 +40,12 @@ __all__ = (
 | 
			
		||||
    "BasePageListView",
 | 
			
		||||
    "PageDetailView",
 | 
			
		||||
    "PageListView",
 | 
			
		||||
    "ProfileView",
 | 
			
		||||
    "ProgramDetailView",
 | 
			
		||||
    "ProgramListView",
 | 
			
		||||
    "ProgramPageDetailView",
 | 
			
		||||
    "ProgramPageListView",
 | 
			
		||||
    "ProgramUpdateView",
 | 
			
		||||
    "attached",
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -50,13 +50,9 @@ class BaseView(TemplateResponseMixin, ContextMixin):
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        kwargs.setdefault("station", self.station)
 | 
			
		||||
        kwargs.setdefault("page", self.get_page())
 | 
			
		||||
        kwargs.setdefault("header_template_name", self.header_template_name)
 | 
			
		||||
 | 
			
		||||
        if "audio_streams" not in kwargs:
 | 
			
		||||
            kwargs["audio_streams"] = self.station.streams
 | 
			
		||||
 | 
			
		||||
        if "model" not in kwargs:
 | 
			
		||||
            model = getattr(self, "model", None) or hasattr(self, "object") and type(self.object)
 | 
			
		||||
            kwargs["model"] = model
 | 
			
		||||
 | 
			
		||||
@ -1,14 +1,20 @@
 | 
			
		||||
from django.shortcuts import reverse
 | 
			
		||||
from django.contrib.auth.mixins import UserPassesTestMixin
 | 
			
		||||
from django.forms.models import modelformset_factory
 | 
			
		||||
from django.urls import reverse
 | 
			
		||||
 | 
			
		||||
from aircox.forms import EpisodeForm
 | 
			
		||||
from aircox.models import Episode, Program, StaticPage, Track
 | 
			
		||||
from ..filters import EpisodeFilters
 | 
			
		||||
from ..models import Episode, Program, StaticPage
 | 
			
		||||
from .page import PageListView
 | 
			
		||||
from .program import ProgramPageDetailView
 | 
			
		||||
from .program import ProgramPageDetailView, BaseProgramMixin
 | 
			
		||||
from .page import PageUpdateView
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
__all__ = (
 | 
			
		||||
    "EpisodeDetailView",
 | 
			
		||||
    "EpisodeListView",
 | 
			
		||||
    "PodcastListView",
 | 
			
		||||
    "EpisodeUpdateView",
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -39,3 +45,43 @@ class EpisodeListView(PageListView):
 | 
			
		||||
class PodcastListView(EpisodeListView):
 | 
			
		||||
    attach_to_value = StaticPage.Target.PODCASTS
 | 
			
		||||
    queryset = Episode.objects.published().with_podcasts().order_by("-pub_date")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EpisodeUpdateView(UserPassesTestMixin, BaseProgramMixin, PageUpdateView):
 | 
			
		||||
    model = Episode
 | 
			
		||||
    form_class = EpisodeForm
 | 
			
		||||
    template_name = "aircox/episode_form.html"
 | 
			
		||||
 | 
			
		||||
    def get_sidebar_queryset(self):
 | 
			
		||||
        return super().get_sidebar_queryset().filter(parent=self.program)
 | 
			
		||||
 | 
			
		||||
    def test_func(self):
 | 
			
		||||
        program = self.get_object().program
 | 
			
		||||
        return self.request.user.has_perm("aircox.%s" % program.change_permission_codename)
 | 
			
		||||
 | 
			
		||||
    def get_success_url(self):
 | 
			
		||||
        return reverse("episode-detail", kwargs={"slug": self.get_object().slug})
 | 
			
		||||
 | 
			
		||||
    def get_object(self, queryset=None):
 | 
			
		||||
        obj = Episode.objects.get(pk=self.kwargs["pk"])
 | 
			
		||||
        return obj
 | 
			
		||||
 | 
			
		||||
    def get_formset(self, *args, **kwargs):
 | 
			
		||||
        fields = ("position", "artist", "title", "tags", "album", "year", "info")
 | 
			
		||||
        TrackFormSet = modelformset_factory(Track, fields=fields, extra=0)
 | 
			
		||||
        return TrackFormSet(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        context = super().get_context_data(**kwargs)
 | 
			
		||||
        context["fields"] = ("position", "artist", "title", "tags", "album", "year", "info")
 | 
			
		||||
        context["formset"] = self.get_formset(queryset=Track.objects.filter(episode=self.object))
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
    def post(self, request, *args, **kwargs):
 | 
			
		||||
        super().post(request, *args, **kwargs)
 | 
			
		||||
        formset = self.get_formset(request.POST)
 | 
			
		||||
        if formset.is_valid():
 | 
			
		||||
            formset.save()
 | 
			
		||||
            return super().form_valid(formset)
 | 
			
		||||
        else:
 | 
			
		||||
            return super().form_valid(formset)  # form_invalid(formset)
 | 
			
		||||
 | 
			
		||||
@ -63,7 +63,7 @@ class ParentMixin:
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        parent = kwargs.setdefault("parent", self.parent)
 | 
			
		||||
 | 
			
		||||
        if parent is not None:
 | 
			
		||||
        if parent is not None and parent.cover:
 | 
			
		||||
            kwargs.setdefault("cover", parent.cover.url)
 | 
			
		||||
        return super().get_context_data(**kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
from django.http import HttpResponse
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
from django.views.generic import DetailView, ListView
 | 
			
		||||
from django.views.generic.edit import UpdateView
 | 
			
		||||
from django.urls import reverse
 | 
			
		||||
from honeypot.decorators import check_honeypot
 | 
			
		||||
 | 
			
		||||
@ -15,6 +16,7 @@ __all__ = [
 | 
			
		||||
    "BasePageDetailView",
 | 
			
		||||
    "PageDetailView",
 | 
			
		||||
    "PageListView",
 | 
			
		||||
    "PageUpdateView",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -180,3 +182,10 @@ class PageDetailView(BasePageDetailView):
 | 
			
		||||
        comment.page = self.object
 | 
			
		||||
        comment.save()
 | 
			
		||||
        return self.get(request, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PageUpdateView(BaseView, UpdateView):
 | 
			
		||||
    context_object_name = "page"
 | 
			
		||||
 | 
			
		||||
    def get_page(self):
 | 
			
		||||
        return self.object
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								aircox/views/profile.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								aircox/views/profile.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
from django.contrib.auth.mixins import LoginRequiredMixin
 | 
			
		||||
from django.views.generic.base import TemplateView
 | 
			
		||||
 | 
			
		||||
from aircox.models import Program
 | 
			
		||||
from aircox.views import BaseView
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProfileView(LoginRequiredMixin, BaseView, TemplateView):
 | 
			
		||||
    template_name = "accounts/profile.html"
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        groups = self.request.user.groups.all()
 | 
			
		||||
        programs = Program.objects.filter(editors__in=groups)
 | 
			
		||||
        kwargs.update({"user": self.request.user, "programs": programs})
 | 
			
		||||
        return super().get_context_data(**kwargs)
 | 
			
		||||
@ -1,10 +1,12 @@
 | 
			
		||||
import random
 | 
			
		||||
 | 
			
		||||
from django.contrib.auth.mixins import UserPassesTestMixin
 | 
			
		||||
from django.urls import reverse
 | 
			
		||||
 | 
			
		||||
from ..models import Article, Page, Program, StaticPage, Episode
 | 
			
		||||
from aircox.forms import ProgramForm
 | 
			
		||||
from aircox.models import Article, Episode, Page, Program, StaticPage
 | 
			
		||||
from .mixins import ParentMixin
 | 
			
		||||
from .page import PageDetailView, PageListView
 | 
			
		||||
from .page import PageDetailView, PageListView, PageUpdateView
 | 
			
		||||
 | 
			
		||||
__all__ = ["ProgramPageDetailView", "ProgramDetailView", "ProgramPageListView"]
 | 
			
		||||
 | 
			
		||||
@ -46,6 +48,24 @@ class ProgramDetailView(BaseProgramMixin, PageDetailView):
 | 
			
		||||
            **kwargs,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def get_template_names(self):
 | 
			
		||||
        return super().get_template_names() + ["aircox/program_detail.html"]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProgramUpdateView(UserPassesTestMixin, BaseProgramMixin, PageUpdateView):
 | 
			
		||||
    model = Program
 | 
			
		||||
    form_class = ProgramForm
 | 
			
		||||
 | 
			
		||||
    def get_sidebar_queryset(self):
 | 
			
		||||
        return super().get_sidebar_queryset().filter(parent=self.program)
 | 
			
		||||
 | 
			
		||||
    def test_func(self):
 | 
			
		||||
        program = self.get_object()
 | 
			
		||||
        return self.request.user.has_perm("aircox.%s" % program.change_permission_codename)
 | 
			
		||||
 | 
			
		||||
    def get_success_url(self):
 | 
			
		||||
        return reverse("program-detail", kwargs={"slug": self.get_object().slug})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProgramListView(PageListView):
 | 
			
		||||
    model = Program
 | 
			
		||||
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@ -238,6 +238,7 @@ TEMPLATES = [
 | 
			
		||||
                "django.template.context_processors.static",
 | 
			
		||||
                "django.template.context_processors.tz",
 | 
			
		||||
                "django.contrib.messages.context_processors.messages",
 | 
			
		||||
                "aircox.context_processors.station",
 | 
			
		||||
            ),
 | 
			
		||||
            "loaders": (
 | 
			
		||||
                "django.template.loaders.filesystem.Loader",
 | 
			
		||||
@ -249,3 +250,5 @@ TEMPLATES = [
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
WSGI_APPLICATION = "instance.wsgi.application"
 | 
			
		||||
 | 
			
		||||
LOGOUT_REDIRECT_URL = "/"
 | 
			
		||||
 | 
			
		||||
@ -23,6 +23,7 @@ import aircox.urls
 | 
			
		||||
 | 
			
		||||
urlpatterns = aircox.urls.urls + [
 | 
			
		||||
    path("admin/", admin.site.urls),
 | 
			
		||||
    path("accounts/", include("django.contrib.auth.urls")),
 | 
			
		||||
    path("ckeditor/", include("ckeditor_uploader.urls")),
 | 
			
		||||
    path("filer/", include("filer.urls")),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user