Whole app
This commit is contained in:
		
						commit
						3a649df550
					
				
							
								
								
									
										259
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										259
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,259 @@ | |||||||
|  | 
 | ||||||
|  | # Byte-compiled / optimized / DLL files | ||||||
|  | __pycache__/ | ||||||
|  | *.py[cod] | ||||||
|  | *$py.class | ||||||
|  | 
 | ||||||
|  | # C extensions | ||||||
|  | *.so | ||||||
|  | 
 | ||||||
|  | # Distribution / packaging | ||||||
|  | .Python | ||||||
|  | build/ | ||||||
|  | develop-eggs/ | ||||||
|  | dist/ | ||||||
|  | downloads/ | ||||||
|  | eggs/ | ||||||
|  | .eggs/ | ||||||
|  | lib/ | ||||||
|  | lib64/ | ||||||
|  | parts/ | ||||||
|  | sdist/ | ||||||
|  | var/ | ||||||
|  | wheels/ | ||||||
|  | share/python-wheels/ | ||||||
|  | *.egg-info/ | ||||||
|  | .installed.cfg | ||||||
|  | *.egg | ||||||
|  | MANIFEST | ||||||
|  | 
 | ||||||
|  | # PyInstaller | ||||||
|  | #  Usually these files are written by a python script from a template | ||||||
|  | #  before PyInstaller builds the exe, so as to inject date/other infos into it. | ||||||
|  | *.manifest | ||||||
|  | *.spec | ||||||
|  | 
 | ||||||
|  | # Installer logs | ||||||
|  | pip-log.txt | ||||||
|  | pip-delete-this-directory.txt | ||||||
|  | 
 | ||||||
|  | # Unit test / coverage reports | ||||||
|  | htmlcov/ | ||||||
|  | .tox/ | ||||||
|  | .nox/ | ||||||
|  | .coverage | ||||||
|  | .coverage.* | ||||||
|  | .cache | ||||||
|  | nosetests.xml | ||||||
|  | coverage.xml | ||||||
|  | *.cover | ||||||
|  | *.py,cover | ||||||
|  | .hypothesis/ | ||||||
|  | .pytest_cache/ | ||||||
|  | cover/ | ||||||
|  | 
 | ||||||
|  | # Translations | ||||||
|  | *.mo | ||||||
|  | *.pot | ||||||
|  | 
 | ||||||
|  | # Django stuff: | ||||||
|  | *.log | ||||||
|  | local_settings.py | ||||||
|  | db.sqlite3 | ||||||
|  | db.sqlite3-journal | ||||||
|  | 
 | ||||||
|  | # Flask stuff: | ||||||
|  | instance/ | ||||||
|  | .webassets-cache | ||||||
|  | 
 | ||||||
|  | # Scrapy stuff: | ||||||
|  | .scrapy | ||||||
|  | 
 | ||||||
|  | # Sphinx documentation | ||||||
|  | docs/_build/ | ||||||
|  | 
 | ||||||
|  | # PyBuilder | ||||||
|  | .pybuilder/ | ||||||
|  | target/ | ||||||
|  | 
 | ||||||
|  | # Jupyter Notebook | ||||||
|  | .ipynb_checkpoints | ||||||
|  | 
 | ||||||
|  | # IPython | ||||||
|  | profile_default/ | ||||||
|  | ipython_config.py | ||||||
|  | 
 | ||||||
|  | # pyenv | ||||||
|  | #   For a library or package, you might want to ignore these files since the code is | ||||||
|  | #   intended to run in multiple environments; otherwise, check them in: | ||||||
|  | # .python-version | ||||||
|  | 
 | ||||||
|  | # pipenv | ||||||
|  | #   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. | ||||||
|  | #   However, in case of collaboration, if having platform-specific dependencies or dependencies | ||||||
|  | #   having no cross-platform support, pipenv may install dependencies that don't work, or not | ||||||
|  | #   install all needed dependencies. | ||||||
|  | #Pipfile.lock | ||||||
|  | 
 | ||||||
|  | # PEP 582; used by e.g. github.com/David-OConnor/pyflow | ||||||
|  | __pypackages__/ | ||||||
|  | 
 | ||||||
|  | # Celery stuff | ||||||
|  | celerybeat-schedule | ||||||
|  | celerybeat.pid | ||||||
|  | 
 | ||||||
|  | # SageMath parsed files | ||||||
|  | *.sage.py | ||||||
|  | 
 | ||||||
|  | # Environments | ||||||
|  | .env | ||||||
|  | .venv | ||||||
|  | env/ | ||||||
|  | venv/ | ||||||
|  | ENV/ | ||||||
|  | env.bak/ | ||||||
|  | venv.bak/ | ||||||
|  | 
 | ||||||
|  | # Spyder project settings | ||||||
|  | .spyderproject | ||||||
|  | .spyproject | ||||||
|  | 
 | ||||||
|  | # Rope project settings | ||||||
|  | .ropeproject | ||||||
|  | 
 | ||||||
|  | # mkdocs documentation | ||||||
|  | /site | ||||||
|  | 
 | ||||||
|  | # mypy | ||||||
|  | .mypy_cache/ | ||||||
|  | .dmypy.json | ||||||
|  | dmypy.json | ||||||
|  | 
 | ||||||
|  | # Pyre type checker | ||||||
|  | .pyre/ | ||||||
|  | 
 | ||||||
|  | # pytype static type analyzer | ||||||
|  | .pytype/ | ||||||
|  | 
 | ||||||
|  | # Cython debug symbols | ||||||
|  | cython_debug/ | ||||||
|  | 
 | ||||||
|  | # Logs | ||||||
|  | logs | ||||||
|  | *.log | ||||||
|  | npm-debug.log* | ||||||
|  | yarn-debug.log* | ||||||
|  | yarn-error.log* | ||||||
|  | lerna-debug.log* | ||||||
|  | 
 | ||||||
|  | # Diagnostic reports (https://nodejs.org/api/report.html) | ||||||
|  | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json | ||||||
|  | 
 | ||||||
|  | # Runtime data | ||||||
|  | pids | ||||||
|  | *.pid | ||||||
|  | *.seed | ||||||
|  | *.pid.lock | ||||||
|  | 
 | ||||||
|  | # Directory for instrumented libs generated by jscoverage/JSCover | ||||||
|  | lib-cov | ||||||
|  | 
 | ||||||
|  | # Coverage directory used by tools like istanbul | ||||||
|  | coverage | ||||||
|  | *.lcov | ||||||
|  | 
 | ||||||
|  | # nyc test coverage | ||||||
|  | .nyc_output | ||||||
|  | 
 | ||||||
|  | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) | ||||||
|  | .grunt | ||||||
|  | 
 | ||||||
|  | # Bower dependency directory (https://bower.io/) | ||||||
|  | bower_components | ||||||
|  | 
 | ||||||
|  | # node-waf configuration | ||||||
|  | .lock-wscript | ||||||
|  | 
 | ||||||
|  | # Compiled binary addons (https://nodejs.org/api/addons.html) | ||||||
|  | build/Release | ||||||
|  | 
 | ||||||
|  | # Dependency directories | ||||||
|  | node_modules/ | ||||||
|  | jspm_packages/ | ||||||
|  | 
 | ||||||
|  | # Snowpack dependency directory (https://snowpack.dev/) | ||||||
|  | web_modules/ | ||||||
|  | 
 | ||||||
|  | # TypeScript cache | ||||||
|  | *.tsbuildinfo | ||||||
|  | 
 | ||||||
|  | # Optional npm cache directory | ||||||
|  | .npm | ||||||
|  | 
 | ||||||
|  | # Optional eslint cache | ||||||
|  | .eslintcache | ||||||
|  | 
 | ||||||
|  | # Microbundle cache | ||||||
|  | .rpt2_cache/ | ||||||
|  | .rts2_cache_cjs/ | ||||||
|  | .rts2_cache_es/ | ||||||
|  | .rts2_cache_umd/ | ||||||
|  | 
 | ||||||
|  | # Optional REPL history | ||||||
|  | .node_repl_history | ||||||
|  | 
 | ||||||
|  | # Output of 'npm pack' | ||||||
|  | *.tgz | ||||||
|  | 
 | ||||||
|  | # Yarn Integrity file | ||||||
|  | .yarn-integrity | ||||||
|  | 
 | ||||||
|  | # dotenv environment variables file | ||||||
|  | .env | ||||||
|  | .env.test | ||||||
|  | 
 | ||||||
|  | # parcel-bundler cache (https://parceljs.org/) | ||||||
|  | .cache | ||||||
|  | .parcel-cache | ||||||
|  | 
 | ||||||
|  | # Next.js build output | ||||||
|  | .next | ||||||
|  | out | ||||||
|  | 
 | ||||||
|  | # Nuxt.js build / generate output | ||||||
|  | .nuxt | ||||||
|  | dist | ||||||
|  | 
 | ||||||
|  | # Gatsby files | ||||||
|  | .cache/ | ||||||
|  | # Comment in the public line in if your project uses Gatsby and not Next.js | ||||||
|  | # https://nextjs.org/blog/next-9-1#public-directory-support | ||||||
|  | # public | ||||||
|  | 
 | ||||||
|  | # vuepress build output | ||||||
|  | .vuepress/dist | ||||||
|  | 
 | ||||||
|  | # Serverless directories | ||||||
|  | .serverless/ | ||||||
|  | 
 | ||||||
|  | # FuseBox cache | ||||||
|  | .fusebox/ | ||||||
|  | 
 | ||||||
|  | # DynamoDB Local files | ||||||
|  | .dynamodb/ | ||||||
|  | 
 | ||||||
|  | # TernJS port file | ||||||
|  | .tern-port | ||||||
|  | 
 | ||||||
|  | # Stores VSCode versions used for testing VSCode extensions | ||||||
|  | .vscode-test | ||||||
|  | 
 | ||||||
|  | # yarn v2 | ||||||
|  | .yarn/cache | ||||||
|  | .yarn/unplugged | ||||||
|  | .yarn/build-state.yml | ||||||
|  | .yarn/install-state.gz | ||||||
|  | .pnp.* | ||||||
|  | 
 | ||||||
|  | /media/ | ||||||
|  | /static/ | ||||||
							
								
								
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | { | ||||||
|  |     "python.pythonPath": ".venv/bin/python" | ||||||
|  | } | ||||||
							
								
								
									
										0
									
								
								app/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								app/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										10
									
								
								app/admin.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/admin.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | from django.contrib import admin | ||||||
|  | from .models import Photo, Album | ||||||
|  | 
 | ||||||
|  | @admin.register(Photo) | ||||||
|  | class PhotoAdmin(admin.ModelAdmin): | ||||||
|  |     list_display = ["title", "user", "created_at", "album"] | ||||||
|  | 
 | ||||||
|  | @admin.register(Album) | ||||||
|  | class AlbumAdmin(admin.ModelAdmin): | ||||||
|  |     list_display = ["title", "user", "created_at"] | ||||||
							
								
								
									
										6
									
								
								app/apps.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								app/apps.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | from django.apps import AppConfig | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class AppConfig(AppConfig): | ||||||
|  |     name = "app" | ||||||
|  |     verbose_name = "Galeria" | ||||||
							
								
								
									
										17
									
								
								app/forms.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								app/forms.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | from django import forms | ||||||
|  | from .models import Photo, Album | ||||||
|  | 
 | ||||||
|  | class PhotoForm(forms.ModelForm): | ||||||
|  |     class Meta: | ||||||
|  |         model = Photo | ||||||
|  |         fields = ['title', 'photo', 'description', 'taken_on'] | ||||||
|  | 
 | ||||||
|  | class PhotoEditForm(forms.ModelForm): | ||||||
|  |     class Meta: | ||||||
|  |         model = Photo | ||||||
|  |         fields = ['title', 'description', 'taken_on'] | ||||||
|  | 
 | ||||||
|  | class AlbumForm(forms.ModelForm): | ||||||
|  |     class Meta: | ||||||
|  |         model = Album | ||||||
|  |         fields = ['title', 'description'] | ||||||
							
								
								
									
										29
									
								
								app/migrations/0001_initial.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								app/migrations/0001_initial.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | |||||||
|  | # Generated by Django 3.0.7 on 2020-06-03 20:42 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations, models | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     initial = True | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.CreateModel( | ||||||
|  |             name='Photo', | ||||||
|  |             fields=[ | ||||||
|  |                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||||||
|  |                 ('created_at', models.DateTimeField(auto_now_add=True)), | ||||||
|  |                 ('updated_at', models.DateTimeField(auto_now=True)), | ||||||
|  |                 ('photo', models.ImageField(upload_to='gallery')), | ||||||
|  |                 ('title', models.CharField(max_length=255)), | ||||||
|  |                 ('description', models.TextField(null=True)), | ||||||
|  |                 ('taken_on', models.DateField(null=True)), | ||||||
|  |             ], | ||||||
|  |             options={ | ||||||
|  |                 'abstract': False, | ||||||
|  |             }, | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										46
									
								
								app/migrations/0002_auto_20200603_2116.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								app/migrations/0002_auto_20200603_2116.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | |||||||
|  | # Generated by Django 3.0.7 on 2020-06-03 21:16 | ||||||
|  | 
 | ||||||
|  | import app.models | ||||||
|  | from django.conf import settings | ||||||
|  | from django.db import migrations, models | ||||||
|  | import django.db.models.deletion | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||||||
|  |         ('app', '0001_initial'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AlterModelOptions( | ||||||
|  |             name='photo', | ||||||
|  |             options={'verbose_name': 'photo', 'verbose_name_plural': 'photos'}, | ||||||
|  |         ), | ||||||
|  |         migrations.AddField( | ||||||
|  |             model_name='photo', | ||||||
|  |             name='user', | ||||||
|  |             field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), | ||||||
|  |         ), | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='photo', | ||||||
|  |             name='description', | ||||||
|  |             field=models.TextField(blank=True, null=True, verbose_name='Description'), | ||||||
|  |         ), | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='photo', | ||||||
|  |             name='photo', | ||||||
|  |             field=models.ImageField(upload_to=app.models.user_directory_path, verbose_name='Photo'), | ||||||
|  |         ), | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='photo', | ||||||
|  |             name='taken_on', | ||||||
|  |             field=models.DateField(blank=True, null=True, verbose_name='Taken on'), | ||||||
|  |         ), | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='photo', | ||||||
|  |             name='title', | ||||||
|  |             field=models.CharField(max_length=255, verbose_name='Title'), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										49
									
								
								app/migrations/0003_auto_20200603_2131.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								app/migrations/0003_auto_20200603_2131.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | |||||||
|  | # Generated by Django 3.0.7 on 2020-06-03 21:31 | ||||||
|  | 
 | ||||||
|  | from django.conf import settings | ||||||
|  | from django.db import migrations, models | ||||||
|  | import django.db.models.deletion | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||||||
|  |         ('app', '0002_auto_20200603_2116'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.CreateModel( | ||||||
|  |             name='Comment', | ||||||
|  |             fields=[ | ||||||
|  |                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||||||
|  |                 ('created_at', models.DateTimeField(auto_now_add=True)), | ||||||
|  |                 ('updated_at', models.DateTimeField(auto_now=True)), | ||||||
|  |                 ('content', models.TextField(verbose_name='Content')), | ||||||
|  |                 ('photo', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='app.Photo')), | ||||||
|  |                 ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), | ||||||
|  |             ], | ||||||
|  |             options={ | ||||||
|  |                 'abstract': False, | ||||||
|  |             }, | ||||||
|  |         ), | ||||||
|  |         migrations.CreateModel( | ||||||
|  |             name='Album', | ||||||
|  |             fields=[ | ||||||
|  |                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||||||
|  |                 ('created_at', models.DateTimeField(auto_now_add=True)), | ||||||
|  |                 ('updated_at', models.DateTimeField(auto_now=True)), | ||||||
|  |                 ('title', models.TextField(max_length=255, verbose_name='Title')), | ||||||
|  |                 ('description', models.TextField(blank=True, null=True, verbose_name='Description')), | ||||||
|  |                 ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), | ||||||
|  |             ], | ||||||
|  |             options={ | ||||||
|  |                 'abstract': False, | ||||||
|  |             }, | ||||||
|  |         ), | ||||||
|  |         migrations.AddField( | ||||||
|  |             model_name='photo', | ||||||
|  |             name='album', | ||||||
|  |             field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='app.Album'), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
							
								
								
									
										0
									
								
								app/migrations/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								app/migrations/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										57
									
								
								app/models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								app/models.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,57 @@ | |||||||
|  | from django.db import models | ||||||
|  | 
 | ||||||
|  | from imagekit.models import ImageSpecField | ||||||
|  | from imagekit.processors import ResizeToFill | ||||||
|  | from django.utils.translation import ugettext_lazy as _ | ||||||
|  | from django.contrib.auth import get_user_model | ||||||
|  | 
 | ||||||
|  | def user_directory_path(instance, filename): | ||||||
|  |     # file will be uploaded to MEDIA_ROOT/photos/<login>/<filename> | ||||||
|  |     return 'photos/{0}/{1}'.format(instance.user.username, filename) | ||||||
|  | 
 | ||||||
|  | class TimestampMixin(models.Model): | ||||||
|  |     created_at = models.DateTimeField(_("Created at"), auto_now_add=True) | ||||||
|  |     updated_at = models.DateTimeField(_("Updated at"), auto_now=True) | ||||||
|  | 
 | ||||||
|  |     class Meta: | ||||||
|  |         abstract = True | ||||||
|  | 
 | ||||||
|  | class UserMixin(models.Model): | ||||||
|  |     user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, null=True, verbose_name=_("User")) | ||||||
|  | 
 | ||||||
|  |     def is_owned_by(self, user): | ||||||
|  |         return self.user is not None and user is not None and self.user.id == user.id | ||||||
|  | 
 | ||||||
|  |     class Meta: | ||||||
|  |         abstract = True | ||||||
|  | 
 | ||||||
|  | class Album(TimestampMixin, UserMixin): | ||||||
|  |     title = models.CharField(_("Title"), max_length=255) | ||||||
|  |     description = models.TextField(_("Description"), null=True, blank=True) | ||||||
|  |      | ||||||
|  |     def __str__(self): | ||||||
|  |         return self.title | ||||||
|  | 
 | ||||||
|  |     class Meta: | ||||||
|  |         verbose_name = _('album') | ||||||
|  |         verbose_name_plural = _('albums') | ||||||
|  | 
 | ||||||
|  | class Photo(TimestampMixin, UserMixin): | ||||||
|  |     photo = models.ImageField(_("Photo"), upload_to=user_directory_path) | ||||||
|  |     thumbnail = ImageSpecField( | ||||||
|  |         source='photo',  | ||||||
|  |         format='JPEG',  | ||||||
|  |         options={'quality': 80},  | ||||||
|  |         processors=[ResizeToFill(300, 200, upscale=False)]) | ||||||
|  | 
 | ||||||
|  |     title = models.CharField(_("Title"), max_length=255) | ||||||
|  |      | ||||||
|  |     # some optional data | ||||||
|  |     description = models.TextField(_("Description"), null=True, blank=True) | ||||||
|  |     taken_on = models.DateField(_("Taken on"), null=True, blank=True) | ||||||
|  | 
 | ||||||
|  |     album = models.ForeignKey(Album, on_delete=models.CASCADE, null=True) | ||||||
|  |      | ||||||
|  |     class Meta: | ||||||
|  |         verbose_name = _('photo') | ||||||
|  |         verbose_name_plural = _('photos') | ||||||
							
								
								
									
										18
									
								
								app/templates/album/add.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								app/templates/album/add.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | {% extends '../base.html' %} | ||||||
|  | 
 | ||||||
|  | {% load bootstrap4 %} | ||||||
|  | 
 | ||||||
|  | {% block breadcrumbs %} | ||||||
|  |     <li class="breadcrumb-item"><a href="{% url 'index' %}">Galeria Zdjęć</a></li> | ||||||
|  |     <li class="breadcrumb-item">Dodaj album</li> | ||||||
|  | {% endblock breadcrumbs %} | ||||||
|  | 
 | ||||||
|  | {% block content %} | ||||||
|  |     <form method="post" action="{% url 'add_album' %}" enctype="multipart/form-data"> | ||||||
|  |         {% csrf_token %} | ||||||
|  |         {% bootstrap_form form %} | ||||||
|  | 
 | ||||||
|  |         <input type="submit" value="dodaj"> | ||||||
|  |         <input type="hidden" name="next" value="{{ next }}"> | ||||||
|  |     </form> | ||||||
|  | {% endblock content %} | ||||||
							
								
								
									
										19
									
								
								app/templates/album/add_photo.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								app/templates/album/add_photo.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | {% extends '../base.html' %} | ||||||
|  | 
 | ||||||
|  | {% load bootstrap4 %} | ||||||
|  | 
 | ||||||
|  | {% block breadcrumbs %} | ||||||
|  |     <li class="breadcrumb-item"><a href="{% url 'index' %}">Galeria Zdjęć</a></li> | ||||||
|  |     <li class="breadcrumb-item"><a href="{% url 'album' album.id %}">Album: {{ album.title }}</a></li> | ||||||
|  |     <li class="breadcrumb-item">Dodaj zdjęcie</li> | ||||||
|  | {% endblock breadcrumbs %} | ||||||
|  | 
 | ||||||
|  | {% block content %} | ||||||
|  |     <form method="post" action="{% url 'add_photo' album.id %}" enctype="multipart/form-data"> | ||||||
|  |         {% csrf_token %} | ||||||
|  |         {% bootstrap_form form %} | ||||||
|  | 
 | ||||||
|  |         <input type="submit" value="dodaj"> | ||||||
|  |         <input type="hidden" name="next" value="{{ next }}"> | ||||||
|  |     </form> | ||||||
|  | {% endblock content %} | ||||||
							
								
								
									
										19
									
								
								app/templates/album/edit.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								app/templates/album/edit.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | {% extends '../base.html' %} | ||||||
|  | 
 | ||||||
|  | {% load bootstrap4 %} | ||||||
|  | 
 | ||||||
|  | {% block breadcrumbs %} | ||||||
|  |     <li class="breadcrumb-item"><a href="{% url 'index' %}">Galeria Zdjęć</a></li> | ||||||
|  |     <li class="breadcrumb-item"><a href="{% url 'album' album.id %}">Album: {{ album.title }}</a></li> | ||||||
|  |     <li class="breadcrumb-item">Zaktualizuj</li> | ||||||
|  | {% endblock breadcrumbs %} | ||||||
|  | 
 | ||||||
|  | {% block content %} | ||||||
|  |     <form method="post" action="{% url 'edit_album' %}" enctype="multipart/form-data"> | ||||||
|  |         {% csrf_token %} | ||||||
|  |         {% bootstrap_form form %} | ||||||
|  | 
 | ||||||
|  |         <input type="submit" value="zaktualizuj"> | ||||||
|  |         <input type="hidden" name="next" value="{{ next }}"> | ||||||
|  |     </form> | ||||||
|  | {% endblock content %} | ||||||
							
								
								
									
										20
									
								
								app/templates/album/edit_photo.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								app/templates/album/edit_photo.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | {% extends '../base.html' %} | ||||||
|  | 
 | ||||||
|  | {% load bootstrap4 %} | ||||||
|  | 
 | ||||||
|  | {% block breadcrumbs %} | ||||||
|  |     <li class="breadcrumb-item"><a href="{% url 'index' %}">Galeria Zdjęć</a></li> | ||||||
|  |     <li class="breadcrumb-item"><a href="{% url 'album' photo.album.id %}">Album: {{ album.title }}</a></li> | ||||||
|  |     <li class="breadcrumb-item"><a href="{% url 'photo' photo.album.id photo.id %}">Zdjęcie: {{ photo.title }}</a></li> | ||||||
|  |     <li class="breadcrumb-item">Zaktualizuj</li> | ||||||
|  | {% endblock breadcrumbs %} | ||||||
|  | 
 | ||||||
|  | {% block content %} | ||||||
|  |     <form method="post" action="{% url 'edit_photo' photo.album.id photo.id %}" enctype="multipart/form-data"> | ||||||
|  |         {% csrf_token %} | ||||||
|  |         {% bootstrap_form form %} | ||||||
|  | 
 | ||||||
|  |         <input type="submit" value="zaktualizuj"> | ||||||
|  |         <input type="hidden" name="next" value="{{ next }}"> | ||||||
|  |     </form> | ||||||
|  | {% endblock content %} | ||||||
							
								
								
									
										21
									
								
								app/templates/album/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								app/templates/album/index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | |||||||
|  | {% extends 'base.html' %} | ||||||
|  | 
 | ||||||
|  | {% block breadcrumbs %} | ||||||
|  |     <li class="breadcrumb-item">Galeria Zdjęć</li> | ||||||
|  | {% endblock breadcrumbs %} | ||||||
|  | 
 | ||||||
|  | {% block content %} | ||||||
|  |     <ul class="gallery"> | ||||||
|  |         {% for album in albums %} | ||||||
|  |             <li class="gallery__entry album"> | ||||||
|  |                 <img src="{{ album.photo_set.first.thumbnail.url }}" class="album__thumbnail" /> | ||||||
|  |                 <div class="album__header"> | ||||||
|  |                     <a class="album__title" href="{% url 'album' album.id %}">{{ album.title }}</a> | ||||||
|  |                 </div> | ||||||
|  |             </li> | ||||||
|  |         {% endfor %} | ||||||
|  |         <li class="gallery__entry gallery__entry--action"> | ||||||
|  |             <a href="{% url 'add_album' %}" class="stretched-link">dodaj +</a> | ||||||
|  |         </li> | ||||||
|  |     </ul> | ||||||
|  | {% endblock content %} | ||||||
							
								
								
									
										35
									
								
								app/templates/album/photo.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								app/templates/album/photo.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | |||||||
|  | {% extends '../base.html' %} | ||||||
|  | 
 | ||||||
|  | {% block breadcrumbs %} | ||||||
|  |     <li class="breadcrumb-item"><a href="{% url 'index' %}">Galeria Zdjęć</a></li> | ||||||
|  |     <li class="breadcrumb-item"><a href="{% url 'album' photo.album.id %}">Album: {{ photo.album.title }}</a></li> | ||||||
|  |     <li class="breadcrumb-item">Zdjęcie: {{ photo.title }}</li> | ||||||
|  | {% endblock breadcrumbs %} | ||||||
|  | 
 | ||||||
|  | {% block subtitle %}<h2>{{ photo.album.title }}</h2>{% endblock %} | ||||||
|  | 
 | ||||||
|  | {% block content %} | ||||||
|  |     <div class="photo"> | ||||||
|  |         <div class="photo__title h1">{{ photo.title }}</div> | ||||||
|  |         <ul class="actions my-2"> | ||||||
|  |             <li class="actions__action"> | ||||||
|  |                 <a href="{% url 'edit_photo' photo.album.id photo.id %}" class="btn btn-sm btn-warning">Aktualizuj</a> | ||||||
|  |             </li> | ||||||
|  |             <li class="actions__action"> | ||||||
|  |                 <form action="{% url 'delete_photo' photo.album.id photo.id %}" method="post"> | ||||||
|  |                     {% csrf_token %} | ||||||
|  |                     <button class="btn btn-sm btn-outline-danger">Usuń</button> | ||||||
|  |                 </form> | ||||||
|  |             </li> | ||||||
|  |         </ul> | ||||||
|  |         <img class="photo__photo" src="{{ photo.photo.url }}" /> | ||||||
|  |         <aside class="photo__meta"> | ||||||
|  |             <p class="photo__description my-2">{{ photo.description }}</p> | ||||||
|  |             <div class="photo__author small"> | ||||||
|  |                 autor: {{ photo.user.username }}{% if photo.taken_on %} | ||||||
|  |                 , {{ photo.taken_on }} | ||||||
|  |                 {% endif %} | ||||||
|  |             </div> | ||||||
|  |         </aside> | ||||||
|  |     </div> | ||||||
|  | {% endblock content %} | ||||||
							
								
								
									
										38
									
								
								app/templates/album/photos.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								app/templates/album/photos.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | |||||||
|  | {% extends '../base.html' %} | ||||||
|  | 
 | ||||||
|  | {% block breadcrumbs %} | ||||||
|  |     <li class="breadcrumb-item"><a href="{% url 'index' %}">Galeria Zdjęć</a></li> | ||||||
|  |     <li class="breadcrumb-item">Album: {{ album.title }}</li> | ||||||
|  | {% endblock breadcrumbs %} | ||||||
|  | 
 | ||||||
|  | {% block subtitle %}<h2>{{ album.title }}</h2>{% endblock %} | ||||||
|  | 
 | ||||||
|  | {% block content %} | ||||||
|  |     {% if is_my %} | ||||||
|  |         <ul class="actions my-2"> | ||||||
|  |             <li class="actions__action"> | ||||||
|  |                 <a href="{% url 'edit_album' album.id %}" class="btn btn-sm btn-warning">Aktualizuj</a> | ||||||
|  |             </li> | ||||||
|  |             <li class="actions__action"> | ||||||
|  |                 <form action="{% url 'delete_album' album.id %}" method="post"> | ||||||
|  |                     {% csrf_token %} | ||||||
|  |                     <button class="btn btn-sm btn-outline-danger">Usuń</button> | ||||||
|  |                 </form> | ||||||
|  |             </li> | ||||||
|  |         </ul> | ||||||
|  |     {% endif %} | ||||||
|  |     <ul class="gallery"> | ||||||
|  |         {% for photo in photos %} | ||||||
|  |             <li class="gallery__entry photo"> | ||||||
|  |                 <a href="{% url 'photo' album.id photo.id %}"> | ||||||
|  |                     <img src="{{ photo.thumbnail.url }}" class="photo__thumbnail" /> | ||||||
|  |                 </a> | ||||||
|  |             </li> | ||||||
|  |         {% endfor %} | ||||||
|  |         {% if is_my %} | ||||||
|  |             <li class="gallery__entry gallery__entry--action"> | ||||||
|  |                 <a href="{% url 'add_photo' album.id %}" class="stretched-link">dodaj + </a> | ||||||
|  |             </li> | ||||||
|  |         {% endif %} | ||||||
|  |     </ul> | ||||||
|  | {% endblock content %} | ||||||
							
								
								
									
										38
									
								
								app/templates/base.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								app/templates/base.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | |||||||
|  | <!doctype html> | ||||||
|  | <html lang="pl"> | ||||||
|  |     {% load static bootstrap4 %} | ||||||
|  |     <head> | ||||||
|  |         <!-- Required meta tags --> | ||||||
|  |         <meta charset="utf-8"> | ||||||
|  |         <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | ||||||
|  | 
 | ||||||
|  |         <!-- Bootstrap CSS --> | ||||||
|  |         <title>Galeria Zdjęć</title> | ||||||
|  |         <script src="{% static 'dist/bundle.js' %}"></script> | ||||||
|  |     </head> | ||||||
|  | 
 | ||||||
|  |     <body> | ||||||
|  |         <header class="container d-flex align-items-center justify-content-end py-2"> | ||||||
|  |             {% if user.is_authenticated %} | ||||||
|  |                 <span>Zalogowany jako: <span>{{ user.username }}</span></span> <a href="{% url 'logout' %}" class="btn btn-link">Wyloguj się</a> | ||||||
|  |             {% else %} | ||||||
|  |                 <a href="{% url 'login' %}" class="btn btn-link">Zaloguj się</a> lub <a href="{% url 'register' %}" class="btn btn-link">zarejestruj</a> | ||||||
|  |             {% endif %} | ||||||
|  |         </header> | ||||||
|  |         <main class="app container"> | ||||||
|  |             <header class="app__header">  | ||||||
|  |                 <h1>Galeria Zdjęć</h1> | ||||||
|  |                 {% block subtitle %}{% endblock %} | ||||||
|  |             </header> | ||||||
|  | 
 | ||||||
|  |             <nav aria-label="Okruszki"> | ||||||
|  |                 <ol class="breadcrumb"> | ||||||
|  |                     {% block breadcrumbs %}{% endblock breadcrumbs %} | ||||||
|  |                 </ol> | ||||||
|  |             </nav> | ||||||
|  |              | ||||||
|  |             {% block content %} | ||||||
|  |             {% endblock content %} | ||||||
|  |         </main> | ||||||
|  |     </body> | ||||||
|  | </html> | ||||||
							
								
								
									
										17
									
								
								app/templates/registration/login.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								app/templates/registration/login.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | {% extends "base.html" %} | ||||||
|  | {% load bootstrap4 %} | ||||||
|  | 
 | ||||||
|  | {% block breadcrumbs %} | ||||||
|  |     <li class="breadcrumb-item"><a href="{% url 'index' %}">Galeria Zdjęć</a></li> | ||||||
|  |     <li class="breadcrumb-item">Zaloguj się</li> | ||||||
|  | {% endblock breadcrumbs %} | ||||||
|  | 
 | ||||||
|  | {% block content %} | ||||||
|  |     <form method="post" action="{% url 'login' %}"> | ||||||
|  |         {% csrf_token %} | ||||||
|  |         {% bootstrap_form form %} | ||||||
|  | 
 | ||||||
|  |         <input type="submit" value="zaloguj"> | ||||||
|  |         <input type="hidden" name="next" value="{{ next }}"> | ||||||
|  |     </form> | ||||||
|  | {% endblock %} | ||||||
							
								
								
									
										17
									
								
								app/templates/registration/register.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								app/templates/registration/register.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | {% extends "base.html" %} | ||||||
|  | {% load bootstrap4 %} | ||||||
|  | 
 | ||||||
|  | {% block breadcrumbs %} | ||||||
|  |     <li class="breadcrumb-item"><a href="{% url 'index' %}">Galeria Zdjęć</a></li> | ||||||
|  |     <li class="breadcrumb-item">Zarejestruj się</li> | ||||||
|  | {% endblock breadcrumbs %} | ||||||
|  | 
 | ||||||
|  | {% block content %} | ||||||
|  |     <form method="post" action="{% url 'login' %}"> | ||||||
|  |         {% csrf_token %} | ||||||
|  |         {% bootstrap_form form %} | ||||||
|  | 
 | ||||||
|  |         <input type="submit" value="zarejestruj się"> | ||||||
|  |         <input type="hidden" name="next" value="{{ next }}"> | ||||||
|  |     </form> | ||||||
|  | {% endblock %} | ||||||
							
								
								
									
										3
									
								
								app/tests.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								app/tests.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | from django.test import TestCase | ||||||
|  | 
 | ||||||
|  | # Create your tests here. | ||||||
							
								
								
									
										16
									
								
								app/urls.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								app/urls.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | from django.urls import path | ||||||
|  | 
 | ||||||
|  | from . import views | ||||||
|  | 
 | ||||||
|  | urlpatterns = [ | ||||||
|  |     path('', views.albums, name='index'), | ||||||
|  |     path('register', views.register, name='register'), | ||||||
|  |     path('add', views.add_album, name='add_album'), | ||||||
|  |     path('album/<int:album_id>', views.photos, name='album'), | ||||||
|  |     path('album/<int:album_id>/edit', views.edit_album, name='edit_album'), | ||||||
|  |     path('album/<int:album_id>/delete', views.delete_album, name='delete_album'), | ||||||
|  |     path('album/<int:album_id>/photo/<int:photo_id>', views.photo, name='photo'), | ||||||
|  |     path('album/<int:album_id>/photo/<int:photo_id>/edit', views.edit_photo, name='edit_photo'), | ||||||
|  |     path('album/<int:album_id>/photo/<int:photo_id>/delete', views.delete_photo, name='delete_photo'), | ||||||
|  |     path('album/<int:album_id>/add', views.add_photo, name='add_photo'), | ||||||
|  | ] | ||||||
							
								
								
									
										121
									
								
								app/views.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								app/views.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,121 @@ | |||||||
|  | from django.shortcuts import render, get_object_or_404, redirect, reverse | ||||||
|  | from .models import Album, Photo | ||||||
|  | from .forms import PhotoForm, AlbumForm | ||||||
|  | from django.contrib.auth.forms import UserCreationForm as RegisterForm | ||||||
|  | from django.core.exceptions import PermissionDenied | ||||||
|  | from django.views.decorators.http import require_http_methods | ||||||
|  | from django.views.decorators.csrf import csrf_exempt | ||||||
|  | from app.forms import PhotoEditForm | ||||||
|  | 
 | ||||||
|  | def register(request): | ||||||
|  |     if request.method == "POST": | ||||||
|  |         form = RegisterForm(request.POST) | ||||||
|  |         if form.is_valid(): | ||||||
|  |             form.save() | ||||||
|  | 
 | ||||||
|  |         return redirect("/") | ||||||
|  |     else: | ||||||
|  |         form = RegisterForm() | ||||||
|  | 
 | ||||||
|  |     return render(request, "registration/register.html", {"form":form}) | ||||||
|  | 
 | ||||||
|  | # Create your views here. | ||||||
|  | def albums(request): | ||||||
|  |     albums = Album.objects.order_by('created_at').prefetch_related('photo_set') | ||||||
|  | 
 | ||||||
|  |     return render(request, "album/index.html", locals()) | ||||||
|  | 
 | ||||||
|  | def photos(request, album_id): | ||||||
|  |     album = get_object_or_404(Album, pk=album_id) | ||||||
|  |     photos = album.photo_set.all() | ||||||
|  |     is_my = album.is_owned_by(request.user) | ||||||
|  | 
 | ||||||
|  |     return render(request, "album/photos.html", locals()) | ||||||
|  | 
 | ||||||
|  | def photo(request, photo_id, album_id): | ||||||
|  |     photo = get_object_or_404(Photo, pk=photo_id) | ||||||
|  |     is_my = photo.is_owned_by(request.user) | ||||||
|  | 
 | ||||||
|  |     return render(request, "album/photo.html", locals()) | ||||||
|  | 
 | ||||||
|  | def add_album(request): | ||||||
|  |     if request.method == 'POST': | ||||||
|  |         form = AlbumForm(request.POST, request.FILES) | ||||||
|  | 
 | ||||||
|  |         if form.is_valid(): | ||||||
|  |             form.instance.user = request.user | ||||||
|  |             form.save() | ||||||
|  |             return redirect(reverse('album', args=[form.instance.id])) | ||||||
|  |     else: | ||||||
|  |         form = AlbumForm() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     return render(request, "album/add.html", locals()) | ||||||
|  | 
 | ||||||
|  | def add_photo(request, album_id): | ||||||
|  |     album = get_object_or_404(Album, pk=album_id) | ||||||
|  | 
 | ||||||
|  |     if request.method == 'POST': | ||||||
|  |         form = PhotoForm(request.POST, request.FILES) | ||||||
|  | 
 | ||||||
|  |         photo = form.instance | ||||||
|  |         photo.album = album | ||||||
|  |         photo.user = request.user | ||||||
|  | 
 | ||||||
|  |         if form.is_valid(): | ||||||
|  |             form.save() | ||||||
|  |             return redirect(reverse('album', args=[album.id])) | ||||||
|  |     else: | ||||||
|  |         form = PhotoForm() | ||||||
|  | 
 | ||||||
|  |     return render(request, "album/add_photo.html", locals()) | ||||||
|  | 
 | ||||||
|  | def edit_album(request, album_id): | ||||||
|  |     album = get_object_or_404(Album, pk=album_id) | ||||||
|  | 
 | ||||||
|  |     if not album.is_owned_by(request.user): | ||||||
|  |         raise PermissionDenied() | ||||||
|  | 
 | ||||||
|  |     form = AlbumForm(request.POST or None, instance=album) | ||||||
|  | 
 | ||||||
|  |     if request.method == 'POST' and form.is_valid(): | ||||||
|  |         form.save() | ||||||
|  |         return redirect(reverse('album', args=[album.id])) | ||||||
|  | 
 | ||||||
|  |     return render(request, "album/edit_album.html", locals()) | ||||||
|  | 
 | ||||||
|  | @require_http_methods(["POST"]) | ||||||
|  | def delete_album(request, album_id): | ||||||
|  |     album = get_object_or_404(Album, pk=album_id) | ||||||
|  | 
 | ||||||
|  |     if not album.is_owned_by(request.user): | ||||||
|  |         raise PermissionDenied() | ||||||
|  | 
 | ||||||
|  |     album.delete() | ||||||
|  | 
 | ||||||
|  |     return redirect(reverse('index')) | ||||||
|  | 
 | ||||||
|  | def edit_photo(request, album_id, photo_id): | ||||||
|  |     photo = get_object_or_404(Photo, pk=photo_id) | ||||||
|  | 
 | ||||||
|  |     if not photo.is_owned_by(request.user): | ||||||
|  |         raise PermissionDenied() | ||||||
|  | 
 | ||||||
|  |     form = PhotoEditForm(request.POST or None, request.FILES or None, instance=photo) | ||||||
|  |      | ||||||
|  |     if request.method == 'POST' and form.is_valid(): | ||||||
|  |         form.save() | ||||||
|  |         return redirect(reverse('photo', args=[photo.album.id, photo.id])) | ||||||
|  | 
 | ||||||
|  |     return render(request, "album/edit_photo.html", locals()) | ||||||
|  | 
 | ||||||
|  | @require_http_methods(["POST"]) | ||||||
|  | def delete_photo(request, album_id, photo_id): | ||||||
|  |     photo = get_object_or_404(Photo, pk=photo_id) | ||||||
|  | 
 | ||||||
|  |     if not photo.is_owned_by(request.user): | ||||||
|  |         raise PermissionDenied() | ||||||
|  | 
 | ||||||
|  |     photo.delete() | ||||||
|  | 
 | ||||||
|  |     return redirect(reverse('album', args=[album_id])) | ||||||
							
								
								
									
										1
									
								
								assets/app.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								assets/app.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | import './style.scss' | ||||||
							
								
								
									
										129
									
								
								assets/style.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								assets/style.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,129 @@ | |||||||
|  | @import "../node_modules/bootstrap/scss/bootstrap.scss"; | ||||||
|  | 
 | ||||||
|  | body { | ||||||
|  |     margin: 0; | ||||||
|  |     font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", | ||||||
|  |         "Droid Sans", "Helvetica Neue", sans-serif; | ||||||
|  |     -webkit-font-smoothing: antialiased; | ||||||
|  |     -moz-osx-font-smoothing: grayscale; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | code { | ||||||
|  |     font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | a { | ||||||
|  |     color: black; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | %link-extended { | ||||||
|  |     &::after { | ||||||
|  |         position: absolute; | ||||||
|  |         top: 0; | ||||||
|  |         bottom: 0; | ||||||
|  |         right: 0; | ||||||
|  |         left: 0; | ||||||
|  |         content: ""; | ||||||
|  | 
 | ||||||
|  |         z-index: 10; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .app { | ||||||
|  |     margin: 100px auto; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .app__header { | ||||||
|  |     margin-bottom: 5rem; | ||||||
|  |     text-align: center; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .gallery { | ||||||
|  |     list-style: none; | ||||||
|  |     padding: 0; | ||||||
|  |     margin: 0 auto; | ||||||
|  |     display: flex; | ||||||
|  |     margin-left: -1rem; | ||||||
|  |     flex-wrap: wrap; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .gallery__entry { | ||||||
|  |     &::after { | ||||||
|  |         padding-bottom: 56.25%; | ||||||
|  |         content: ""; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     width: calc(33.33% - 1rem); | ||||||
|  |     margin-left: 1rem; | ||||||
|  |     margin-bottom: 1rem; | ||||||
|  |     position: relative; | ||||||
|  | 
 | ||||||
|  |     transform: scale(1) rotate(0); | ||||||
|  |     transition: 150ms ease-in-out transform; | ||||||
|  | 
 | ||||||
|  |     &:hover { | ||||||
|  |         transform: scale(1.02) rotate(0.3deg); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .gallery__entry--action { | ||||||
|  |     background-color: #ddd; | ||||||
|  |     display: flex; | ||||||
|  |     align-items: center; | ||||||
|  |     justify-content: center; | ||||||
|  |     font-weight: bold; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .album { | ||||||
|  |     position: relative; | ||||||
|  |     display: flex; | ||||||
|  |     flex-direction: column-reverse; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .album__thumbnail, .photo__thumbnail { | ||||||
|  |     position: absolute; | ||||||
|  |     z-index: -1; | ||||||
|  |     width: 100%; | ||||||
|  |     background-color: #ddd; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .album__header { | ||||||
|  |     bottom: 0; | ||||||
|  |     background-color: rgba(black, 0.5); | ||||||
|  |     padding: 1rem; | ||||||
|  |     text-align: center; | ||||||
|  |     z-index: 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .album__title { | ||||||
|  |     font-weight: bold; | ||||||
|  |     color: white; | ||||||
|  |     text-shadow: 0 0 2px rgba(black, 0.5); | ||||||
|  | 
 | ||||||
|  |     @extend %link-extended; | ||||||
|  | 
 | ||||||
|  |     &:hover { | ||||||
|  |         color: white; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .photo__photo { | ||||||
|  |     max-width: 100%; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .actions { | ||||||
|  |     list-style: none; | ||||||
|  |     margin: 0; | ||||||
|  |     padding: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .actions__action { | ||||||
|  |     margin-right: .5rem; | ||||||
|  |     display: inline-block; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @include media-breakpoint-down(sm) { | ||||||
|  |     .gallery__entry { | ||||||
|  |         width: 100% | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										0
									
								
								gallery/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								gallery/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										16
									
								
								gallery/asgi.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								gallery/asgi.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | """ | ||||||
|  | ASGI config for gallery project. | ||||||
|  | 
 | ||||||
|  | It exposes the ASGI callable as a module-level variable named ``application``. | ||||||
|  | 
 | ||||||
|  | For more information on this file, see | ||||||
|  | https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/ | ||||||
|  | """ | ||||||
|  | 
 | ||||||
|  | import os | ||||||
|  | 
 | ||||||
|  | from django.core.asgi import get_asgi_application | ||||||
|  | 
 | ||||||
|  | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'gallery.settings') | ||||||
|  | 
 | ||||||
|  | application = get_asgi_application() | ||||||
							
								
								
									
										153
									
								
								gallery/settings.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								gallery/settings.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,153 @@ | |||||||
|  | """ | ||||||
|  | Django settings for gallery project. | ||||||
|  | 
 | ||||||
|  | Generated by 'django-admin startproject' using Django 3.0.6. | ||||||
|  | 
 | ||||||
|  | For more information on this file, see | ||||||
|  | https://docs.djangoproject.com/en/3.0/topics/settings/ | ||||||
|  | 
 | ||||||
|  | For the full list of settings and their values, see | ||||||
|  | https://docs.djangoproject.com/en/3.0/ref/settings/ | ||||||
|  | """ | ||||||
|  | 
 | ||||||
|  | import os | ||||||
|  | 
 | ||||||
|  | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) | ||||||
|  | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # Quick-start development settings - unsuitable for production | ||||||
|  | # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ | ||||||
|  | 
 | ||||||
|  | # SECURITY WARNING: keep the secret key used in production secret! | ||||||
|  | SECRET_KEY = '$t2(9!*g*ncmt@o7l3cxqtfm=a348(q7$ax1hp2z!fddrxjqh-' | ||||||
|  | 
 | ||||||
|  | # SECURITY WARNING: don't run with debug turned on in production! | ||||||
|  | DEBUG = True | ||||||
|  | 
 | ||||||
|  | ALLOWED_HOSTS = ['gallery.localhost', 'gallery.kadet.net'] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # Application definition | ||||||
|  | 
 | ||||||
|  | INSTALLED_APPS = [ | ||||||
|  |     'django.contrib.admin', | ||||||
|  |     'django.contrib.auth', | ||||||
|  |     'django.contrib.contenttypes', | ||||||
|  |     'django.contrib.sessions', | ||||||
|  |     'django.contrib.messages', | ||||||
|  |     'django.contrib.staticfiles', | ||||||
|  |     'app.apps.AppConfig', | ||||||
|  |     'bootstrap4' | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | MIDDLEWARE = [ | ||||||
|  |     'django.middleware.security.SecurityMiddleware', | ||||||
|  |     'django.contrib.sessions.middleware.SessionMiddleware', | ||||||
|  |     'django.middleware.common.CommonMiddleware', | ||||||
|  |     'django.middleware.csrf.CsrfViewMiddleware', | ||||||
|  |     'django.contrib.auth.middleware.AuthenticationMiddleware', | ||||||
|  |     'django.contrib.messages.middleware.MessageMiddleware', | ||||||
|  |     'django.middleware.clickjacking.XFrameOptionsMiddleware', | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | ROOT_URLCONF = 'gallery.urls' | ||||||
|  | 
 | ||||||
|  | TEMPLATES = [ | ||||||
|  |     { | ||||||
|  |         'BACKEND': 'django.template.backends.django.DjangoTemplates', | ||||||
|  |         'DIRS': [], | ||||||
|  |         'APP_DIRS': True, | ||||||
|  |         'OPTIONS': { | ||||||
|  |             'context_processors': [ | ||||||
|  |                 'django.template.context_processors.debug', | ||||||
|  |                 'django.template.context_processors.request', | ||||||
|  |                 'django.contrib.auth.context_processors.auth', | ||||||
|  |                 'django.contrib.messages.context_processors.messages', | ||||||
|  |             ], | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | WSGI_APPLICATION = 'gallery.wsgi.application' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # Database | ||||||
|  | # https://docs.djangoproject.com/en/3.0/ref/settings/#databases | ||||||
|  | 
 | ||||||
|  | DATABASES = { | ||||||
|  |     'default': { | ||||||
|  |         'ENGINE': 'django.db.backends.sqlite3', | ||||||
|  |         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # Password validation | ||||||
|  | # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators | ||||||
|  | 
 | ||||||
|  | AUTH_PASSWORD_VALIDATORS = [ | ||||||
|  |     { | ||||||
|  |         'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', | ||||||
|  |     }, | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # Internationalization | ||||||
|  | # https://docs.djangoproject.com/en/3.0/topics/i18n/ | ||||||
|  | 
 | ||||||
|  | LANGUAGE_CODE = 'pl-pl' | ||||||
|  | TIME_ZONE = 'UTC' | ||||||
|  | USE_I18N = True | ||||||
|  | USE_L10N = True | ||||||
|  | USE_TZ = True | ||||||
|  | 
 | ||||||
|  | LOCALE_PATHS = [ os.path.join('locale/') ]  | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # Static files (CSS, JavaScript, Images) | ||||||
|  | # https://docs.djangoproject.com/en/3.0/howto/static-files/ | ||||||
|  | 
 | ||||||
|  | STATIC_URL = '/static/' | ||||||
|  | STATIC_ROOT = '' | ||||||
|  | STATICFILES_DIRS = [ os.path.join('static') ] | ||||||
|  | 
 | ||||||
|  | MEDIA_URL = '/media/' | ||||||
|  | MEDIA_ROOT = os.path.join('media/') | ||||||
|  | 
 | ||||||
|  | PHOTOS_URL  = '/photos/' | ||||||
|  | PHOTOS_ROOT = os.path.join('photos/') | ||||||
|  | 
 | ||||||
|  | LOGIN_REDIRECT_URL = "index" | ||||||
|  | LOGOUT_REDIRECT_URL = "index" | ||||||
|  | 
 | ||||||
|  | LOGGING = { | ||||||
|  |     'version': 1, | ||||||
|  |     'filters': { | ||||||
|  |         'require_debug_true': { | ||||||
|  |             '()': 'django.utils.log.RequireDebugTrue', | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     'handlers': { | ||||||
|  |         'console': { | ||||||
|  |             'level': 'DEBUG', | ||||||
|  |             'filters': ['require_debug_true'], | ||||||
|  |             'class': 'logging.StreamHandler', | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     'loggers': { | ||||||
|  |         'django.db.backends': { | ||||||
|  |             'level': 'DEBUG', | ||||||
|  |             'handlers': ['console'], | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								gallery/urls.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								gallery/urls.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | """gallery URL Configuration | ||||||
|  | 
 | ||||||
|  | The `urlpatterns` list routes URLs to views. For more information please see: | ||||||
|  |     https://docs.djangoproject.com/en/3.0/topics/http/urls/ | ||||||
|  | Examples: | ||||||
|  | Function views | ||||||
|  |     1. Add an import:  from my_app import views | ||||||
|  |     2. Add a URL to urlpatterns:  path('', views.home, name='home') | ||||||
|  | Class-based views | ||||||
|  |     1. Add an import:  from other_app.views import Home | ||||||
|  |     2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home') | ||||||
|  | Including another URLconf | ||||||
|  |     1. Import the include() function: from django.urls import include, path | ||||||
|  |     2. Add a URL to urlpatterns:  path('blog/', include('blog.urls')) | ||||||
|  | """ | ||||||
|  | from django.contrib import admin | ||||||
|  | from django.urls import path, include | ||||||
|  | from django.conf.urls.static import static | ||||||
|  | from django.conf import settings | ||||||
|  | 
 | ||||||
|  | urlpatterns = [ | ||||||
|  |     path('accounts/', include('django.contrib.auth.urls')), | ||||||
|  |     path('admin/', admin.site.urls), | ||||||
|  |     path('', include('app.urls')), | ||||||
|  | ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) \ | ||||||
|  |   + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)  | ||||||
							
								
								
									
										16
									
								
								gallery/wsgi.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								gallery/wsgi.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | """ | ||||||
|  | WSGI config for gallery project. | ||||||
|  | 
 | ||||||
|  | It exposes the WSGI callable as a module-level variable named ``application``. | ||||||
|  | 
 | ||||||
|  | For more information on this file, see | ||||||
|  | https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/ | ||||||
|  | """ | ||||||
|  | 
 | ||||||
|  | import os | ||||||
|  | 
 | ||||||
|  | from django.core.wsgi import get_wsgi_application | ||||||
|  | 
 | ||||||
|  | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'gallery.settings') | ||||||
|  | 
 | ||||||
|  | application = get_wsgi_application() | ||||||
							
								
								
									
										67
									
								
								locale/pl/LC_MESSAGES/django.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								locale/pl/LC_MESSAGES/django.po
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,67 @@ | |||||||
|  | # SOME DESCRIPTIVE TITLE. | ||||||
|  | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER | ||||||
|  | # This file is distributed under the same license as the PACKAGE package. | ||||||
|  | # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. | ||||||
|  | # | ||||||
|  | msgid "" | ||||||
|  | msgstr "" | ||||||
|  | "Project-Id-Version: PACKAGE VERSION\n" | ||||||
|  | "Report-Msgid-Bugs-To: \n" | ||||||
|  | "POT-Creation-Date: 2020-06-08 20:39+0000\n" | ||||||
|  | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | ||||||
|  | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | ||||||
|  | "Language-Team: LANGUAGE <LL@li.org>\n" | ||||||
|  | "Language: \n" | ||||||
|  | "MIME-Version: 1.0\n" | ||||||
|  | "Content-Type: text/plain; charset=UTF-8\n" | ||||||
|  | "Content-Transfer-Encoding: 8bit\n" | ||||||
|  | "Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n" | ||||||
|  | "%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n" | ||||||
|  | "%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" | ||||||
|  | 
 | ||||||
|  | #: app/models.py:13 | ||||||
|  | msgid "Created at" | ||||||
|  | msgstr "Data utworzenia" | ||||||
|  | 
 | ||||||
|  | #: app/models.py:14 | ||||||
|  | msgid "Updated at" | ||||||
|  | msgstr "Data aktualizacji" | ||||||
|  | 
 | ||||||
|  | #: app/models.py:20 | ||||||
|  | msgid "User" | ||||||
|  | msgstr "Użytkownik" | ||||||
|  | 
 | ||||||
|  | #: app/models.py:29 app/models.py:44 | ||||||
|  | msgid "Title" | ||||||
|  | msgstr "Tytuł" | ||||||
|  | 
 | ||||||
|  | #: app/models.py:30 app/models.py:47 | ||||||
|  | msgid "Description" | ||||||
|  | msgstr "Opis" | ||||||
|  | 
 | ||||||
|  | #: app/models.py:33 | ||||||
|  | msgid "album" | ||||||
|  | msgstr "album" | ||||||
|  | 
 | ||||||
|  | #: app/models.py:34 | ||||||
|  | msgid "albums" | ||||||
|  | msgstr "albumy" | ||||||
|  | 
 | ||||||
|  | #: app/models.py:37 | ||||||
|  | msgid "Photo" | ||||||
|  | msgstr "Zdjęcie" | ||||||
|  | 
 | ||||||
|  | #: app/models.py:48 | ||||||
|  | msgid "Taken on" | ||||||
|  | msgstr "Data wykonania" | ||||||
|  | 
 | ||||||
|  | #: app/models.py:53 | ||||||
|  | msgid "photo" | ||||||
|  | msgstr "zdjęcie" | ||||||
|  | 
 | ||||||
|  | #: app/models.py:54 | ||||||
|  | msgid "photos" | ||||||
|  | msgstr "zdjęcia" | ||||||
|  | 
 | ||||||
|  | #~ msgid "Content" | ||||||
|  | #~ msgstr "Treść" | ||||||
							
								
								
									
										21
									
								
								manage.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										21
									
								
								manage.py
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,21 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | """Django's command-line utility for administrative tasks.""" | ||||||
|  | import os | ||||||
|  | import sys | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def main(): | ||||||
|  |     os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'gallery.settings') | ||||||
|  |     try: | ||||||
|  |         from django.core.management import execute_from_command_line | ||||||
|  |     except ImportError as exc: | ||||||
|  |         raise ImportError( | ||||||
|  |             "Couldn't import Django. Are you sure it's installed and " | ||||||
|  |             "available on your PYTHONPATH environment variable? Did you " | ||||||
|  |             "forget to activate a virtual environment?" | ||||||
|  |         ) from exc | ||||||
|  |     execute_from_command_line(sys.argv) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | if __name__ == '__main__': | ||||||
|  |     main() | ||||||
							
								
								
									
										22
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | { | ||||||
|  |   "name": "P04", | ||||||
|  |   "version": "1.0.0", | ||||||
|  |   "main": "index.js", | ||||||
|  |   "author": "Kacper Donat", | ||||||
|  |   "license": "MIT", | ||||||
|  |   "private": true, | ||||||
|  |   "devDependencies": { | ||||||
|  |     "bootstrap": "^4.5.0", | ||||||
|  |     "copy-webpack-plugin": "^6.0.2", | ||||||
|  |     "css-loader": "^3.5.3", | ||||||
|  |     "file-loader": "^6.0.0", | ||||||
|  |     "imagemin-webpack-plugin": "^2.4.2", | ||||||
|  |     "node-sass": "^4.14.1", | ||||||
|  |     "sass-loader": "^8.0.2", | ||||||
|  |     "style-loader": "^1.2.1", | ||||||
|  |     "ts-loader": "^7.0.5", | ||||||
|  |     "typescript": "^3.9.3", | ||||||
|  |     "webpack": "^4.43.0", | ||||||
|  |     "webpack-cli": "^3.3.11" | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										16
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | { | ||||||
|  |     "compilerOptions": { | ||||||
|  |         "module": "commonjs", | ||||||
|  |         "noImplicitAny": true, | ||||||
|  |         "removeComments": true, | ||||||
|  |         "preserveConstEnums": true, | ||||||
|  |         "sourceMap": true | ||||||
|  |     }, | ||||||
|  |     "include": [ | ||||||
|  |         "assets/**/*.ts" | ||||||
|  |     ], | ||||||
|  |     "exclude": [ | ||||||
|  |         "node_modules", | ||||||
|  |         "**/*.spec.ts" | ||||||
|  |     ] | ||||||
|  | } | ||||||
							
								
								
									
										49
									
								
								webpack.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								webpack.config.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | |||||||
|  | const path = require('path'); | ||||||
|  | const CopyWebpackPlugin = require('copy-webpack-plugin') | ||||||
|  | const ImageminPlugin = require('imagemin-webpack-plugin').default; | ||||||
|  | 
 | ||||||
|  | const config = { | ||||||
|  |     entry: { | ||||||
|  |         main: ['./assets/app.ts'], | ||||||
|  |     }, | ||||||
|  |     output: { | ||||||
|  |         path: path.resolve('./static/dist/'), | ||||||
|  |         publicPath: "/dist/", | ||||||
|  |         filename: "bundle.js", | ||||||
|  |         chunkFilename: 'bundle.[chunkhash:8].js' | ||||||
|  |     }, | ||||||
|  |     resolve: { | ||||||
|  |         extensions: ['.tsx', '.ts', '.js'], | ||||||
|  |     }, | ||||||
|  |     module: { | ||||||
|  |         rules: [{ | ||||||
|  |             test: /\.s[ac]ss$/, | ||||||
|  |             use: ["style-loader", "css-loader?sourceMap", "sass-loader?sourceMap"] | ||||||
|  |         }, { | ||||||
|  |             test: /\.css$/, | ||||||
|  |             use: ["style-loader", "css-loader"] | ||||||
|  |         }, { | ||||||
|  |             test: /\.tsx?$/, | ||||||
|  |             use: 'ts-loader', | ||||||
|  |             exclude: /node_modules/ | ||||||
|  |         }, { | ||||||
|  |             test: /\.(png|svg|jpg|gif)$/, | ||||||
|  |             use: 'file-loader', | ||||||
|  |         }, { | ||||||
|  |             test: /\.(woff|woff2|eot|ttf|otf)$/, | ||||||
|  |             use: 'file-loader' | ||||||
|  |         }] | ||||||
|  |     }, | ||||||
|  |     plugins: [ | ||||||
|  |         new CopyWebpackPlugin({ patterns: [{ from: './assets/images/', to: '../images/' }] }), | ||||||
|  |         new ImageminPlugin({ test: /\.(jpe?g|png|gif|svg)$/i }), | ||||||
|  |     ] | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | module.exports = (env, argv) => { | ||||||
|  |     if (argv.mode === 'development') { | ||||||
|  |         config.devtool = 'inline-source-map'; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return config; | ||||||
|  | }; | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user