Commit 77f3a1f1 authored by wangyong's avatar wangyong

add asset add

parent d0d433db
......@@ -10,6 +10,9 @@ build
_mailinglist
.tox
.cache/
migrations/
.idea/
db.sqlite3
config.py
*/migrations/*
*.log
## [文档和规范]
// Jumpserver //
~ Jumpserver是什么?
Jumpserver是一款开源的跳板机(堡垒机)产品, 主要使用Python,Django开发
他实现了跳板机(堡垒机)的主要功能,删减、优化了传统堡垒机,致力于为互联网
运维提供服务
~ 版本依赖
* Python 2.7
* Django 1.10
~ 快速开始
```
pip install -r requirements.txt
cp config-example.py config.py
cd apps/ && python manage.py loaddata init # 初始化数据
python manage.py runserver 0.0.0.0:80
```
~ 文档
#### [项目结构描述](https://code.simcu.com/jumpserver/jumpserver/blob/master/docs/project_structure.md)
#### [Python代码规范](https://code.simcu.com/jumpserver/jumpserver/blob/master/docs/python_style_guide.md)
#### [API设计规范](https://code.simcu.com/jumpserver/jumpserver/blob/master/docs/api_style_guide.md)
#### [表结构](https://code.simcu.com/jumpserver/jumpserver/wikis/table_structure_image)
* [项目结构描述](https://code.simcu.com/jumpserver/jumpserver/blob/master/docs/project_structure.md)
* [Python代码规范](https://code.simcu.com/jumpserver/jumpserver/blob/master/docs/python_style_guide.md)
* [API设计规范](https://code.simcu.com/jumpserver/jumpserver/blob/master/docs/api_style_guide.md)
* [表结构](https://code.simcu.com/jumpserver/jumpserver/wikis/table_structure_image)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
if __name__ == '__main__':
pass
# ~*~ coding: utf-8 ~*~
#
from rest_framework import serializers
from .models import (
AssetGroup,Asset,IDC,AssetExtend
)
from rest_framework import viewsets,serializers
class AssetGroupSerializer(serializers.ModelSerializer):
class Meta:
model = AssetGroup
#exclude = [
#'password', 'first_name', 'last_name', 'secret_key_otp',
#'private_key', 'public_key', 'avatar',
#]
class AssetSerializer(serializers.ModelSerializer):
class Meta:
model = Asset
#fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
class IDCSerializer(serializers.ModelSerializer):
class Meta:
model = IDC
#fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
class AssetGroupViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows AssetGroup to be viewed or edited.
"""
queryset = AssetGroup.objects.all()
serializer_class = AssetGroupSerializer
class AssetViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows Asset to be viewed or edited.
"""
queryset = Asset.objects.all()
serializer_class = AssetSerializer
class IDCViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows IDC to be viewed or edited.
"""
queryset = IDC.objects.all()
serializer_class = IDCSerializer
\ No newline at end of file
......@@ -6,7 +6,7 @@
<div class="col-sm-10">
<div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title">
<h5> 填写资产基本信息 </h5>
<h5> 添加资产 </h5>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
......@@ -22,12 +22,12 @@
<div class="ibox-content">
<div class="panel blank-panel">
<div class="panel-options">
<ul class="nav nav-tabs">
<li class="active"><a href="{% url 'assets:asset-add' %}" class="text-center"><i class="fa fa-laptop"></i> 单台添加 </a></li>
{# <div class="panel-options">#}
{# <ul class="nav nav-tabs">#}
{# <li class="active"><a href="{% url 'assets:asset-add' %}" class="text-center"><i class="fa fa-laptop"></i> 单台添加 </a></li>#}
{# <li><a href="{% url 'asset_add_batch' %}" class="text-center"><i class="fa fa-bar-chart-o"></i> 批量添加 </a></li>#}
</ul>
</div>
{# </ul>#}
{# </div>#}
<div class="panel-body">
<div class="tab-content">
<div id="tab-1" class="ibox float-e-margins tab-pane active">
......@@ -40,6 +40,7 @@
<form id="assetForm" method="post" class="form-horizontal">
{% csrf_token %}
<h3 class="widget-head-color-box">基本信息</h3>
{{ form.hostname|bootstrap_horizontal }}
......@@ -79,12 +80,38 @@
</div>
</div>
<div class="hr-line-dashed"></div>
{{ form.group|bootstrap_horizontal }}
{# <div class="hr-line-dashed"></div>#}
{# {{ form.group|bootstrap_horizontal }}#}
{# {{ af.is_active|bootstrap_horizontal }}#}
<div class="hr-line-dashed"></div>
{{ form.comment|bootstrap_horizontal }}
<div class="hr-line-dashed"></div>
<h3>关联资产用户</h3>
<div class="form-group">
<label for="j_group" class="col-sm-2 control-label">管理用户<span class="red-fonts"> *</span></label>
<div class="col-sm-8">
<div class="radio i-checks">
<label><input type="radio" checked="checked" id="id_use_default_auth" name="use_default_auth"><span>使用预定义管理用户</span></label>
<label><input type="radio" checked="checked" id="id_use_default_auth" name="use_default_auth"><span>自定义</span></label>
</div>
</div>
</div>
<p class="col-sm-offset-2">Tips: 管理用户是服务器存在的root或拥有sudo的用户,用来推送系统用户</p>
<div class="form-group" id="admin_account" style="display: none">
<label class="col-sm-2 control-label"> <span class="red-fonts"></span> </label>
<div class="col-sm-3">
<input type="text" placeholder="Username" name="username" class="form-control">
</div>
<label class="col-sm-1 control-label"> <span class="red-fonts"></span> </label>
<div class="col-sm-4">
<input type="password" placeholder="Password" name="password" class="form-control">
</div>
</div>
<div class="form-group"><label class="col-sm-2 control-label"> 是否激活<span class="red-fonts"> *</span> </label>
<div class="col-sm-8">
<div class="radio i-checks">
......
# coding:utf-8
from django.conf.urls import url
from django.conf.urls import url,include
from .views import *
from .api import (
AssetGroupViewSet,AssetViewSet,IDCViewSet
)
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r'assetgroup', AssetGroupViewSet)
router.register(r'asset', AssetViewSet)
router.register(r'idc', IDCViewSet)
app_name = 'assets'
urlpatterns = [
......@@ -9,4 +16,5 @@ urlpatterns = [
url(r'^$', AssetListView.as_view(), name='asset-list'),
url(r'^(?P<pk>[0-9]+)/delete/$', AssetDeleteView.as_view(), name='asset-list'),
url(r'^(?P<pk>[0-9]+)/detail/$', AssetDetailView.as_view(), name='asset-detail'),
url(r'^api/v1.0/', include(router.urls)),
]
## Celery usage
Jumpserver use celery to run task async. Using redis as the broker, so
you should run a redis instance
#### Run redis
$ yum -y install redis
or
$ docker run -name jumpserver-redis -d -p 6379:6379 redis redis-server
#### Write tasks in app_name/tasks.py
ops/tasks.py
```
from __future__ import absolute_import
import time
from celery import shared_task
from common import celery_app
@shared_task
def longtime_add(x, y):
print 'long time task begins'
# sleep 5 seconds
time.sleep(5)
print 'long time task finished'
return x + y
@celery_app.task(name='hello-world')
def hello():
print 'hello world!'
```
#### Run celery in development
```
$ cd apps
$ celery -A common worker -l info
```
#### Test using task
```
$ ./manage.py shell
>>> from ops.tasks import longtime_add
>>> res = longtime_add.delay(1, 2)
>>> res.get()
```
from __future__ import absolute_import
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app
from __future__ import unicode_literals
from django.apps import AppConfig
class CommonConfig(AppConfig):
name = 'common'
# ~*~ coding: utf-8 ~*~
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'jumpserver.settings')
from django.conf import settings
app = Celery('jumpserver')
# Using a string here means the worker will not have to
# pickle the object when using Windows.
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: [app_config.split('.')[0] for app_config in settings.INSTALLED_APPS])
from __future__ import unicode_literals
from django.db import models
# Create your models here.
from __future__ import absolute_import
from celery import shared_task
from django.core.mail import send_mail
from django.conf import settings
@shared_task(name='send_mail_async')
def send_mail_async(*args, **kwargs):
""" Using celery to send email async
You can use it as django send_mail function
Example:
send_mail_sync.delay(subject, message, from_mail, recipient_list, fail_silently=False, html_message=None)
Also you can ignore the from_mail, unlike django send_mail, from_email is not a require args:
Example:
send_mail_sync.delay(subject, message, recipient_list, fail_silently=False, html_message=None)
"""
if len(args) == 3:
args = list(args)
args[0] = settings.EMAIL_SUBJECT_PREFIX + args[0]
args.insert(2, settings.EMAIL_HOST_USER)
args = tuple(args)
send_mail(*args, **kwargs)
# def send_mail_async(subject, message, from_mail, recipient_list, fail_silently=False, html_message=None):
# if settings.CONFIG.MAIL_SUBJECT_PREFIX:
# subject += settings.CONFIG.MAIL_SUBJECT_PREFIX
# send_mail(subject, message, from_mail, recipient_list, fail_silently=fail_silently, html_message=html_message)
{% load static %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }}</title>
{% include '_head_css_js.html' %}
<link href="{% static "css/jumpserver.css" %}" rel="stylesheet">
<script src="{% static "js/jumpserver.js" %}"></script>
</head>
<body class="gray-bg">
<div class="passwordBox2 animated fadeInDown">
<div class="row">
<div class="col-md-12">
<div class="ibox-content">
<div>
<img src="{% static 'img/logo.png' %}" style="margin: auto" width="82" height="82">
<h2 style="display: inline">Jumpserver</h2>
</div>
{% if errors %}
<p>
<div class="alert alert-danger">
{{ errors }}
</div>
</p>
{% endif %}
{% if messages %}
<p>
<div class="alert alert-success">
{{ messages }}
</div>
</p>
{% endif %}
<div class="row">
<div class="col-lg-3">
<a href="{{ redirect_url }}" class="btn btn-primary block full-width m-b">返回</a>
</div>
</div>
</div>
</div>
</div>
<hr/>
<div class="row">
<div class="col-md-6">
Copyright Jumpserver.org
</div>
<div class="col-md-6 text-right">
<small>© 2014-2016</small>
</div>
</div>
</div>
</body>
</html>
# ~*~ coding: utf-8 ~*~
from django import template
from django.utils import timezone
from django.conf import settings
register = template.Library()
@register.filter
def join_queryset_attr(queryset, attr, delimiter=', '):
return delimiter.join([getattr(obj, attr, '') for obj in queryset])
@register.filter
def pagination_range(total_page, current_num=1, display=5):
"""Return Page range
:param total_page: Total numbers of paginator
:param current_num: current display page num
:param display: Display as many as [:display:] page
In order to display many page num on web like:
< 1 2 3 4 5 >
"""
try:
current_num = int(current_num)
except ValueError:
current_num = 1
start = current_num - display/2 if current_num > display/2 else 1
end = start + display if start + display <= total_page else total_page + 1
return range(start, end)
# -*- coding: utf-8 -*-
#
from __future__ import unicode_literals
from django.shortcuts import reverse as dj_reverse
from django.conf import settings
def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None, external=False):
url = dj_reverse(viewname, urlconf=urlconf, args=args, kwargs=kwargs, current_app=current_app)
if external:
url = settings.SITE_URL.strip('/') + url
return url
def get_object_or_none(model, **kwargs):
try:
obj = model.objects.get(**kwargs)
except model.DoesNotExist:
obj = None
return obj
from __future__ import absolute_import, unicode_literals
from django.shortcuts import render
from django.views.generic import TemplateView
This diff is collapsed.
[{"model": "users.role", "pk": 1, "fields": {"name": "Administrator", "date_added": "2016-08-20T17:03:42.631Z", "created_by": "System", "comment": "\u7ba1\u7406\u5458", "permissions": [16, 17, 18, 19, 20, 21, 10, 11, 12, 13, 14, 15, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 1, 2, 3, 4, 5, 6, 7, 8, 9]}}, {"model": "users.role", "pk": 2, "fields": {"name": "User", "date_added": "2016-08-20T17:03:42.671Z", "created_by": "System", "comment": "\u7528\u6237", "permissions": []}}, {"model": "users.role", "pk": 3, "fields": {"name": "Auditor", "date_added": "2016-08-20T17:03:42.683Z", "created_by": "System", "comment": "\u5ba1\u8ba1\u5458", "permissions": []}}, {"model": "users.usergroup", "pk": 1, "fields": {"name": "ALL", "comment": "Default usergroup for all user", "date_added": "2016-08-20T17:03:42.693Z", "created_by": "System"}}, {"model": "users.user", "pk": 1, "fields": {"password": "pbkdf2_sha256$30000$xZUhPadgI8rs$n2rm5futcOv7Ww4b4BflN8K90Vk3u7ozfnOS7GQq0ns=", "last_login": null, "is_superuser": false, "first_name": "", "last_name": "", "is_staff": false, "is_active": true, "date_joined": "2016-08-20T17:03:42.752Z", "username": "admin", "name": "Administrator", "email": "admin@jumpserver.org", "avatar": "", "wechat": "", "phone": "", "enable_otp": false, "secret_key_otp": "", "role": 1, "private_key": "", "public_key": "", "comment": "Administrator is the super user of system", "date_expired": "2086-08-03T17:03:42.753Z", "created_by": "System", "user_permissions": [], "groups": [1]}}][{"model": "users.usergroup", "pk": 1, "fields": {"name": "Default", "comment": "Default user group for all user", "date_added": "2016-08-24T08:24:34.436Z", "created_by": "System"}}, {"model": "users.user", "pk": 1, "fields": {"password": "pbkdf2_sha256$30000$MC3vobX7pa0C$l9qIj4UwHqODnj1hMvVy9DjLxbBumZaioQWIFrWQR7c=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2016-08-24T08:24:34.438Z", "username": "admin", "name": "Administrator", "email": "admin@jumpserver.org", "role": "Admin", "avatar": "", "wechat": "", "phone": "", "enable_otp": false, "secret_key_otp": "", "private_key": "", "public_key": "", "comment": "Administrator is the super user of system", "date_expired": "2086-08-07T08:24:34.438Z", "created_by": "System", "user_permissions": [], "groups": [1]}}]
\ No newline at end of file
[{"model": "users.usergroup", "pk": 1, "fields": {"name": "Default", "comment": "Default user group for all user", "date_added": "2016-08-24T08:24:34.436Z", "created_by": "System"}}, {"model": "users.user", "pk": 1, "fields": {"password": "pbkdf2_sha256$30000$MC3vobX7pa0C$l9qIj4UwHqODnj1hMvVy9DjLxbBumZaioQWIFrWQR7c=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2016-08-24T08:24:34.438Z", "username": "admin", "name": "Administrator", "email": "admin@jumpserver.org", "role": "Admin", "avatar": "", "wechat": "", "phone": "", "enable_otp": false, "secret_key_otp": "", "private_key": "", "public_key": "", "comment": "Administrator is the super user of system", "date_expired": "2086-08-07T08:24:34.438Z", "created_by": "System", "user_permissions": [], "groups": [1]}}]
\ No newline at end of file
This diff is collapsed.
......@@ -11,22 +11,42 @@ https://docs.djangoproject.com/en/1.10/ref/settings/
"""
import os
import sys
from django.urls import reverse_lazy
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
PROJECT_DIR = os.path.dirname(BASE_DIR)
sys.path.append(PROJECT_DIR)
# Import project config setting
try:
from config import config as env_config, env
CONFIG = env_config.get(env, 'default')()
except ImportError:
CONFIG = type('_', (), {'__getattr__': None})()
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '2vym+ky!997d5kkcc64mnz06y1mmui3lut#(^wd=%s_qj$1%xv'
SECRET_KEY = CONFIG.SECRET_KEY or '2vym+ky!997d5kkcc64mnz06y1mmui3lut#(^wd=%s_qj$1%x'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
DEBUG = CONFIG.DEBUG or False
# Absolute url for some case, for example email link
SITE_URL = CONFIG.SITE_URL or 'http://localhost'
ALLOWED_HOSTS = []
# LOG LEVEL
LOG_LEVEL = 'DEBUG' if DEBUG else CONFIG.LOG_LEVEL or 'WARNING'
ALLOWED_HOSTS = CONFIG.ALLOWED_HOSTS or []
# Application definition
......@@ -34,8 +54,12 @@ INSTALLED_APPS = [
'users.apps.UsersConfig',
'assets.apps.AssetsConfig',
'perms.apps.PermsConfig',
'webterminal.apps.WebterminalConfig',
'ops.apps.OpsConfig',
'audits.apps.AuditsConfig',
'common.apps.CommonConfig',
'rest_framework',
'rest_framework.authtoken',
'bootstrapform',
# 'django.contrib.admin',
'django.contrib.auth',
......@@ -43,6 +67,8 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'ws4redis',
]
MIDDLEWARE = [
......@@ -68,24 +94,39 @@ TEMPLATES = [
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'django.template.context_processors.static',
'django.template.context_processors.request',
'ws4redis.context_processors.default',
],
},
},
]
WSGI_APPLICATION = 'jumpserver.wsgi.application'
# WSGI_APPLICATION = 'jumpserver.wsgi.application'
LOGIN_REDIRECT_URL = reverse_lazy('index')
# Database
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
if CONFIG.DB_ENGINE == 'sqlite':
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': CONFIG.DB_NAME or os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
else:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.%s' % CONFIG.DB_ENGINE,
'NAME': CONFIG.DB_NAME,
'HOST': CONFIG.DB_HOST,
'PORT': CONFIG.DB_PORT,
'USER': CONFIG.DB_USER,
'PASSWORD': CONFIG.DB_PASSWORD,
}
}
}
# Password validation
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
......@@ -105,6 +146,69 @@ AUTH_PASSWORD_VALIDATORS = [
},
]
# Logging setting
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
},
'main': {
'datefmt': '%Y-%m-%d %H:%M:%S',
'format': '%(asctime)s [%(module)s %(levelname)s] %(message)s',
},
'simple': {
'format': '%(levelname)s %(message)s'
},
},
'handlers': {
'null': {
'level': 'DEBUG',
'class': 'logging.NullHandler',
},
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'main'
},
'file': {
'level': 'DEBUG',
'class': 'logging.FileHandler',
'formatter': 'main',
'filename': os.path.join(PROJECT_DIR, 'logs', 'jumpserver.log')
},
},
'loggers': {
'django': {
'handlers': ['null'],
'propagate': False,
'level': LOG_LEVEL,
},
'django.request': {
'handlers': ['console', 'file'],
'level': LOG_LEVEL,
'propagate': False,
},
'django.server': {
'handlers': ['console', 'file'],
'level': LOG_LEVEL,
'propagate': False,
},
'jumpserver': {
'handlers': ['console', 'file'],
'level': LOG_LEVEL,
},
'jumpserver.users.api': {
'handlers': ['console', 'file'],
'level': LOG_LEVEL,
},
'jumpserver.users.view': {
'handlers': ['console', 'file'],
'level': LOG_LEVEL,
}
}
}
# Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/
......@@ -119,14 +223,82 @@ USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
AUTH_USER_MODEL = 'users.User'
# Media files (File, ImageField) will be save these
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media').replace('\\', '/') + '/'
# Use django-bootstrap-form to format template, input max width arg
BOOTSTRAP_COLUMN_COUNT = 11
# Init data or generate fake data source for development
FIXTURE_DIRS = [os.path.join(BASE_DIR, 'fixtures'), ]
# Email config
EMAIL_HOST = CONFIG.EMAIL_HOST
EMAIL_PORT = CONFIG.EMAIL_PORT
EMAIL_HOST_USER = CONFIG.EMAIL_HOST_USER
EMAIL_HOST_PASSWORD = CONFIG.EMAIL_HOST_PASSWORD
EMAIL_USE_SSL = CONFIG.EMAIL_USE_SSL
EMAIL_USE_TLS = CONFIG.EMAIL_USE_TLS
EMAIL_SUBJECT_PREFIX = CONFIG.EMAIL_SUBJECT_PREFIX
REST_FRAMEWORK = {
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAdminUser',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
),
}
# This setting is required to override the Django's main loop, when running in
# development mode, such as ./manage runserver
WSGI_APPLICATION = 'ws4redis.django_runserver.application'
# URL that distinguishes websocket connections from normal requests
WEBSOCKET_URL = '/ws/'
# WebSocket Redis
WS4REDIS_CONNECTION = {
'host': CONFIG.REDIS_HOST or '127.0.0.1',
'port': CONFIG.REDIS_PORT or 6379,
'db': 2,
}
# Set the number of seconds each message shall persisted
WS4REDIS_EXPIRE = 3600
WS4REDIS_HEARTBEAT = 'love you'
WS4REDIS_PREFIX = 'demo'
SESSION_ENGINE = 'redis_sessions.session'
SESSION_REDIS_PREFIX = 'session'
# Custom User Auth model
AUTH_USER_MODEL = 'users.User'
# Celery using redis as broker
BROKER_URL = 'redis://%(password)s%(host)s:%(port)s/3' % {
'password': CONFIG.REDIS_PASSWORD + ':' if CONFIG.REDIS_PASSWORD else '',
'host': CONFIG.REDIS_HOST or '127.0.0.1',
'port': CONFIG.REDIS_PORT or 6379,
}
CELERY_RESULT_BACKEND = BROKER_URL
......@@ -14,10 +14,29 @@ Including another URLconf
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url, include
#from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static
from django.views.generic.base import TemplateView
from django.http import HttpResponseRedirect
# def view(request, **kwargs):
# if kwargs:
# print kwargs
# return HttpResponseRedirect('/' + kwargs["module"] + '/' + kwargs["version"] + '/' + kwargs["api"])
urlpatterns = [
url(r'^users/', include('users.urls')),
url(r'^$', TemplateView.as_view(template_name='base.html'), name='index'),
url(r'^(api/)?users/', include('users.urls')),
url(r'^assets/', include('assets.urls')),
# url(r'^admin/', admin.site.urls),
url(r'^terminal/', include('webterminal.urls')),
]
#urlpatterns += [
# url(r'^api/users/', include('users.api_urls')),
#]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
This diff is collapsed.
from .tasks import longtime_add
import time
result = longtime_add.delay(1,2)
print 'Task finished? ', result.ready()
print 'Task result: ', result.result
time.sleep(10)
print 'Task finished? ', result.ready()
print 'Task result: ', result.result
\ No newline at end of file
from __future__ import absolute_import
import time
from celery import shared_task
from common import celery_app
@shared_task
def longtime_add(x, y):
print 'long time task begins'
# sleep 5 seconds
time.sleep(5)
print 'long time task finished'
return x + y
@celery_app.task(name='hello-world')
def hello():
print('hello world!')
/* The MIT License */
.dropzone,
.dropzone *,
.dropzone-previews,
.dropzone-previews * {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.dropzone {
position: relative;
border: 1px solid rgba(0,0,0,0.08);
background: rgba(0,0,0,0.02);
padding: 1em;
}
.dropzone.dz-clickable {
cursor: pointer;
}
.dropzone.dz-clickable .dz-message,
.dropzone.dz-clickable .dz-message span {
cursor: pointer;
}
.dropzone.dz-clickable * {
cursor: default;
}
.dropzone .dz-message {
opacity: 1;
-ms-filter: none;
filter: none;
}
.dropzone.dz-drag-hover {
border-color: rgba(0,0,0,0.15);
background: rgba(0,0,0,0.04);
}
.dropzone.dz-started .dz-message {
display: none;
}
.dropzone .dz-preview,
.dropzone-previews .dz-preview {
background: rgba(255,255,255,0.8);
position: relative;
display: inline-block;
margin: 17px;
vertical-align: top;
border: 1px solid #acacac;
padding: 6px 6px 6px 6px;
}
.dropzone .dz-preview.dz-file-preview [data-dz-thumbnail],
.dropzone-previews .dz-preview.dz-file-preview [data-dz-thumbnail] {
display: none;
}
.dropzone .dz-preview .dz-details,
.dropzone-previews .dz-preview .dz-details {
width: 100px;
height: 100px;
position: relative;
background: #ebebeb;
padding: 5px;
margin-bottom: 22px;
}
.dropzone .dz-preview .dz-details .dz-filename,
.dropzone-previews .dz-preview .dz-details .dz-filename {
overflow: hidden;
height: 100%;
}
.dropzone .dz-preview .dz-details img,
.dropzone-previews .dz-preview .dz-details img {
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
}
.dropzone .dz-preview .dz-details .dz-size,
.dropzone-previews .dz-preview .dz-details .dz-size {
position: absolute;
bottom: -28px;
left: 3px;
height: 28px;
line-height: 28px;
}
.dropzone .dz-preview.dz-error .dz-error-mark,
.dropzone-previews .dz-preview.dz-error .dz-error-mark {
display: block;
}
.dropzone .dz-preview.dz-success .dz-success-mark,
.dropzone-previews .dz-preview.dz-success .dz-success-mark {
display: block;
}
.dropzone .dz-preview:hover .dz-details img,
.dropzone-previews .dz-preview:hover .dz-details img {
display: none;
}
.dropzone .dz-preview .dz-success-mark,
.dropzone-previews .dz-preview .dz-success-mark,
.dropzone .dz-preview .dz-error-mark,
.dropzone-previews .dz-preview .dz-error-mark {
display: none;
position: absolute;
width: 40px;
height: 40px;
font-size: 30px;
text-align: center;
right: -10px;
top: -10px;
}
.dropzone .dz-preview .dz-success-mark,
.dropzone-previews .dz-preview .dz-success-mark {
color: #8cc657;
}
.dropzone .dz-preview .dz-error-mark,
.dropzone-previews .dz-preview .dz-error-mark {
color: #ee162d;
}
.dropzone .dz-preview .dz-progress,
.dropzone-previews .dz-preview .dz-progress {
position: absolute;
top: 100px;
left: 6px;
right: 6px;
height: 6px;
background: #d7d7d7;
display: none;
}
.dropzone .dz-preview .dz-progress .dz-upload,
.dropzone-previews .dz-preview .dz-progress .dz-upload {
display: block;
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 0%;
background-color: #8cc657;
}
.dropzone .dz-preview.dz-processing .dz-progress,
.dropzone-previews .dz-preview.dz-processing .dz-progress {
display: block;
}
.dropzone .dz-preview .dz-error-message,
.dropzone-previews .dz-preview .dz-error-message {
display: none;
position: absolute;
top: -5px;
left: -20px;
background: rgba(245,245,245,0.8);
padding: 8px 10px;
color: #800;
min-width: 140px;
max-width: 500px;
z-index: 500;
}
.dropzone .dz-preview:hover.dz-error .dz-error-message,
.dropzone-previews .dz-preview:hover.dz-error .dz-error-message {
display: block;
}
This diff is collapsed.
.red-fonts {
color: #ed5565;
}
.form-group.required .control-label:after {
content: " *";
color: red;
}
.n-invalid {border: 1px solid #f00;}
.primary-panel .ibox-title {
color: #ffffff;
background-color: #1AB394;
}
.primary-panel .ibox-content {
border: 1px solid #1AB394;
}
.info-panel .ibox-title {
color: #ffffff;
background-color: #23c6c8;
}
.info-panel .ibox-content {
border: 1px solid #23c6c8;;
}
th a {
color: #676a6c;
}
.select2-container--default .select2-results__option--highlighted[aria-selected] {
background-color: #1ab394;
color: white;
}
.select2-selection--multiple {
border: 1px solid #e5e6e7 !important;
cursor: text !important;
}
.select2-container--forcus {
border: 1px solid #1AB394 !important;
}
.select2-selection__choice,
.chosen-container-multi .chosen-choices li.search-choice {
background: #f1f1f1 !important;
border: 1px solid #e5e6e7 !important;
/*border: 1px solid #ededed;*/
border-radius: 2px !important;
box-shadow: none !important;
color: #333333 !important;
cursor: default !important;
line-height: 13px !important;
/*margin: 3px 0 3px 5px !important;*/
padding: 3px 20px 3px 5px !important;
position: relative !important;
}
.select2-container--default.select2-container--focus .select2-selection--multiple {
border: 1px solid #1ab394 !important;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3) !important;
}
.passwordBox2 {
max-width: 660px;
margin: 0 auto;
padding: 100px 20px 20px 20px;
}
.no-borders-tr td {
border-top: none !important;
}
/* Magnific Popup CSS */
.mfp-bg {
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1042;
overflow: hidden;
position: fixed;
background: #0b0b0b;
opacity: 0.8;
filter: alpha(opacity=80); }
.mfp-wrap {
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1043;
position: fixed;
outline: none !important;
-webkit-backface-visibility: hidden; }
.mfp-container {
text-align: center;
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
padding: 0 8px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box; }
.mfp-container:before {
content: '';
display: inline-block;
height: 100%;
vertical-align: middle; }
.mfp-align-top .mfp-container:before {
display: none; }
.mfp-content {
position: relative;
display: inline-block;
vertical-align: middle;
margin: 0 auto;
text-align: left;
z-index: 1045; }
.mfp-inline-holder .mfp-content, .mfp-ajax-holder .mfp-content {
width: 100%;
cursor: auto; }
.mfp-ajax-cur {
cursor: progress; }
.mfp-zoom-out-cur, .mfp-zoom-out-cur .mfp-image-holder .mfp-close {
cursor: -moz-zoom-out;
cursor: -webkit-zoom-out;
cursor: zoom-out; }
.mfp-zoom {
cursor: pointer;
cursor: -webkit-zoom-in;
cursor: -moz-zoom-in;
cursor: zoom-in; }
.mfp-auto-cursor .mfp-content {
cursor: auto; }
.mfp-close, .mfp-arrow, .mfp-preloader, .mfp-counter {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none; }
.mfp-loading.mfp-figure {
display: none; }
.mfp-hide {
display: none !important; }
.mfp-preloader {
color: #CCC;
position: absolute;
top: 50%;
width: auto;
text-align: center;
margin-top: -0.8em;
left: 8px;
right: 8px;
z-index: 1044; }
.mfp-preloader a {
color: #CCC; }
.mfp-preloader a:hover {
color: #FFF; }
.mfp-s-ready .mfp-preloader {
display: none; }
.mfp-s-error .mfp-content {
display: none; }
button.mfp-close, button.mfp-arrow {
overflow: visible;
cursor: pointer;
background: transparent;
border: 0;
-webkit-appearance: none;
display: block;
outline: none;
padding: 0;
z-index: 1046;
-webkit-box-shadow: none;
box-shadow: none; }
button::-moz-focus-inner {
padding: 0;
border: 0; }
.mfp-close {
width: 44px;
height: 44px;
line-height: 44px;
position: absolute;
right: 0;
top: 0;
text-decoration: none;
text-align: center;
opacity: 0.65;
filter: alpha(opacity=65);
padding: 0 0 18px 10px;
color: #FFF;
font-style: normal;
font-size: 28px;
font-family: Arial, Baskerville, monospace; }
.mfp-close:hover, .mfp-close:focus {
opacity: 1;
filter: alpha(opacity=100); }
.mfp-close:active {
top: 1px; }
.mfp-close-btn-in .mfp-close {
color: #333; }
.mfp-image-holder .mfp-close, .mfp-iframe-holder .mfp-close {
color: #FFF;
right: -6px;
text-align: right;
padding-right: 6px;
width: 100%; }
.mfp-counter {
position: absolute;
top: 0;
right: 0;
color: #CCC;
font-size: 12px;
line-height: 18px;
white-space: nowrap; }
.mfp-arrow {
position: absolute;
opacity: 0.65;
filter: alpha(opacity=65);
margin: 0;
top: 50%;
margin-top: -55px;
padding: 0;
width: 90px;
height: 110px;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); }
.mfp-arrow:active {
margin-top: -54px; }
.mfp-arrow:hover, .mfp-arrow:focus {
opacity: 1;
filter: alpha(opacity=100); }
.mfp-arrow:before, .mfp-arrow:after, .mfp-arrow .mfp-b, .mfp-arrow .mfp-a {
content: '';
display: block;
width: 0;
height: 0;
position: absolute;
left: 0;
top: 0;
margin-top: 35px;
margin-left: 35px;
border: medium inset transparent; }
.mfp-arrow:after, .mfp-arrow .mfp-a {
border-top-width: 13px;
border-bottom-width: 13px;
top: 8px; }
.mfp-arrow:before, .mfp-arrow .mfp-b {
border-top-width: 21px;
border-bottom-width: 21px;
opacity: 0.7; }
.mfp-arrow-left {
left: 0; }
.mfp-arrow-left:after, .mfp-arrow-left .mfp-a {
border-right: 17px solid #FFF;
margin-left: 31px; }
.mfp-arrow-left:before, .mfp-arrow-left .mfp-b {
margin-left: 25px;
border-right: 27px solid #3F3F3F; }
.mfp-arrow-right {
right: 0; }
.mfp-arrow-right:after, .mfp-arrow-right .mfp-a {
border-left: 17px solid #FFF;
margin-left: 39px; }
.mfp-arrow-right:before, .mfp-arrow-right .mfp-b {
border-left: 27px solid #3F3F3F; }
.mfp-iframe-holder {
padding-top: 40px;
padding-bottom: 40px; }
.mfp-iframe-holder .mfp-content {
line-height: 0;
width: 100%;
max-width: 900px; }
.mfp-iframe-holder .mfp-close {
top: -40px; }
.mfp-iframe-scaler {
width: 100%;
height: 0;
overflow: hidden;
padding-top: 56.25%; }
.mfp-iframe-scaler iframe {
position: absolute;
display: block;
top: 0;
left: 0;
width: 100%;
height: 100%;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
background: #000; }
/* Main image in popup */
img.mfp-img {
width: auto;
max-width: 100%;
height: auto;
display: block;
line-height: 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 40px 0 40px;
margin: 0 auto; }
/* The shadow behind the image */
.mfp-figure {
line-height: 0; }
.mfp-figure:after {
content: '';
position: absolute;
left: 0;
top: 40px;
bottom: 40px;
display: block;
right: 0;
width: auto;
height: auto;
z-index: -1;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
background: #444; }
.mfp-figure small {
color: #BDBDBD;
display: block;
font-size: 12px;
line-height: 14px; }
.mfp-figure figure {
margin: 0; }
.mfp-bottom-bar {
margin-top: -36px;
position: absolute;
top: 100%;
left: 0;
width: 100%;
cursor: auto; }
.mfp-title {
text-align: left;
line-height: 18px;
color: #F3F3F3;
word-wrap: break-word;
padding-right: 36px; }
.mfp-image-holder .mfp-content {
max-width: 100%; }
.mfp-gallery .mfp-image-holder .mfp-figure {
cursor: pointer; }
@media screen and (max-width: 800px) and (orientation: landscape), screen and (max-height: 300px) {
/**
* Remove all paddings around the image on small screen
*/
.mfp-img-mobile .mfp-image-holder {
padding-left: 0;
padding-right: 0; }
.mfp-img-mobile img.mfp-img {
padding: 0; }
.mfp-img-mobile .mfp-figure:after {
top: 0;
bottom: 0; }
.mfp-img-mobile .mfp-figure small {
display: inline;
margin-left: 5px; }
.mfp-img-mobile .mfp-bottom-bar {
background: rgba(0, 0, 0, 0.6);
bottom: 0;
margin: 0;
top: auto;
padding: 3px 5px;
position: fixed;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box; }
.mfp-img-mobile .mfp-bottom-bar:empty {
padding: 0; }
.mfp-img-mobile .mfp-counter {
right: 5px;
top: 3px; }
.mfp-img-mobile .mfp-close {
top: 0;
right: 0;
width: 35px;
height: 35px;
line-height: 35px;
background: rgba(0, 0, 0, 0.6);
position: fixed;
text-align: center;
padding: 0; }
}
@media all and (max-width: 900px) {
.mfp-arrow {
-webkit-transform: scale(0.75);
transform: scale(0.75); }
.mfp-arrow-left {
-webkit-transform-origin: 0;
transform-origin: 0; }
.mfp-arrow-right {
-webkit-transform-origin: 100%;
transform-origin: 100%; }
.mfp-container {
padding-left: 6px;
padding-right: 6px; }
}
.mfp-ie7 .mfp-img {
padding: 0; }
.mfp-ie7 .mfp-bottom-bar {
width: 600px;
left: 50%;
margin-left: -300px;
margin-top: 5px;
padding-bottom: 5px; }
.mfp-ie7 .mfp-container {
padding: 0; }
.mfp-ie7 .mfp-content {
padding-top: 44px; }
.mfp-ie7 .mfp-close {
top: 0;
right: 0;
padding-top: 0; }
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
apps/static/img/facio.ico

1.59 KB | W: | H:

apps/static/img/facio.ico

1.7 KB | W: | H:

apps/static/img/facio.ico
apps/static/img/facio.ico
apps/static/img/facio.ico
apps/static/img/facio.ico
  • 2-up
  • Swipe
  • Onion skin
......@@ -34,9 +34,9 @@ $(document).ready(function () {
});
// Append config box / Only for demo purpose
$.get("/skin_config/", function (data) {
$('body').append(data);
});
//$.get("/skin_config/", function (data) {
// $('body').append(data);
//});
// minimalize menu
$('.navbar-minimalize').click(function () {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment