Compare commits
No commits in common. "dev/2.7.10" and "master" have entirely different histories.
dev/2.7.10
...
master
88 changed files with 384 additions and 1296 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,6 +1,6 @@
|
|||
settings.ini
|
||||
.idea/
|
||||
.venv/
|
||||
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### Python template
|
||||
# Byte-compiled / optimized / DLL files
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
.venv
|
||||
.git
|
||||
__pycache__/
|
||||
*.egg-info/
|
||||
venv
|
BIN
FreeSans.ttf
Normal file
BIN
FreeSans.ttf
Normal file
Binary file not shown.
BIN
FreeSansBold.ttf
Normal file
BIN
FreeSansBold.ttf
Normal file
Binary file not shown.
BIN
FreeSansBoldOblique.ttf
Normal file
BIN
FreeSansBoldOblique.ttf
Normal file
Binary file not shown.
BIN
FreeSansOblique.ttf
Normal file
BIN
FreeSansOblique.ttf
Normal file
Binary file not shown.
4
Makefile
4
Makefile
|
@ -1,4 +0,0 @@
|
|||
DEST:=/opt/nativecloud
|
||||
|
||||
sync:
|
||||
rsync -rvza --exclude-from .rsyncignore --delete ./ root@192.168.158.136:/opt/nativecloud/
|
11
README.md
11
README.md
|
@ -10,7 +10,6 @@ Statuses:
|
|||
- 3: Процесс деактивации
|
||||
- 4: Создание...
|
||||
- 5: Удаление...
|
||||
- 6: Перезапуск
|
||||
|
||||
_Tasks_
|
||||
|
||||
|
@ -34,12 +33,6 @@ Statuses:
|
|||
|
||||
_Get containers status_
|
||||
|
||||
```shell
|
||||
curl -X GET http://127.0.0.1:5000/server_api/containers/status/ \
|
||||
-u f411b7d6-bf93-4fcd-91ee-03e5343d0187:b3c9a8b0-95ca-11e5-bec1-28d244e159e9
|
||||
```
|
||||
`curl -X GET http://127.0.0.1:5000/server_api/containers/status/ -u f411b7d6-bf93-4fcd-91ee-03e5343d0187:b3c9a8b0-95ca-11e5-bec1-28d244e159e9`
|
||||
|
||||
```shell
|
||||
curl -X POST http://127.0.0.1:5000/server_api/containers/status/663b31b4-22b1-4846-bfaf-27d6389beef4 \
|
||||
-u f411b7d6-bf93-4fcd-91ee-03e5343d0187:b3c9a8b0-95ca-11e5-bec1-28d244e159e9 -d 'status=0&message="test"'
|
||||
```
|
||||
`curl -X POST http://127.0.0.1:5000/server_api/containers/status/663b31b4-22b1-4846-bfaf-27d6389beef4 -u f411b7d6-bf93-4fcd-91ee-03e5343d0187:b3c9a8b0-95ca-11e5-bec1-28d244e159e9 -d 'status=0&message="test"'`
|
|
@ -0,0 +1,35 @@
|
|||
# coding: utf-8
|
||||
|
||||
from flask import Blueprint, jsonify, g
|
||||
from flask_httpauth import HTTPBasicAuth
|
||||
from SWSCloudCore.controllers.users import ControllerAPI
|
||||
from SWSCloudCore.controllers.users import ControllerUsers
|
||||
|
||||
|
||||
api = Blueprint('api', __name__, url_prefix='/api/v1')
|
||||
auth = HTTPBasicAuth()
|
||||
|
||||
"""
|
||||
TODO: Реализовать Процесс авторизации в версии API 2.0
|
||||
- получаем емейл и секретный ключ
|
||||
- создаём временный токен
|
||||
- выдаём токен
|
||||
"""
|
||||
|
||||
|
||||
@auth.verify_password
|
||||
def verify_password(username, password):
|
||||
if not ControllerAPI().auth(username, password):
|
||||
return False
|
||||
g.user_id = ControllerUsers().get_id_by_email(username)
|
||||
return True
|
||||
|
||||
|
||||
@api.route('/')
|
||||
@auth.login_required
|
||||
def index():
|
||||
"""
|
||||
curl -X POST http://localhost:5000/api/v1/ -u <email>:<secret>
|
||||
:return:
|
||||
"""
|
||||
return jsonify(user_id=g.user_id)
|
|
@ -1,2 +0,0 @@
|
|||
|
||||
from .token import api_v2_token
|
|
@ -1,59 +0,0 @@
|
|||
# coding: utf-8
|
||||
|
||||
from flask import Blueprint, jsonify, request, g
|
||||
from SWSCloudCore.models import Users
|
||||
from SWSCloudAPI.API.compute.v2.common import *
|
||||
from SWSCloudAPI.Utils import decorators, Tokens
|
||||
|
||||
api_v2_token = Blueprint('v2token', __name__, url_prefix='/api/auth/v2')
|
||||
|
||||
|
||||
@api_v2_token.route('/token', methods=['POST'])
|
||||
@decorators.content_type
|
||||
@decorators.login_required
|
||||
def token_post():
|
||||
"""Get token
|
||||
|
||||
_Example_
|
||||
|
||||
curl -X POST http://localhost:5001/api/auth/v2/token -d '{"email":"vanzhiganov@ya.ru","password":"qwepoi123"}' -H "Content-Type: application/json"
|
||||
|
||||
|
||||
{
|
||||
"status": "ok",
|
||||
"payload": {
|
||||
"token": "422f45a4-eab9-4a79-9954-61c568bae0eb",
|
||||
"email": "email@my.com"
|
||||
}
|
||||
}
|
||||
:return:
|
||||
"""
|
||||
# get user data
|
||||
user = Users.get_by_email(request.json.get('email'))
|
||||
#
|
||||
new_token = Tokens().set(dict(user_id=str(user.id), email=user.email), TOKEN_TTL)
|
||||
#
|
||||
return jsonify(status='ok', payload={'token': new_token})
|
||||
|
||||
|
||||
@api_v2_token.route('/token', methods=['GET'])
|
||||
@decorators.content_type
|
||||
@decorators.auth_token
|
||||
def token_get():
|
||||
"""Get token data
|
||||
curl -X GET http://localhost:5001/api/auth/v2/token -H "X-Auth-Token: 422f45a4-eab9-4a79-9954-61c568bae0eb" -H "Content-Type: application/json"
|
||||
:return:
|
||||
"""
|
||||
return jsonify(status='ok', payload=g.tokens.get(g.auth_token))
|
||||
|
||||
|
||||
@api_v2_token.route('/token', methods=['DELETE'])
|
||||
@decorators.content_type
|
||||
@decorators.auth_token
|
||||
def token_delete():
|
||||
"""
|
||||
curl -X DELETE http://localhost:5001/api/auth/v2/token -H "X-Auth-Token: 422f45a4-eab9-4a79-9954-61c568bae0eb" -H "Content-Type: application/json"
|
||||
:return:
|
||||
"""
|
||||
g.tokens.delete(g.auth_token)
|
||||
return jsonify(status='ok')
|
|
@ -1 +0,0 @@
|
|||
# coding: utf-8
|
|
@ -1,16 +0,0 @@
|
|||
|
||||
from SWSCloudCore.controllers.users import ControllerAPI
|
||||
from SWSCloudCore.controllers.users import ControllerUsers
|
||||
|
||||
from flask import g
|
||||
from flask_httpauth import HTTPBasicAuth
|
||||
|
||||
auth = HTTPBasicAuth()
|
||||
|
||||
|
||||
@auth.verify_password
|
||||
def verify_password(username, password):
|
||||
if not ControllerAPI().auth(username, password):
|
||||
return False
|
||||
g.user_id = ControllerUsers().get_id_by_email(username)
|
||||
return True
|
|
@ -1,4 +0,0 @@
|
|||
from .containers import api_v1_containers
|
||||
from .datacenters import api_v1_datacenters
|
||||
from .pricing import api_v1_pricing
|
||||
from .vms import api_v1_vms
|
|
@ -1,24 +0,0 @@
|
|||
# coding: utf-8
|
||||
|
||||
from flask import Blueprint, jsonify
|
||||
from SWSCloudAPI.API.compute.v1.common import auth
|
||||
from SWSCloudCore.models import DataCenters
|
||||
|
||||
|
||||
api_v1_datacenters = Blueprint('datacenters', __name__, url_prefix='/api/compute/v1/datacenters')
|
||||
|
||||
|
||||
@api_v1_datacenters.route('/', methods=['GET'])
|
||||
@auth.login_required
|
||||
def index():
|
||||
"""
|
||||
get containers list
|
||||
curl -X http://localhost:5000/api/compute/v1/datacenters/ -u <email>:<secret>
|
||||
:return:
|
||||
"""
|
||||
# dc_list = ControllerDataCenters().get()
|
||||
dc_list = DataCenters.get_available()
|
||||
items = list()
|
||||
for x in dc_list:
|
||||
items.append(x)
|
||||
return jsonify(total=len(dc_list), items=items)
|
|
@ -1,3 +0,0 @@
|
|||
from .views.datacenters import api_v2_datacenters
|
||||
from .views.pricing import api_v2_pricing
|
||||
from .views.vms import api_v2_vms
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
TOKEN_TTL = 1800
|
||||
TOKEN_PREFIX = 'token_'
|
||||
|
|
@ -1,254 +0,0 @@
|
|||
# coding: utf-8
|
||||
|
||||
from uuid import uuid4
|
||||
|
||||
from flask import Blueprint, jsonify, request, g
|
||||
|
||||
from SWSCloudAPI.Utils import Tokens
|
||||
from SWSCloudAPI.Utils import decorators
|
||||
from SWSCloudCore.controllers.billing import ControllerBilling
|
||||
from SWSCloudCore.controllers.common import ControllerCommon, ControllerMessagesEmail
|
||||
from SWSCloudCore.controllers.containers import (
|
||||
ControllerContainers, ControllerContainersStatistics, ControllerContainersStatisticsState)
|
||||
from SWSCloudCore.controllers.datacenters import ControllerDataCenters
|
||||
from SWSCloudCore.controllers.ips import ControllerIps
|
||||
from SWSCloudCore.controllers.tasks import ControllerTasks
|
||||
from SWSCloudCore.controllers.users import ControllerSSHKey
|
||||
from SWSCloudCore.controllers.users import ControllerUsers
|
||||
|
||||
api_v2_containers = Blueprint('v2containers', __name__, url_prefix='/api/compute/v2/containers')
|
||||
|
||||
|
||||
@api_v2_containers.route('/', methods=['GET'])
|
||||
@decorators.content_type
|
||||
@decorators.auth_token
|
||||
def containers_list():
|
||||
"""
|
||||
curl -X GET http://localhost:5000/api/v1/containers/ -u <email>:<secret>
|
||||
:return:
|
||||
"""
|
||||
tokens = Tokens()
|
||||
|
||||
# get containers list
|
||||
containers = ControllerContainers(g.user_id).get_items()
|
||||
#
|
||||
return jsonify(total=containers['total'], items=containers['items'])
|
||||
|
||||
|
||||
@api_v2_containers.route('/', methods=['POST'])
|
||||
@decorators.content_type
|
||||
@decorators.auth_token
|
||||
def container_create():
|
||||
"""
|
||||
curl -X POST http://localhost:5000/api/v1/containers/ -u <email>:<secret> -d "datacenter_id=123"
|
||||
:return:
|
||||
"""
|
||||
# Check exists data center
|
||||
if not ControllerDataCenters().exists(request.form.get('datacenter')):
|
||||
return jsonify(message='datacenter not exists')
|
||||
|
||||
tokens = Tokens()
|
||||
|
||||
# Check money
|
||||
if ControllerBilling().get(g.user_id) <= 0:
|
||||
return jsonify(message='no money')
|
||||
|
||||
# select server from selected region with available ip-addresses
|
||||
# select IP
|
||||
select_ip = ControllerIps().getfree(request.form.get('datacenter'))
|
||||
# mark ip as busy (taken)
|
||||
ControllerIps().setbusy(select_ip.id)
|
||||
# generate password for container user
|
||||
password = ControllerCommon().generate_password(size=14)
|
||||
|
||||
user_ssh = ControllerSSHKey(g.user_id)
|
||||
|
||||
new_container = dict(
|
||||
container_id=str(uuid4()),
|
||||
datacenter_id=str(select_ip.datacenter.id),
|
||||
server_id=str(select_ip.server.id),
|
||||
ipv4=select_ip.ipv4,
|
||||
ipv6=select_ip.ipv6,
|
||||
ipv4_gateway=select_ip.ipv4_gateway,
|
||||
ipv6_gateway=select_ip.ipv6_gateway,
|
||||
username='ubuntu',
|
||||
password=password,
|
||||
ssh_key='',
|
||||
)
|
||||
|
||||
# SSH key
|
||||
if user_ssh.check():
|
||||
new_container['ssh_key'] = user_ssh.get()
|
||||
|
||||
# create container record in database
|
||||
# status 4: creation
|
||||
status = 4
|
||||
container_create = ControllerContainers(g.user_id).create(
|
||||
new_container['container_id'],
|
||||
new_container['datacenter_id'],
|
||||
new_container['server_id'],
|
||||
new_container['ipv4'],
|
||||
new_container['ipv6'],
|
||||
status
|
||||
)
|
||||
# create default state data
|
||||
ControllerContainersStatisticsState().set(new_container['container_id'], dict())
|
||||
if container_create:
|
||||
# create task for create new container
|
||||
ControllerTasks(g.user_id).create(
|
||||
new_container['datacenter_id'],
|
||||
new_container['server_id'],
|
||||
'container_create',
|
||||
0,
|
||||
container_id=new_container['container_id'],
|
||||
ipv4=new_container['ipv4'],
|
||||
ipv6=new_container['ipv6'],
|
||||
ipv4_gateway=new_container['ipv4_gateway'],
|
||||
ipv6_gateway=new_container['ipv6_gateway'],
|
||||
username=new_container['username'],
|
||||
password=new_container['password'],
|
||||
ssh_key=new_container['ssh_key']
|
||||
)
|
||||
|
||||
# send mail message with recovery code
|
||||
message_parts = []
|
||||
|
||||
if new_container['ipv4']:
|
||||
message_parts.append(u"IPv4: %s" % new_container['ipv4'])
|
||||
if new_container['ipv6']:
|
||||
message_parts.append(u"IPv6: %s" % new_container['ipv6'])
|
||||
message_parts.append(u"Пользователь: %s" % new_container['username'])
|
||||
message_parts.append(u"Пароль: %s" % new_container['password'])
|
||||
if new_container['ssh_key']:
|
||||
message_parts.append(u"SSH ключ: добавлен")
|
||||
|
||||
message = '<br/>\n'.join(message_parts)
|
||||
subject = u'GoCloud.ru: Новый контейнер'
|
||||
lead = u"""Поздравляем с новым контейнером."""
|
||||
callout = u"""
|
||||
Для входа в личный кабинет воспользуйтесь
|
||||
<a href="https://gocloud.ru/account/login">страницей авторизации</a>.
|
||||
"""
|
||||
|
||||
user_data = ControllerUsers(g.user_id).get()
|
||||
|
||||
email = ControllerMessagesEmail()
|
||||
email.send(title=subject, to=user_data.email, lead=lead, message=message, callout=callout)
|
||||
|
||||
#
|
||||
return jsonify(message='ok')
|
||||
|
||||
|
||||
@api_v2_containers.route('/container/<uuid:container_id>', methods=['DELETE'])
|
||||
@decorators.content_type
|
||||
@decorators.auth_token
|
||||
def container_delete(container_id):
|
||||
"""
|
||||
curl -X DELETE http://gocloud.ru/api/v1/container/<uuid:container_id> -u <email>:<secret> -d "container_id=<uuid:container_id>"
|
||||
:return:
|
||||
"""
|
||||
auth_token = request.headers.get('X-Auth-Token')
|
||||
tokens = Tokens()
|
||||
|
||||
containers = ControllerContainers(g.user_id)
|
||||
# check the user have a selected rule
|
||||
# if user not have a container then redirect to the container list
|
||||
if not containers.check_exists_item(container_id):
|
||||
return jsonify(message='container_not_exists')
|
||||
|
||||
# get container details
|
||||
container_details = ControllerContainers(g.user_id).get_item(container_id)
|
||||
|
||||
# Обновляем статус "5" для правила
|
||||
containers.set_status(container_id, 5)
|
||||
# Создание задания
|
||||
ControllerTasks(g.user_id).create(
|
||||
container_details.datacenter.id,
|
||||
container_details.server.id,
|
||||
'container_delete',
|
||||
0,
|
||||
container_id=container_id
|
||||
)
|
||||
# TODO: send email container was deleted about
|
||||
return jsonify(status=0, message='container has been deleted')
|
||||
|
||||
|
||||
@api_v2_containers.route('/<uuid:container_id>', methods=['GET'])
|
||||
@decorators.content_type
|
||||
@decorators.auth_token
|
||||
def container_info(container_id):
|
||||
"""
|
||||
curl -X GET http://localhost:5000/api/v1/container/<uuid:container_id> -u <email>:<secret>
|
||||
:return:
|
||||
"""
|
||||
# init
|
||||
containers = ControllerContainers(g.user_id)
|
||||
# check the user have a selected rule
|
||||
# if user not have a container then redirect to the container list
|
||||
if not containers.check_exists_item(container_id):
|
||||
return jsonify(message='container_not_found')
|
||||
# get container details
|
||||
container_details = containers.get_item(container_id)
|
||||
# print ControllerContainersStatisticsState().get(container_id)
|
||||
|
||||
statistics = list()
|
||||
for s in ControllerContainersStatistics(container_id).size_get(1):
|
||||
created = s.created
|
||||
statistics.append({
|
||||
'year': created.strftime('%Y'),
|
||||
'month': created.strftime('%m'),
|
||||
'day': created.strftime('%d'),
|
||||
'hour': created.strftime('%H'),
|
||||
'minute': created.strftime('%M'),
|
||||
'data': s.memory
|
||||
})
|
||||
# return
|
||||
return jsonify(container=container_details, stats_memory=statistics)
|
||||
|
||||
|
||||
@api_v2_containers.route('/<uuid:container_id>', methods=['POST'])
|
||||
@decorators.content_type
|
||||
@decorators.auth_token
|
||||
def container_actions(container_id):
|
||||
"""
|
||||
curl -X POST http://localhost:5000/api/v1/container/<uuid:container_id> -u <email>:<secret> -d "status=inactive"
|
||||
curl -X POST http://localhost:5000/api/v1/container/<uuid:container_id> -u <email>:<secret> -d "action=active"
|
||||
:return:
|
||||
"""
|
||||
containers = ControllerContainers(g.user_id)
|
||||
# check the user have a selected rule
|
||||
# if user not have a container then redirect to the container list
|
||||
if not containers.check_exists_item(container_id):
|
||||
return jsonify(status='error', message='container_not_found')
|
||||
|
||||
# get container details
|
||||
container_details = containers.get_item(container_id)
|
||||
|
||||
if request.form.get('status') == "inactive":
|
||||
containers.set_status(container_id, 3)
|
||||
# Создание задания
|
||||
ControllerTasks(g.user_id).create(
|
||||
container_details.datacenter.id,
|
||||
container_details.server.id,
|
||||
'container_stop',
|
||||
0,
|
||||
container_id=container_id
|
||||
)
|
||||
elif request.form.get('status') == 'active':
|
||||
balance = ControllerBilling().get(g.user_id)
|
||||
|
||||
if balance <= 0:
|
||||
return jsonify(message='no money')
|
||||
|
||||
containers.set_status(container_id, 2)
|
||||
# Создание задания
|
||||
ControllerTasks(g.user_id).create(
|
||||
container_details.datacenter.id,
|
||||
container_details.server.id,
|
||||
'container_start',
|
||||
0,
|
||||
container_id=container_details.id
|
||||
)
|
||||
return jsonify(message='ok')
|
||||
else:
|
||||
return jsonify(status=1, message='require action')
|
|
@ -1,25 +0,0 @@
|
|||
# coding: utf-8
|
||||
|
||||
from flask import Blueprint, jsonify, g
|
||||
|
||||
from SWSCloudAPI.Utils import decorators
|
||||
from SWSCloudCore.models import DataCenters
|
||||
|
||||
api_v2_datacenters = Blueprint('v2datacenters', __name__, url_prefix='/api/compute/v2/datacenters')
|
||||
|
||||
|
||||
@api_v2_datacenters.route('/', methods=['GET'])
|
||||
@decorators.content_type
|
||||
@decorators.auth_token
|
||||
def datacenter_list():
|
||||
"""Get containers list
|
||||
curl -X http://localhost:5000/api/compute/v2/datacenters/ -H "X-Auth-Token: a90bb6cd-681f-4f87-b1ca-ea30921e3440" -H "Content-Type: application/json"
|
||||
|
||||
:return:
|
||||
"""
|
||||
#
|
||||
dc_list = DataCenters.get_available()
|
||||
items = list()
|
||||
for x in dc_list:
|
||||
items.append(dict(id=str(x.id), name=x.name, country=x.country, city=x.city))
|
||||
return jsonify(status='ok', payload=items, total=len(dc_list))
|
|
@ -1,22 +0,0 @@
|
|||
# coding: utf-8
|
||||
|
||||
from flask import Blueprint, jsonify, g
|
||||
|
||||
from SWSCloudAPI.Utils import decorators
|
||||
from SWSCloudCore.controllers.plans import ControllerPlans
|
||||
|
||||
api_v2_pricing = Blueprint('v2pricing', __name__, url_prefix='/api/compute/v2/pricing')
|
||||
|
||||
|
||||
@api_v2_pricing.route('/')
|
||||
@decorators.content_type
|
||||
@decorators.auth_token
|
||||
def pricing():
|
||||
"""get pricing list
|
||||
curl -XGET http://localhost:5001/api/compute/v2/pricing/ -H "X-Auth-Token: ad89abee-49bc-4434-98ee-c7598c2f0adc" -H "Content-Type: application/json"
|
||||
|
||||
:return:
|
||||
"""
|
||||
#
|
||||
payload = ControllerPlans().get_plans(status='active')
|
||||
return jsonify(status='ok', payload=payload)
|
|
@ -1,245 +0,0 @@
|
|||
# coding: utf-8
|
||||
|
||||
from uuid import uuid4
|
||||
|
||||
from flask import Blueprint, jsonify, request, g
|
||||
|
||||
from SWSCloudCore import models
|
||||
from SWSCloudAPI.Utils import decorators
|
||||
from SWSCloudCore.controllers.billing import ControllerBilling
|
||||
from SWSCloudCore.controllers.common import ControllerCommon, ControllerMessagesEmail
|
||||
from SWSCloudCore.controllers.ips import ControllerIps
|
||||
from SWSCloudCore.controllers.plans import ControllerPlans
|
||||
from SWSCloudCore.controllers.tasks import ControllerTasks
|
||||
from SWSCloudCore.controllers.users import ControllerSSHKey
|
||||
from SWSCloudCore.controllers.users import ControllerUsers
|
||||
from SWSCloudCore.controllers.vms import ControllerVMS
|
||||
|
||||
api_v2_vms = Blueprint('v2vms', __name__, url_prefix='/api/compute/v2/vms')
|
||||
|
||||
|
||||
@api_v2_vms.route('/', methods=['GET'])
|
||||
@decorators.content_type
|
||||
@decorators.auth_token
|
||||
def vms_list():
|
||||
"""Get virtual servers list"""
|
||||
return jsonify(status='ok', payload=models.Vms.get_user_items(g.user.get('user_id')))
|
||||
|
||||
|
||||
@api_v2_vms.route('/', methods=['POST'])
|
||||
@decorators.content_type
|
||||
@decorators.auth_token
|
||||
def vms_create():
|
||||
"""Create virtual server"""
|
||||
user_balance = ControllerBilling().get(g.user.get('user_id'))
|
||||
user_ssh = ControllerSSHKey(g.user.get('user_id'))
|
||||
controller_plans = ControllerPlans()
|
||||
|
||||
# check user money
|
||||
if user_balance <= 0:
|
||||
return jsonify(status='error', message='no money')
|
||||
|
||||
new_vm = dict()
|
||||
new_vm['vm_id'] = str(uuid4())
|
||||
|
||||
# check exists plan
|
||||
if not controller_plans.exists(request.json.get('plan')):
|
||||
return jsonify(status='error', message='plan not exists')
|
||||
|
||||
# load plan details
|
||||
plan_details = controller_plans.plan_get(request.json.get('plan'))
|
||||
|
||||
new_vm['plan'] = request.json.get('plan')
|
||||
|
||||
# select server from selected region with available ip-addresses
|
||||
# select IP
|
||||
select_ip = ControllerIps().getfree(request.json.get('datacenter'))
|
||||
# mark ip as busy (taken)
|
||||
ControllerIps().setbusy(select_ip.id)
|
||||
|
||||
# generate password for container user
|
||||
new_vm['password'] = ControllerCommon().generate_password(size=14)
|
||||
new_vm['hostname'] = ControllerCommon().generate_password(size=7)
|
||||
|
||||
new_vm['datacenter_id'] = str(select_ip.datacenter.id)
|
||||
new_vm['server_id'] = str(select_ip.server.id)
|
||||
|
||||
new_vm['platform'] = 'x86_64'
|
||||
new_vm['ipv4'] = select_ip.ipv4
|
||||
new_vm['ipv6'] = select_ip.ipv6
|
||||
|
||||
new_vm['ipv4_gateway'] = select_ip.ipv4_gateway
|
||||
new_vm['ipv6_gateway'] = select_ip.ipv6_gateway
|
||||
|
||||
# TODO: remove hardcore
|
||||
new_vm['dns1'] = '8.8.8.8'
|
||||
new_vm['dns2'] = '8.8.4.4'
|
||||
|
||||
new_vm['cores'] = plan_details.cores
|
||||
new_vm['storage'] = plan_details.storage
|
||||
new_vm['swap'] = plan_details.swap
|
||||
new_vm['memory'] = plan_details.memory
|
||||
|
||||
new_vm['os_name'] = 'ubuntu'
|
||||
new_vm['os_suite'] = 'trusty'
|
||||
|
||||
# sshkey
|
||||
new_vm['ssh_key'] = None
|
||||
if user_ssh.check():
|
||||
new_vm['ssh_key'] = user_ssh.get()
|
||||
|
||||
# create container record in database
|
||||
# status 4: creation
|
||||
status = 4
|
||||
container_create = ControllerVMS(g.user.get('user_id')).create(
|
||||
vm_id=new_vm['vm_id'],
|
||||
datacenter_id=new_vm['datacenter_id'],
|
||||
server_id=new_vm['server_id'],
|
||||
hostname=new_vm['hostname'],
|
||||
ipv4=new_vm['ipv4'],
|
||||
ipv6=new_vm['ipv6'],
|
||||
plan=new_vm['plan'],
|
||||
platform=new_vm['platform'],
|
||||
os_name=new_vm['os_name'],
|
||||
os_suite=new_vm['os_suite'],
|
||||
status=status
|
||||
)
|
||||
# create default state data
|
||||
# ControllerContainersStatisticsState().set(new_container['container_id'], dict())
|
||||
if not container_create:
|
||||
# mark ip as free
|
||||
ControllerIps().setfree(select_ip.id)
|
||||
return jsonify(status='error', message='fail')
|
||||
|
||||
# create task for create new container
|
||||
ControllerTasks(g.user.get('user_id')).create(
|
||||
new_vm['datacenter_id'],
|
||||
new_vm['server_id'],
|
||||
'vm_create',
|
||||
0,
|
||||
vm_id=new_vm['vm_id'],
|
||||
ipv4=new_vm['ipv4'],
|
||||
ipv4_gateway=new_vm['ipv4_gateway'],
|
||||
ipv6=new_vm['ipv6'],
|
||||
ipv6_gateway=new_vm['ipv6_gateway'],
|
||||
password=new_vm['password'],
|
||||
hostname=new_vm['hostname'],
|
||||
platform=new_vm['platform'],
|
||||
# TODO: remove hardcore
|
||||
dns1=new_vm['dns1'],
|
||||
dns2=new_vm['dns2'],
|
||||
|
||||
cores=new_vm['cores'],
|
||||
storage=new_vm['storage'],
|
||||
swap=new_vm['swap'],
|
||||
memory=new_vm['memory'],
|
||||
|
||||
os_name=new_vm['os_name'],
|
||||
os_suite=new_vm['os_suite'],
|
||||
|
||||
ssh_key=new_vm['ssh_key'],
|
||||
)
|
||||
|
||||
# send mail message with recovery code
|
||||
message_parts = []
|
||||
|
||||
if new_vm['ipv4']:
|
||||
message_parts.append(u"IPv4: %s" % new_vm['ipv4'])
|
||||
if new_vm['ipv6']:
|
||||
message_parts.append(u"IPv6: %s" % new_vm['ipv6'])
|
||||
message_parts.append(u"Пользователь: %s" % 'administrator')
|
||||
# message_parts.append(u"Пользователь: %s" % new_vm['username'])
|
||||
message_parts.append(u"Пароль: %s" % new_vm['password'])
|
||||
if new_vm['ssh_key']:
|
||||
message_parts.append(u"SSH ключ: добавлен")
|
||||
|
||||
message = '<br/>\n'.join(message_parts)
|
||||
subject = u'GoCloud.ru: Новый виртуальный сервер'
|
||||
lead = u"""Поздравляем с новым виртуальным сервером."""
|
||||
callout = u"""
|
||||
Для входа в личный кабинет воспользуйтесь
|
||||
<a href="https://gocloud.ru/account/login">страницей авторизации</a>.
|
||||
"""
|
||||
|
||||
user_data = ControllerUsers(g.user.get('user_id')).get()
|
||||
|
||||
email = ControllerMessagesEmail()
|
||||
email.send(title=subject, to=user_data.email, lead=lead, message=message, callout=callout)
|
||||
|
||||
return jsonify(
|
||||
status='ok', payload=dict(
|
||||
user='root', password=new_vm['password'], ipv4=new_vm['ipv4'],
|
||||
public_ssh_key='added' if new_vm['ssh_key'] else 'empty'))
|
||||
|
||||
|
||||
@api_v2_vms.route('/<uuid:vm_id>/status', methods=['POST'])
|
||||
@decorators.content_type
|
||||
@decorators.auth_token
|
||||
def vm_actions(vm_id):
|
||||
"""
|
||||
"""
|
||||
# init ...
|
||||
vm = ControllerVMS(g.user.get('user_id'))
|
||||
# get container details
|
||||
vm_details = vm.get(vm_id=vm_id)
|
||||
|
||||
if request.json.get('action') == "start":
|
||||
if ControllerBilling().get(g.user.get('user_id')) <= 0:
|
||||
return jsonify(message='no money')
|
||||
|
||||
vm.set_status(vm_id, 2)
|
||||
# Создание задания
|
||||
ControllerTasks(g.user.get('user_id')).create(
|
||||
vm_details.datacenter.id, vm_details.server.id, 'vm_start', 0, vm_id=vm_details.id)
|
||||
|
||||
if request.json.get('action') == "restart":
|
||||
#
|
||||
vm.status_set(vm_id, 6)
|
||||
# Создание задания
|
||||
ControllerTasks(g.user.get('user_id')).create(
|
||||
vm_details.datacenter.id, vm_details.server.id, 'vm_restart', 0, vm_id=vm_id)
|
||||
|
||||
if request.json.get('action') == "stop":
|
||||
#
|
||||
vm.status_set(vm_id, 3)
|
||||
# Создание задания
|
||||
ControllerTasks(g.user.get('user_id')).create(
|
||||
vm_details.datacenter.id, vm_details.server.id, 'vm_stop', 0, vm_id=vm_id)
|
||||
|
||||
if request.json.get('action') == "delete":
|
||||
# Обновляем статус "5" для правила
|
||||
vm.set_status(vm_id, 5)
|
||||
# Создание задания
|
||||
models.Tasks.set_task(
|
||||
vm_details.datacenter.id, vm_details.server.id, vm_details.user.id, 'vm_delete', 0, vm_id=vm_id)
|
||||
return jsonify(status='ok')
|
||||
|
||||
|
||||
@api_v2_vms.route('/<uuid:vm_id>', methods=['DELETE'])
|
||||
@decorators.content_type
|
||||
@decorators.auth_token
|
||||
def vm_delete(vm_id):
|
||||
"""Delete virtual machine
|
||||
:param vm_id:
|
||||
:return:
|
||||
"""
|
||||
|
||||
vms = ControllerVMS(g.user.get('user_id'))
|
||||
tasks = ControllerTasks(g.user.get('user_id'))
|
||||
|
||||
# check the user have a selected rule
|
||||
# if user not have a container then redirect to the container list
|
||||
if not vms.exists(vm_id):
|
||||
return jsonify(status='error', message='not exists')
|
||||
|
||||
# get container details
|
||||
vm_details = models.Vms.get_item(vm_id)
|
||||
|
||||
# Обновляем статус "5" для правила
|
||||
vms.set_status(vm_id, 5)
|
||||
|
||||
# Создание задания
|
||||
models.Tasks.set_task(
|
||||
vm_details.datacenter.id, vm_details.server.id, vm_details.user.id, 'vm_delete', 0, vm_id=vm_id)
|
||||
|
||||
return jsonify(status=0, message='ok')
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from uuid import uuid4
|
||||
from flask import Blueprint, jsonify, request, g
|
||||
from SWSCloudAPI.API.compute.v1.common import auth
|
||||
from SWSCloudAPI.API import auth
|
||||
from SWSCloudCore.controllers.datacenters import ControllerDataCenters
|
||||
from SWSCloudCore.controllers.ips import ControllerIps
|
||||
from SWSCloudCore.controllers.users import ControllerUsers
|
||||
|
@ -13,7 +13,7 @@ from SWSCloudCore.controllers.tasks import ControllerTasks
|
|||
from SWSCloudCore.controllers.containers import (
|
||||
ControllerContainers, ControllerContainersStatistics, ControllerContainersStatisticsState)
|
||||
|
||||
api_v1_containers = Blueprint('containers', __name__, url_prefix='/api/compute/v1/containers')
|
||||
api_v1_containers = Blueprint('containers', __name__, url_prefix='/api/v1/containers')
|
||||
|
||||
|
||||
@api_v1_containers.route('/', methods=['GET'])
|
20
SWSCloudAPI/API/datacenters.py
Normal file
20
SWSCloudAPI/API/datacenters.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
# coding: utf-8
|
||||
|
||||
from flask import Blueprint, jsonify
|
||||
from SWSCloudAPI.API import auth
|
||||
from SWSCloudCore.controllers.datacenters import ControllerDataCenters
|
||||
|
||||
|
||||
api_v1_datacenters = Blueprint('datacenters', __name__, url_prefix='/api/v1/datacenters')
|
||||
|
||||
|
||||
@api_v1_datacenters.route('/', methods=['GET'])
|
||||
@auth.login_required
|
||||
def index():
|
||||
"""
|
||||
get containers list
|
||||
curl -X http://localhost:5000/api/v1/datacenters/ -u <email>:<secret>
|
||||
:return:
|
||||
"""
|
||||
dc_list = ControllerDataCenters().get()
|
||||
return jsonify(total=dc_list.get('total'), items=dc_list.get('items'))
|
|
@ -1,13 +1,13 @@
|
|||
# coding: utf-8
|
||||
|
||||
from flask import Blueprint, jsonify
|
||||
from SWSCloudAPI.API.compute.v1.common import auth
|
||||
from SWSCloudAPI.API import auth
|
||||
from SWSCloudCore.controllers.plans import ControllerPlans
|
||||
|
||||
api_v1_pricing = Blueprint('pricing', __name__, url_prefix='/api/compute/v1/pricing')
|
||||
api_v1_pricing = Blueprint('pricing', __name__, url_prefix='/api/v1/pricing')
|
||||
|
||||
|
||||
@api_v1_pricing.route('/vms')
|
||||
@api_v1_pricing.route('/pricing/vms/')
|
||||
@auth.login_required
|
||||
def pricing_vms():
|
||||
"""
|
||||
|
@ -18,7 +18,7 @@ def pricing_vms():
|
|||
return jsonify(pricing=ControllerPlans().get_plans(status='active'))
|
||||
|
||||
|
||||
@api_v1_pricing.route('/containers')
|
||||
@api_v1_pricing.route('/pricing/containers/')
|
||||
@auth.login_required
|
||||
def pricing_containers():
|
||||
"""
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from uuid import uuid4
|
||||
from flask import Blueprint, jsonify, request, g
|
||||
from SWSCloudAPI.API.compute.v1.common import auth
|
||||
from SWSCloudAPI.API import auth
|
||||
from SWSCloudCore.controllers.ips import ControllerIps
|
||||
from SWSCloudCore.controllers.plans import ControllerPlans
|
||||
from SWSCloudCore.controllers.users import ControllerUsers
|
||||
|
@ -12,7 +12,7 @@ from SWSCloudCore.controllers.common import ControllerCommon, ControllerMessages
|
|||
from SWSCloudCore.controllers.tasks import ControllerTasks
|
||||
from SWSCloudCore.controllers.vms import ControllerVMS
|
||||
|
||||
api_v1_vms = Blueprint('vms', __name__, url_prefix='/api/compute/v1/vms')
|
||||
api_v1_vms = Blueprint('vms', __name__, url_prefix='/api/v1/vms')
|
||||
|
||||
|
||||
@api_v1_vms.route('/', methods=['GET'])
|
|
@ -1,102 +0,0 @@
|
|||
# Compute API v1
|
||||
|
||||
...
|
||||
|
||||
# Compute API v2
|
||||
|
||||
## Auth
|
||||
|
||||
Create new Token
|
||||
|
||||
$ curl -X POST http://localhost:5001/api/auth/v2/token \
|
||||
-d '{"email":"vanzhiganov@ya.ru","password":"qwepoi123"}' \
|
||||
-H "Content-Type: application/json"
|
||||
|
||||
{
|
||||
"payload": {
|
||||
"token": true
|
||||
},
|
||||
"status": "ok"
|
||||
}
|
||||
|
||||
Get token data
|
||||
|
||||
curl -X GET http://localhost:5001/api/auth/v2/token \
|
||||
-H 'X-Auth-Token: e7a49627-1199-4c3a-a7d3-b482c00fa503' \
|
||||
-H "Content-Type: application/json"
|
||||
|
||||
{
|
||||
"payload": {
|
||||
"email": "vanzhiganov@ya.ru",
|
||||
"user_id": "1f3936af-be4c-43d5-b352-2f9c88c56857"
|
||||
},
|
||||
"status": "ok"
|
||||
}
|
||||
|
||||
Delete token
|
||||
|
||||
curl -X DELETE http://localhost:5001/api/auth/v2/token \
|
||||
-H 'X-Auth-Token: e7a49627-1199-4c3a-a7d3-b482c00fa503' \
|
||||
-H "Content-Type: application/json"
|
||||
|
||||
{
|
||||
"status": "ok"
|
||||
}
|
||||
|
||||
## Data Centers
|
||||
|
||||
Get list data centers
|
||||
|
||||
curl -X GET http://localhost:5001/api/compute/v2/datacenters/ \
|
||||
-H "X-Auth-Token: ef381b13-425d-4635-9d8a-bba91910dd26" \
|
||||
-H "Content-Type: application/json"
|
||||
{
|
||||
"payload": [
|
||||
{
|
||||
"city": "moscow",
|
||||
"country": "russia",
|
||||
"id": "531511b2-dcf5-11e6-9175-a315ee8fdabf",
|
||||
"name": "moscow 1"
|
||||
}
|
||||
],
|
||||
"status": "ok",
|
||||
"total": 1
|
||||
}
|
||||
|
||||
## Pricing
|
||||
|
||||
curl -X GET http://localhost:5001/api/compute/v2/pricing/ \
|
||||
-H "X-Auth-Token: ef381b13-425d-4635-9d8a-bba91910dd26" \
|
||||
-H "Content-Type: application/json"
|
||||
{
|
||||
"payload": [],
|
||||
"status": "ok"
|
||||
}
|
||||
|
||||
## Virtual machines
|
||||
|
||||
Create new virtual achine
|
||||
|
||||
|
||||
curl -X POST http://localhost:5001/api/compute/v2/vms/ \
|
||||
-H "X-Auth-Token: ef381b13-425d-4635-9d8a-bba91910dd26" \
|
||||
-H "Content-Type: application/json" '
|
||||
-d '{"plan": "", "datacenter": "", }'
|
||||
|
||||
|
||||
Errors
|
||||
|
||||
{
|
||||
"message": "no money",
|
||||
"status": "error"
|
||||
}
|
||||
|
||||
Get list virtual achines
|
||||
|
||||
curl -X GET http://localhost:5001/api/compute/v2/vms/ \
|
||||
-H "X-Auth-Token: ef381b13-425d-4635-9d8a-bba91910dd26" \
|
||||
-H "Content-Type: application/json"
|
||||
{
|
||||
"payload": [],
|
||||
"status": "ok"
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
from .tokens import Tokens
|
|
@ -1,48 +0,0 @@
|
|||
from functools import wraps
|
||||
|
||||
import validators
|
||||
from flask import g, request, jsonify
|
||||
|
||||
from SWSCloudAPI.Utils import Tokens
|
||||
from SWSCloudCore.models import Users
|
||||
|
||||
|
||||
def login_required(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
# validate email
|
||||
if not validators.email(request.json.get('email')):
|
||||
return jsonify(status='error', message='invalid email format')
|
||||
# verify email/password
|
||||
if not Users.auth(request.json.get('email'), request.json.get('password').encode()):
|
||||
return jsonify(status='error', message='invalid auth')
|
||||
#
|
||||
return f(*args, **kwargs)
|
||||
return decorated_function
|
||||
|
||||
|
||||
def content_type(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if request.headers.get('Content-Type') != 'application/json':
|
||||
return jsonify(status='error', message='content-type must be application/json')
|
||||
return f(*args, **kwargs)
|
||||
return decorated_function
|
||||
|
||||
|
||||
def auth_token(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
#
|
||||
g.auth_token = request.headers.get('X-Auth-Token', None)
|
||||
#
|
||||
if not g.auth_token:
|
||||
return jsonify(status='error', message='X-Auth-Token not specified')
|
||||
# check exists token
|
||||
if not Tokens.exists(g.auth_token):
|
||||
return jsonify(status='error', message='token not exists')
|
||||
#
|
||||
g.tokens = Tokens()
|
||||
g.user = g.tokens.get(g.auth_token)
|
||||
return f(*args, **kwargs)
|
||||
return decorated_function
|
|
@ -1,5 +0,0 @@
|
|||
|
||||
from SWSCloudCore.config import config
|
||||
from redis import StrictRedis
|
||||
|
||||
rediskc = StrictRedis(config.get('Redis', 'host'), config.get('Redis', 'port'), config.get('Redis', 'db'))
|
|
@ -1,74 +0,0 @@
|
|||
import json
|
||||
import uuid
|
||||
from flask import g
|
||||
from SWSCloudAPI.API.compute.v2.common import TOKEN_PREFIX, TOKEN_TTL
|
||||
|
||||
|
||||
class Tokens(object):
|
||||
def set(self, payload, ttl=1800):
|
||||
"""Create new token
|
||||
|
||||
Example
|
||||
>>> Tokens().set({'user_id': 1, 'email': 'user@email.com'}, 1800)
|
||||
|
||||
:param payload: dict
|
||||
:param ttl: int
|
||||
:return: boolean
|
||||
"""
|
||||
token = self.generate_id()
|
||||
g.redis_connect.set(TOKEN_PREFIX + token, json.dumps(payload), ttl)
|
||||
return token
|
||||
|
||||
@staticmethod
|
||||
def get(token, ttl=None):
|
||||
"""Get token data
|
||||
|
||||
>>> Tokens.get('d0dd3bfa-e0f2-11e6-a2ce-17cec9ffa761')
|
||||
>>> Tokens.get('d0dd3bfa-e0f2-11e6-a2ce-17cec9ffa761', 1800)
|
||||
"""
|
||||
if ttl and type(ttl) == int:
|
||||
g.redis_connect.expire(TOKEN_PREFIX + token, ttl)
|
||||
return json.loads(g.redis_connect.get(TOKEN_PREFIX + token))
|
||||
|
||||
@staticmethod
|
||||
def expire(token, ttl=1800):
|
||||
"""
|
||||
|
||||
>>> Tokens.expire('d0dd3bfa-e0f2-11e6-a2ce-17cec9ffa761', 1800)
|
||||
|
||||
:param token: uuid
|
||||
:param ttl: int
|
||||
:return: boolean
|
||||
"""
|
||||
g.redis_connect.expire(TOKEN_PREFIX + token, ttl)
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def exists(token):
|
||||
"""Check exists token in redis
|
||||
|
||||
:param token: uuid
|
||||
:return: boolean
|
||||
"""
|
||||
if g.redis_connect.exists(TOKEN_PREFIX + token):
|
||||
return True
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def delete(token):
|
||||
try:
|
||||
g.redis_connect.delete(TOKEN_PREFIX + token)
|
||||
except:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def generate_id():
|
||||
"""Generate UUID strinfg
|
||||
|
||||
>>> Tokens.generate_id()
|
||||
|
||||
:return: str
|
||||
"""
|
||||
return str(uuid.uuid4())
|
|
@ -1,61 +1,55 @@
|
|||
# coding: utf-8
|
||||
|
||||
from flask import Flask, g, jsonify
|
||||
from SWSCloudAPI.API import api
|
||||
from SWSCloudAPI.API.vms import api_v1_vms
|
||||
from SWSCloudAPI.API.containers import api_v1_containers
|
||||
from SWSCloudAPI.API.datacenters import api_v1_datacenters
|
||||
from SWSCloudAPI.API.pricing import api_v1_pricing
|
||||
from SWSCloudCore import models
|
||||
from SWSCloudCore.config import config
|
||||
from SWSCloudCore.models import database
|
||||
# v1
|
||||
from SWSCloudAPI.API.compute.v1.views import *
|
||||
# v2
|
||||
from SWSCloudAPI.API.auth.v2 import *
|
||||
from SWSCloudAPI.API.compute.v2 import *
|
||||
#
|
||||
from SWSCloudAPI.Utils.redisc import rediskc
|
||||
from SWSCloudCore.config import config
|
||||
|
||||
app = Flask(__name__)
|
||||
# Думал, что получится сделать автопрефик для всего приложения, но это не сработало
|
||||
# app.config["APPLICATION_ROOT"] = "/api/v1"
|
||||
# app.config['SERVER_NAME'] = settings.get('Application', 'SERVER_NAME')
|
||||
app.config['DEBUG'] = config.getboolean('Application', 'DEBUG')
|
||||
app.config['SECRET_KEY'] = config.get("Application", "SECRET_KEY")
|
||||
|
||||
# V1
|
||||
app.register_blueprint(api)
|
||||
app.register_blueprint(api_v1_vms)
|
||||
app.register_blueprint(api_v1_containers)
|
||||
app.register_blueprint(api_v1_pricing)
|
||||
app.register_blueprint(api_v1_datacenters)
|
||||
|
||||
# V2
|
||||
app.register_blueprint(api_v2_token)
|
||||
app.register_blueprint(api_v2_pricing)
|
||||
app.register_blueprint(api_v2_datacenters)
|
||||
app.register_blueprint(api_v2_vms)
|
||||
|
||||
|
||||
@app.errorhandler(404)
|
||||
def page_not_found(e):
|
||||
app.logger.error(e)
|
||||
return jsonify(status='error', message='resource not found')
|
||||
return jsonify(dict(message='resource not found')), 404
|
||||
|
||||
|
||||
@app.errorhandler(403)
|
||||
def access_deny(e):
|
||||
app.logger.error(e)
|
||||
return jsonify(status='error', message='access deny'), 403
|
||||
return jsonify(dict(message='access deny')), 403
|
||||
|
||||
|
||||
@app.errorhandler(410)
|
||||
def page_not_found(e):
|
||||
app.logger.error(e)
|
||||
return jsonify({})
|
||||
return jsonify(dict()), 410
|
||||
|
||||
|
||||
@app.errorhandler(500)
|
||||
def page_not_found(e):
|
||||
app.logger.error(e)
|
||||
return jsonify(status='maintenance')
|
||||
return jsonify(dict(message='maintenance')), 500
|
||||
|
||||
|
||||
@app.before_request
|
||||
def before_request():
|
||||
g.redis_connect = rediskc
|
||||
g.settings = dict()
|
||||
# извлекаем настройки и определяем их в глобальную переменную
|
||||
for setting in models.Settings.select(models.Settings.key, models.Settings.val).execute():
|
||||
|
|
|
@ -21,38 +21,35 @@ from SWSCloudCore import models
|
|||
viewAdministrator = Blueprint('administrator', __name__, url_prefix='/administrator')
|
||||
|
||||
|
||||
@viewAdministrator.route('/login.html', methods=['GET'])
|
||||
@viewAdministrator.route('/login.html', methods=['GET', 'POST'])
|
||||
def login():
|
||||
if request.method == 'POST':
|
||||
admin_email = request.form.get('email').encode('utf-8')
|
||||
admin_password = request.form.get('password').encode('utf-8')
|
||||
|
||||
# validation entered data
|
||||
if not validators.email(admin_email):
|
||||
flash('Invalid registration data')
|
||||
return redirect(url_for('administrator.login'))
|
||||
|
||||
# try auth only active users (with status code 1)
|
||||
if models.Admins.auth(admin_email, admin_password, 1):
|
||||
# get user_id
|
||||
user_id = ControllerAdministrators().get_id_by_email(admin_email)
|
||||
|
||||
# save user data to session
|
||||
session['admin_id'] = str(user_id)
|
||||
session['admin_email'] = admin_email
|
||||
session['admin_password'] = admin_password
|
||||
|
||||
# redirect to rules list
|
||||
return redirect(url_for('administrator.dashboard'))
|
||||
else:
|
||||
flash('Invalid login. Please try again.')
|
||||
return redirect(url_for('administrator.login'))
|
||||
return render_template('administrator/login.html')
|
||||
|
||||
|
||||
@viewAdministrator.route('/login.html', methods=['POST'])
|
||||
def login_post():
|
||||
admin_email = request.form.get('email').encode('utf-8')
|
||||
admin_password = request.form.get('password').encode('utf-8')
|
||||
|
||||
# validation entered data
|
||||
if not validators.email(admin_email):
|
||||
flash('Invalid registration data')
|
||||
return redirect(url_for('administrator.login'))
|
||||
|
||||
# try auth only active users (with status code 1)
|
||||
if not models.Admins.auth(admin_email, admin_password, 1):
|
||||
flash('Invalid login. Please try again.')
|
||||
return redirect(url_for('administrator.login'))
|
||||
|
||||
# get user_id
|
||||
user_id = ControllerAdministrators().get_id_by_email(admin_email)
|
||||
|
||||
# save user data to session
|
||||
session['admin_id'] = str(user_id)
|
||||
session['admin_email'] = admin_email
|
||||
session['admin_password'] = admin_password
|
||||
|
||||
# redirect to rules list
|
||||
return redirect(url_for('administrator.dashboard'))
|
||||
|
||||
|
||||
@viewAdministrator.route('/logout.html')
|
||||
def logout():
|
||||
session.pop('admin_id', None)
|
||||
|
@ -167,7 +164,7 @@ def ips_index():
|
|||
def ips_create():
|
||||
#
|
||||
if request.method == "POST":
|
||||
print(request.form)
|
||||
print request.form
|
||||
if ControllerManageIPs().is_valid_ipv4_address(request.form['ipv4'])\
|
||||
and ControllerManageIPs().is_valid_ipv4_address(request.form['ipv4_gateway']):
|
||||
ControllerManageIPs().item_create(
|
||||
|
@ -203,7 +200,7 @@ def ips_create():
|
|||
def ips_edit(ip_id):
|
||||
#
|
||||
if request.method == 'POST':
|
||||
print(request.form)
|
||||
print request.form
|
||||
# if ControllerManageIPs().is_valid_ipv4_address(request.form['ipv4'])\
|
||||
# and ControllerManageIPs().is_valid_ipv4_address(request.form['ipv4_gateway']):
|
||||
ControllerManageIPs().item_update(
|
||||
|
@ -235,7 +232,7 @@ def ips_delete():
|
|||
@requires_login
|
||||
def servers_create():
|
||||
if request.method == "POST":
|
||||
print(request.form)
|
||||
print request.form
|
||||
params = {
|
||||
'datacenter_id': request.form['datacenter_id'],
|
||||
'server_id': uuid4(),
|
||||
|
|
|
@ -7,19 +7,15 @@ from SWSCloudCore.controllers.tasks import ControllerTasks
|
|||
from SWSCloudCore import models
|
||||
from SWSCloudAdministrator.Administrator.common import requires_login
|
||||
|
||||
view_administrator_compute_vms = Blueprint(
|
||||
'administrator_compute_vms',
|
||||
__name__,
|
||||
url_prefix='/administrator/compute/vms')
|
||||
view_administrator_compute_vms = Blueprint('administrator_compute_vms', __name__, url_prefix='/administrator/compute/vms')
|
||||
|
||||
|
||||
@view_administrator_compute_vms.route('/', methods=['GET'])
|
||||
@requires_login
|
||||
def index():
|
||||
"""Virtual Machines list"""
|
||||
template = 'administrator/compute/vms/index.html'
|
||||
items = models.Vms.get_items()
|
||||
return render_template(template, vms=items)
|
||||
# формируем список правил
|
||||
return render_template(
|
||||
'administrator/compute/vms/index.html', vms=models.Vms.get_items())
|
||||
|
||||
|
||||
@view_administrator_compute_vms.route('/<uuid:vm_id>', methods=['GET'])
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
"""Stack Web Services LLC"""
|
||||
# coding: utf-8
|
||||
|
||||
import validators
|
||||
from flask import Blueprint, redirect, render_template, request, url_for
|
||||
# from uuid import uuid4
|
||||
# import validators
|
||||
|
||||
from flask import Blueprint, flash, g, jsonify, redirect, render_template, request, session, url_for
|
||||
|
||||
from SWSCloudCore.controllers.administrators import ControllerAdministrators
|
||||
from SWSCloudCore.controllers.tasks.manage import ControllerManageTasks
|
||||
from SWSCloudAdministrator.Administrator.common import requires_login
|
||||
from SWSCloudCore import models
|
||||
|
||||
view_administrator_tasks = Blueprint(
|
||||
'administrator_tasks', __name__,
|
||||
url_prefix='/administrator/tasks')
|
||||
view_administrator_tasks = Blueprint('administrator_tasks', __name__, url_prefix='/administrator/tasks')
|
||||
|
||||
|
||||
@view_administrator_tasks.route('/', methods=['GET'])
|
||||
|
@ -23,29 +25,23 @@ def index():
|
|||
@view_administrator_tasks.route('/edit.html', methods=['GET'])
|
||||
@requires_login
|
||||
def edit():
|
||||
task_id = request.form.get('task_id')
|
||||
if not validators.uuid(task_id) or not models.Tasks.exists(task_id):
|
||||
return redirect(url_for('administrator_tasks.index'))
|
||||
task = ControllerManageTasks().get_task(task_id)
|
||||
task_id = request.args.get('task_id')
|
||||
|
||||
# TODO: check exists
|
||||
|
||||
return render_template(
|
||||
'administrator/tasks/edit.html',
|
||||
task=task)
|
||||
task=ControllerManageTasks().get_task(task_id))
|
||||
|
||||
|
||||
@view_administrator_tasks.route('/edit.html', methods=['POST'])
|
||||
@requires_login
|
||||
def edit_post():
|
||||
task_id = request.form.get('task_id')
|
||||
# todo: validate
|
||||
status = request.form.get('status')
|
||||
|
||||
if not validators.uuid(task_id) or not models.Tasks.exists(task_id):
|
||||
return redirect(url_for('administrator_tasks.index'))
|
||||
|
||||
task = models.Tasks.update(
|
||||
status=status
|
||||
).where(models.Tasks.id == task_id)
|
||||
task.execute()
|
||||
# TODO: check exists
|
||||
x = models.Tasks.update(status=request.form.get('status')).where(models.Tasks.id == task_id)
|
||||
x.execute()
|
||||
|
||||
return redirect(url_for('administrator_tasks.edit', task_id=task_id))
|
||||
|
||||
|
@ -55,13 +51,11 @@ def edit_post():
|
|||
def delete():
|
||||
task_id = request.args.get('task_id')
|
||||
|
||||
if not validators.uuid(task_id) or not models.Tasks.exists(task_id):
|
||||
return redirect(url_for('administrator_tasks.index'))
|
||||
# TODO: check exists
|
||||
|
||||
task = ControllerManageTasks().get_task(task_id)
|
||||
return render_template(
|
||||
'administrator/tasks/delete.html',
|
||||
task=task
|
||||
task=ControllerManageTasks().get_task(task_id)
|
||||
)
|
||||
|
||||
|
||||
|
@ -70,10 +64,8 @@ def delete():
|
|||
def delete_post():
|
||||
task_id = request.form.get('task_id')
|
||||
|
||||
if not validators.uuid(task_id) or not models.Tasks.exists(task_id):
|
||||
return redirect(url_for('administrator_tasks.index'))
|
||||
|
||||
task = models.Tasks.delete().where(models.Tasks.id == task_id)
|
||||
task.execute()
|
||||
# TODO: check exists
|
||||
x = models.Tasks.delete().where(models.Tasks.id == task_id)
|
||||
x.execute()
|
||||
|
||||
return redirect(url_for('administrator_tasks.index'))
|
||||
|
|
|
@ -43,7 +43,7 @@ app.register_blueprint(view_administrator_compute_containers)
|
|||
|
||||
# @app.errorhandler(500)
|
||||
# def page_not_found(e):
|
||||
# print(e)
|
||||
# print e
|
||||
# return render_template('errors/500.html'), 500
|
||||
|
||||
|
||||
|
@ -51,11 +51,7 @@ app.register_blueprint(view_administrator_compute_containers)
|
|||
def before_request():
|
||||
g.settings = dict()
|
||||
# извлекаем настройки и определяем их в глобальную переменную
|
||||
settings = models.Settings.select(
|
||||
models.Settings.key,
|
||||
models.Settings.val
|
||||
).execute()
|
||||
for setting in settings:
|
||||
for setting in models.Settings.select(models.Settings.key, models.Settings.val).execute():
|
||||
g.settings[setting.key] = setting.val
|
||||
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<form action="{{ url_for('administrator.login_post') }}" method="post">
|
||||
<label for="email">email</label>
|
||||
<form action="{{ url_for('administrator.login') }}" method="post">
|
||||
<label for="email">email</lable>
|
||||
<input type="text" name="email" value="" id="email" />
|
||||
<label for="password">password</label>
|
||||
<input type="password" name="password" value="" id="password" />
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
# coding: utf-8
|
||||
|
||||
import sys
|
||||
import os
|
||||
from configparser import ConfigParser
|
||||
import ConfigParser
|
||||
|
||||
__config_file__ = os.getenv('CONFIG', '/etc/sws/cloud/core.ini')
|
||||
__config_file__ = os.getenv('CLOUD_CONFIG_FILE', '/etc/sws/cloud/core.ini')
|
||||
|
||||
# setting file read
|
||||
config = ConfigParser()
|
||||
config = ConfigParser.ConfigParser()
|
||||
if os.path.exists(__config_file__):
|
||||
config.read(__config_file__)
|
||||
|
||||
|
|
|
@ -222,7 +222,7 @@ class Datacenters:
|
|||
"status": i.status
|
||||
}
|
||||
dcs['items'].append(dc)
|
||||
# print(i)
|
||||
# print i
|
||||
return dcs
|
||||
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ class ControllerContainers:
|
|||
)
|
||||
except Exception as e:
|
||||
# TODO: write to log
|
||||
print(e)
|
||||
print e
|
||||
return False
|
||||
return True
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ class ControllerUsers:
|
|||
def update(self, user_id, **kwargs):
|
||||
if 'password' in kwargs:
|
||||
x = models.Users.update(
|
||||
password=md5(kwargs['password'].encode()).hexdigest()
|
||||
password=md5(kwargs['password']).hexdigest()
|
||||
).where(
|
||||
models.Users.id == user_id
|
||||
)
|
||||
|
@ -69,7 +69,7 @@ class ControllerUsers:
|
|||
:param password:
|
||||
:return:
|
||||
"""
|
||||
password_hash = md5(password.encode()).hexdigest()
|
||||
password_hash = md5(password).hexdigest()
|
||||
result = models.Users.select().where(
|
||||
models.Users.email == email,
|
||||
models.Users.password == password_hash,
|
||||
|
@ -86,7 +86,7 @@ class ControllerUsers:
|
|||
:param password:
|
||||
:return:
|
||||
"""
|
||||
password_hash = md5(password.encode()).hexdigest()
|
||||
password_hash = md5(password).hexdigest()
|
||||
user_id = uuid.uuid4()
|
||||
# TODO: add date registration and update of date - =datetime.datetime.now()
|
||||
user = models.Users.create(id=user_id, email=email, password=password_hash, status=1)
|
||||
|
@ -95,7 +95,7 @@ class ControllerUsers:
|
|||
return False
|
||||
|
||||
def password_update(self, user_id, password):
|
||||
password_hash = md5(password.encode()).hexdigest()
|
||||
password_hash = md5(password).hexdigest()
|
||||
u = models.Users.get(models.Users.id == user_id)
|
||||
u.password = password_hash
|
||||
u.save()
|
||||
|
|
|
@ -35,7 +35,7 @@ class ControllerManageUsers:
|
|||
models.UsersBalance
|
||||
)
|
||||
for j in jj:
|
||||
print(j.usersbalance.balance)
|
||||
print j.usersbalance.balance
|
||||
return {
|
||||
'total': len(jj),
|
||||
'items': jj
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
# coding: utf-8
|
||||
|
||||
import json
|
||||
from hashlib import md5
|
||||
import datetime
|
||||
import uuid
|
||||
|
@ -43,16 +42,6 @@ class DataCenters(PgSQLModel):
|
|||
city = CharField()
|
||||
status = IntegerField(default=0)
|
||||
|
||||
@staticmethod
|
||||
def get_available():
|
||||
return DataCenters.select().where(
|
||||
DataCenters.status == 1 and
|
||||
DataCenters.id << Servers.select(Servers.datacenter).where(
|
||||
Servers.status == 1 and
|
||||
Servers.id << Ips.select(Ips.server).where(
|
||||
Ips.status == 0).group_by(Ips.server)
|
||||
).group_by(Servers.datacenter)).execute()
|
||||
|
||||
|
||||
class Servers(PgSQLModel):
|
||||
id = UUIDField(unique=True, primary_key=True)
|
||||
|
@ -121,9 +110,7 @@ class Users(PgSQLModel):
|
|||
@staticmethod
|
||||
def auth(email, password, status=1):
|
||||
if Users.select().where(
|
||||
Users.email == email,
|
||||
Users.password == Users.hash_password(password),
|
||||
Users.status == status
|
||||
Users.email == email, Users.password == Users.hash_password(password), Users.status == status
|
||||
).count() == 0:
|
||||
return False
|
||||
return True
|
||||
|
@ -134,11 +121,7 @@ class Users(PgSQLModel):
|
|||
|
||||
@staticmethod
|
||||
def get_by_id(user_id):
|
||||
return Users.select().where(Users.id == user_id).first()
|
||||
|
||||
@staticmethod
|
||||
def get_by_email(email):
|
||||
return Users.select().where(Users.email == email).first()
|
||||
return Users.select().where(Users.id == user_id).get()
|
||||
|
||||
|
||||
class UsersRecoveryCodes(PgSQLModel):
|
||||
|
@ -264,14 +247,6 @@ class Vms(PgSQLModel):
|
|||
def get_items():
|
||||
return Vms.select()
|
||||
|
||||
@staticmethod
|
||||
def get_user_items(user_id):
|
||||
items = list()
|
||||
for x in Vms.select().where(Vms.user == user_id):
|
||||
items.append(dict(id=str(x.id), datacenter=str(x.datacenter.id), plan=x.plan.id, hostname=x.hostname,
|
||||
osname=x.os_name, ossuite=x.os_suite, ipv4=x.ipv4, ipv6=x.ipv6, status=x.status))
|
||||
return items
|
||||
|
||||
@staticmethod
|
||||
def get_item(vm_id):
|
||||
return Vms.select().where(Vms.id == vm_id).first()
|
||||
|
@ -323,27 +298,22 @@ class Tasks(PgSQLModel):
|
|||
Tasks.select().where(Tasks.status == status).count()
|
||||
return Tasks.select().count()
|
||||
|
||||
@staticmethod
|
||||
def set_task(datacenter_id, server_id, user_id, task, status, **args):
|
||||
task_id = uuid.uuid4()
|
||||
plain = dict()
|
||||
for arg in args:
|
||||
plain[arg] = str(args[arg])
|
||||
|
||||
Tasks.create(
|
||||
id=task_id,
|
||||
datacenter=datacenter_id,
|
||||
server=server_id,
|
||||
task=task,
|
||||
status=status,
|
||||
user=user_id,
|
||||
plain=json.dumps(plain))
|
||||
|
||||
@staticmethod
|
||||
def exists(task_id):
|
||||
if Tasks.select().where(Tasks.id == task_id).count() == 0:
|
||||
return False
|
||||
return True
|
||||
# @staticmethod
|
||||
# def set_task(datacenter_id, server_id, task, status, **args):
|
||||
# task_id = uuid.uuid4()
|
||||
# plain = dict()
|
||||
# for arg in args:
|
||||
# plain[arg] = str(args[arg])
|
||||
#
|
||||
# Tasks.create(
|
||||
# id=task_id,
|
||||
# datacenter=datacenter_id,
|
||||
# server=server_id,
|
||||
# task=task,
|
||||
# status=status,
|
||||
# user=self.user_id,
|
||||
# plain=json.dumps(plain)
|
||||
# )
|
||||
|
||||
|
||||
class Settings(PgSQLModel):
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
"""Stack Web Services LLC."""
|
||||
# coding: utf-8
|
||||
|
||||
import json
|
||||
from flask import Blueprint, jsonify, request, g
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# coding: utf-8
|
||||
import logging
|
||||
|
||||
import os
|
||||
from flask import Flask, g, render_template
|
||||
from flask_babel import Babel
|
||||
|
@ -42,7 +42,7 @@ if app.config.get('THEME_STATIC_FOLDER', False):
|
|||
static_folder = app.config['THEME_STATIC_FOLDER']
|
||||
if static_folder[0] != '/':
|
||||
static_folder = os.path.join(app.root_path, 'static', static_folder)
|
||||
# print(static_folder)
|
||||
print static_folder
|
||||
# Unlike templates, to serve static files from multiples folders we
|
||||
# need flask-multistatic
|
||||
# app.static_folder = [static_folder, os.path.join(app.root_path, 'static')]
|
||||
|
@ -90,20 +90,17 @@ def page_not_found(e):
|
|||
|
||||
@app.errorhandler(500)
|
||||
def page_not_found(e):
|
||||
print(e)
|
||||
print e
|
||||
return render_template('errors/500.html'), 500
|
||||
|
||||
|
||||
@app.before_request
|
||||
def before_request():
|
||||
g.settings = dict()
|
||||
try:
|
||||
# извлекаем настройки и определяем их в глобальную переменную
|
||||
for setting in models.Settings.select(models.Settings.key, models.Settings.val).execute():
|
||||
g.settings[setting.key] = setting.val
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
# exit(1)
|
||||
# извлекаем настройки и определяем их в глобальную переменную
|
||||
for setting in models.Settings.select(models.Settings.key, models.Settings.val).execute():
|
||||
g.settings[setting.key] = setting.val
|
||||
|
||||
|
||||
@app.before_first_request
|
||||
def before_first_request():
|
||||
|
|
|
@ -16,7 +16,7 @@ def requires_login(f):
|
|||
else:
|
||||
return redirect(url_for("account.logout"))
|
||||
|
||||
if not Users.auth(session.get('email'), session.get('password').encode(), 1):
|
||||
if not Users.auth(session.get('email'), session.get('password'), 1):
|
||||
return redirect(url_for("account.logout"))
|
||||
|
||||
return f(*args, **kwargs)
|
||||
|
|
1
SWSCloudWeb/static/assets/css/app.min.css
vendored
1
SWSCloudWeb/static/assets/css/app.min.css
vendored
File diff suppressed because one or more lines are too long
7
SWSCloudWeb/static/assets/js/app.min.js
vendored
7
SWSCloudWeb/static/assets/js/app.min.js
vendored
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 3.9 KiB |
|
@ -83,5 +83,6 @@
|
|||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block footer %}
|
||||
{% endblock %}
|
|
@ -5,7 +5,7 @@
|
|||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="large-12 columns">
|
||||
<h2>{{ _('Вход') }}</h2>
|
||||
<h3>{{ _('Вход') }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
|
|
@ -8,12 +8,18 @@
|
|||
<h2>Регистрация</h2>
|
||||
<form action="{{ url_for('account.registration') }}" method="post">
|
||||
<input type="hidden" name="method" value="member_add" />
|
||||
<label for="email">Адрес электронной почты</label>
|
||||
<input type="text" name="email" value="" class="email" id="email" />
|
||||
<label for="password">Пароль</label>
|
||||
<input type="password" name="password" value="" id="password" />
|
||||
<label for="password2">Пароль (повторно)</label>
|
||||
<input type="password" name="password2" value="" id="password2" />
|
||||
<label for="email">
|
||||
Адрес ел. почты
|
||||
<input type="text" name="email" value="" class="email" id="email" />
|
||||
</label>
|
||||
<label for="password">
|
||||
Пароль
|
||||
<input type="password" name="password" value="" id="password" />
|
||||
</label>
|
||||
<label for="password2">
|
||||
Пароль (повторно)
|
||||
<input type="password" name="password2" value="" id="password2" />
|
||||
</label>
|
||||
<input type="submit" value="Зарегистрироваться" class="button success" />
|
||||
</form>
|
||||
</div>
|
||||
|
|
11
SWSCloudWeb/templates/default/kb/index.html
Normal file
11
SWSCloudWeb/templates/default/kb/index.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
{% extends "default/_layout.html" %}
|
||||
|
||||
{% block title %}База знаний{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="large-12 columns">
|
||||
{% filter markdown %}{{ kb_markdown }}{% endfilter %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -4,8 +4,7 @@
|
|||
<meta charset="utf-8" />
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}Облачный хостинг GoCloud{% endblock %}</title>
|
||||
<meta name="description" content="{% block description %}GoCloud предлагает вам арендовать виртуальные серверные мощности{% endblock %}">
|
||||
<title>Облачный хостинг GoCloud</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='assets/css/app.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<h1>Облачный хостинг</h1>
|
||||
<h2>Виртуальный сервер от 200 рублей в месяц</h2>
|
||||
<h2>
|
||||
<a href="{{ url_for('account.registration') }}" class="button alert">Создать виртуальный сервер</a>
|
||||
<a href="{{ url_for('account.registration') }}" class="button success">Создать виртуальный сервер</a>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
{% extends "gocloud2016/layouts/default.html" %}
|
||||
|
||||
{% block title %}Стоимость аренды виртуального сервера - GoCloud{% endblock %}
|
||||
|
||||
{% block description %}Расценки на стоимость аренды виртуальных серверов различной конфигурации{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="large-12 columns">
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
{% extends "gocloud2016/layouts/default.html" %}
|
||||
|
||||
{% block title %}Поддержка онлайн виртуального сервера - GoCloud{% endblock %}
|
||||
|
||||
{% block description %}Наши технические специалисты ответят на ваши вопросы{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="large-12 columns">
|
||||
<h2>Поддержка</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="large-12 columns">
|
||||
<form action="{{ url_for('support.index_post') }}" method="post">
|
||||
{% if not session['email'] %}
|
||||
<label for="email">Адрес электронной почты</label>
|
||||
<input type="text" name="email" id="email" />
|
||||
{% else %}
|
||||
<input type="hidden" name="email" value="{{ session['email'] }}" />
|
||||
{% endif %}
|
||||
<label for="subject">Заголовок</label>
|
||||
<input type="text" name="subject" id="subject" />
|
||||
<label for="message">Сообщение</label>
|
||||
<textarea name="message" id="message" rows="7"></textarea>
|
||||
<input type="submit" class="button success large" value="Отправить сообщение" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,21 +0,0 @@
|
|||
{% extends "gocloud2016/layouts/default.html" %}
|
||||
|
||||
{% block title %}Поддержка онлайн виртуального сервера - GoCloud{% endblock %}
|
||||
|
||||
{% block description %}Наши технические специалисты ответят на ваши вопросы{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="large-12 columns">
|
||||
<h2>Поддержка</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="large-12 columns">
|
||||
<h3>Спасибо!</h3>
|
||||
</div>
|
||||
<div class="large-12 columns">
|
||||
<p>Спасибо за обращение в техническую поддержку. Мы ответим вам в кратчайшее время.</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -114,15 +114,14 @@ def registration():
|
|||
user_id = ControllerUsers().get_id_by_email(email)
|
||||
|
||||
ControllerUsersDetails(user_id).details_create()
|
||||
ControllerBilling().create(user_id, g.settings.get('bonus', 0))
|
||||
ControllerBilling().create(user_id, g.settings['bonus'])
|
||||
ControllerAPI().set(user_id=user_id, secret=user_id, acl='', status=0)
|
||||
# ControllerU
|
||||
# send mail message with recovery code
|
||||
|
||||
message = u"""
|
||||
Е-почта: %s
|
||||
Пароль: %s
|
||||
""" % (request.form.get('email'), request.form.get('password'))
|
||||
""" % (request.form['email'], request.form['password'])
|
||||
subject = u'GoCloud.ru: Успешная регистрация'
|
||||
lead = u"""
|
||||
Поздравляем с успешной регистрацией.
|
||||
|
@ -131,12 +130,10 @@ def registration():
|
|||
Для входа в личный кабинет воспользуйтесь
|
||||
<a href="https://gocloud.ru/account/login">страницей авторизации</a>.
|
||||
"""
|
||||
try:
|
||||
email = ControllerMessagesEmail()
|
||||
email.send(title=subject, to=request.form['email'], lead=lead, message=message, callout=callout)
|
||||
except Exception as e:
|
||||
# TODO: write message
|
||||
pass
|
||||
|
||||
email = ControllerMessagesEmail()
|
||||
email.send(title=subject, to=request.form['email'], lead=lead, message=message, callout=callout)
|
||||
|
||||
# redirect to login page
|
||||
flash(u'Учетная запись успешно зарегистрирована.', 'success')
|
||||
return redirect(url_for('account.login'))
|
||||
|
|
|
@ -1,38 +1,42 @@
|
|||
# coding: utf-8
|
||||
|
||||
import validators
|
||||
from flask import Blueprint, g, redirect, render_template, request, url_for, flash
|
||||
from SWSCloudCore.controllers.common import ControllerMessagesEmail
|
||||
from flask import Blueprint
|
||||
from flask import g
|
||||
from flask import redirect
|
||||
from flask import render_template
|
||||
from flask import request
|
||||
from flask import url_for
|
||||
|
||||
viewSupport = Blueprint('support', __name__, url_prefix='/support')
|
||||
|
||||
|
||||
@viewSupport.route('/', methods=['GET'])
|
||||
@viewSupport.route('/', methods=['GET', 'POST'])
|
||||
def index():
|
||||
return render_template('gocloud2016/pages/support/index.html')
|
||||
# ControllerMessagesEmail().send()
|
||||
# print session
|
||||
|
||||
if request.method == "POST":
|
||||
print request.form
|
||||
# TODO: validate
|
||||
ticket_title = request.form['title']
|
||||
ticket_message = request.form['message']
|
||||
ticket_email = request.form['email']
|
||||
|
||||
# send mail message with recovery code
|
||||
subject = ticket_title
|
||||
message = ticket_message
|
||||
lead = u'Отправитель: %s' % ticket_email
|
||||
callout = u''
|
||||
|
||||
email = ControllerMessagesEmail()
|
||||
# email.send(title=subject, to=ticket_email, lead=lead, message=message, callout=callout)
|
||||
email.send(title=subject, to=g.settings['contacts.email'], lead=lead, message=message, callout=callout)
|
||||
|
||||
return redirect(url_for('support.thank'))
|
||||
return render_template('default/support/index.html')
|
||||
|
||||
|
||||
@viewSupport.route('/', methods=['POST'])
|
||||
def index_post():
|
||||
ticket_subject = request.form.get('subject')
|
||||
ticket_message = request.form.get('message')
|
||||
ticket_email = request.form.get('email')
|
||||
|
||||
if not validators.email(ticket_email):
|
||||
flash('Некорректный адрес электронной почты', category='error')
|
||||
return redirect(url_for('support.index'))
|
||||
|
||||
# send mail message with recovery code
|
||||
lead = u'Отправитель: %s' % ticket_email
|
||||
callout = u''
|
||||
|
||||
email = ControllerMessagesEmail()
|
||||
# email.send(title=subject, to=ticket_email, lead=lead, message=message, callout=callout)
|
||||
email.send(
|
||||
title=ticket_subject, to=g.settings.get('contacts.email'), lead=lead, message=ticket_message, callout=callout)
|
||||
return redirect(url_for('support.thank'))
|
||||
|
||||
|
||||
@viewSupport.route('/thank.html')
|
||||
@viewSupport.route('/thank')
|
||||
def thank():
|
||||
return render_template('gocloud2016/pages/support/thanks.html')
|
||||
return render_template('default/support/thank.html')
|
||||
|
|
|
@ -23,7 +23,7 @@ def view(document_name):
|
|||
if not os.path.exists('docs/%s.md' % document_name):
|
||||
return redirect(url_for('homepage.index'))
|
||||
#
|
||||
print(document_name)
|
||||
print document_name
|
||||
doc_markdown = u''
|
||||
for ss in file('docs/%s.md' % document_name, 'r'):
|
||||
doc_markdown += ss.decode('UTF-8')
|
||||
|
|
|
@ -2,13 +2,8 @@ import requests
|
|||
|
||||
|
||||
class SWSStatisticsClient(object):
|
||||
def get_vm(self, vm_id: str, limit: int = 96):
|
||||
r = requests.get(
|
||||
f"http://server-stats.gocloud.ru/stats/v1/compute/vms/{vm_id}",
|
||||
params={
|
||||
'limit': limit
|
||||
}
|
||||
)
|
||||
def get_vm(self, vm_id, limit=96):
|
||||
r = requests.get('http://server-stats.gocloud.ru/stats/v1/compute/vms/%s' % vm_id, params={'limit': limit})
|
||||
if r.status_code == 200:
|
||||
return r.json()
|
||||
return None
|
||||
|
|
5
cloud-admin-add.py
Executable file → Normal file
5
cloud-admin-add.py
Executable file → Normal file
|
@ -1,7 +1,6 @@
|
|||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
import validators
|
||||
from hashlib import md5
|
||||
|
@ -26,13 +25,13 @@ if not validators.email(args.email):
|
|||
|
||||
admin_id = uuid4()
|
||||
admin_email = args.email
|
||||
admin_password = md5(args.password.encode()).hexdigest()
|
||||
admin_password = md5(args.password).hexdigest()
|
||||
|
||||
models.database.connect()
|
||||
|
||||
if models.Admins.select().where(models.Admins.email == args.email).count() == 0:
|
||||
models.Admins.create(id=admin_id, email=admin_email, password=admin_password, status=1)
|
||||
else:
|
||||
print("already exists")
|
||||
print "already exists"
|
||||
|
||||
models.database.close()
|
||||
|
|
12
cloud-admin-ls.py
Executable file → Normal file
12
cloud-admin-ls.py
Executable file → Normal file
|
@ -9,13 +9,13 @@ __author__ = 'vanzhiganov'
|
|||
admins_total = models.Admins.select().count()
|
||||
admins_items = models.Admins.select()
|
||||
|
||||
print("Total admins: %i" % admins_total)
|
||||
print "Total admins: %i" % admins_total
|
||||
|
||||
if admins_total == 0:
|
||||
print('')
|
||||
print ''
|
||||
else:
|
||||
print('List:')
|
||||
print 'List:'
|
||||
for item in admins_items:
|
||||
print('%s\t%s\t%s' % (item.id, item.email, item.status))
|
||||
print('---')
|
||||
print('For create a new admin account use command "procdn-admin-add --email <email> --password <password>"')
|
||||
print '%s\t%s\t%s' % (item.id, item.email, item.status)
|
||||
print '---'
|
||||
print 'For create a new admin account use command "procdn-admin-add --email <email> --password <password>"'
|
||||
|
|
10
cloud-admin-password.py
Executable file → Normal file
10
cloud-admin-password.py
Executable file → Normal file
|
@ -18,13 +18,13 @@ args = parser.parse_args()
|
|||
admin_id = uuid4()
|
||||
# todo: validate admin email
|
||||
admin_email = args.email
|
||||
admin_password = md5(args.password.encode()).hexdigest()
|
||||
admin_password = md5(args.password).hexdigest()
|
||||
|
||||
if models.Admins.select().where(models.Admins.email == args.email).count() == 0:
|
||||
print("Admin account with email '%s' not exists." % admin_email)
|
||||
print('---')
|
||||
print('For create a new admin account use command "procdn-admin-add --email <email> --password <password>"')
|
||||
print "Admin account with email '%s' not exists." % admin_email
|
||||
print '---'
|
||||
print 'For create a new admin account use command "procdn-admin-add --email <email> --password <password>"'
|
||||
else:
|
||||
query = models.Admins.update(password=admin_password).where(models.Admins.email == admin_email)
|
||||
query.execute()
|
||||
print('Password updated.')
|
||||
print 'Password updated.'
|
||||
|
|
10
cloud-cron-balance.py
Executable file → Normal file
10
cloud-cron-balance.py
Executable file → Normal file
|
@ -8,13 +8,13 @@ from SWSCloudCore.controllers.vms import ControllerVMS
|
|||
nb = models.Settings.get_item('NEGATIVE_BALANCE')
|
||||
|
||||
if int(models.Settings.get_item('SERVICE_VMS_ENABLE')) == 1:
|
||||
print('total vms:', models.Vms.select().where(models.Vms.status == 1).count())
|
||||
print 'total vms:', models.Vms.select().where(models.Vms.status == 1).count()
|
||||
|
||||
for vm in models.Vms.select().where(models.Vms.status == 1):
|
||||
# Высчитываем, сколько стоит виртуальная машина 15 минут
|
||||
price_quarter = vm.plan.price / 30 / 24 / 4
|
||||
|
||||
print(dict(id=vm.id, user=vm.user.id, plan=vm.plan.id, cost_mo=vm.plan.price, cost_quarter=price_quarter))
|
||||
print dict(id=vm.id, user=vm.user.id, plan=vm.plan.id, cost_mo=vm.plan.price, cost_quarter=price_quarter)
|
||||
|
||||
# Списание средств
|
||||
x = models.UsersBalance.update(
|
||||
|
@ -26,14 +26,14 @@ if int(models.Settings.get_item('SERVICE_VMS_ENABLE')) == 1:
|
|||
user_balance = models.UsersBalance.select(
|
||||
models.UsersBalance.balance).where(models.UsersBalance.user == vm.user.id).get().balance
|
||||
if -500 > user_balance and models.Vms.get_state(vm.id) == 1:
|
||||
print("user_balance", user_balance)
|
||||
print "user_balance", user_balance
|
||||
ControllerVMS(vm.user.id).status_set(vm.id, 3)
|
||||
# Создание задания
|
||||
ControllerTasks(vm.user.id).create(vm.datacenter.id, vm.server.id, 'vm_stop', 0, vm_id=vm.id)
|
||||
|
||||
|
||||
if int(models.Settings.get_item('SERVICE_CONTAINERS_ENABLE')) == 1:
|
||||
print('total containers:', models.Containers.select().count())
|
||||
print 'total containers:', models.Containers.select().count()
|
||||
for container in models.Containers.select():
|
||||
container_state = models.ContainersStatisticsState.select().where(
|
||||
models.ContainersStatisticsState.container == container.id
|
||||
|
@ -43,7 +43,7 @@ if int(models.Settings.get_item('SERVICE_CONTAINERS_ENABLE')) == 1:
|
|||
# # Высчитываем, сколько стоит виртуальная машина 15 минут
|
||||
price_quarter = min_price / 30 / 24 / 4
|
||||
#
|
||||
# print(dict(id=vm.id, user=vm.user.id, plan=vm.plan.id, cost_mo=vm.plan.price, cost_quarter=price_quarter))
|
||||
# print dict(id=vm.id, user=vm.user.id, plan=vm.plan.id, cost_mo=vm.plan.price, cost_quarter=price_quarter)
|
||||
#
|
||||
# Списание средств
|
||||
x = models.UsersBalance.update(
|
||||
|
|
0
cloud-db-init.py
Executable file → Normal file
0
cloud-db-init.py
Executable file → Normal file
2
cloud-dc-add.py
Executable file → Normal file
2
cloud-dc-add.py
Executable file → Normal file
|
@ -28,4 +28,4 @@ if models.DataCenters.select().where(
|
|||
status=1
|
||||
)
|
||||
else:
|
||||
print("Data center with code '%s' already exists." % args.code)
|
||||
print "Data center with code '%s' already exists." % args.code
|
||||
|
|
12
cloud-dc-ls.py
Executable file → Normal file
12
cloud-dc-ls.py
Executable file → Normal file
|
@ -25,13 +25,13 @@ x = models.Ips.select().join(models.Servers).where(
|
|||
).first()
|
||||
|
||||
|
||||
print('total: %s' % total)
|
||||
print('items: ')
|
||||
print 'total: %s' % total
|
||||
print 'items: '
|
||||
|
||||
for item in items:
|
||||
print('id: %s code: %s name: %s country: %s, city: %s, status: %s' % (
|
||||
print 'id: %s code: %s name: %s country: %s, city: %s, status: %s' % (
|
||||
item.id, item.code, item.name, item.country, item.city, item.status
|
||||
))
|
||||
)
|
||||
|
||||
print('---')
|
||||
print('if you want to add a new data center, use cli-dc-add.py --')
|
||||
print '---'
|
||||
print 'if you want to add a new data center, use cli-dc-add.py --'
|
||||
|
|
2
cloud-invoicer.py
Executable file → Normal file
2
cloud-invoicer.py
Executable file → Normal file
|
@ -169,7 +169,7 @@ html = u"""
|
|||
</html>
|
||||
"""
|
||||
|
||||
print(type(html))
|
||||
print type(html)
|
||||
pdf = MyFPDF()
|
||||
# First page
|
||||
pdf.add_page()
|
||||
|
|
0
cloud-invoicer2.py
Executable file → Normal file
0
cloud-invoicer2.py
Executable file → Normal file
4
cloud-ip-add.py
Executable file → Normal file
4
cloud-ip-add.py
Executable file → Normal file
|
@ -3,7 +3,7 @@
|
|||
import argparse
|
||||
|
||||
from SWSCloudCore import models
|
||||
from SWSCloudCore.controllers.ips.manage import ControllerManageIPs
|
||||
from SWSCloudCore.controllers import ControllerManageIPs
|
||||
|
||||
parser = argparse.ArgumentParser(description='')
|
||||
parser.add_argument('--dc', dest="datacenter")
|
||||
|
@ -30,5 +30,5 @@ if success:
|
|||
args.datacenter, args.server, args.ipv4, args.ipv4_gateway, args.ipv6, args.ipv6_gateway, args.status
|
||||
)
|
||||
else:
|
||||
print('fail')
|
||||
print 'fail'
|
||||
# print "Admin account with email '%s' already exists." % args
|
||||
|
|
0
cloud-runserver-admin.py
Executable file → Normal file
0
cloud-runserver-admin.py
Executable file → Normal file
1
cloud-runserver.py
Executable file → Normal file
1
cloud-runserver.py
Executable file → Normal file
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
from SWSCloudWeb import app
|
||||
|
||||
|
|
4
cloud-server-add.py
Executable file → Normal file
4
cloud-server-add.py
Executable file → Normal file
|
@ -2,7 +2,7 @@
|
|||
|
||||
import argparse
|
||||
from uuid import uuid4
|
||||
from SWSCloudCore.controllers.servers.manage import ControllerManageServer
|
||||
from SWSCloudCore.controllers import ControllerManageServer
|
||||
|
||||
parser = argparse.ArgumentParser(description='')
|
||||
parser.add_argument('--dc', dest="datacenter")
|
||||
|
@ -21,5 +21,5 @@ if not ControllerManageServer().check_exists(args.ip, None, args.hostname):
|
|||
args.ip, None, args.status
|
||||
)
|
||||
else:
|
||||
print('fail')
|
||||
print 'fail'
|
||||
# print "Admin account with email '%s' already exists." % args
|
||||
|
|
8
cloud-server-ls.py
Executable file → Normal file
8
cloud-server-ls.py
Executable file → Normal file
|
@ -16,10 +16,10 @@ items = models.Servers.select().where(
|
|||
models.Servers.status == args.status
|
||||
)
|
||||
|
||||
print('total: %s' % total)
|
||||
print('items: ')
|
||||
print 'total: %s' % total
|
||||
print 'items: '
|
||||
|
||||
for item in items:
|
||||
print('id: %s dc: %s status: %s ip: %s hostname: %s' % (
|
||||
print 'id: %s dc: %s status: %s ip: %s hostname: %s' % (
|
||||
item.id, item.datacenter.id, item.status, item.ip, item.hostname
|
||||
))
|
||||
)
|
||||
|
|
2
cloud-settings-init.py
Executable file → Normal file
2
cloud-settings-init.py
Executable file → Normal file
|
@ -7,7 +7,7 @@ def create_key(key, val=''):
|
|||
if models.Settings.select().where(models.Settings.key == key).count() == 0:
|
||||
models.Settings.create(key=key, val=val)
|
||||
else:
|
||||
print('key %s already exists' % key)
|
||||
print 'key %s already exists' % key
|
||||
|
||||
|
||||
create_key('bonus', '300')
|
||||
|
|
0
cloud-settings.py
Executable file → Normal file
0
cloud-settings.py
Executable file → Normal file
|
@ -1,9 +1,9 @@
|
|||
[Database]
|
||||
host = localhost
|
||||
user = cherry
|
||||
password = P@ss5476
|
||||
user = postgres
|
||||
password = postgres
|
||||
port = 5432
|
||||
name = testdb
|
||||
name = gocloud
|
||||
|
||||
[Application]
|
||||
DEBUG = true
|
||||
|
|
|
@ -1,23 +1,19 @@
|
|||
[uwsgi]
|
||||
|
||||
env = HOME=/opt/nativecloud/.venv
|
||||
env = CONFIG=/opt/nativecloud/extra/settings.origin.ini
|
||||
|
||||
chdir = /opt/nativecloud
|
||||
virtualenv = /home/gocloud/env
|
||||
|
||||
;for http
|
||||
protocol = http
|
||||
socket = 0.0.0.0:8080
|
||||
;protocol = http
|
||||
;socket = 127.0.0.1:8080
|
||||
|
||||
; for unix-socket
|
||||
; socket = /var/run/nativecloud-web.sock
|
||||
; chmod-socket = 777
|
||||
socket = /var/run/sws/gocloud_web.sock
|
||||
chmod-socket = 777
|
||||
|
||||
module = SWSCloudWeb:app
|
||||
|
||||
master = true
|
||||
processes = 2
|
||||
vacuum = true
|
||||
die-on-term = true
|
||||
|
||||
thunder-lock = true
|
||||
enable-threads = true
|
||||
vacuum = true
|
||||
|
||||
die-on-term = true
|
||||
|
|
13
kb/README.md
Normal file
13
kb/README.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
# База знаний
|
||||
|
||||
## Обзие вопросы
|
||||
|
||||
- Как создать контейнер
|
||||
- Как оплатить
|
||||
-
|
||||
|
||||
## API
|
||||
|
||||
- Описание
|
||||
- Запросы
|
||||
- Коды ошибок
|
57
letter.pdf
Normal file
57
letter.pdf
Normal file
|
@ -0,0 +1,57 @@
|
|||
%PDF-1.4
|
||||
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
|
||||
1 0 obj
|
||||
<< /F1 2 0 R /F2 3 0 R /F3 4 0 R >>
|
||||
endobj
|
||||
2 0 obj
|
||||
<< /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >>
|
||||
endobj
|
||||
3 0 obj
|
||||
<< /BaseFont /ZapfDingbats /Encoding /ZapfDingbatsEncoding /Name /F2 /Subtype /Type1 /Type /Font >>
|
||||
endobj
|
||||
4 0 obj
|
||||
<< /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font >>
|
||||
endobj
|
||||
5 0 obj
|
||||
<< /Contents 9 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >>
|
||||
/Type /Page >>
|
||||
endobj
|
||||
6 0 obj
|
||||
<< /Outlines 10 0 R /PageMode /UseNone /Pages 8 0 R /Type /Catalog >>
|
||||
endobj
|
||||
7 0 obj
|
||||
<< /Author (anonymous) /CreationDate (D:20161016043545-03'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20161016043545-03'00') /Producer (ReportLab PDF Library - www.reportlab.com)
|
||||
/Subject (unspecified) /Title (untitled) /Trapped /False >>
|
||||
endobj
|
||||
8 0 obj
|
||||
<< /Count 1 /Kids [ 5 0 R ] /Type /Pages >>
|
||||
endobj
|
||||
9 0 obj
|
||||
<< /Filter [ /ASCII85Decode /FlateDecode ] /Length 735 >>
|
||||
stream
|
||||
GasJPgN)"%&;KYAnN1Qb2mh$p3r4rMVN;4S9M8:0o\'IG#dN4>AdE<^Be<hY@c;s8q=i@@FtJURd5T$fOTF5_E-4g)1.YG2KeFQoJ8+#&rd#f(=\4%YGebF-,<qiQl'Vh@an4dMP`TG>kQ+u/`Zr=3r2g^b-k.lUmI^LCk74u@CK)JQ#\18LWr5OS(-LdAS.D-;?`\=9'WQ4E)2H=GYuQ&Q:IVk]/;C:l,6%eP0-JM^Zo*hl9jJh13EmLqHkqBD>Fd\H2g+u@9V&>(\Lr(ZQ1*g4Q1/*N?/uhi?OS@-82hCT,T;,0dWmd#HA`%oY>R#_4KDHdZUmAdH%(AsJ1C4KcP[FDkE/;>k(8W,b"d_+GdLB1<BW$RY%:1"40!+_$"V>@5R;R"gGohPUPnc7,oXVAuZmRX:!mDlIV+%o0q+r6%6G_c\l:h4ZQ0a*n,/G=3b/IIli@D4@7"^rsL,8!"o'B7*N6I_.<76^h:?OIIk_oRsp`I=[aXl(P.[]4MPhpSe,6WhKr^h$#^6Q'EJ(Cf#9[g^o.O'pVP1<l/9g\KR2>FGms]h6\mnF++Nc#`c[5M^T0T1R[^UYMBR$o3nG#;>SA&Z)_+*ZRTi=A]Th,)r\&#?IWGdY82-R'\?<!NN$c<6bWHVXIL#)60S&<+<jAYeJb)DkoSHQqsV@:.N>%O@5Fq@s],dSsSJJS`X-9'K]D3V<LYJ[Au3rWiC:C+3rf(rW.VMNog~>endstream
|
||||
endobj
|
||||
10 0 obj
|
||||
<< /Count 0 /Type /Outlines >>
|
||||
endobj
|
||||
xref
|
||||
0 11
|
||||
0000000000 65535 f
|
||||
0000000075 00000 n
|
||||
0000000129 00000 n
|
||||
0000000239 00000 n
|
||||
0000000357 00000 n
|
||||
0000000472 00000 n
|
||||
0000000669 00000 n
|
||||
0000000757 00000 n
|
||||
0000001057 00000 n
|
||||
0000001119 00000 n
|
||||
0000001949 00000 n
|
||||
trailer
|
||||
<< /ID
|
||||
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
|
||||
[(F\377\262C\004ZI\203\233\321\244^\250\251\025\300) (F\377\262C\004ZI\203\233\321\244^\250\251\025\300)]
|
||||
/Info 7 0 R /Root 6 0 R /Size 11 >>
|
||||
startxref
|
||||
1999
|
||||
%%EOF
|
|
@ -1,38 +0,0 @@
|
|||
async-timeout==5.0.1
|
||||
babel==2.16.0
|
||||
certifi==2024.8.30
|
||||
charset-normalizer==3.4.0
|
||||
click==8.1.7
|
||||
configparser==7.1.0
|
||||
dateutils==0.6.12
|
||||
decorator==5.1.1
|
||||
ecdsa==0.19.0
|
||||
Flask==0.12.5
|
||||
Flask-Babel==0.9
|
||||
Flask-HTTPAuth==3.1.1
|
||||
Flask-Markdown==0.3
|
||||
flask-multistatic==1.0
|
||||
flask-peewee==0.6.0
|
||||
idna==3.10
|
||||
importlib_metadata==8.5.0
|
||||
itsdangerous==2.0.1
|
||||
Jinja2==2.8
|
||||
Markdown==3.7
|
||||
MarkupSafe==2.0.1
|
||||
peewee==2.8.0
|
||||
psycopg2-binary==2.9.10
|
||||
pycrypto==2.6.1
|
||||
python-dateutil==2.9.0.post0
|
||||
pytz==2024.2
|
||||
pyuwsgi==2.0.28.post1
|
||||
redis==5.2.1
|
||||
requests==2.32.3
|
||||
six==1.17.0
|
||||
speaklater==1.3
|
||||
sshpubkeys==1.0.6
|
||||
urllib3==2.2.3
|
||||
validators==0.10
|
||||
Werkzeug==0.16.1
|
||||
wtf-peewee==0.2.6
|
||||
WTForms==3.2.1
|
||||
zipp==3.21.0
|
30
setup.py
30
setup.py
|
@ -1,12 +1,10 @@
|
|||
import os
|
||||
from setuptools import setup
|
||||
# coding: utf-8
|
||||
|
||||
with open('requirements.txt') as f:
|
||||
required = f.read().splitlines()
|
||||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name='SWSCloudCore',
|
||||
version='2.7.10',
|
||||
version='2.7.9',
|
||||
author='Vyacheslav Anzhiganov',
|
||||
author_email='hello@anzhiganov.com',
|
||||
packages=[
|
||||
|
@ -81,6 +79,7 @@ setup(
|
|||
'templates/default/documents/*.html',
|
||||
'templates/default/homepage/*.html',
|
||||
'templates/default/id/*.html',
|
||||
'templates/default/kb/*.html',
|
||||
'templates/default/payment/*.html',
|
||||
'templates/default/payment/robokassa/*.html',
|
||||
'templates/default/support/*.html',
|
||||
|
@ -91,7 +90,6 @@ setup(
|
|||
'templates/gocloud2016/layouts/*.html',
|
||||
'templates/gocloud2016/macros/*.html',
|
||||
'templates/gocloud2016/pages/*.html',
|
||||
'templates/gocloud2016/pages/*/*.html',
|
||||
# Errors
|
||||
'templates/errors/*.html',
|
||||
],
|
||||
|
@ -120,6 +118,7 @@ setup(
|
|||
'templates/administrator/settings/messages/*.html',
|
||||
'templates/administrator/tasks/*.html',
|
||||
'templates/administrator/users/*.html',
|
||||
# 'templates/administrator/payments/*.html',
|
||||
'templates/administrator/wiki/*.html',
|
||||
'templates/administrator/wiki/article/*.html',
|
||||
'templates/administrator/wiki/category/*.html',
|
||||
|
@ -147,5 +146,22 @@ setup(
|
|||
# billing
|
||||
'cloud-cron-balance.py',
|
||||
],
|
||||
install_requires=required
|
||||
install_requires=[
|
||||
'Flask==0.10',
|
||||
'Flask-Markdown==0.3',
|
||||
'Flask-Babel==0.9',
|
||||
'flask-peewee==0.6.0',
|
||||
'flask-multistatic',
|
||||
'Jinja2==2.8',
|
||||
'peewee==2.8',
|
||||
'validators==0.10',
|
||||
'psycopg2==2.6.1',
|
||||
'configparser',
|
||||
'flask_httpauth==3.1.1',
|
||||
'requests==2.7',
|
||||
'uWSGI==2.0.11.1',
|
||||
'wsgiref==0.1.2',
|
||||
'sshpubkeys==1.0.6',
|
||||
'dateutils',
|
||||
]
|
||||
)
|
||||
|
|
BIN
tutorial.pdf
Normal file
BIN
tutorial.pdf
Normal file
Binary file not shown.
Loading…
Add table
Reference in a new issue