Compare commits
5 Commits
master
...
add-django
| Author | SHA1 | Date |
|---|---|---|
|
|
680c71a5c6 | |
|
|
92b133ffbe | |
|
|
fe0cdd6b9e | |
|
|
beb95c9bee | |
|
|
c65377ffc0 |
|
|
@ -0,0 +1,9 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
# 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/
|
||||||
|
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
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# 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/
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"python.pythonPath": "/home/odie/.virtualenvs/social-scheduler-BIGBnu0C/bin/python"
|
||||||
|
}
|
||||||
6
Pipfile
6
Pipfile
|
|
@ -4,8 +4,12 @@ url = "https://pypi.org/simple"
|
||||||
verify_ssl = true
|
verify_ssl = true
|
||||||
|
|
||||||
[dev-packages]
|
[dev-packages]
|
||||||
|
flake8 = "*"
|
||||||
|
autopep8 = "*"
|
||||||
|
|
||||||
[packages]
|
[packages]
|
||||||
facebook-sdk = "*"
|
facebook-sdk = "*"
|
||||||
social-scheduler = {editable = true,path = "."}
|
|
||||||
instagramapi = "*"
|
instagramapi = "*"
|
||||||
|
django = "*"
|
||||||
|
social-scheduler = {editable = true,path = "."}
|
||||||
|
pillow = "*"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,202 @@
|
||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "e2f708932f4a52135061cf56ff125977a6e74cab2448464de0000ffdd1274ffe"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"decorator": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:73cbaadb8bc4e3c65fe1100773d56331a2d756cc0f5c7b9d8d5d5223fe04f600",
|
||||||
|
"sha256:953d6bf082b100f43229cf547f4f97f97e970f5ad645ee7601d55ff87afdfe76"
|
||||||
|
],
|
||||||
|
"version": "==4.0.11"
|
||||||
|
},
|
||||||
|
"django": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:275bec66fd2588dd517ada59b8bfb23d4a9abc5a362349139ddda3c7ff6f5ade",
|
||||||
|
"sha256:939652e9d34d7d53d74d5d8ef82a19e5f8bb2de75618f7e5360691b6e9667963"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.1.7"
|
||||||
|
},
|
||||||
|
"facebook-sdk": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2e987b3e0f466a6f4ee77b935eb023dba1384134f004a2af21f1cfff7fe0806e",
|
||||||
|
"sha256:cabcd2e69ea3d9f042919c99b353df7aa1e2be86d040121f6e9f5e63c1cf0f8d"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==3.1.0"
|
||||||
|
},
|
||||||
|
"imageio": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:89d7692d9f513aa21665af7de94948bc1ef110d812fa66c34bfd486590d986bb"
|
||||||
|
],
|
||||||
|
"version": "==2.1.2"
|
||||||
|
},
|
||||||
|
"instagramapi": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:a8dfcb7bd25d8eecefacc2b872d464888535c8ee0a99c8a5b81066fdc953e64f"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.0.2"
|
||||||
|
},
|
||||||
|
"moviepy": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:59d550a81ed1c9f6cf167da6d0707cea52ab250ddc2bc6d48b14ab1fc0ea4a0d",
|
||||||
|
"sha256:c733967656fa4be4c37ec48af72b63ab2991455aa862321437a013705797c4ab"
|
||||||
|
],
|
||||||
|
"version": "==0.2.3.2"
|
||||||
|
},
|
||||||
|
"numpy": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1980f8d84548d74921685f68096911585fee393975f53797614b34d4f409b6da",
|
||||||
|
"sha256:22752cd809272671b273bb86df0f505f505a12368a3a5fc0aa811c7ece4dfd5c",
|
||||||
|
"sha256:23cc40313036cffd5d1873ef3ce2e949bdee0646c5d6f375bf7ee4f368db2511",
|
||||||
|
"sha256:2b0b118ff547fecabc247a2668f48f48b3b1f7d63676ebc5be7352a5fd9e85a5",
|
||||||
|
"sha256:3a0bd1edf64f6a911427b608a894111f9fcdb25284f724016f34a84c9a3a6ea9",
|
||||||
|
"sha256:3f25f6c7b0d000017e5ac55977a3999b0b1a74491eacb3c1aa716f0e01f6dcd1",
|
||||||
|
"sha256:4061c79ac2230594a7419151028e808239450e676c39e58302ad296232e3c2e8",
|
||||||
|
"sha256:560ceaa24f971ab37dede7ba030fc5d8fa173305d94365f814d9523ffd5d5916",
|
||||||
|
"sha256:62be044cd58da2a947b7e7b2252a10b42920df9520fc3d39f5c4c70d5460b8ba",
|
||||||
|
"sha256:6c692e3879dde0b67a9dc78f9bfb6f61c666b4562fd8619632d7043fb5b691b0",
|
||||||
|
"sha256:6f65e37b5a331df950ef6ff03bd4136b3c0bbcf44d4b8e99135d68a537711b5a",
|
||||||
|
"sha256:7a78cc4ddb253a55971115f8320a7ce28fd23a065fc33166d601f51760eecfa9",
|
||||||
|
"sha256:80a41edf64a3626e729a62df7dd278474fc1726836552b67a8c6396fd7e86760",
|
||||||
|
"sha256:893f4d75255f25a7b8516feb5766c6b63c54780323b9bd4bc51cdd7efc943c73",
|
||||||
|
"sha256:972ea92f9c1b54cc1c1a3d8508e326c0114aaf0f34996772a30f3f52b73b942f",
|
||||||
|
"sha256:9f1d4865436f794accdabadc57a8395bd3faa755449b4f65b88b7df65ae05f89",
|
||||||
|
"sha256:9f4cd7832b35e736b739be03b55875706c8c3e5fe334a06210f1a61e5c2c8ca5",
|
||||||
|
"sha256:adab43bf657488300d3aeeb8030d7f024fcc86e3a9b8848741ea2ea903e56610",
|
||||||
|
"sha256:bd2834d496ba9b1bdda3a6cf3de4dc0d4a0e7be306335940402ec95132ad063d",
|
||||||
|
"sha256:d20c0360940f30003a23c0adae2fe50a0a04f3e48dc05c298493b51fd6280197",
|
||||||
|
"sha256:d3b3ed87061d2314ff3659bb73896e622252da52558f2380f12c421fbdee3d89",
|
||||||
|
"sha256:dc235bf29a406dfda5790d01b998a1c01d7d37f449128c0b1b7d1c89a84fae8b",
|
||||||
|
"sha256:fb3c83554f39f48f3fa3123b9c24aecf681b1c289f9334f8215c1d3c8e2f6e5b"
|
||||||
|
],
|
||||||
|
"version": "==1.16.2"
|
||||||
|
},
|
||||||
|
"pillow": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:051de330a06c99d6f84bcf582960487835bcae3fc99365185dc2d4f65a390c0e",
|
||||||
|
"sha256:0ae5289948c5e0a16574750021bd8be921c27d4e3527800dc9c2c1d2abc81bf7",
|
||||||
|
"sha256:0b1efce03619cdbf8bcc61cfae81fcda59249a469f31c6735ea59badd4a6f58a",
|
||||||
|
"sha256:163136e09bd1d6c6c6026b0a662976e86c58b932b964f255ff384ecc8c3cefa3",
|
||||||
|
"sha256:18e912a6ccddf28defa196bd2021fe33600cbe5da1aa2f2e2c6df15f720b73d1",
|
||||||
|
"sha256:24ec3dea52339a610d34401d2d53d0fb3c7fd08e34b20c95d2ad3973193591f1",
|
||||||
|
"sha256:267f8e4c0a1d7e36e97c6a604f5b03ef58e2b81c1becb4fccecddcb37e063cc7",
|
||||||
|
"sha256:3273a28734175feebbe4d0a4cde04d4ed20f620b9b506d26f44379d3c72304e1",
|
||||||
|
"sha256:4c678e23006798fc8b6f4cef2eaad267d53ff4c1779bd1af8725cc11b72a63f3",
|
||||||
|
"sha256:4d4bc2e6bb6861103ea4655d6b6f67af8e5336e7216e20fff3e18ffa95d7a055",
|
||||||
|
"sha256:505738076350a337c1740a31646e1de09a164c62c07db3b996abdc0f9d2e50cf",
|
||||||
|
"sha256:5233664eadfa342c639b9b9977190d64ad7aca4edc51a966394d7e08e7f38a9f",
|
||||||
|
"sha256:5d95cb9f6cced2628f3e4de7e795e98b2659dfcc7176ab4a01a8b48c2c2f488f",
|
||||||
|
"sha256:7eda4c737637af74bac4b23aa82ea6fbb19002552be85f0b89bc27e3a762d239",
|
||||||
|
"sha256:801ddaa69659b36abf4694fed5aa9f61d1ecf2daaa6c92541bbbbb775d97b9fe",
|
||||||
|
"sha256:825aa6d222ce2c2b90d34a0ea31914e141a85edefc07e17342f1d2fdf121c07c",
|
||||||
|
"sha256:9c215442ff8249d41ff58700e91ef61d74f47dfd431a50253e1a1ca9436b0697",
|
||||||
|
"sha256:a3d90022f2202bbb14da991f26ca7a30b7e4c62bf0f8bf9825603b22d7e87494",
|
||||||
|
"sha256:a631fd36a9823638fe700d9225f9698fb59d049c942d322d4c09544dc2115356",
|
||||||
|
"sha256:a6523a23a205be0fe664b6b8747a5c86d55da960d9586db039eec9f5c269c0e6",
|
||||||
|
"sha256:a756ecf9f4b9b3ed49a680a649af45a8767ad038de39e6c030919c2f443eb000",
|
||||||
|
"sha256:b117287a5bdc81f1bac891187275ec7e829e961b8032c9e5ff38b70fd036c78f",
|
||||||
|
"sha256:ba04f57d1715ca5ff74bb7f8a818bf929a204b3b3c2c2826d1e1cc3b1c13398c",
|
||||||
|
"sha256:cd878195166723f30865e05d87cbaf9421614501a4bd48792c5ed28f90fd36ca",
|
||||||
|
"sha256:cee815cc62d136e96cf76771b9d3eb58e0777ec18ea50de5cfcede8a7c429aa8",
|
||||||
|
"sha256:d1722b7aa4b40cf93ac3c80d3edd48bf93b9208241d166a14ad8e7a20ee1d4f3",
|
||||||
|
"sha256:d7c1c06246b05529f9984435fc4fa5a545ea26606e7f450bdbe00c153f5aeaad",
|
||||||
|
"sha256:e9c8066249c040efdda84793a2a669076f92a301ceabe69202446abb4c5c5ef9",
|
||||||
|
"sha256:f227d7e574d050ff3996049e086e1f18c7bd2d067ef24131e50a1d3fe5831fbc",
|
||||||
|
"sha256:fc9a12aad714af36cf3ad0275a96a733526571e52710319855628f476dcb144e"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==5.4.1"
|
||||||
|
},
|
||||||
|
"pytz": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9",
|
||||||
|
"sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c"
|
||||||
|
],
|
||||||
|
"version": "==2018.9"
|
||||||
|
},
|
||||||
|
"requests": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:545c4855cd9d7c12671444326337013766f4eea6068c3f0307fb2dc2696d580e",
|
||||||
|
"sha256:5acf980358283faba0b897c73959cecf8b841205bb4b2ad3ef545f46eae1a133"
|
||||||
|
],
|
||||||
|
"version": "==2.11.1"
|
||||||
|
},
|
||||||
|
"requests-toolbelt": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:33899d4a559c3f0f5e9fbc115d337c4236febdc083755a160a4132d92fc3c91a",
|
||||||
|
"sha256:a0432b1124e6b33151ecf694497b4808690dd94ce68c6648c1daa63b771278c4"
|
||||||
|
],
|
||||||
|
"version": "==0.7.0"
|
||||||
|
},
|
||||||
|
"social-scheduler": {
|
||||||
|
"editable": true,
|
||||||
|
"path": "."
|
||||||
|
},
|
||||||
|
"tqdm": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:14baa7a9ea7723d46f60de5f8c6f20e840baa7e3e193bf0d9ec5fe9103a15254",
|
||||||
|
"sha256:1621b3476c2224045d8bd57209aab006612a46ae2cc518b4a92ad988983e4c3d"
|
||||||
|
],
|
||||||
|
"version": "==4.11.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {
|
||||||
|
"autopep8": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:33d2b5325b7e1afb4240814fe982eea3a92ebea712869bfd08b3c0393404248c"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.4.3"
|
||||||
|
},
|
||||||
|
"entrypoints": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19",
|
||||||
|
"sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"
|
||||||
|
],
|
||||||
|
"version": "==0.3"
|
||||||
|
},
|
||||||
|
"flake8": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:859996073f341f2670741b51ec1e67a01da142831aa1fdc6242dbf88dffbe661",
|
||||||
|
"sha256:a796a115208f5c03b18f332f7c11729812c8c3ded6c46319c59b53efd3819da8"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==3.7.7"
|
||||||
|
},
|
||||||
|
"mccabe": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
|
||||||
|
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
|
||||||
|
],
|
||||||
|
"version": "==0.6.1"
|
||||||
|
},
|
||||||
|
"pycodestyle": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56",
|
||||||
|
"sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"
|
||||||
|
],
|
||||||
|
"version": "==2.5.0"
|
||||||
|
},
|
||||||
|
"pyflakes": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0",
|
||||||
|
"sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"
|
||||||
|
],
|
||||||
|
"version": "==2.1.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
|
|
@ -1,11 +0,0 @@
|
||||||
Metadata-Version: 1.2
|
|
||||||
Name: social-scheduler
|
|
||||||
Version: 0.0.1
|
|
||||||
Summary: Posts to social media on a schedule
|
|
||||||
Home-page: UNKNOWN
|
|
||||||
Author: Patrick Neff
|
|
||||||
Author-email: odie86@gmail.com
|
|
||||||
License: BSD
|
|
||||||
Description: UNKNOWN
|
|
||||||
Platform: UNKNOWN
|
|
||||||
Requires-Python: >= 3.6
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
README.md
|
|
||||||
setup.cfg
|
|
||||||
setup.py
|
|
||||||
social_scheduler/__init__.py
|
|
||||||
social_scheduler/__main__.py
|
|
||||||
social_scheduler/main.py
|
|
||||||
social_scheduler/scheduler.py
|
|
||||||
social_scheduler.egg-info/PKG-INFO
|
|
||||||
social_scheduler.egg-info/SOURCES.txt
|
|
||||||
social_scheduler.egg-info/dependency_links.txt
|
|
||||||
social_scheduler.egg-info/top_level.txt
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
social_scheduler
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'web.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)
|
||||||
|
|
@ -2,6 +2,6 @@ from .workers.instagram import InstagramWorker
|
||||||
from .workers.facebook import FacebookWorker
|
from .workers.facebook import FacebookWorker
|
||||||
|
|
||||||
|
|
||||||
def run_scheduler():
|
def run_scheduler(accounts):
|
||||||
#facebook = FacebookWorker('', '')
|
#facebook = FacebookWorker('', '')
|
||||||
#instagram = InstagramWorker('', '')
|
#instagram = InstagramWorker('', '')
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
from django.contrib.admin import AdminSite
|
||||||
|
|
||||||
|
|
||||||
|
class SocialSchedulerAdmimSite(AdminSite):
|
||||||
|
site_header = 'Social Scheduler'
|
||||||
|
|
||||||
|
|
||||||
|
admin_site = SocialSchedulerAdmimSite(name='Social Scheduler Administration')
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from ..admin import admin_site
|
||||||
|
|
||||||
|
from .models import Post, Image
|
||||||
|
|
||||||
|
|
||||||
|
class ImageInline(admin.TabularInline):
|
||||||
|
model = Image
|
||||||
|
extra = 1
|
||||||
|
|
||||||
|
|
||||||
|
class PostAdmin(admin.ModelAdmin):
|
||||||
|
fieldsets = [
|
||||||
|
('Publikationsdatum', {'fields': ['publication_date']}),
|
||||||
|
('Nachricht', {'fields': ['message', 'posted']}),
|
||||||
|
]
|
||||||
|
readonly_fields = ['posted']
|
||||||
|
list_display = ['message', 'posted']
|
||||||
|
inlines = [ImageInline]
|
||||||
|
|
||||||
|
|
||||||
|
admin_site.register(Post, PostAdmin)
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class PostsConfig(AppConfig):
|
||||||
|
name = 'posts'
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
from social_scheduler.web.posts.models import Post, Image
|
||||||
|
from social_scheduler.workers.instagram import InstagramWorker
|
||||||
|
from social_scheduler.workers.facebook import FacebookWorker
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Post all scheduled posts.'
|
||||||
|
|
||||||
|
def post(self, message, images):
|
||||||
|
self.facebook = FacebookWorker('', '')
|
||||||
|
self.instagram = InstagramWorker('', '')
|
||||||
|
if len(images) > 1:
|
||||||
|
self.facebook.post_multiple(message, images)
|
||||||
|
self.instagram.post_multiple(message, images[0:9])
|
||||||
|
elif len(images) == 1:
|
||||||
|
for image in images:
|
||||||
|
self.facebook.post_single(message, image)
|
||||||
|
self.instagram.post_single(message, image)
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
posts = Post.objects.filter(
|
||||||
|
publication_date__lte=datetime.now().astimezone(),
|
||||||
|
posted=False)
|
||||||
|
for post in posts:
|
||||||
|
images = Image.objects.filter(post_id=post.id)
|
||||||
|
imgs = {img.path.path: img.caption for img in images}
|
||||||
|
|
||||||
|
self.post(post.message, imgs)
|
||||||
|
self.stdout.write(self.style.SUCCESS(post.message))
|
||||||
|
self.stdout.write(self.style.SUCCESS(imgs))
|
||||||
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Generated by Django 2.1.7 on 2019-03-02 13:30
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Image',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('path', models.CharField(max_length=4096)),
|
||||||
|
('caption', models.CharField(max_length=2048)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Post',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('message', models.CharField(max_length=4096)),
|
||||||
|
('publication_date', models.DateTimeField()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 2.1.7 on 2019-03-02 13:36
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('posts', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='image',
|
||||||
|
name='post',
|
||||||
|
field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='posts.Post'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.1.7 on 2019-03-02 14:00
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('posts', '0002_image_post'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='image',
|
||||||
|
name='path',
|
||||||
|
field=models.FileField(default=None, upload_to='media/'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Generated by Django 2.1.7 on 2019-03-02 15:22
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('posts', '0003_auto_20190302_1500'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='image',
|
||||||
|
options={'verbose_name': 'Bild', 'verbose_name_plural': 'Bilder'},
|
||||||
|
),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='post',
|
||||||
|
options={'verbose_name': 'Post'},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='post',
|
||||||
|
name='posted',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='Gepostet'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='image',
|
||||||
|
name='caption',
|
||||||
|
field=models.CharField(max_length=2048, verbose_name='Beschreibung'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='image',
|
||||||
|
name='path',
|
||||||
|
field=models.FileField(default=None, upload_to='media/', verbose_name='Bild'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='post',
|
||||||
|
name='message',
|
||||||
|
field=models.CharField(max_length=4096, verbose_name='Nachricht'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='post',
|
||||||
|
name='publication_date',
|
||||||
|
field=models.DateTimeField(verbose_name='Publizieren am'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.1.7 on 2019-03-02 15:44
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('posts', '0004_auto_20190302_1622'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='image',
|
||||||
|
name='path',
|
||||||
|
field=models.ImageField(default=None, upload_to='media/', verbose_name='Bild'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
from datetime import datetime
|
||||||
|
from os.path import basename, join
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
def change_upload_path(instance, filename):
|
||||||
|
ext = filename.split('.')[-1]
|
||||||
|
now = datetime.now()
|
||||||
|
return join(str(now.year), str(now.month),
|
||||||
|
f'{uuid4()}.{ext}')
|
||||||
|
|
||||||
|
|
||||||
|
class Post(models.Model):
|
||||||
|
message = models.CharField('Nachricht', max_length=4096)
|
||||||
|
posted = models.BooleanField('Gepostet', default=False)
|
||||||
|
publication_date = models.DateTimeField('Publizieren am')
|
||||||
|
|
||||||
|
class Meta():
|
||||||
|
verbose_name = 'Post'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
date = self.publication_date.strftime('%d.%m.%Y %H:%M')
|
||||||
|
return f'{date}: {self.message[0:50]}'
|
||||||
|
|
||||||
|
|
||||||
|
class Image(models.Model):
|
||||||
|
path = models.ImageField('Bild', upload_to=change_upload_path,
|
||||||
|
default=None)
|
||||||
|
caption = models.CharField('Beschreibung', max_length=2048)
|
||||||
|
|
||||||
|
post = models.ForeignKey(Post, on_delete=models.CASCADE, default=None)
|
||||||
|
|
||||||
|
class Meta():
|
||||||
|
verbose_name = 'Bild'
|
||||||
|
verbose_name_plural = 'Bilder'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
path = basename(str(self.path))
|
||||||
|
return f'{path}: {self.caption[0:50]}'
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('', views.index),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
from django.shortcuts import render
|
||||||
|
from django.http import HttpResponse
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
|
|
||||||
|
def index(request):
|
||||||
|
return HttpResponse("Hello, World")
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
"""
|
||||||
|
Django settings for social_scheduler.web project.
|
||||||
|
|
||||||
|
Generated by 'django-admin startproject' using Django 2.1.7.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/2.1/topics/settings/
|
||||||
|
|
||||||
|
For the full list of settings and their values, see
|
||||||
|
https://docs.djangoproject.com/en/2.1/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.1/howto/deployment/checklist/
|
||||||
|
|
||||||
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
|
SECRET_KEY = '$oyqqo98y5^biuhhexa7%l-8aq_kj+jv$3*+9i1^-$$gk6cp#v'
|
||||||
|
|
||||||
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
|
DEBUG = True
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = ['10.0.0.144', '127.0.0.1', 'localhost']
|
||||||
|
|
||||||
|
|
||||||
|
# Application definition
|
||||||
|
|
||||||
|
INSTALLED_APPS = [
|
||||||
|
'social_scheduler.web.posts',
|
||||||
|
'django.contrib.admin',
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.messages',
|
||||||
|
'django.contrib.staticfiles',
|
||||||
|
]
|
||||||
|
|
||||||
|
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 = 'social_scheduler.web.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 = 'social_scheduler.web.wsgi.application'
|
||||||
|
|
||||||
|
|
||||||
|
# Database
|
||||||
|
# https://docs.djangoproject.com/en/2.1/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.1/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.1/topics/i18n/
|
||||||
|
|
||||||
|
LANGUAGE_CODE = 'de-de'
|
||||||
|
|
||||||
|
TIME_ZONE = 'Europe/Berlin'
|
||||||
|
|
||||||
|
USE_I18N = True
|
||||||
|
|
||||||
|
USE_L10N = True
|
||||||
|
|
||||||
|
USE_TZ = True
|
||||||
|
|
||||||
|
|
||||||
|
# Static files (CSS, JavaScript, Images)
|
||||||
|
# https://docs.djangoproject.com/en/2.1/howto/static-files/
|
||||||
|
|
||||||
|
STATIC_URL = '/static/'
|
||||||
|
|
||||||
|
MEDIA_URL = '/media/'
|
||||||
|
MEDIA_ROOT = 'media/'
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
"""social_scheduler_web URL Configuration
|
||||||
|
|
||||||
|
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||||
|
https://docs.djangoproject.com/en/2.1/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.conf import settings
|
||||||
|
from django.conf.urls.static import static
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from .admin import admin_site
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('', admin_site.urls),
|
||||||
|
] + \
|
||||||
|
static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + \
|
||||||
|
static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
"""
|
||||||
|
WSGI config for social_scheduler_web 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.1/howto/deployment/wsgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'social_scheduler_web.settings')
|
||||||
|
|
||||||
|
application = get_wsgi_application()
|
||||||
Binary file not shown.
|
|
@ -1,12 +1,26 @@
|
||||||
import facebook
|
import facebook
|
||||||
|
|
||||||
|
from .worker import Worker
|
||||||
|
|
||||||
class FacebookWorker(object):
|
|
||||||
|
class FacebookWorker(Worker):
|
||||||
def __init__(self, page_id, oauth_access_token):
|
def __init__(self, page_id, oauth_access_token):
|
||||||
self.page_id = page_id
|
self.page_id = page_id
|
||||||
self.oauth_access_token = oauth_access_token
|
self.oauth_access_token = oauth_access_token
|
||||||
self.api = facebook.GraphAPI(self.oauth_access_token)
|
self.api = facebook.GraphAPI(self.oauth_access_token)
|
||||||
|
|
||||||
def post(self, image, caption):
|
def post_single(self, caption, image):
|
||||||
with open(image, 'rb') as photo:
|
with open(image, 'rb') as photo:
|
||||||
self.api.put_object(self.page_id, 'photos', message=caption, source=photo.read())
|
self.api.put_object(self.page_id, 'photos', message=caption,
|
||||||
|
source=photo.read())
|
||||||
|
|
||||||
|
def post_multiple(self, message, images):
|
||||||
|
ids = []
|
||||||
|
for image, msg in images.items:
|
||||||
|
with open(image, 'rb') as photo:
|
||||||
|
result = self.api.put_object(self.page_id, 'photos',
|
||||||
|
message=msg, source=photo.read(),
|
||||||
|
published=False)
|
||||||
|
ids.append(result['id'])
|
||||||
|
self.api.put_object(self.page_id, 'feed', message=message,
|
||||||
|
attached_media=ids)
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,21 @@
|
||||||
from InstagramAPI import InstagramAPI
|
from InstagramAPI import InstagramAPI
|
||||||
|
|
||||||
|
from .worker import Worker
|
||||||
|
|
||||||
class InstagramWorker(object):
|
|
||||||
|
class InstagramWorker(Worker):
|
||||||
def __init__(self, username, password):
|
def __init__(self, username, password):
|
||||||
self.api = InstagramAPI(username, password)
|
self.api = InstagramAPI(username, password)
|
||||||
self.api.login()
|
self.api.login()
|
||||||
|
|
||||||
def post(self, image, caption):
|
def post_single(self, caption, image):
|
||||||
self.api.uploadPhoto(image, caption)
|
self.api.uploadPhoto(image, caption)
|
||||||
|
|
||||||
|
def post_multiple(self, message, images):
|
||||||
|
imgs = list()
|
||||||
|
for image in images.keys():
|
||||||
|
imgs.append({
|
||||||
|
'type': 'photo',
|
||||||
|
'file': image
|
||||||
|
})
|
||||||
|
self.api.uploadAlbum(imgs, caption=message)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
class Worker(object):
|
||||||
|
def post_single(self, caption, image):
|
||||||
|
raise NotImplementedError('post_single has to be implemented')
|
||||||
|
|
||||||
|
def post_multiple(self, message, images):
|
||||||
|
raise NotImplementedError('post_multiple has to be implemented')
|
||||||
Loading…
Reference in New Issue