├── .github └── FUNDING.yml ├── .gitignore ├── .slugignore ├── Procfile ├── README.md ├── VERSION ├── api ├── .dockerignore ├── .gitignore ├── Dockerfile ├── LICENSE ├── config.sample ├── gen_config.py ├── models.py ├── resources │ ├── dfile.py │ └── index.py ├── services │ ├── __init__.py │ ├── ipfs.py │ ├── s3.py │ └── shorty.py ├── sh │ ├── dfile.fish │ └── dfile.zsh └── yopo │ ├── app.py │ ├── app_context.py │ ├── compat.py │ ├── conf.py │ ├── database.py │ ├── extensions.py │ ├── log.py │ ├── queryable_mixin.py │ ├── snowflake.py │ └── util.py ├── app.py ├── app ├── .dockerignore ├── .env-example ├── .gitignore ├── .prettierrc ├── CNAME ├── LICENSE ├── asserts │ └── scss │ │ ├── _hack.scss │ │ ├── bootstrap │ │ ├── _alert.scss │ │ ├── _badge.scss │ │ ├── _breadcrumb.scss │ │ ├── _button-group.scss │ │ ├── _buttons.scss │ │ ├── _card.scss │ │ ├── _carousel.scss │ │ ├── _close.scss │ │ ├── _code.scss │ │ ├── _custom-forms.scss │ │ ├── _dropdown.scss │ │ ├── _forms.scss │ │ ├── _functions.scss │ │ ├── _grid.scss │ │ ├── _images.scss │ │ ├── _input-group.scss │ │ ├── _jumbotron.scss │ │ ├── _list-group.scss │ │ ├── _media.scss │ │ ├── _mixins.scss │ │ ├── _modal.scss │ │ ├── _nav.scss │ │ ├── _navbar.scss │ │ ├── _pagination.scss │ │ ├── _popover.scss │ │ ├── _print.scss │ │ ├── _progress.scss │ │ ├── _reboot.scss │ │ ├── _root.scss │ │ ├── _tables.scss │ │ ├── _tooltip.scss │ │ ├── _transitions.scss │ │ ├── _type.scss │ │ ├── _utilities.scss │ │ ├── _variables.scss │ │ ├── mixins │ │ │ ├── _alert.scss │ │ │ ├── _background-variant.scss │ │ │ ├── _badge.scss │ │ │ ├── _border-radius.scss │ │ │ ├── _box-shadow.scss │ │ │ ├── _breakpoints.scss │ │ │ ├── _buttons.scss │ │ │ ├── _caret.scss │ │ │ ├── _clearfix.scss │ │ │ ├── _float.scss │ │ │ ├── _forms.scss │ │ │ ├── _gradients.scss │ │ │ ├── _grid-framework.scss │ │ │ ├── _grid.scss │ │ │ ├── _hover.scss │ │ │ ├── _image.scss │ │ │ ├── _list-group.scss │ │ │ ├── _lists.scss │ │ │ ├── _nav-divider.scss │ │ │ ├── _pagination.scss │ │ │ ├── _reset-text.scss │ │ │ ├── _resize.scss │ │ │ ├── _screen-reader.scss │ │ │ ├── _size.scss │ │ │ ├── _table-row.scss │ │ │ ├── _text-emphasis.scss │ │ │ ├── _text-hide.scss │ │ │ ├── _text-truncate.scss │ │ │ ├── _transition.scss │ │ │ └── _visibility.scss │ │ └── utilities │ │ │ ├── _align.scss │ │ │ ├── _background.scss │ │ │ ├── _borders.scss │ │ │ ├── _clearfix.scss │ │ │ ├── _display.scss │ │ │ ├── _embed.scss │ │ │ ├── _flex.scss │ │ │ ├── _float.scss │ │ │ ├── _position.scss │ │ │ ├── _screenreaders.scss │ │ │ ├── _shadows.scss │ │ │ ├── _sizing.scss │ │ │ ├── _spacing.scss │ │ │ ├── _text.scss │ │ │ └── _visibility.scss │ │ ├── core │ │ ├── alerts │ │ │ ├── _alert-dismissible.scss │ │ │ └── _alert.scss │ │ ├── avatars │ │ │ ├── _avatar-group.scss │ │ │ └── _avatar.scss │ │ ├── badges │ │ │ ├── _badge-circle.scss │ │ │ ├── _badge-dot.scss │ │ │ └── _badge.scss │ │ ├── buttons │ │ │ ├── _button-brand.scss │ │ │ ├── _button-icon.scss │ │ │ └── _button.scss │ │ ├── cards │ │ │ ├── _card-animations.scss │ │ │ ├── _card-blockquote.scss │ │ │ ├── _card-profile.scss │ │ │ ├── _card-stats.scss │ │ │ └── _card.scss │ │ ├── charts │ │ │ └── _chart.scss │ │ ├── close │ │ │ └── _close.scss │ │ ├── custom-forms │ │ │ ├── _custom-checkbox.scss │ │ │ ├── _custom-control.scss │ │ │ ├── _custom-form.scss │ │ │ ├── _custom-radio.scss │ │ │ └── _custom-toggle.scss │ │ ├── dropdowns │ │ │ └── _dropdown.scss │ │ ├── footers │ │ │ └── _footer.scss │ │ ├── forms │ │ │ ├── _form-validation.scss │ │ │ ├── _form.scss │ │ │ └── _input-group.scss │ │ ├── headers │ │ │ └── _header.scss │ │ ├── icons │ │ │ ├── _icon-shape.scss │ │ │ └── _icon.scss │ │ ├── list-groups │ │ │ └── _list-group.scss │ │ ├── maps │ │ │ └── _map.scss │ │ ├── masks │ │ │ └── _mask.scss │ │ ├── mixins │ │ │ ├── _alert.scss │ │ │ ├── _background-variant.scss │ │ │ ├── _badge.scss │ │ │ ├── _buttons.scss │ │ │ ├── _forms.scss │ │ │ ├── _icon.scss │ │ │ ├── _modals.scss │ │ │ └── _popover.scss │ │ ├── modals │ │ │ └── _modal.scss │ │ ├── navbars │ │ │ ├── _navbar-collapse.scss │ │ │ ├── _navbar-dropdown.scss │ │ │ ├── _navbar-search.scss │ │ │ ├── _navbar-vertical.scss │ │ │ └── _navbar.scss │ │ ├── navs │ │ │ ├── _nav-pills.scss │ │ │ └── _nav.scss │ │ ├── paginations │ │ │ └── _pagination.scss │ │ ├── popovers │ │ │ └── _popover.scss │ │ ├── progresses │ │ │ └── _progress.scss │ │ ├── separators │ │ │ └── _separator.scss │ │ ├── tables │ │ │ └── _table.scss │ │ ├── type │ │ │ ├── _article.scss │ │ │ ├── _display.scss │ │ │ ├── _heading.scss │ │ │ └── _type.scss │ │ ├── utilities │ │ │ ├── _backgrounds.scss │ │ │ ├── _blurable.scss │ │ │ ├── _floating.scss │ │ │ ├── _helper.scss │ │ │ ├── _image.scss │ │ │ ├── _opacity.scss │ │ │ ├── _overflow.scss │ │ │ ├── _position.scss │ │ │ ├── _shadows.scss │ │ │ ├── _sizing.scss │ │ │ ├── _spacing.scss │ │ │ ├── _text.scss │ │ │ └── _transform.scss │ │ └── vendors │ │ │ ├── _bootstrap-datepicker.scss │ │ │ ├── _headroom.scss │ │ │ ├── _media-player.scss │ │ │ ├── _nouislider.scss │ │ │ ├── _range-mixins.scss │ │ │ ├── _scrollbar.scss │ │ │ └── _toast.scss │ │ ├── custom │ │ ├── _alert.scss │ │ ├── _avatar.scss │ │ ├── _badge.scss │ │ ├── _buttons.scss │ │ ├── _card.scss │ │ ├── _chart.scss │ │ ├── _close.scss │ │ ├── _components.scss │ │ ├── _content.scss │ │ ├── _custom-forms.scss │ │ ├── _dropdown.scss │ │ ├── _footer.scss │ │ ├── _forms.scss │ │ ├── _functions.scss │ │ ├── _header.scss │ │ ├── _icons.scss │ │ ├── _input-group.scss │ │ ├── _list-group.scss │ │ ├── _map.scss │ │ ├── _mask.scss │ │ ├── _mixins.scss │ │ ├── _modal.scss │ │ ├── _nav.scss │ │ ├── _navbar.scss │ │ ├── _pagination.scss │ │ ├── _popover.scss │ │ ├── _progress.scss │ │ ├── _reboot.scss │ │ ├── _section.scss │ │ ├── _separator.scss │ │ ├── _spinner.scss │ │ ├── _tables.scss │ │ ├── _type.scss │ │ ├── _utilities.scss │ │ ├── _variables.scss │ │ └── _vendors.scss │ │ ├── react │ │ ├── _buttons.scss │ │ ├── _mixins.scss │ │ ├── _navbar-dropdown.scss │ │ ├── _navbar.scss │ │ ├── _tables.scss │ │ ├── plugins │ │ │ └── _plugin-react-datetime.scss │ │ └── react-differences.scss │ │ └── yopo.scss ├── common │ ├── util.js │ └── withLang.js ├── components │ ├── analytics.js │ ├── base-layout.js │ ├── footer.js │ ├── github-buttons.js │ ├── layout.js │ └── navbar.js ├── empty_module.js ├── favicon.ico ├── i18n.js ├── lambda │ ├── common │ │ ├── parser.js │ │ ├── snowflake.js │ │ └── util.js │ ├── d.js │ ├── db │ │ ├── index.js │ │ └── pg.js │ ├── hash.js │ ├── hello-json.js │ ├── hello.js │ ├── stat.js │ ├── test-id.js │ ├── test-ipfs-hash.js │ ├── test-ua.js │ └── up.js ├── netlify.toml ├── next.config.js ├── package.json ├── pages │ ├── 404.js │ ├── _app.js │ └── index.js ├── public │ └── static │ │ ├── img │ │ ├── banner-neehow.svg │ │ ├── blockchain.svg │ │ ├── close.svg │ │ ├── cloud.svg │ │ ├── database.svg │ │ ├── dfile-usage.gif │ │ ├── discord.svg │ │ ├── facebook.svg │ │ ├── favicon.ico │ │ ├── free.svg │ │ ├── github.svg │ │ ├── icon.svg │ │ ├── lang-cn.svg │ │ ├── lang-en.svg │ │ ├── lang-jp.svg │ │ ├── lang-kr.svg │ │ ├── lang-ru.svg │ │ ├── link.svg │ │ ├── loading.svg │ │ ├── logo-grey.svg │ │ ├── logo.svg │ │ ├── patreon.png │ │ ├── paypal.png │ │ ├── star.svg │ │ └── terminal.svg │ │ └── locales │ │ ├── cn │ │ └── common.json │ │ └── en │ │ └── common.json ├── server.js ├── tools │ └── sitemap.js ├── webpack.common.js ├── webpack.dev.js └── webpack.prod.js ├── build.sh ├── docker-compose.yml ├── logs └── .gitkeep ├── migrations ├── README ├── alembic.ini ├── env.py ├── script.py.mako └── versions │ └── 376aa0821605_20200516_init.py ├── netlify.toml ├── requirements.txt └── share └── img ├── dfile-usage.gif ├── dfile-usage.mp4 ├── dfile-v0.1.png └── dfile.png /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [coolcode] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: xbruce # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | __pycache__/ 4 | .py[cod] 5 | .sqlite 6 | venv/ 7 | .db 8 | config.py 9 | *.log* 10 | app/functions -------------------------------------------------------------------------------- /.slugignore: -------------------------------------------------------------------------------- 1 | /app 2 | /nginx 3 | /share 4 | *.yml 5 | *.sh 6 | *.md 7 | *.toml -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: python api/gen_config.py && gunicorn --chdir ./ -t 300 --graceful-timeout 60 app:app --log-file - -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | v1.20.0512 -------------------------------------------------------------------------------- /api/.dockerignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | .py[cod] 3 | .sqlite 4 | .DS_Store 5 | venv/ 6 | .db 7 | .idea 8 | .log -------------------------------------------------------------------------------- /api/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolcode/dfile/7d7fe4bf459be611efd810766dfbbb635110dee2/api/.gitignore -------------------------------------------------------------------------------- /api/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6.7 2 | 3 | RUN mkdir -p /server 4 | WORKDIR /server 5 | COPY requirements.txt /server 6 | RUN pip install --no-cache-dir -r requirements.txt 7 | 8 | COPY . /server -------------------------------------------------------------------------------- /api/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright © 2019, Bruce Meerkat 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /api/config.sample: -------------------------------------------------------------------------------- 1 | DOMAIN = "http://localhost:5000" 2 | S3_REGION = "" 3 | S3_ENDPOINT = "https://s3-domain.com" 4 | S3_KEY = "" 5 | S3_SECRET = "" 6 | INIT_FILE_COUNT = 0 7 | SQLALCHEMY_DATABASE_URI = 'sqlite:////tmp/dfile.db' 8 | # SQLALCHEMY_DATABASE_URI = 'postgresql://localhost/dfile' 9 | SQLALCHEMY_TRACK_MODIFICATIONS = False 10 | CACHE_TYPE = 'simple' # Can be "memcached", "redis", etc. 11 | 12 | CORS_ORIGIN_WHITELIST = [ 13 | 'http://0.0.0.0:3000', 14 | 'http://0.0.0.0:3001', 15 | 'http://localhost:3000' 16 | 'http://localhost:3001', 17 | ] -------------------------------------------------------------------------------- /api/gen_config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | APP_DIR = os.path.abspath(os.path.dirname(__file__)) 4 | api_dir = os.path.join(APP_DIR, '') 5 | 6 | config_value = os.environ.get('CONFIG') 7 | 8 | if config_value: 9 | print(f'** config: \n{config_value}') 10 | config_filename = os.environ.get('CONFIG_NAME') or 'config' 11 | full_config_name = config_filename + '.py' 12 | config_file = os.path.join(api_dir, full_config_name) 13 | print(f'** write to {config_file}') 14 | with open(config_file, "w") as file: 15 | file.write(config_value) 16 | file.close() 17 | -------------------------------------------------------------------------------- /api/models.py: -------------------------------------------------------------------------------- 1 | import datetime as dt 2 | 3 | from .yopo.database import db, Model, reference_col, relationship, SurrogatePK 4 | 5 | 6 | class File(Model, SurrogatePK): 7 | __tablename__ = 'file' 8 | id = db.Column(db.BigInteger, primary_key=True) 9 | slug = db.Column(db.String(32), unique=True, nullable=False, index=True) 10 | filename = db.Column(db.String(256), unique=False, nullable=False) 11 | size = db.Column(db.Integer, nullable=True) 12 | path = db.Column(db.String(256), nullable=False, index=True) 13 | source = db.Column(db.String(32), nullable=True) # web, shell 14 | dl_num = db.Column(db.Integer, nullable=True) 15 | hash = db.Column(db.String(46), nullable=True, index=True) 16 | status = db.Column(db.String(1), nullable=True, default='Y') # D: delete, 17 | created_at = db.Column(db.DateTime, nullable=False, default=dt.datetime.utcnow) 18 | updated_at = db.Column(db.DateTime, nullable=False, default=dt.datetime.utcnow) 19 | lastdl_at = db.Column(db.DateTime, nullable=True, default=dt.datetime.utcnow) 20 | 21 | def __init__(self, **kwargs): 22 | self.created_at = dt.datetime.utcnow() 23 | self.updated_at = dt.datetime.utcnow() 24 | db.Model.__init__(self, **kwargs) 25 | 26 | def __repr__(self): 27 | """Represent instance as a unique string.""" 28 | return ''.format(**self) 29 | -------------------------------------------------------------------------------- /api/resources/index.py: -------------------------------------------------------------------------------- 1 | from ..yopo.app_context import app_context 2 | 3 | app = app_context(__name__) 4 | 5 | 6 | @app.route("/", methods=["GET"]) 7 | def index(): 8 | return "DFile - A fancy file sharing mode. Github: https://github.com/coolcode/dfile" 9 | 10 | 11 | @app.route('/version', methods=["GET"]) 12 | def version(): 13 | with open('./VERSION', 'rb') as file: 14 | ver = str(file.read(), 'utf-8') 15 | msg = f'DFile API {ver}' 16 | app.log.info(msg) 17 | return msg 18 | 19 | 20 | @app.route('/503', methods=["GET"]) 21 | def p503(): 22 | raise ValueError('503 error!') 23 | -------------------------------------------------------------------------------- /api/services/__init__.py: -------------------------------------------------------------------------------- 1 | from .s3 import S3 2 | from .ipfs import ipfs_hash 3 | from .shorty import i58encode, i58decode -------------------------------------------------------------------------------- /api/services/ipfs.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | 3 | from base58 import b58encode, b58decode 4 | 5 | SHA1 = 0x11 6 | SHA256 = 0x12 7 | SHA512 = 0x13 8 | 9 | hash_functions = { 10 | SHA1: hashlib.sha1, 11 | SHA256: hashlib.sha256, 12 | SHA512: hashlib.sha512, 13 | } 14 | 15 | 16 | def ipfs_hash(bytes, func_id=SHA256): 17 | try: 18 | hash_func = hash_functions[func_id] 19 | except KeyError: 20 | raise Exception("Requested hash type is not supported") 21 | 22 | hasher = hash_func(bytes) 23 | data = hasher.digest() 24 | size = hasher.digest_size 25 | 26 | if size > 127: 27 | raise Exception("multihash does not yet support digests longer than 127 bytes") 28 | 29 | output = chr(func_id).encode('ascii') + chr(size).encode('ascii') + data 30 | return str(b58encode(output), 'latin-1') 31 | 32 | 33 | if __name__ == "__main__": 34 | print(ipfs_hash(b"Hash me!") == b"QmepSLzJZG2LpJi9fak5Sgg4nQ2y7MaMGbD54DWyDrrxJt") 35 | -------------------------------------------------------------------------------- /api/services/shorty.py: -------------------------------------------------------------------------------- 1 | from base58 import b58encode, b58decode 2 | 3 | 4 | def i58encode(n): 5 | bs = __int_to_bytes(n) 6 | return str(b58encode(bs), 'latin-1') 7 | 8 | 9 | def i58decode(s): 10 | if not s: 11 | return 0 12 | bs = bytes(s, 'latin-1') 13 | bs = b58decode(bs) 14 | n = __int_from_bytes(bs) 15 | return n 16 | 17 | 18 | def __int_to_bytes(x: int) -> bytes: 19 | return x.to_bytes((x.bit_length() + 7) // 8, 'big') 20 | 21 | 22 | def __int_from_bytes(xbytes: bytes) -> int: 23 | return int.from_bytes(xbytes, 'big') 24 | 25 | 26 | if __name__ == "__main__": 27 | ns = [0, 1232, 30839699496976, 31014832656400, 31034599989264] 28 | for n in ns: 29 | s = i58encode(n) 30 | print(f'{n} -> {s}') 31 | n = i58decode(s) 32 | print(f'{s} -> {n}') 33 | -------------------------------------------------------------------------------- /api/sh/dfile.fish: -------------------------------------------------------------------------------- 1 | function dfile --description "https://dfile.app" 2 | if test (count $argv) -eq 0 3 | echo "No arguments specified. Usage:\necho dfile /tmp/test.md\ncat /tmp/test.md | dfile test.md" 4 | return 1 5 | end 6 | 7 | ## get temporarily filename, output is written to this file show progress can be showed 8 | set tmpfile ( mktemp -t transferXXX ) 9 | 10 | ## upload stdin or file 11 | set file $argv[1] 12 | 13 | set basefile (basename "$file" | sed -e 's/[^a-zA-Z0-9._-]/-/g') 14 | 15 | if test -d $file 16 | # zip directory and transfer 17 | set zipfile ( mktemp -t transferXXX.zip ) 18 | # echo (dirname $file) 19 | #cd (dirname $file) and echo (pwd) 20 | zip -r -q - $file >> $zipfile 21 | curl --progress-bar -F file=@"$zipfile" "https://dfile.app" >> $tmpfile 22 | rm -f $zipfile 23 | else 24 | # transfer file 25 | curl --progress-bar -F file=@$file "https://dfile.app" >> $tmpfile 26 | end 27 | 28 | ## cat output link 29 | cat $tmpfile 30 | 31 | ## cleanup 32 | rm -f $tmpfile 33 | end -------------------------------------------------------------------------------- /api/sh/dfile.zsh: -------------------------------------------------------------------------------- 1 | dfile() { 2 | if [ $# -eq 0 ]; then 3 | echo -e "No arguments specified. Usage: echo dfile /tmp/test.md cat /tmp/test.md | dfile test.md"; 4 | return 1; 5 | fi; 6 | tmpfile=$( mktemp -t transferXXX ); 7 | if tty -s; then 8 | basefile=$(basename "$1" | sed -e 's/[^a-zA-Z0-9._-]/-/g'); 9 | curl --progress-bar -F file=@"$1" "https://dfile.app" >> $tmpfile; 10 | else 11 | curl --progress-bar -F file=@"-" "https://dfile.app/$1" >> $tmpfile; 12 | fi; 13 | cat $tmpfile; 14 | rm -f $tmpfile; 15 | } -------------------------------------------------------------------------------- /api/yopo/compat.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Python 2/3 compatibility module.""" 3 | import sys 4 | 5 | # PY2 = int(sys.version[0]) == 2 6 | # 7 | # if PY2: 8 | # text_type = unicode # noqa 9 | # binary_type = str 10 | # string_types = (str, unicode) # noqa 11 | # unicode = unicode # noqa 12 | # basestring = basestring # noqa 13 | # else: 14 | # text_type = str 15 | # binary_type = bytes 16 | # string_types = (str,) 17 | # unicode = str 18 | # basestring = (str, bytes) 19 | text_type = str 20 | binary_type = bytes 21 | string_types = (str,) 22 | unicode = str 23 | basestring = (str, bytes) 24 | -------------------------------------------------------------------------------- /api/yopo/conf.py: -------------------------------------------------------------------------------- 1 | from flask.config import Config 2 | import os 3 | 4 | APP_DIR = os.path.abspath(os.path.dirname(__file__)) 5 | APP_DIR = os.path.abspath(os.path.join(APP_DIR, os.pardir)) 6 | api_dir = os.path.join(APP_DIR, '') 7 | 8 | config = Config(api_dir) 9 | config_value = os.environ.get('CONFIG') 10 | config_file = '' 11 | 12 | # if config_value: 13 | # print(f'** config: \n{config_value}') 14 | # config_filename = "_config" 15 | # full_config_name = config_filename + '.py' 16 | # config_file = os.path.join(api_dir, full_config_name) 17 | # print(f'** write to {config_file}') 18 | # with open(config_file, "w") as file: 19 | # file.write(config_value) 20 | # file.close() 21 | # else: 22 | 23 | config_filename = os.environ.get('CONFIG_NAME') or 'config' 24 | full_config_name = config_filename + '.py' 25 | config_file = os.path.join(api_dir, full_config_name) 26 | print(f'-> config: {config_file}') 27 | 28 | # log_dir = os.path.join(api_dir, os.pardir, 'logs') 29 | # if not os.path.exists(log_dir): 30 | # os.makedirs(log_dir) 31 | # 32 | # print(f'-> log dir: {log_dir}') 33 | 34 | config.from_pyfile(config_file) 35 | -------------------------------------------------------------------------------- /api/yopo/database.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy.orm import relationship 2 | from .extensions import db 3 | from .queryable_mixin import QueryableMixin 4 | import json 5 | 6 | 7 | def commit_session(): 8 | db.session.commit() 9 | 10 | 11 | def execute_sql(statement, *multiparams, **params): 12 | return db.engine.execute(statement, *multiparams, **params) 13 | 14 | 15 | db.commit = commit_session 16 | db.execute_sql = execute_sql 17 | # Alias common SQLAlchemy names 18 | Column = db.Column 19 | relationship = relationship 20 | 21 | 22 | def to_dict(inst, cls=None): 23 | """ 24 | Jsonify the sql alchemy query result. 25 | """ 26 | convert = dict() 27 | convert["DATETIME"] = __convert_datetime 28 | # add your conversions for things like datetime's 29 | # and what-not that aren't serializable. 30 | d = dict() 31 | if cls is None: 32 | cls = inst.__class__ 33 | for c in cls.__table__.columns: 34 | v = getattr(inst, c.name) 35 | # print("c.type: " + str(c.type)) 36 | if str(c.type) in convert.keys() and v is not None: 37 | try: 38 | # print("c(v): " + str(convert[str(c.type)](v))) 39 | d[c.name] = convert[str(c.type)](v) 40 | except: 41 | d[c.name] = "Error: Failed to convert using ", str(convert[str(c.type)]) 42 | elif v is None: 43 | d[c.name] = str() 44 | else: 45 | d[c.name] = v 46 | return d 47 | 48 | 49 | def __convert_datetime(v): 50 | return v.strftime('%Y-%m-%d %H:%M:%S') 51 | 52 | 53 | QueryableMixin.session = db.session 54 | 55 | 56 | class BaseModel(db.Model, QueryableMixin): 57 | __abstract__ = True 58 | 59 | # @property 60 | # def session(self): 61 | # return db.session 62 | 63 | @property 64 | def dict(self): 65 | return to_dict(self) 66 | 67 | def __str__(self): 68 | return json.dumps(to_dict(self)) 69 | 70 | 71 | Model = BaseModel 72 | 73 | 74 | # From Mike Bayer's "Building the app" talk 75 | # https://speakerdeck.com/zzzeek/building-the-app 76 | class SurrogatePK(object): 77 | """A mixin that adds a surrogate integer 'primary key' column named ``id`` \ 78 | to any declarative-mapped class. 79 | """ 80 | 81 | __table_args__ = {'extend_existing': True} 82 | 83 | id = db.Column(db.Integer, primary_key=True) 84 | 85 | 86 | def reference_col(tablename, nullable=False, pk_name='id', **kwargs): 87 | """Column that adds primary key foreign key reference. 88 | 89 | Usage: :: 90 | 91 | category_id = reference_col('category') 92 | category = relationship('Category', backref='categories') 93 | """ 94 | return db.Column(db.ForeignKey('{0}.{1}'.format(tablename, pk_name)), nullable=nullable, **kwargs) 95 | -------------------------------------------------------------------------------- /api/yopo/extensions.py: -------------------------------------------------------------------------------- 1 | # from flask_bcrypt import Bcrypt 2 | from flask_caching import Cache 3 | from flask_cors import CORS 4 | from flask_migrate import Migrate 5 | from flask_sqlalchemy import SQLAlchemy 6 | 7 | # bcrypt = Bcrypt() 8 | db = SQLAlchemy() # SQLAlchemy(model_class=QueryableMixin) 9 | 10 | migrate = Migrate() 11 | cache = Cache() 12 | cors = CORS() 13 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from api.yopo.app import create_app 2 | 3 | app = create_app() 4 | -------------------------------------------------------------------------------- /app/.dockerignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # dotenv environment variables file 55 | .env 56 | 57 | # gatsby files 58 | .cache/ 59 | public 60 | 61 | # Mac files 62 | .DS_Store 63 | 64 | # Yarn 65 | yarn-error.log 66 | .pnp/ 67 | .pnp.js 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | 72 | 73 | # next.js build output 74 | .next 75 | 76 | # app 77 | build 78 | out 79 | yarn.lock 80 | .idea 81 | -------------------------------------------------------------------------------- /app/.env-example: -------------------------------------------------------------------------------- 1 | PGHOST = localhost 2 | PGUSER = postgres 3 | PGDATABASE = dfile 4 | PGPASSWORD = 5 | PGPORT = 5432 6 | DATABASE_URL = postgresql://localhost/dfile 7 | 8 | S3_REGION = 9 | S3_ENDPOINT = https://s3-domain.com 10 | S3_KEY = 11 | S3_SECRET = 12 | INIT_FILE_COUNT = 0 13 | 14 | VERSION = v1.20.0520 15 | GACODE = 16 | DOMAIN = https://dfile.app -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # dotenv environment variables file 55 | .env 56 | 57 | # gatsby files 58 | .cache/ 59 | 60 | # Mac files 61 | .DS_Store 62 | 63 | # Yarn 64 | yarn-error.log 65 | .pnp/ 66 | .pnp.js 67 | # Yarn Integrity file 68 | .yarn-integrity 69 | 70 | 71 | 72 | # next.js build output 73 | .next 74 | 75 | # app 76 | build 77 | out 78 | yarn.lock 79 | .idea 80 | package-lock.json 81 | -------------------------------------------------------------------------------- /app/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": false, 4 | "singleQuote": false, 5 | "tabWidth": 2, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /app/CNAME: -------------------------------------------------------------------------------- 1 | dfile.app -------------------------------------------------------------------------------- /app/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 gatsbyjs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /app/asserts/scss/bootstrap/_alert.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Base styles 3 | // 4 | 5 | .alert { 6 | position: relative; 7 | padding: $alert-padding-y $alert-padding-x; 8 | margin-bottom: $alert-margin-bottom; 9 | border: $alert-border-width solid transparent; 10 | @include border-radius($alert-border-radius); 11 | } 12 | 13 | // Headings for larger alerts 14 | .alert-heading { 15 | // Specified to prevent conflicts of changing $headings-color 16 | color: inherit; 17 | } 18 | 19 | // Provide class for links that match alerts 20 | .alert-link { 21 | font-weight: $alert-link-font-weight; 22 | } 23 | 24 | 25 | // Dismissible alerts 26 | // 27 | // Expand the right padding and account for the close button's positioning. 28 | 29 | .alert-dismissible { 30 | padding-right: ($close-font-size + $alert-padding-x * 2); 31 | 32 | // Adjust close link position 33 | .close { 34 | position: absolute; 35 | top: 0; 36 | right: 0; 37 | padding: $alert-padding-y $alert-padding-x; 38 | color: inherit; 39 | } 40 | } 41 | 42 | 43 | // Alternate styles 44 | // 45 | // Generate contextual modifier classes for colorizing the alert. 46 | 47 | @each $color, $value in $theme-colors { 48 | .alert-#{$color} { 49 | @include alert-variant(theme-color-level($color, $alert-bg-level), theme-color-level($color, $alert-border-level), theme-color-level($color, $alert-color-level)); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/asserts/scss/bootstrap/_badge.scss: -------------------------------------------------------------------------------- 1 | // Base class 2 | // 3 | // Requires one of the contextual, color modifier classes for `color` and 4 | // `background-color`. 5 | 6 | .badge { 7 | display: inline-block; 8 | padding: $badge-padding-y $badge-padding-x; 9 | font-size: $badge-font-size; 10 | font-weight: $badge-font-weight; 11 | line-height: 1; 12 | text-align: center; 13 | white-space: nowrap; 14 | vertical-align: baseline; 15 | @include border-radius($badge-border-radius); 16 | 17 | // Empty badges collapse automatically 18 | &:empty { 19 | display: none; 20 | } 21 | } 22 | 23 | // Quick fix for badges in buttons 24 | .btn .badge { 25 | position: relative; 26 | top: -1px; 27 | } 28 | 29 | // Pill badges 30 | // 31 | // Make them extra rounded with a modifier to replace v3's badges. 32 | 33 | .badge-pill { 34 | padding-right: $badge-pill-padding-x; 35 | padding-left: $badge-pill-padding-x; 36 | @include border-radius($badge-pill-border-radius); 37 | } 38 | 39 | // Colors 40 | // 41 | // Contextual variations (linked badges get darker on :hover). 42 | 43 | @each $color, $value in $theme-colors { 44 | .badge-#{$color} { 45 | @include badge-variant($value); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/asserts/scss/bootstrap/_breadcrumb.scss: -------------------------------------------------------------------------------- 1 | .breadcrumb { 2 | display: flex; 3 | flex-wrap: wrap; 4 | padding: $breadcrumb-padding-y $breadcrumb-padding-x; 5 | margin-bottom: $breadcrumb-margin-bottom; 6 | list-style: none; 7 | background-color: $breadcrumb-bg; 8 | @include border-radius($breadcrumb-border-radius); 9 | } 10 | 11 | .breadcrumb-item { 12 | // The separator between breadcrumbs (by default, a forward-slash: "/") 13 | + .breadcrumb-item { 14 | padding-left: $breadcrumb-item-padding; 15 | 16 | &::before { 17 | display: inline-block; // Suppress underlining of the separator in modern browsers 18 | padding-right: $breadcrumb-item-padding; 19 | color: $breadcrumb-divider-color; 20 | content: $breadcrumb-divider; 21 | } 22 | } 23 | 24 | // IE9-11 hack to properly handle hyperlink underlines for breadcrumbs built 25 | // without `
    `s. The `::before` pseudo-element generates an element 26 | // *within* the .breadcrumb-item and thereby inherits the `text-decoration`. 27 | // 28 | // To trick IE into suppressing the underline, we give the pseudo-element an 29 | // underline and then immediately remove it. 30 | + .breadcrumb-item:hover::before { 31 | text-decoration: underline; 32 | } 33 | // stylelint-disable-next-line no-duplicate-selectors 34 | + .breadcrumb-item:hover::before { 35 | text-decoration: none; 36 | } 37 | 38 | &.active { 39 | color: $breadcrumb-active-color; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/asserts/scss/bootstrap/_close.scss: -------------------------------------------------------------------------------- 1 | .close { 2 | float: right; 3 | font-size: $close-font-size; 4 | font-weight: $close-font-weight; 5 | line-height: 1; 6 | color: $close-color; 7 | text-shadow: $close-text-shadow; 8 | opacity: .5; 9 | 10 | &:not(:disabled):not(.disabled) { 11 | 12 | @include hover-focus { 13 | color: $close-color; 14 | text-decoration: none; 15 | opacity: .75; 16 | } 17 | 18 | // Opinionated: add "hand" cursor to non-disabled .close elements 19 | cursor: pointer; 20 | } 21 | } 22 | 23 | // Additional properties for button version 24 | // iOS requires the button element instead of an anchor tag. 25 | // If you want the anchor version, it requires `href="#"`. 26 | // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile 27 | 28 | // stylelint-disable property-no-vendor-prefix, selector-no-qualifying-type 29 | button.close { 30 | padding: 0; 31 | background-color: transparent; 32 | border: 0; 33 | -webkit-appearance: none; 34 | } 35 | // stylelint-enable 36 | -------------------------------------------------------------------------------- /app/asserts/scss/bootstrap/_code.scss: -------------------------------------------------------------------------------- 1 | // Inline code 2 | code { 3 | font-size: $code-font-size; 4 | color: $code-color; 5 | word-break: break-word; 6 | 7 | // Streamline the style when inside anchors to avoid broken underline and more 8 | a > & { 9 | color: inherit; 10 | } 11 | } 12 | 13 | // User input typically entered via keyboard 14 | kbd { 15 | padding: $kbd-padding-y $kbd-padding-x; 16 | font-size: $kbd-font-size; 17 | color: $kbd-color; 18 | background-color: $kbd-bg; 19 | @include border-radius($border-radius-sm); 20 | @include box-shadow($kbd-box-shadow); 21 | 22 | kbd { 23 | padding: 0; 24 | font-size: 100%; 25 | font-weight: $nested-kbd-font-weight; 26 | @include box-shadow(none); 27 | } 28 | } 29 | 30 | // Blocks of code 31 | pre { 32 | display: block; 33 | font-size: $code-font-size; 34 | color: $pre-color; 35 | 36 | // Account for some code outputs that place code tags in pre tags 37 | code { 38 | font-size: inherit; 39 | color: inherit; 40 | word-break: normal; 41 | } 42 | } 43 | 44 | // Enable scrollable blocks of code 45 | .pre-scrollable { 46 | max-height: $pre-scrollable-max-height; 47 | overflow-y: scroll; 48 | } 49 | -------------------------------------------------------------------------------- /app/asserts/scss/bootstrap/_grid.scss: -------------------------------------------------------------------------------- 1 | // Container widths 2 | // 3 | // Set the container width, and override it for fixed navbars in media queries. 4 | 5 | @if $enable-grid-classes { 6 | .container { 7 | @include make-container(); 8 | @include make-container-max-widths(); 9 | } 10 | } 11 | 12 | // Fluid container 13 | // 14 | // Utilizes the mixin meant for fixed width containers, but with 100% width for 15 | // fluid, full width layouts. 16 | 17 | @if $enable-grid-classes { 18 | .container-fluid { 19 | @include make-container(); 20 | } 21 | } 22 | 23 | // Row 24 | // 25 | // Rows contain and clear the floats of your columns. 26 | 27 | @if $enable-grid-classes { 28 | .row { 29 | @include make-row(); 30 | } 31 | 32 | // Remove the negative margin from default .row, then the horizontal padding 33 | // from all immediate children columns (to prevent runaway style inheritance). 34 | .no-gutters { 35 | margin-right: 0; 36 | margin-left: 0; 37 | 38 | > .col, 39 | > [class*="col-"] { 40 | padding-right: 0; 41 | padding-left: 0; 42 | } 43 | } 44 | } 45 | 46 | // Columns 47 | // 48 | // Common styles for small and large grid columns 49 | 50 | @if $enable-grid-classes { 51 | @include make-grid-columns(); 52 | } 53 | -------------------------------------------------------------------------------- /app/asserts/scss/bootstrap/_images.scss: -------------------------------------------------------------------------------- 1 | // Responsive images (ensure images don't scale beyond their parents) 2 | // 3 | // This is purposefully opt-in via an explicit class rather than being the default for all ``s. 4 | // We previously tried the "images are responsive by default" approach in Bootstrap v2, 5 | // and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps) 6 | // which weren't expecting the images within themselves to be involuntarily resized. 7 | // See also https://github.com/twbs/bootstrap/issues/18178 8 | .img-fluid { 9 | @include img-fluid; 10 | } 11 | 12 | 13 | // Image thumbnails 14 | .img-thumbnail { 15 | padding: $thumbnail-padding; 16 | background-color: $thumbnail-bg; 17 | border: $thumbnail-border-width solid $thumbnail-border-color; 18 | @include border-radius($thumbnail-border-radius); 19 | @include box-shadow($thumbnail-box-shadow); 20 | 21 | // Keep them at most 100% wide 22 | @include img-fluid; 23 | } 24 | 25 | // 26 | // Figures 27 | // 28 | 29 | .figure { 30 | // Ensures the caption's text aligns with the image. 31 | display: inline-block; 32 | } 33 | 34 | .figure-img { 35 | margin-bottom: ($spacer / 2); 36 | line-height: 1; 37 | } 38 | 39 | .figure-caption { 40 | font-size: $figure-caption-font-size; 41 | color: $figure-caption-color; 42 | } 43 | -------------------------------------------------------------------------------- /app/asserts/scss/bootstrap/_jumbotron.scss: -------------------------------------------------------------------------------- 1 | .jumbotron { 2 | padding: $jumbotron-padding ($jumbotron-padding / 2); 3 | margin-bottom: $jumbotron-padding; 4 | background-color: $jumbotron-bg; 5 | @include border-radius($border-radius-lg); 6 | 7 | @include media-breakpoint-up(sm) { 8 | padding: ($jumbotron-padding * 2) $jumbotron-padding; 9 | } 10 | } 11 | 12 | .jumbotron-fluid { 13 | padding-right: 0; 14 | padding-left: 0; 15 | @include border-radius(0); 16 | } 17 | -------------------------------------------------------------------------------- /app/asserts/scss/bootstrap/_media.scss: -------------------------------------------------------------------------------- 1 | .media { 2 | display: flex; 3 | align-items: flex-start; 4 | } 5 | 6 | .media-body { 7 | flex: 1; 8 | } 9 | -------------------------------------------------------------------------------- /app/asserts/scss/bootstrap/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Toggles 2 | // 3 | // Used in conjunction with global variables to enable certain theme features. 4 | 5 | // Utilities 6 | @import "mixins/breakpoints"; 7 | @import "mixins/hover"; 8 | @import "mixins/image"; 9 | @import "mixins/badge"; 10 | @import "mixins/resize"; 11 | @import "mixins/screen-reader"; 12 | @import "mixins/size"; 13 | @import "mixins/reset-text"; 14 | @import "mixins/text-emphasis"; 15 | @import "mixins/text-hide"; 16 | @import "mixins/text-truncate"; 17 | @import "mixins/visibility"; 18 | 19 | // // Components 20 | @import "mixins/alert"; 21 | @import "mixins/buttons"; 22 | @import "mixins/caret"; 23 | @import "mixins/pagination"; 24 | @import "mixins/lists"; 25 | @import "mixins/list-group"; 26 | @import "mixins/nav-divider"; 27 | @import "mixins/forms"; 28 | @import "mixins/table-row"; 29 | 30 | // // Skins 31 | @import "mixins/background-variant"; 32 | @import "mixins/border-radius"; 33 | @import "mixins/box-shadow"; 34 | @import "mixins/gradients"; 35 | @import "mixins/transition"; 36 | 37 | // // Layout 38 | @import "mixins/clearfix"; 39 | @import "mixins/grid-framework"; 40 | @import "mixins/grid"; 41 | @import "mixins/float"; 42 | -------------------------------------------------------------------------------- /app/asserts/scss/bootstrap/_nav.scss: -------------------------------------------------------------------------------- 1 | // Base class 2 | // 3 | // Kickstart any navigation component with a set of style resets. Works with 4 | // `