diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..8412c494 --- /dev/null +++ b/.gitignore @@ -0,0 +1,156 @@ + +# Created by https://www.toptal.com/developers/gitignore/api/django +# Edit at https://www.toptal.com/developers/gitignore?templates=django + +### Django ### +*.log +*.pot +*.pyc +__pycache__/ +local_settings.py +db.sqlite3 +db.sqlite3-journal +media + +# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/ +# in your Git repository. Update and uncomment the following line accordingly. +# /staticfiles/ + +### Django.Python Stack ### +# Byte-compiled / optimized / DLL files +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +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/ + +# Translations +*.mo + +# Django stuff: + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.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/ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +Hongji0611/ministagram/.vscode/ diff --git a/Hongji0611/ministagram/accounts/__init__.py b/Hongji0611/ministagram/accounts/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/Hongji0611/ministagram/accounts/admin.py b/Hongji0611/ministagram/accounts/admin.py new file mode 100644 index 00000000..e8daddc9 --- /dev/null +++ b/Hongji0611/ministagram/accounts/admin.py @@ -0,0 +1,7 @@ +from django.contrib import admin +from accounts.models import FollowRelation + +class FollowRelationAdmin(admin.ModelAdmin): + list_display = ('follower', ) + +admin.site.register(FollowRelation, FollowRelationAdmin) \ No newline at end of file diff --git a/Hongji0611/ministagram/accounts/apps.py b/Hongji0611/ministagram/accounts/apps.py new file mode 100644 index 00000000..9b3fc5a4 --- /dev/null +++ b/Hongji0611/ministagram/accounts/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class AccountsConfig(AppConfig): + name = 'accounts' diff --git a/Hongji0611/ministagram/accounts/migrations/0001_initial.py b/Hongji0611/ministagram/accounts/migrations/0001_initial.py new file mode 100644 index 00000000..d0af9b59 --- /dev/null +++ b/Hongji0611/ministagram/accounts/migrations/0001_initial.py @@ -0,0 +1,25 @@ +# Generated by Django 3.0.8 on 2020-07-12 07:51 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='FollowRelation', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('followee', models.ManyToManyField(related_name='followee', to=settings.AUTH_USER_MODEL)), + ('follower', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='follower', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/Hongji0611/ministagram/accounts/migrations/__init__.py b/Hongji0611/ministagram/accounts/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/Hongji0611/ministagram/accounts/models.py b/Hongji0611/ministagram/accounts/models.py new file mode 100644 index 00000000..cc46bd14 --- /dev/null +++ b/Hongji0611/ministagram/accounts/models.py @@ -0,0 +1,12 @@ +from django.db import models +from django.contrib.auth.models import User + +# Create your models here. + + +class FollowRelation(models.Model): + objects = models.Manager() + DoesNotExist = models.Manager() + follower = models.OneToOneField( + User, related_name='follower', on_delete=models.CASCADE) # 나를 팔로우 하는 사람 + followee = models.ManyToManyField(User, related_name='followee') # 내가 팔로우 diff --git a/Hongji0611/ministagram/accounts/templates/accounts/login.html b/Hongji0611/ministagram/accounts/templates/accounts/login.html new file mode 100644 index 00000000..ab8bc847 --- /dev/null +++ b/Hongji0611/ministagram/accounts/templates/accounts/login.html @@ -0,0 +1,21 @@ +{% extends 'base.html' %} + +{% block title %} +{% endblock %} + +{% block content %} +
+
+
+ +
+ {% csrf_token %} + {{form.as_p}} + +
+
+
+ +
+{% endblock %} \ No newline at end of file diff --git a/Hongji0611/ministagram/accounts/templates/accounts/logout.html b/Hongji0611/ministagram/accounts/templates/accounts/logout.html new file mode 100644 index 00000000..d384bb0d --- /dev/null +++ b/Hongji0611/ministagram/accounts/templates/accounts/logout.html @@ -0,0 +1,17 @@ +{% extends 'base.html' %} + +{% block title %} +{% endblock %} + +{% block content %} +
+
+
+ + login 하기 +
+
+ +
+{% endblock %} \ No newline at end of file diff --git a/Hongji0611/ministagram/accounts/templates/accounts/relation.html b/Hongji0611/ministagram/accounts/templates/accounts/relation.html new file mode 100644 index 00000000..7a70564d --- /dev/null +++ b/Hongji0611/ministagram/accounts/templates/accounts/relation.html @@ -0,0 +1,99 @@ +{% extends 'base.html' %} + +{% block title %} +{% endblock %} + +{% block content %} +
+ +

사용자 찾기

+ + +

+

+

+ + +

날 팔로우하는 사람들

+ {% if followers %} + + {% endif %} + +

내가 팔로우하는 사람들

+ {% if followees %} + + {% endif %} +
+ + + +{% endblock %} \ No newline at end of file diff --git a/Hongji0611/ministagram/accounts/templates/accounts/signup.html b/Hongji0611/ministagram/accounts/templates/accounts/signup.html new file mode 100644 index 00000000..56f6b5ca --- /dev/null +++ b/Hongji0611/ministagram/accounts/templates/accounts/signup.html @@ -0,0 +1,22 @@ +{% extends 'base.html' %} + +{% block title %} +{% endblock %} + +{% block content %} +
+
+
+ +
+ {% csrf_token %} + {{ signup_form }} +
+ +
+
+
+ +
+{% endblock %} \ No newline at end of file diff --git a/Hongji0611/ministagram/accounts/tests.py b/Hongji0611/ministagram/accounts/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/Hongji0611/ministagram/accounts/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/Hongji0611/ministagram/accounts/urls.py b/Hongji0611/ministagram/accounts/urls.py new file mode 100644 index 00000000..b34284ee --- /dev/null +++ b/Hongji0611/ministagram/accounts/urls.py @@ -0,0 +1,17 @@ + +from django.urls import path +from django.contrib.auth.views import LoginView, LogoutView +from .views import RelationView, RelationCreateView, RelationDeleteView, UserInfoGetView +from . import views + +app_name = "accounts" + +urlpatterns = [ + path('relationuserinfo/', UserInfoGetView.as_view(), name='relationuserinfo'), + path('relationdelete/', RelationDeleteView.as_view(), name='relationdelete'), + path('relationcreate/', RelationCreateView.as_view(), name='relationcreate'), + path('relation/', RelationView.as_view(template_name='accounts/relation.html'), name='relation'), + path('signup/', views.signup, name='signup'), + path('login/', LoginView.as_view(template_name='accounts/login.html'), name='login'), + path('logout/', LogoutView.as_view(template_name='accounts/logout.html'), name='logout'), +] diff --git a/Hongji0611/ministagram/accounts/views.py b/Hongji0611/ministagram/accounts/views.py new file mode 100644 index 00000000..16f54f15 --- /dev/null +++ b/Hongji0611/ministagram/accounts/views.py @@ -0,0 +1,127 @@ +from django.shortcuts import render, redirect +from django.contrib.auth.forms import UserCreationForm + +from django.contrib.auth.decorators import login_required +from django.utils.decorators import method_decorator +from .models import FollowRelation +from django.db import IntegrityError + +from django.views import View +from django.views.decorators.csrf import csrf_exempt +from django.http import JsonResponse + +from django.views.generic import TemplateView +from django.contrib.auth.models import User +from django.urls import reverse + + +def signup(request): + if request.method == 'POST': + signup_form = UserCreationForm(request.POST) + if signup_form.is_valid(): + signup_form.save() + return redirect('/accounts/login') + else: + signup_form = UserCreationForm() + + return render(request, 'accounts/signup.html', {'signup_form': signup_form}) + + +@method_decorator(csrf_exempt, name="dispatch") +class BaseView(View): + @staticmethod + def response(data={}, message='', status=200): + result = { + 'data': data, + 'message': message, + } + return JsonResponse(result, status=status) + +# 팔로우 버튼을 눌렀을 때 + + +@method_decorator(login_required, name="dispatch") +class RelationCreateView(BaseView): + def post(self, request): + try: # 상대방의 아이디가 존재하는지 확인 + user_id = request.POST.get('id', '') + except: # 존재하지 않는 아이디 + return self.response(message='잘못된 요청입니다.', status=400) + + try: # 내 관계망이 존재하는 지 + relation = FollowRelation.objects.get(follower=request.user) + except: # 없을 경우 새 객체 생성 + relation = FollowRelation.objects.create(follower=request.user) + + try: # 내 아이디일경우 팔로우 x + if user_id == request.user.id: + raise IntegrityError + relation.followee.add(user_id) # 내 followee에 추가 + relation.save() + except: + return self.response(message='잘못된 요청입니다.', status=400) + + return self.response({}) + +# 언팔로우 + + +@method_decorator(login_required, name='dispatch') +class RelationDeleteView(BaseView): + def post(self, request): + try: # 상대 아이디 존재 확인 + user_id = request.POST.get('id', '') + except: + return self.response(message="잘못된 요청입니다.", status=400) + + try: # 나의 관계망이 존재하는지 확인 + relation = FollowRelation.objects.get(follower=request.user) + except: + return self.response(message="잘못된 요청입니다.", status=400) + + try: + if user_id == request.user.id: # 자기 자신 언팔로우 불가 + raise IntegrityError + relation.followee.remove(user_id) # 언팔로우 + relation.save() + except: + return self.response(message="잘못된 요청입니다.", status=400) + + return self.response({}) + +# 친구 목록 페이지 + + +@method_decorator(login_required, name='dispatch') +class RelationView(TemplateView): + # template_name = 'relation.html' #템플릿으로 렌더링 + def get_context_data(self, **kwargs): + context = super(RelationView, self).get_context_data(**kwargs) + user = self.request.user + + try: + followers = FollowRelation.objects.get( + follower=user).followee.all() # 내 followee를 모두 가져옴 + context['followees'] = followers + context['followees_ids'] = list( + followers.values_list('id', flat=True)) + + except: # 없을경우 넘어감 + pass + # 나를 팔로우하는 사람, follower를 저장 + context['followers'] = FollowRelation.objects.select_related( + 'follower').filter(followee__in=[user]) + return context + +# 사용자 검색 + + +class UserInfoGetView(BaseView): + def get(self, request): + username = request.GET.get('username', '').strip() + try: + user = User.objects.get(username=username) + except: + self.response(message="사용자를 찾을 수 없습니다.", status=404) + + return self.response({'username': username, 'email': user.email, 'id': user.id}) diff --git a/Hongji0611/ministagram/layout/base.html b/Hongji0611/ministagram/layout/base.html new file mode 100644 index 00000000..b5e7fa40 --- /dev/null +++ b/Hongji0611/ministagram/layout/base.html @@ -0,0 +1,116 @@ +{% load static %} + + + + + + + + + + + + + {% block title %} {% endblock %} + + + + + + {% if messages %} +
+
+
+ {% for message in messages %} +
{{message}}
+ {% endfor %} +
+
+
+
+ {% endif %} + + {% block content %} + + {% endblock %} + + + \ No newline at end of file diff --git a/Hongji0611/ministagram/manage.py b/Hongji0611/ministagram/manage.py new file mode 100644 index 00000000..66ed3a9d --- /dev/null +++ b/Hongji0611/ministagram/manage.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.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) diff --git a/Hongji0611/ministagram/mysite/__init__.py b/Hongji0611/ministagram/mysite/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/Hongji0611/ministagram/mysite/settings.py b/Hongji0611/ministagram/mysite/settings.py new file mode 100644 index 00000000..ceb96625 --- /dev/null +++ b/Hongji0611/ministagram/mysite/settings.py @@ -0,0 +1,131 @@ +""" +Django settings for mysite project. + +Generated by 'django-admin startproject' using Django 2.0.13. + +For more information on this file, see +https://docs.djangoproject.com/en/2.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/2.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/2.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'k5+m@98q)a(%@y_o-ld&pp4&yg=#+#hm#c00@ka#r#2osct(zr' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ['127.0.0.1', '.pythonanywhere.com'] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'photo', + 'accounts', + +] + +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 = 'mysite.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR, 'layout')], + '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 = 'mysite.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/2.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/2.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/2.0/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'Asia/Seoul' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/2.0/howto/static-files/ + +STATIC_URL = '/static/' +STATICFILES_DIRS = ( + os.path.join(BASE_DIR, "static"), # Root의 static 파일 +) + +MEDIA_URL = '/res/' +MEDIA_ROOT = os.path.join(BASE_DIR, 'media') + +LOGIN_REDIRECT_URL = '/' diff --git a/Hongji0611/ministagram/mysite/urls.py b/Hongji0611/ministagram/mysite/urls.py new file mode 100644 index 00000000..9d57d414 --- /dev/null +++ b/Hongji0611/ministagram/mysite/urls.py @@ -0,0 +1,23 @@ +"""mysite URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/2.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 + +urlpatterns = [ + path('accounts/', include('accounts.urls')), + path('admin/', admin.site.urls), + path('', include("photo.urls")), +] diff --git a/Hongji0611/ministagram/mysite/wsgi.py b/Hongji0611/ministagram/mysite/wsgi.py new file mode 100644 index 00000000..ffbfe4f5 --- /dev/null +++ b/Hongji0611/ministagram/mysite/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for mysite 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/2.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") + +application = get_wsgi_application() diff --git a/Hongji0611/ministagram/myvenv/Scripts/Activate.ps1 b/Hongji0611/ministagram/myvenv/Scripts/Activate.ps1 new file mode 100644 index 00000000..e86c678a --- /dev/null +++ b/Hongji0611/ministagram/myvenv/Scripts/Activate.ps1 @@ -0,0 +1,385 @@ +<# +.Synopsis +Activate a Python virtual environment for the current PowerShell session. + +.Description +Pushes the python executable for a virtual environment to the front of the +$Env:PATH environment variable and sets the prompt to signify that you are +in a Python virtual environment. Makes use of the command line switches as +well as the `pyvenv.cfg` file values present in the virtual environment. + +.Parameter VenvDir +Path to the directory that contains the virtual environment to activate. The +default value for this is the parent of the directory that the Activate.ps1 +script is located within. + +.Parameter Prompt +The prompt prefix to display when this virtual environment is activated. By +default, this prompt is the name of the virtual environment folder (VenvDir) +surrounded by parentheses and followed by a single space (ie. '(.venv) '). + +.Example +Activate.ps1 +Activates the Python virtual environment that contains the Activate.ps1 script. + +.Example +Activate.ps1 -Verbose +Activates the Python virtual environment that contains the Activate.ps1 script, +and shows extra information about the activation as it executes. + +.Example +Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv +Activates the Python virtual environment located in the specified location. + +.Example +Activate.ps1 -Prompt "MyPython" +Activates the Python virtual environment that contains the Activate.ps1 script, +and prefixes the current prompt with the specified string (surrounded in +parentheses) while the virtual environment is active. + +.Notes +On Windows, it may be required to enable this Activate.ps1 script by setting the +execution policy for the user. You can do this by issuing the following PowerShell +command: + +PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +For more information on Execution Policies: +ttps:/go.microsoft.com/fwlink/?LinkID=135170 + +#> +Param( + [Parameter(Mandatory = $false)] + [String] + $VenvDir, + [Parameter(Mandatory = $false)] + [String] + $Prompt +) + +<# Function declarations --------------------------------------------------- #> + +<# +.Synopsis +Remove all shell session elements added by the Activate script, including the +addition of the virtual environment's Python executable from the beginning of +the PATH variable. + +.Parameter NonDestructive +If present, do not remove this function from the global namespace for the +session. + +#> +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + + # The prior prompt: + if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { + Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt + Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT + } + + # The prior PYTHONHOME: + if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { + Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME + Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME + } + + # The prior PATH: + if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { + Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH + Remove-Item -Path Env:_OLD_VIRTUAL_PATH + } + + # Just remove the VIRTUAL_ENV altogether: + if (Test-Path -Path Env:VIRTUAL_ENV) { + Remove-Item -Path env:VIRTUAL_ENV + } + + # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: + if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { + Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force + } + + # Leave deactivate function in the global namespace if requested: + if (-not $NonDestructive) { + Remove-Item -Path function:deactivate + } +} + +<# +.Description +Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the +given folder, and returns them in a map. + +For each line in the pyvenv.cfg file, if that line can be parsed into exactly +two strings separated by `=` (with any amount of whitespace surrounding the =) +then it is considered a `key = value` line. The left hand string is the key, +the right hand is the value. + +If the value starts with a `'` or a `"` then the first and last character is +stripped from the value before being captured. + +.Parameter ConfigDir +Path to the directory that contains the `pyvenv.cfg` file. +#> +function Get-PyVenvConfig( + [String] + $ConfigDir +) { + Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" + + # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). + $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue + + # An empty map will be returned if no config file is found. + $pyvenvConfig = @{ } + + if ($pyvenvConfigPath) { + + Write-Verbose "File exists, parse `key = value` lines" + $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath + + $pyvenvConfigContent | ForEach-Object { + $keyval = $PSItem -split "\s*=\s*", 2 + if ($keyval[0] -and $keyval[1]) { + $val = $keyval[1] + + # Remove extraneous quotations around a string value. + if ("'""".Contains($val.Substring(0, 1))) { + $val = $val.Substring(1, $val.Length - 2) + } + + $pyvenvConfig[$keyval[0]] = $val + Write-Verbose "Adding Key: '$($keyval[0])'='$val'" + } + } + } + return $pyvenvConfig +} + + +<# Begin Activate script --------------------------------------------------- #> + +# Determine the containing directory of this script +$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition +$VenvExecDir = Get-Item -Path $VenvExecPath + +Write-Verbose "Activation script is located in path: '$VenvExecPath'" +Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" +Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" + +# Set values required in priority: CmdLine, ConfigFile, Default +# First, get the location of the virtual environment, it might not be +# VenvExecDir if specified on the command line. +if ($VenvDir) { + Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" +} +else { + Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." + $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") + Write-Verbose "VenvDir=$VenvDir" +} + +# Next, read the `pyvenv.cfg` file to determine any required value such +# as `prompt`. +$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir + +# Next, set the prompt from the command line, or the config file, or +# just use the name of the virtual environment folder. +if ($Prompt) { + Write-Verbose "Prompt specified as argument, using '$Prompt'" +} +else { + Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" + if ($pyvenvCfg -and $pyvenvCfg['prompt']) { + Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" + $Prompt = $pyvenvCfg['prompt']; + } + else { + Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virutal environment)" + Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" + $Prompt = Split-Path -Path $venvDir -Leaf + } +} + +Write-Verbose "Prompt = '$Prompt'" +Write-Verbose "VenvDir='$VenvDir'" + +# Deactivate any currently active virtual environment, but leave the +# deactivate function in place. +deactivate -nondestructive + +# Now set the environment variable VIRTUAL_ENV, used by many tools to determine +# that there is an activated venv. +$env:VIRTUAL_ENV = $VenvDir + +if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { + + Write-Verbose "Setting prompt to '$Prompt'" + + # Set the prompt to include the env name + # Make sure _OLD_VIRTUAL_PROMPT is global + function global:_OLD_VIRTUAL_PROMPT { "" } + Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT + New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt + + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " + _OLD_VIRTUAL_PROMPT + } +} + +# Clear PYTHONHOME +if (Test-Path -Path Env:PYTHONHOME) { + Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME + Remove-Item -Path Env:PYTHONHOME +} + +# Add the venv to the PATH +Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH +$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" + +# SIG # Begin signature block +# MIIaVgYJKoZIhvcNAQcCoIIaRzCCGkMCAQExDzANBglghkgBZQMEAgEFADB5Bgor +# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG +# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCB4FjjwuGJ5gSL0 +# iL6S7lcEZZkUeR8WmjwNHaW4JFCdraCCFBgwggPuMIIDV6ADAgECAhB+k+v7fMZO +# WepLmnfUBvw7MA0GCSqGSIb3DQEBBQUAMIGLMQswCQYDVQQGEwJaQTEVMBMGA1UE +# CBMMV2VzdGVybiBDYXBlMRQwEgYDVQQHEwtEdXJiYW52aWxsZTEPMA0GA1UEChMG +# VGhhd3RlMR0wGwYDVQQLExRUaGF3dGUgQ2VydGlmaWNhdGlvbjEfMB0GA1UEAxMW +# VGhhd3RlIFRpbWVzdGFtcGluZyBDQTAeFw0xMjEyMjEwMDAwMDBaFw0yMDEyMzAy +# MzU5NTlaMF4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3Jh +# dGlvbjEwMC4GA1UEAxMnU3ltYW50ZWMgVGltZSBTdGFtcGluZyBTZXJ2aWNlcyBD +# QSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsayzSVRLlxwS +# CtgleZEiVypv3LgmxENza8K/LlBa+xTCdo5DASVDtKHiRfTot3vDdMwi17SUAAL3 +# Te2/tLdEJGvNX0U70UTOQxJzF4KLabQry5kerHIbJk1xH7Ex3ftRYQJTpqr1SSwF +# eEWlL4nO55nn/oziVz89xpLcSvh7M+R5CvvwdYhBnP/FA1GZqtdsn5Nph2Upg4XC +# YBTEyMk7FNrAgfAfDXTekiKryvf7dHwn5vdKG3+nw54trorqpuaqJxZ9YfeYcRG8 +# 4lChS+Vd+uUOpyyfqmUg09iW6Mh8pU5IRP8Z4kQHkgvXaISAXWp4ZEXNYEZ+VMET +# fMV58cnBcQIDAQABo4H6MIH3MB0GA1UdDgQWBBRfmvVuXMzMdJrU3X3vP9vsTIAu +# 3TAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnRoYXd0 +# ZS5jb20wEgYDVR0TAQH/BAgwBgEB/wIBADA/BgNVHR8EODA2MDSgMqAwhi5odHRw +# Oi8vY3JsLnRoYXd0ZS5jb20vVGhhd3RlVGltZXN0YW1waW5nQ0EuY3JsMBMGA1Ud +# JQQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIBBjAoBgNVHREEITAfpB0wGzEZ +# MBcGA1UEAxMQVGltZVN0YW1wLTIwNDgtMTANBgkqhkiG9w0BAQUFAAOBgQADCZuP +# ee9/WTCq72i1+uMJHbtPggZdN1+mUp8WjeockglEbvVt61h8MOj5aY0jcwsSb0ep +# rjkR+Cqxm7Aaw47rWZYArc4MTbLQMaYIXCp6/OJ6HVdMqGUY6XlAYiWWbsfHN2qD +# IQiOQerd2Vc/HXdJhyoWBl6mOGoiEqNRGYN+tjCCBKMwggOLoAMCAQICEA7P9DjI +# /r81bgTYapgbGlAwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxHTAbBgNV +# BAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMTAwLgYDVQQDEydTeW1hbnRlYyBUaW1l +# IFN0YW1waW5nIFNlcnZpY2VzIENBIC0gRzIwHhcNMTIxMDE4MDAwMDAwWhcNMjAx +# MjI5MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29y +# cG9yYXRpb24xNDAyBgNVBAMTK1N5bWFudGVjIFRpbWUgU3RhbXBpbmcgU2Vydmlj +# ZXMgU2lnbmVyIC0gRzQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCi +# Yws5RLi7I6dESbsO/6HwYQpTk7CY260sD0rFbv+GPFNVDxXOBD8r/amWltm+YXkL +# W8lMhnbl4ENLIpXuwitDwZ/YaLSOQE/uhTi5EcUj8mRY8BUyb05Xoa6IpALXKh7N +# S+HdY9UXiTJbsF6ZWqidKFAOF+6W22E7RVEdzxJWC5JH/Kuu9mY9R6xwcueS51/N +# ELnEg2SUGb0lgOHo0iKl0LoCeqF3k1tlw+4XdLxBhircCEyMkoyRLZ53RB9o1qh0 +# d9sOWzKLVoszvdljyEmdOsXF6jML0vGjG/SLvtmzV4s73gSneiKyJK4ux3DFvk6D +# Jgj7C72pT5kI4RAocqrNAgMBAAGjggFXMIIBUzAMBgNVHRMBAf8EAjAAMBYGA1Ud +# JQEB/wQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIHgDBzBggrBgEFBQcBAQRn +# MGUwKgYIKwYBBQUHMAGGHmh0dHA6Ly90cy1vY3NwLndzLnN5bWFudGVjLmNvbTA3 +# BggrBgEFBQcwAoYraHR0cDovL3RzLWFpYS53cy5zeW1hbnRlYy5jb20vdHNzLWNh +# LWcyLmNlcjA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vdHMtY3JsLndzLnN5bWFu +# dGVjLmNvbS90c3MtY2EtZzIuY3JsMCgGA1UdEQQhMB+kHTAbMRkwFwYDVQQDExBU +# aW1lU3RhbXAtMjA0OC0yMB0GA1UdDgQWBBRGxmmjDkoUHtVM2lJjFz9eNrwN5jAf +# BgNVHSMEGDAWgBRfmvVuXMzMdJrU3X3vP9vsTIAu3TANBgkqhkiG9w0BAQUFAAOC +# AQEAeDu0kSoATPCPYjA3eKOEJwdvGLLeJdyg1JQDqoZOJZ+aQAMc3c7jecshaAba +# tjK0bb/0LCZjM+RJZG0N5sNnDvcFpDVsfIkWxumy37Lp3SDGcQ/NlXTctlzevTcf +# Q3jmeLXNKAQgo6rxS8SIKZEOgNER/N1cdm5PXg5FRkFuDbDqOJqxOtoJcRD8HHm0 +# gHusafT9nLYMFivxf1sJPZtb4hbKE4FtAC44DagpjyzhsvRaqQGvFZwsL0kb2yK7 +# w/54lFHDhrGCiF3wPbRRoXkzKy57udwgCRNx62oZW8/opTBXLIlJP7nPf8m/PiJo +# Y1OavWl0rMUdPH+S4MO8HNgEdTCCBTAwggQYoAMCAQICEAQJGBtf1btmdVNDtW+V +# UAgwDQYJKoZIhvcNAQELBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lD +# ZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGln +# aUNlcnQgQXNzdXJlZCBJRCBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAy +# MjEyMDAwMFowcjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ +# MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hB +# MiBBc3N1cmVkIElEIENvZGUgU2lnbmluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQAD +# ggEPADCCAQoCggEBAPjTsxx/DhGvZ3cH0wsxSRnP0PtFmbE620T1f+Wondsy13Hq +# dp0FLreP+pJDwKX5idQ3Gde2qvCchqXYJawOeSg6funRZ9PG+yknx9N7I5TkkSOW +# kHeC+aGEI2YSVDNQdLEoJrskacLCUvIUZ4qJRdQtoaPpiCwgla4cSocI3wz14k1g +# GL6qxLKucDFmM3E+rHCiq85/6XzLkqHlOzEcz+ryCuRXu0q16XTmK/5sy350OTYN +# kO/ktU6kqepqCquE86xnTrXE94zRICUj6whkPlKWwfIPEvTFjg/BougsUfdzvL2F +# sWKDc0GCB+Q4i2pzINAPZHM8np+mM6n9Gd8lk9ECAwEAAaOCAc0wggHJMBIGA1Ud +# EwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUF +# BwMDMHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGln +# aWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5j +# b20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0MIGBBgNVHR8EejB4MDqgOKA2 +# hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290 +# Q0EuY3JsMDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRB +# c3N1cmVkSURSb290Q0EuY3JsME8GA1UdIARIMEYwOAYKYIZIAYb9bAACBDAqMCgG +# CCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAoGCGCGSAGG +# /WwDMB0GA1UdDgQWBBRaxLl7KgqjpepxA8Bg+S32ZXUOWDAfBgNVHSMEGDAWgBRF +# 66Kv9JLLgjEtUYunpyGd823IDzANBgkqhkiG9w0BAQsFAAOCAQEAPuwNWiSz8yLR +# FcgsfCUpdqgdXRwtOhrE7zBh134LYP3DPQ/Er4v97yrfIFU3sOH20ZJ1D1G0bqWO +# WuJeJIFOEKTuP3GOYw4TS63XX0R58zYUBor3nEZOXP+QsRsHDpEV+7qvtVHCjSSu +# JMbHJyqhKSgaOnEoAjwukaPAJRHinBRHoXpoaK+bp1wgXNlxsQyPu6j4xRJon89A +# y0BEpRPw5mQMJQhCMrI2iiQC/i9yfhzXSUWW6Fkd6fp0ZGuy62ZD2rOwjNXpDd32 +# ASDOmTFjPQgaGLOBm0/GkxAG/AeB+ova+YJJ92JuoVP6EpQYhS6SkepobEQysmah +# 5xikmmRR7zCCBkcwggUvoAMCAQICEAM+1e2gZdG4yR38+Spsm9gwDQYJKoZIhvcN +# AQELBQAwcjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcG +# A1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBB +# c3N1cmVkIElEIENvZGUgU2lnbmluZyBDQTAeFw0xODEyMTgwMDAwMDBaFw0yMTEy +# MjIxMjAwMDBaMIGDMQswCQYDVQQGEwJVUzEWMBQGA1UECBMNTmV3IEhhbXBzaGly +# ZTESMBAGA1UEBxMJV29sZmVib3JvMSMwIQYDVQQKExpQeXRob24gU29mdHdhcmUg +# Rm91bmRhdGlvbjEjMCEGA1UEAxMaUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24w +# ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqvaRLsnW5buglHGWx2sRM +# CMpqt+gflMjw9ZJPphvbE+ig/u8dPiJpVfIvkvN7V/ncnDrtKn67nbh8ld/fSodW +# IRbG6bLZFYbSdyJTZ36YyrOOVoBZJk0XS7hFy/IMmiQRXRFQ6ojkIbnM8jdb25Do +# uJSTccJhbqSkfXvsDlPenD8+jw7woSskafVqdqq0ggKr33JLGsxp3/aE8wFF/o11 +# qHt/sc+fWCRJJMCh6PK6oXmH4HSojj4krn5Uu/Prn1VNsBYmxhqSTFnFVZikW/gp +# 5BJLCijQPMy+YRGxPM29UExaG706uIk2D5B8WZ/3rNVO73dxn6vvEyltfJ8g4YqE +# cxpG5nyKG5YjHeAj1YcMVfp8EpHz4eWF2RqIERYixdGjL4RBTIrvNSz4Wo6jaxFi +# 21uzwxMX1gMoVnDI+Of1af6AsZ3k1QRXI28P1BUYES03u/Hztt24lQHwXgPKUSwy +# 1lN+PD9q7oCY6ead4rlRypIm7BHJloY2TvLeqPTq63H4dNOoeCL3vlSnF/KvACqS +# i+hkRYFVKm+S7w9WGQFdwuY17owQeUWJoyiIAMB4qZflEVGQ35WuZgZODjNqPF90 +# d4hjxO8t/jy1N+adAl33yB4lC//TU1TL8XG7CoC5ORp7Pk2XUvE/QKlMeGCHM7gV +# EPiK1PbCpOHiOmiPD1BmewIDAQABo4IBxTCCAcEwHwYDVR0jBBgwFoAUWsS5eyoK +# o6XqcQPAYPkt9mV1DlgwHQYDVR0OBBYEFPwqv37Uvqzzgpykz3siATu4jwfyMA4G +# A1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzB3BgNVHR8EcDBuMDWg +# M6Axhi9odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLWNzLWcx +# LmNybDA1oDOgMYYvaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJl +# ZC1jcy1nMS5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAwEwKjAoBggrBgEFBQcC +# ARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBBAEwgYQGCCsG +# AQUFBwEBBHgwdjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t +# ME4GCCsGAQUFBzAChkJodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl +# cnRTSEEyQXNzdXJlZElEQ29kZVNpZ25pbmdDQS5jcnQwDAYDVR0TAQH/BAIwADAN +# BgkqhkiG9w0BAQsFAAOCAQEAS3WhLbVfRrGJp8+PJj6+ViqNYq5S79gW5hYgSrqJ +# FFoVps0OGP1EEVAX9omITmaytAQ58APr/qBVIf3WVlYGqDo0R4b1P1JduIA+8n0I +# RYWx2RdSuNtaG8Ke5nuSpS5TkEC6YjVBFuliBkvdQD6JleSaNsaHWWfytSFYjFsF +# gvhKDaeqkHjinsJQViQ+P8xvBTaC8FXaleOPlZqyShm2wAIy/mDjYE2hUuhECL56 +# /qzTs8634m0dEibzuVPK5zzCHSzBM9TCSwpstTVl2P0Kmq3Nee5UTTDnR7Em9FIr +# dW3iD7S+KCkjeo+YN2mR/37gy/LRcw1yqu2HDbRH4+QiUzGCBZQwggWQAgEBMIGG +# MHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsT +# EHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJl +# ZCBJRCBDb2RlIFNpZ25pbmcgQ0ECEAM+1e2gZdG4yR38+Spsm9gwDQYJYIZIAWUD +# BAIBBQCggdAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIB +# CzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIPNbsYAL3juaSl9Roa7m +# dLCGeSOJmm7EQN82IOS7MbKgMGQGCisGAQQBgjcCAQwxVjBUoFKAUABCAHUAaQBs +# AHQAOgAgAFIAZQBsAGUAYQBzAGUAXwBtAGEAcwB0AGUAcgBfAHYAMwAuADgALgAz +# AF8AMgAwADIAMAAwADUAMQAzAC4AMAAxMA0GCSqGSIb3DQEBAQUABIICAFoBI+k0 +# KxpgzPUZdhZWI7pSojbxbgQUSwEHAlM67AW37d2QEG+dfaSFfDoESv+OaDrrF9jL +# m4zya5Gbp3LqfaRhaiH8tBn8MNSNfreNLvIjjFWBl6LwW3uvjzsIGvFUHze9KPlO +# WpmYvzpl5JE0jd8SvwnOSo3BMaxBOfu9e0T1o6ZRSOvnqaVQ4Wh3+OBrjlNXLY89 +# i77bzA7T/VJiYfSzcU+Xz6aJT9LuhMJFhTt4pCML/PkNyUy9Ul2K0QdbFV92BBE/ +# 7qN7J1kBy3dKiCr6iZQml4nV0AoR1f+1i9tlo1Qn70lqBI+DEczeEJLtF0yJmM10 +# GyIyGIWy2cup22NToMH/kotY7d4nNIRJVoa+2X+6vnbDahyEs7hAwR6lT7gUEFA4 +# lucVUvRU8OC/cddtRgDlntXSml82NI7cByZWE4LFJbrVTt2mGm5/jg+usKI54VMX +# +VDp7m6EP1pMKx5z+KjXyX40R/pfc4aHVoFFKhku64gIFfqNSbMc++vqLWDp3OHR +# RrdWVoc9NY74uJAduhtKHmns7/InDIbyVflQkV3s2PWRp5HQmx5DlPdMzWc8z9t8 +# Dq9gbZGvKdd5BVFufDHOtMdY9wsgEh5FufVpg8DPkQAHLttHTLJFDF7i51+tUtaX +# aIhg7D05Qe8GolwnqzoPTpu2md817f9GmtS/oYICCzCCAgcGCSqGSIb3DQEJBjGC +# AfgwggH0AgEBMHIwXjELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENv +# cnBvcmF0aW9uMTAwLgYDVQQDEydTeW1hbnRlYyBUaW1lIFN0YW1waW5nIFNlcnZp +# Y2VzIENBIC0gRzICEA7P9DjI/r81bgTYapgbGlAwCQYFKw4DAhoFAKBdMBgGCSqG +# SIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTIwMDUxMzIyNDAz +# NlowIwYJKoZIhvcNAQkEMRYEFGvGhq7WjDU26Cx/8cBMSpp1ezCYMA0GCSqGSIb3 +# DQEBAQUABIIBAFjCxGzXx3VcKnVQwlVZDRFhwa2ydhxi6FrVWqUWJSrskemZO2XP +# d5tTIDsk3m5rhwsRpyS2PlflF/MaYC6JCg2ub7taF/JAN0eie+G2jlrgO1gHO+eU +# e4IayFrBTEk11igHAleYCjYSnuPmkj0cvtF+iXO4vO10udWPuf5+kDfZr8N4FNFF +# 4ccPlA9HJq3afqsa98IJOyo8QhaVeKwP7w9jE2gPKndfc02oRI7y5qiI7+/jT1Iy +# smmUsl9VxIhPSsinxuwbypy/bTcGFYPrO6nciLrvrQajYjOeiz4geYcbHMGtNHfD +# q+pqvBqD3fe0YICRI775km7P4AYxGPKZBW4= +# SIG # End signature block diff --git a/Hongji0611/ministagram/myvenv/Scripts/activate b/Hongji0611/ministagram/myvenv/Scripts/activate new file mode 100644 index 00000000..a6fbdd09 --- /dev/null +++ b/Hongji0611/ministagram/myvenv/Scripts/activate @@ -0,0 +1,76 @@ +# This file must be used with "source bin/activate" *from bash* +# you cannot run it directly + +deactivate () { + # reset old environment variables + if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then + PATH="${_OLD_VIRTUAL_PATH:-}" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then + PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" + export PYTHONHOME + unset _OLD_VIRTUAL_PYTHONHOME + fi + + # This should detect bash and zsh, which have a hash command that must + # be called to get it to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then + hash -r + fi + + if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then + PS1="${_OLD_VIRTUAL_PS1:-}" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + if [ ! "${1:-}" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +VIRTUAL_ENV="C:\Users\82106\Tasks\Hongji0611\ministagram\myvenv" +export VIRTUAL_ENV + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/Scripts:$PATH" +export PATH + +# unset PYTHONHOME if set +# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) +# could use `if (set -u; : $PYTHONHOME) ;` in bash +if [ -n "${PYTHONHOME:-}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then + _OLD_VIRTUAL_PS1="${PS1:-}" + if [ "x(myvenv) " != x ] ; then + PS1="(myvenv) ${PS1:-}" + else + if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then + # special case for Aspen magic directories + # see http://www.zetadev.com/software/aspen/ + PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1" + else + PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1" + fi + fi + export PS1 +fi + +# This should detect bash and zsh, which have a hash command that must +# be called to get it to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then + hash -r +fi diff --git a/Hongji0611/ministagram/myvenv/Scripts/activate.bat b/Hongji0611/ministagram/myvenv/Scripts/activate.bat new file mode 100644 index 00000000..b7acb621 --- /dev/null +++ b/Hongji0611/ministagram/myvenv/Scripts/activate.bat @@ -0,0 +1,33 @@ +@echo off + +rem This file is UTF-8 encoded, so we need to update the current code page while executing it +for /f "tokens=2 delims=:." %%a in ('"%SystemRoot%\System32\chcp.com"') do ( + set _OLD_CODEPAGE=%%a +) +if defined _OLD_CODEPAGE ( + "%SystemRoot%\System32\chcp.com" 65001 > nul +) + +set VIRTUAL_ENV=C:\Users\82106\Tasks\Hongji0611\ministagram\myvenv + +if not defined PROMPT set PROMPT=$P$G + +if defined _OLD_VIRTUAL_PROMPT set PROMPT=%_OLD_VIRTUAL_PROMPT% +if defined _OLD_VIRTUAL_PYTHONHOME set PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME% + +set _OLD_VIRTUAL_PROMPT=%PROMPT% +set PROMPT=(myvenv) %PROMPT% + +if defined PYTHONHOME set _OLD_VIRTUAL_PYTHONHOME=%PYTHONHOME% +set PYTHONHOME= + +if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH% +if not defined _OLD_VIRTUAL_PATH set _OLD_VIRTUAL_PATH=%PATH% + +set PATH=%VIRTUAL_ENV%\Scripts;%PATH% + +:END +if defined _OLD_CODEPAGE ( + "%SystemRoot%\System32\chcp.com" %_OLD_CODEPAGE% > nul + set _OLD_CODEPAGE= +) diff --git a/Hongji0611/ministagram/myvenv/Scripts/deactivate.bat b/Hongji0611/ministagram/myvenv/Scripts/deactivate.bat new file mode 100644 index 00000000..1205c618 --- /dev/null +++ b/Hongji0611/ministagram/myvenv/Scripts/deactivate.bat @@ -0,0 +1,21 @@ +@echo off + +if defined _OLD_VIRTUAL_PROMPT ( + set "PROMPT=%_OLD_VIRTUAL_PROMPT%" +) +set _OLD_VIRTUAL_PROMPT= + +if defined _OLD_VIRTUAL_PYTHONHOME ( + set "PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME%" + set _OLD_VIRTUAL_PYTHONHOME= +) + +if defined _OLD_VIRTUAL_PATH ( + set "PATH=%_OLD_VIRTUAL_PATH%" +) + +set _OLD_VIRTUAL_PATH= + +set VIRTUAL_ENV= + +:END diff --git a/Hongji0611/ministagram/myvenv/Scripts/django-admin.exe b/Hongji0611/ministagram/myvenv/Scripts/django-admin.exe new file mode 100644 index 00000000..eb0356fd Binary files /dev/null and b/Hongji0611/ministagram/myvenv/Scripts/django-admin.exe differ diff --git a/Hongji0611/ministagram/myvenv/Scripts/django-admin.py b/Hongji0611/ministagram/myvenv/Scripts/django-admin.py new file mode 100644 index 00000000..649aa974 --- /dev/null +++ b/Hongji0611/ministagram/myvenv/Scripts/django-admin.py @@ -0,0 +1,5 @@ +#!c:\users\82106\tasks\hongji0611\ministagram\myvenv\scripts\python.exe +from django.core import management + +if __name__ == "__main__": + management.execute_from_command_line() diff --git a/Hongji0611/ministagram/myvenv/Scripts/easy_install-3.8.exe b/Hongji0611/ministagram/myvenv/Scripts/easy_install-3.8.exe new file mode 100644 index 00000000..767c8dc6 Binary files /dev/null and b/Hongji0611/ministagram/myvenv/Scripts/easy_install-3.8.exe differ diff --git a/Hongji0611/ministagram/myvenv/Scripts/easy_install.exe b/Hongji0611/ministagram/myvenv/Scripts/easy_install.exe new file mode 100644 index 00000000..767c8dc6 Binary files /dev/null and b/Hongji0611/ministagram/myvenv/Scripts/easy_install.exe differ diff --git a/Hongji0611/ministagram/myvenv/Scripts/epylint.exe b/Hongji0611/ministagram/myvenv/Scripts/epylint.exe new file mode 100644 index 00000000..f9574451 Binary files /dev/null and b/Hongji0611/ministagram/myvenv/Scripts/epylint.exe differ diff --git a/Hongji0611/ministagram/myvenv/Scripts/isort.exe b/Hongji0611/ministagram/myvenv/Scripts/isort.exe new file mode 100644 index 00000000..0e8e540f Binary files /dev/null and b/Hongji0611/ministagram/myvenv/Scripts/isort.exe differ diff --git a/Hongji0611/ministagram/myvenv/Scripts/pip.exe b/Hongji0611/ministagram/myvenv/Scripts/pip.exe new file mode 100644 index 00000000..d357bbee Binary files /dev/null and b/Hongji0611/ministagram/myvenv/Scripts/pip.exe differ diff --git a/Hongji0611/ministagram/myvenv/Scripts/pip3.8.exe b/Hongji0611/ministagram/myvenv/Scripts/pip3.8.exe new file mode 100644 index 00000000..d357bbee Binary files /dev/null and b/Hongji0611/ministagram/myvenv/Scripts/pip3.8.exe differ diff --git a/Hongji0611/ministagram/myvenv/Scripts/pip3.exe b/Hongji0611/ministagram/myvenv/Scripts/pip3.exe new file mode 100644 index 00000000..d357bbee Binary files /dev/null and b/Hongji0611/ministagram/myvenv/Scripts/pip3.exe differ diff --git a/Hongji0611/ministagram/myvenv/Scripts/pylint.exe b/Hongji0611/ministagram/myvenv/Scripts/pylint.exe new file mode 100644 index 00000000..9dbb4700 Binary files /dev/null and b/Hongji0611/ministagram/myvenv/Scripts/pylint.exe differ diff --git a/Hongji0611/ministagram/myvenv/Scripts/pyreverse.exe b/Hongji0611/ministagram/myvenv/Scripts/pyreverse.exe new file mode 100644 index 00000000..4cd4c59b Binary files /dev/null and b/Hongji0611/ministagram/myvenv/Scripts/pyreverse.exe differ diff --git a/Hongji0611/ministagram/myvenv/Scripts/python.exe b/Hongji0611/ministagram/myvenv/Scripts/python.exe new file mode 100644 index 00000000..4344885a Binary files /dev/null and b/Hongji0611/ministagram/myvenv/Scripts/python.exe differ diff --git a/Hongji0611/ministagram/myvenv/Scripts/pythonw.exe b/Hongji0611/ministagram/myvenv/Scripts/pythonw.exe new file mode 100644 index 00000000..a622c693 Binary files /dev/null and b/Hongji0611/ministagram/myvenv/Scripts/pythonw.exe differ diff --git a/Hongji0611/ministagram/myvenv/Scripts/sqlformat.exe b/Hongji0611/ministagram/myvenv/Scripts/sqlformat.exe new file mode 100644 index 00000000..63230772 Binary files /dev/null and b/Hongji0611/ministagram/myvenv/Scripts/sqlformat.exe differ diff --git a/Hongji0611/ministagram/myvenv/Scripts/symilar.exe b/Hongji0611/ministagram/myvenv/Scripts/symilar.exe new file mode 100644 index 00000000..7aaafdf7 Binary files /dev/null and b/Hongji0611/ministagram/myvenv/Scripts/symilar.exe differ diff --git a/Hongji0611/ministagram/myvenv/pyvenv.cfg b/Hongji0611/ministagram/myvenv/pyvenv.cfg new file mode 100644 index 00000000..c408e64b --- /dev/null +++ b/Hongji0611/ministagram/myvenv/pyvenv.cfg @@ -0,0 +1,3 @@ +home = C:\Users\82106\AppData\Local\Programs\Python\Python38 +include-system-site-packages = false +version = 3.8.3 diff --git a/Hongji0611/ministagram/photo/__init__.py b/Hongji0611/ministagram/photo/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/Hongji0611/ministagram/photo/admin.py b/Hongji0611/ministagram/photo/admin.py new file mode 100644 index 00000000..c23aafc2 --- /dev/null +++ b/Hongji0611/ministagram/photo/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin +from .models import Photo + +admin.site.register(Photo) +# Register your models here. diff --git a/Hongji0611/ministagram/photo/apps.py b/Hongji0611/ministagram/photo/apps.py new file mode 100644 index 00000000..4288cbe0 --- /dev/null +++ b/Hongji0611/ministagram/photo/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class PhotoConfig(AppConfig): + name = 'photo' diff --git a/Hongji0611/ministagram/photo/migrations/0001_initial.py b/Hongji0611/ministagram/photo/migrations/0001_initial.py new file mode 100644 index 00000000..c6e5885c --- /dev/null +++ b/Hongji0611/ministagram/photo/migrations/0001_initial.py @@ -0,0 +1,31 @@ +# Generated by Django 2.0.13 on 2020-06-24 16:40 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Photo', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('text', models.TextField(blank=True)), + ('image', models.ImageField(upload_to='timeline_photo/%Y/%m/%d')), + ('created', models.DateTimeField(auto_now_add=True)), + ('updated', models.DateTimeField(auto_now=True)), + ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'ordering': ['-created'], + }, + ), + ] diff --git a/Hongji0611/ministagram/photo/migrations/0002_auto_20200704_2254.py b/Hongji0611/ministagram/photo/migrations/0002_auto_20200704_2254.py new file mode 100644 index 00000000..389d0176 --- /dev/null +++ b/Hongji0611/ministagram/photo/migrations/0002_auto_20200704_2254.py @@ -0,0 +1,25 @@ +# Generated by Django 2.0.13 on 2020-07-04 13:54 + +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('photo', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='photo', + name='favorite', + field=models.ManyToManyField(blank=True, related_name='favorite_post', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='photo', + name='like', + field=models.ManyToManyField(blank=True, related_name='like_post', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/Hongji0611/ministagram/photo/migrations/__init__.py b/Hongji0611/ministagram/photo/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/Hongji0611/ministagram/photo/models.py b/Hongji0611/ministagram/photo/models.py new file mode 100644 index 00000000..b1e98773 --- /dev/null +++ b/Hongji0611/ministagram/photo/models.py @@ -0,0 +1,24 @@ +from django.contrib.auth.models import User +from django.db import models +from django.urls import reverse + +# Create your models here. + +class Photo(models.Model): + author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user') + text = models.TextField(blank=True) + image = models.ImageField(upload_to='timeline_photo/%Y/%m/%d') + created = models.DateTimeField(auto_now_add=True) + updated = models.DateTimeField(auto_now=True) + + like = models.ManyToManyField(User, related_name='like_post', blank = True) + favorite = models.ManyToManyField(User, related_name='favorite_post', blank = True) + + def __str__(self): + return "text : "+self.text + + class Meta: + ordering=['-created'] + + def get_absolute_url(self): + return reverse('photo:detail', args=[self,id]) \ No newline at end of file diff --git a/Hongji0611/ministagram/photo/static/images/instagramicon.png b/Hongji0611/ministagram/photo/static/images/instagramicon.png new file mode 100644 index 00000000..5c2c5f65 Binary files /dev/null and b/Hongji0611/ministagram/photo/static/images/instagramicon.png differ diff --git a/Hongji0611/ministagram/photo/templates/photo/photo_create.html b/Hongji0611/ministagram/photo/templates/photo/photo_create.html new file mode 100644 index 00000000..4be41933 --- /dev/null +++ b/Hongji0611/ministagram/photo/templates/photo/photo_create.html @@ -0,0 +1,18 @@ +{% extends 'base.html' %} +{% block content %} +
+
+
+ +
+ {% csrf_token %} + + {{form.as_p}} + +
+
+
+
+{% endblock %} diff --git a/Hongji0611/ministagram/photo/templates/photo/photo_delete.html b/Hongji0611/ministagram/photo/templates/photo/photo_delete.html new file mode 100644 index 00000000..7673be32 --- /dev/null +++ b/Hongji0611/ministagram/photo/templates/photo/photo_delete.html @@ -0,0 +1,10 @@ +{% extends 'base.html' %} +{% block content %} + +
+ {% csrf_token%} + +
+{% endblock %} diff --git a/Hongji0611/ministagram/photo/templates/photo/photo_detail.html b/Hongji0611/ministagram/photo/templates/photo/photo_detail.html new file mode 100644 index 00000000..6e7a60ca --- /dev/null +++ b/Hongji0611/ministagram/photo/templates/photo/photo_detail.html @@ -0,0 +1,34 @@ +{% extends 'base.html' %} +{% block title %} +{% endblock %} + +{% block content %} + +
+
+
+ {{ object.author }} +
+
+ +
+
+
+ {{ object.text }} +
+
+ {{ object.created }} +
+
+ +
+
+ {% if user == object.author %} + 수정 + 삭제 + {% endif %} +
+
+
+
+{% endblock %} \ No newline at end of file diff --git a/Hongji0611/ministagram/photo/templates/photo/photo_list.html b/Hongji0611/ministagram/photo/templates/photo/photo_list.html new file mode 100644 index 00000000..bfad06da --- /dev/null +++ b/Hongji0611/ministagram/photo/templates/photo/photo_list.html @@ -0,0 +1,41 @@ +{% extends 'base.html' %} +{% block title %} +{% endblock %} + +{% block content %} + +
+ {% for object in object_list %} + {% for user in followees %} + {% ifequal object.author user.username %} +
+
+ {{ object.author }} +
+
+ +
+
+
+ {{ object.text }} +
+
+ {{ object.created }} +
+
+
+
+ 댓글 + {% if user == object.author %} + 수정 + 삭제 + {% endif %} +
+
+
+ {% endifequal %} + {% endfor %} + {% endfor %} +
+ +{% endblock %} \ No newline at end of file diff --git a/Hongji0611/ministagram/photo/templates/photo/photo_update.html b/Hongji0611/ministagram/photo/templates/photo/photo_update.html new file mode 100644 index 00000000..f9a9eabb --- /dev/null +++ b/Hongji0611/ministagram/photo/templates/photo/photo_update.html @@ -0,0 +1,14 @@ +{% extends 'base.html' %} +{% block content %} +
+
+
+
+ {% csrf_token %} + {{form.as_p}} + +
+
+
+
+{% endblock %} diff --git a/Hongji0611/ministagram/photo/tests.py b/Hongji0611/ministagram/photo/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/Hongji0611/ministagram/photo/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/Hongji0611/ministagram/photo/urls.py b/Hongji0611/ministagram/photo/urls.py new file mode 100644 index 00000000..1fd29612 --- /dev/null +++ b/Hongji0611/ministagram/photo/urls.py @@ -0,0 +1,19 @@ +from django.urls import path +from .views import PhotoList, PhotoDelete, PhotoDetail, PhotoUpdate, PhotoCreate +from django.conf.urls.static import static +from django.conf import settings + +app_name = "photo" +urlpatterns = [ + path("create/",PhotoCreate.as_view(), name='create'), + # path("like//",PhotoLike.as_view(), name = 'like'), + # path("favorite//", PhotoFavorite.as_view(), name = 'favorite'), + path("delete//",PhotoDelete.as_view(), name='delete'), + path("update//",PhotoUpdate.as_view(), name='update'), + path("detail//",PhotoDetail.as_view(), name='detail'), + path("",PhotoList.as_view(), name='index'), +] + + + +urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/Hongji0611/ministagram/photo/views.py b/Hongji0611/ministagram/photo/views.py new file mode 100644 index 00000000..dd1a50c1 --- /dev/null +++ b/Hongji0611/ministagram/photo/views.py @@ -0,0 +1,113 @@ + +from django.views.generic.list import ListView +from django.views.generic.edit import UpdateView, CreateView, DeleteView +from django.views.generic.detail import DetailView +from django.http import HttpResponseRedirect +from django.urls import reverse +from django.shortcuts import redirect +from django.contrib import messages +from django.views.generic.base import View +from django.contrib.auth.models import User +from django.http import HttpResponseForbidden +from urllib.parse import urlparse +from .models import Photo +from accounts.models import FollowRelation + + +class PhotoList(ListView): + template_name_suffix = '_list' + queryset = Photo.objects.all() + + def get_context_data(self, **kwargs): + user = self.request.user + context = super(PhotoList, self).get_context_data(**kwargs) + followers = FollowRelation.objects.get( + follower=user).followee.all() + context['object'] = self.queryset + context['followees'] = followers + return context + + +class PhotoCreate(CreateView): + model = Photo + fields = ['text', 'image'] + template_name_suffix = '_create' + success_url = '/' + + def form_valid(self, form): + form.instance.author_id = self.request.user.id + if form.is_valid(): + form.instance.save() + return redirect('/') + else: + return self.render_to_response({'form': form}) + + +class PhotoUpdate(UpdateView): + model = Photo + fields = ['text', 'image'] + template_name_suffix = '_update' + success_url = '/' + + def dispatch(self, request, *args, **kwargs): + object = self.get_object() + if object.author != request.user: + messages.warning(request, '수정할 권한이 없습니다.') + return HttpResponseRedirect('/') + else: + return super(PhotoUpdate, self).dispatch(request, *args, **kwargs) + + +class PhotoDelete(DeleteView): + model = Photo + template_name_suffix = '_delete' + success_url = '/' + + def dispatch(self, request, *args, **kwargs): + object = self.get_object() + if object.author != request.user: + messages.warning(request, '삭제할 권한이 없습니다.') + return HttpResponseRedirect('/') + else: + return super(PhotoDelete, self).dispatch(request, *args, **kwargs) + + +class PhotoDetail(DetailView): + model = Photo + template_name_suffix = '_detail' + + +# class PhotoLike(View): +# def get(self, request, *args, **kwargs): +# if not request.user.is_authenticated: # 로그인확인 +# return HttpResponseForbidden() +# else: +# if 'photo_id' in kwargs: +# photo_id = kwargs['photo_id'] +# photo = Photo.objects.get(pk=photo_id) +# user = request.user +# if user in photo.like.all(): +# photo.like.remove(user) +# else: +# photo.like.add(user) +# referer_url = request.META.get('HTTP_REFERER') +# path = urlparse(referer_url).path +# return HttpResponseRedirect(path) + + +# class PhotoFavorite(View): +# def get(self, request, *args, **kwargs): +# if not request.user.is_authenticated: # 로그인확인 +# return HttpResponseForbidden() +# else: +# if 'photo_id' in kwargs: +# photo_id = kwargs['photo_id'] +# photo = Photo.objects.get(pk=photo_id) +# user = request.user +# if user in photo.favorite.all(): +# photo.favorite.remove(user) +# else: +# photo.favorite.add(user) +# referer_url = request.META.get('HTTP_REFERER') +# path = urlparse(referer_url).path +# return HttpResponseRedirect(path) diff --git a/Hongji0611/ministagram/static/css/base.css b/Hongji0611/ministagram/static/css/base.css new file mode 100644 index 00000000..b6901587 --- /dev/null +++ b/Hongji0611/ministagram/static/css/base.css @@ -0,0 +1,9 @@ +.navbar { + border-bottom: 1px solid #dbdbdb; + margin-bottom: 20px; +} + +body, +html { + background-color: #fafafa !important; +} \ No newline at end of file diff --git a/Hongji0611/ministagram/static/css/create.css b/Hongji0611/ministagram/static/css/create.css new file mode 100644 index 00000000..e69de29b diff --git a/Hongji0611/ministagram/static/css/list.css b/Hongji0611/ministagram/static/css/list.css new file mode 100644 index 00000000..2a24dd33 --- /dev/null +++ b/Hongji0611/ministagram/static/css/list.css @@ -0,0 +1,45 @@ +.box { + padding: 0 !important; +} + +.photo-header, +.photo-content, +.photo-comment { + padding: 0.5rem 1.25rem; +} + +.photo-header { + font-weight: bold; +} + +.photo-img img { + width: 100%; +} + +.photo-comment { + border-top: 1px solid #dbdbdb; +} + +.photo-comment a { + text-decoration: none !important; + color: #000000 !important; + font-weight: bold; + margin-right: 8px; +} + +.photo-text { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: #000000 !important; + font-size: 16px; + margin-bottom: 10px; +} + +.photo-created { + font-size: 12px; +} + +.box:last-child { + margin-bottom: 40px; +} \ No newline at end of file diff --git a/Hongji0611/ministagram/static/css/login.css b/Hongji0611/ministagram/static/css/login.css new file mode 100644 index 00000000..e69de29b diff --git a/Hongji0611/ministagram/static/css/logout.css b/Hongji0611/ministagram/static/css/logout.css new file mode 100644 index 00000000..e69de29b diff --git a/Hongji0611/ministagram/static/css/reset.css b/Hongji0611/ministagram/static/css/reset.css new file mode 100644 index 00000000..e69de29b diff --git a/Hongji0611/ministagram/static/css/signup.css b/Hongji0611/ministagram/static/css/signup.css new file mode 100644 index 00000000..e69de29b diff --git a/Hongji0611/ministagram/static/images/instagram-logo.png b/Hongji0611/ministagram/static/images/instagram-logo.png new file mode 100644 index 00000000..08b41fa0 Binary files /dev/null and b/Hongji0611/ministagram/static/images/instagram-logo.png differ diff --git a/Hongji0611/python practice/search.py b/Hongji0611/python practice/search.py new file mode 100644 index 00000000..e2dc0c39 --- /dev/null +++ b/Hongji0611/python practice/search.py @@ -0,0 +1,54 @@ +import os + +def search(dirname): + try: #os.path.isdir()함수 호출시, 권한이 없는 디렉터리 접근 오류 처리 + filenames =os.listdir(dirname) #os.listdir: 해당 디렉터리에 있는 파일의 리스트 + for filename in filenames: + full_filename=os.path.join(dirname,filename) #경로까지 보여주기 + if os.path.isdir(full_filename): #디렉터리인지, 파일인지 구별 + search(full_filename) #디렉터리일 경우 재귀호출로 하위 디렉터리까지 검색 + else: + print(filename) #파일명만 출력 + except PermissionError: + pass + +def search2(dirname, path): + try: #os.path.isdir()함수 호출시, 권한이 없는 디렉터리 접근 오류 처리 + filenames =os.listdir(dirname) #os.listdir: 해당 디렉터리에 있는 파일의 리스트 + for filename in filenames: + full_filename=os.path.join(dirname,filename) #경로까지 보여주기 + if os.path.isdir(full_filename): #디렉터리인지, 파일인지 구별 + if flag==1 and path==filename: + break + else: + search(full_filename) #디렉터리일 경우 재귀호출로 하위 디렉터리까지 검색 + else: + if flag==2 and filename==path: #파일명 같지 않을 경우 + continue + else: + print(filename) #파일명만 출력 + + except PermissionError: + pass + + +flag=0; +check=[] #입력 리스트 +str=input() #입력 +check=str.split('-') + +if check[0]=='random': + flag=0 + search("c:/") #전체 경로 출력 +elif check[0]=='ignore': + if (check[1])[len(check[1])-1]=='/': #마지막이 /일 경우 하위폴더 제외 + flag=1 + search2("c:/",check[1]) + else: #해당 폴더만 출력 제외 + flag=2 + search2("c:/",check[1]) +else: + flag=3 + search(check[0]) + +