class terrariumWebserver(object): app = Bottle() app.install(terrariumWebserverHeaders()) def __init__(self, terrariumEngine): self.__terrariumEngine = terrariumEngine self.__app = terrariumWebserver.app self.__config = self.__terrariumEngine.get_config('system') self.__caching_days = 30 terrariumWebserver.app.terrarium = self.__terrariumEngine # Load language gettext.translation('terrariumpi', 'locales/', languages=[ self.__terrariumEngine.config.get_language() ]).install(True) self.__translations = terrariumTranslations() self.__routes() # Custom HTTP authentication routine. This way there is an option to optional secure the hole web interface def __auth_basic2(self, check, required, realm="private", text="Access denied"): """ Callback decorator to require HTTP auth (basic). TODO: Add route(check_auth=...) parameter. """ def decorator(func): @functools.wraps(func) def wrapper(*a, **ka): user, password = request.auth or (None, None) if required or terrariumUtils.is_true( self.__terrariumEngine.config.get_system() ['always_authenticate']): if user is None or not check(user, password): err = HTTPError(401, text) err.add_header('WWW-Authenticate', 'Basic realm="%s"' % realm) return err return func(*a, **ka) return wrapper return decorator def __authenticate(self, required): return self.__auth_basic2(self.__terrariumEngine.authenticate, required, _('TerrariumPI') + ' ' + _('Authentication'), _('Authenticate to make any changes')) def __logout_authenticate(self, user, password): return True def __routes(self): self.__app.route('/', method="GET", callback=self.__render_page, apply=self.__authenticate(False)) self.__app.route('/<template_name:re:[^/]+\.html$>', method="GET", callback=self.__render_page, apply=self.__authenticate(False)) self.__app.route('/<filename:re:robots\.txt>', method="GET", callback=self.__static_file) self.__app.route('/<root:re:static/extern>/<filename:path>', method="GET", callback=self.__static_file) self.__app.route( '/<root:re:(static|gentelella|webcam|audio|log)>/<filename:path>', method="GET", callback=self.__static_file, apply=self.__authenticate(False)) self.__app.route('/api/<path:re:(config/notifications)>', method=['GET'], callback=self.__get_api_call, apply=self.__authenticate(True)) self.__app.route('/api/<path:path>', method=['GET'], callback=self.__get_api_call, apply=self.__authenticate(False)) self.__app.route('/api/switch/toggle/<switchid:path>', method=['POST'], callback=self.__toggle_switch, apply=self.__authenticate(True)) self.__app.route('/api/switch/state/<switchid:path>/<value:int>', method=['POST'], callback=self.__state_switch, apply=self.__authenticate(True)) self.__app.route( '/api/config/<path:re:(system|weather|switches|sensors|webcams|doors|audio|environment|profile|notifications)>', method=['PUT', 'POST', 'DELETE'], callback=self.__update_api_call, apply=self.__authenticate(True)) self.__app.route( '/api/audio/player/<action:re:(start|stop|volumeup|volumedown|mute|unmute)>', method=['POST'], callback=self.__player_commands, apply=self.__authenticate(True)) self.__app.route('/api/audio/file', method=['POST'], callback=self.__upload_audio_file, apply=self.__authenticate(True)) self.__app.route('/api/audio/file/<audiofileid:path>', method=['DELETE'], callback=self.__delete_audio_file, apply=self.__authenticate(True)) self.__app.route('/logout', method=['GET'], callback=self.__logout_url, apply=auth_basic( self.__logout_authenticate, _('TerrariumPI') + ' ' + _('Authentication'), _('Authenticate to make any changes'))) def __template_variables(self, template): variables = { 'lang': self.__terrariumEngine.config.get_language(), 'title': self.__config['title'], 'version': self.__config['version'], 'page_title': _(template.replace('_', ' ').capitalize()), 'temperature_indicator': self.__terrariumEngine.get_temperature_indicator(), 'distance_indicator': self.__terrariumEngine.get_distance_indicator(), 'volume_indicator': self.__terrariumEngine.get_volume_indicator(), 'horizontal_graph_legend': 1 if self.__terrariumEngine.get_horizontal_graph_legend() else 0, 'translations': self.__translations, 'device': self.__terrariumEngine.device, 'notifications': self.__terrariumEngine.notification } if 'index' == template or 'profile' == template: variables['person_name'] = self.__terrariumEngine.get_profile_name( ) variables[ 'person_image'] = self.__terrariumEngine.get_profile_image() return variables def __render_page(self, template_name='index.html'): template_name = template_name[:-5] if not os.path.isfile('views/' + template_name + '.tpl'): template_name = '404' return template(template_name, **self.__template_variables(template_name)) def __static_file(self, filename, root='static'): if filename == 'js/terrariumpi.js': response.headers[ 'Content-Type'] = 'application/javascript; charset=UTF-8' response.headers['Expires'] = ( datetime.datetime.utcnow() + datetime.timedelta(days=self.__caching_days) ).strftime('%a, %d %b %Y %H:%M:%S GMT') return template(filename, template_lookup=[root]) staticfile = static_file(filename, root=root) if isinstance(staticfile, HTTPError): return staticfile if 'webcam' == root or 'log' == root: staticfile.add_header( 'Expires', datetime.datetime.utcnow().strftime( '%a, %d %b %Y %H:%M:%S GMT')) if 'log' == root: staticfile.add_header('Content-Type', 'text/text; charset=UTF-8') staticfile.add_header('Content-Disposition', 'Attachment;filename=' + filename) else: staticfile.add_header('Expires', (datetime.datetime.utcnow() + datetime.timedelta(days=self.__caching_days) ).strftime('%a, %d %b %Y %H:%M:%S GMT')) if staticfile.get_header('Last-Modified') is not None: staticfile.add_header( 'Etag', hashlib.md5(staticfile.get_header( 'Last-Modified').encode()).hexdigest()) return staticfile def __player_commands(self, action): result = { 'ok': False, 'title': _('Error!'), 'message': _('Player command could ot be executed!') } if 'start' == action: self.__terrariumEngine.audio_player_start() elif 'stop' == action: self.__terrariumEngine.audio_player_stop() elif 'volumeup' == action: self.__terrariumEngine.audio_player_volume_up() result = { 'ok': True, 'title': _('OK!'), 'message': _('Player command executed!') } elif 'volumedown' == action: self.__terrariumEngine.audio_player_volume_down() result = { 'ok': True, 'title': _('OK!'), 'message': _('Player command executed!') } elif 'mute' == action: pass elif 'unmute' == action: pass return result def __upload_audio_file(self): result = { 'ok': False, 'title': _('Error!'), 'message': _('File is not uploaded!') } upload = request.files.get('file') try: upload.save(terrariumAudioPlayer.AUDIO_FOLDER) self.__terrariumEngine.reload_audio_files() result = { 'ok': True, 'title': _('Success!'), 'message': _('File \'%s\' is uploaded') % (upload.filename, ) } except IOError as message: result['message'] = _('Duplicate file \'%s\'') % ( upload.filename, ) return result def __delete_audio_file(self, audiofileid): result = { 'ok': False, 'title': _('Error!'), 'message': _('Action could not be satisfied') } if self.__terrariumEngine.delete_audio_file(audiofileid): result = { 'ok': True, 'title': _('Success!'), 'message': _('Audio file is deleted') } return result def __update_api_call(self, path): result = { 'ok': False, 'title': _('Error!'), 'message': _('Data could not be saved') } postdata = {} if request.json is not None: postdata = request.json result['ok'] = self.__terrariumEngine.set_config( path, postdata, request.files) if result['ok']: result['title'] = _('Data saved') result['message'] = _('Your changes are saved') # Reload language if needed if 'language' in postdata: gettext.translation( 'terrariumpi', 'locales/', languages=[self.__terrariumEngine.config.get_language() ]).install(True) self.__translations.reload() return result def __get_api_call(self, path): response.headers['Expires'] = (datetime.datetime.utcnow() + datetime.timedelta(seconds=10) ).strftime('%a, %d %b %Y %H:%M:%S GMT') response.headers['Access-Control-Allow-Origin'] = '*' result = {} parameters = path.strip('/').split('/') action = parameters[0] del (parameters[0]) if 'switches' == action: result = self.__terrariumEngine.get_switches(parameters) elif 'doors' == action: if len(parameters) > 0 and parameters[0] == 'status': result = {'status': self.__terrariumEngine.get_doors_status()} else: result = self.__terrariumEngine.get_doors() elif 'profile' == action: result = self.__terrariumEngine.get_profile() elif 'sensors' == action: result = self.__terrariumEngine.get_sensors(parameters) elif 'webcams' == action: result = self.__terrariumEngine.get_webcams(parameters) elif 'audio' == action: if len(parameters) > 0 and parameters[0] == 'files': del (parameters[0]) result = self.__terrariumEngine.get_audio_files(parameters) elif len(parameters) > 0 and parameters[0] == 'playing': del (parameters[0]) result = self.__terrariumEngine.get_audio_playing() elif len(parameters) > 0 and parameters[0] == 'hardware': del (parameters[0]) result = { 'audiohardware': terrariumAudioPlayer.get_sound_cards() } else: result = self.__terrariumEngine.get_audio_playlists(parameters) elif 'environment' == action: result = self.__terrariumEngine.get_environment(parameters) elif 'weather' == action: result = self.__terrariumEngine.get_weather(parameters) elif 'uptime' == action: result = self.__terrariumEngine.get_uptime() elif 'power_usage' == action: result = self.__terrariumEngine.get_power_usage_water_flow( )['power'] elif 'water_usage' == action: result = self.__terrariumEngine.get_power_usage_water_flow( )['water'] elif 'system' == action: result = self.__terrariumEngine.get_system_stats() elif 'config' == action: # TODO: New way of data processing.... fix other config options result = self.__terrariumEngine.get_config( parameters[0] if len(parameters) == 1 else None) elif 'history' == action or 'export' == action: response.headers['Expires'] = ( datetime.datetime.utcnow() + datetime.timedelta(minutes=1) ).strftime('%a, %d %b %Y %H:%M:%S GMT') if 'export' == action: parameters.append('all') result = self.__terrariumEngine.get_history(parameters) if 'export' == action: csv = '' export_name = 'error' for datatype in result: for dataid in result[datatype]: export_name = datatype + '_' + dataid + '.csv' # Header fields = list(result[datatype][dataid].keys()) if 'totals' in fields: fields.remove('totals') csv = '"' + '","'.join(['timestamp'] + fields) + "\"\n" for counter in range( 0, len(result[datatype][dataid][fields[0]])): # Timestamp row = [ datetime.datetime.fromtimestamp( int( str( int(result[datatype][dataid][ fields[0]][counter][0] / 1000)))).strftime( '%Y-%m-%d %H:%M:%S') ] for field in fields: # Row values row.append( str(result[datatype][dataid][field] [counter][1])) csv += '"' + '","'.join(row) + "\"\n" response.headers['Content-Type'] = 'application/csv' response.headers[ 'Content-Disposition'] = 'attachment; filename=' + export_name return csv return result def __toggle_switch(self, switchid): if switchid in self.__terrariumEngine.power_switches: self.__terrariumEngine.power_switches[switchid].toggle() return {'ok': True} return {'ok': False} def __state_switch(self, switchid, value): if switchid in self.__terrariumEngine.power_switches: if value == 1: self.__terrariumEngine.power_switches[switchid].set_state(True) return {'ok': True} elif value == 0: self.__terrariumEngine.power_switches[switchid].set_state( False) return {'ok': True} else: self.__terrariumEngine.power_switches[switchid].set_state( value) return {'ok': True} return {'ok': False} def __logout_url(self): return { 'ok': True, 'title': _('Log out'), 'message': _('You are now logged out') } @app.error(404) def error404(error): config = terrariumWebserver.app.terrarium.get_config('system') variables = { 'lang': terrariumWebserver.app.terrarium.config.get_language(), 'title': config['title'], 'page_title': config['title'] + ' | 404' } return template('404', **variables) @app.route('/live', apply=[websocket]) def handle_websocket(socket): messages = Queue() def listen_for_messages(messages, socket): while True: message = messages.get() try: socket.send(json.dumps(message)) except Exception as ex: # Socket connection is lost, stop looping.... break messages.task_done() while True: try: message = socket.receive() except Exception as ex: break if message is not None: message = json.loads(message) if message['type'] == 'client_init': _thread.start_new_thread(listen_for_messages, (messages, socket)) terrariumWebserver.app.terrarium.subscribe(messages) terrariumWebserver.app.terrarium.get_doors_status(socket=True) terrariumWebserver.app.terrarium.get_uptime(socket=True) terrariumWebserver.app.terrarium.get_environment(socket=True) terrariumWebserver.app.terrarium.get_power_usage_water_flow( socket=True) def start(self): # Start the webserver logger.info('Running webserver at %s:%s' % (self.__config['host'], self.__config['port'])) print( '%s - INFO - terrariumWebserver - Running webserver at %s:%s' % (datetime.datetime.today().strftime('%Y-%m-%d %H:%M:%S,000'), self.__config['host'], self.__config['port'])) self.__app.run(host=self.__config['host'], port=self.__config['port'], server=GeventWebSocketServer, debug=True, reloader=False, quiet=True)
from bottle import route, run, error, template, request, response, Bottle from json import dumps app = application = Bottle() # class EnableCors(object): # name = 'enable_cors' # api = 2 # # def apply(self, fn, context): # def _enable_cors(*args, **kwargs): # # set CORS headers # response.headers['Access-Control-Allow-Origin'] = '*' # response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, OPTIONS' # response.headers['Access-Control-Allow-Headers'] = 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token' # # if request.method != 'OPTIONS': # # actual request; reply with the actual response # return fn(*args, **kwargs) # # return _enable_cors def temp(file_name, *args, title="", extension=".html", template_dir="view/", **kwargs): file_name = template_dir + file_name + extension return template("view/layout/skeleton.html", body_file=file_name)
from bottle import Bottle, request import datetime import pickle import base64 api = Bottle() @api.route("/") def index(): """Index endpoint""" return "token" @api.route("/token", method="PUT") def token(): """Token endpoint See https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html """ ttl = request.headers.get("X-aws-ec2-metadata-token-ttl-seconds") if ttl is None: return else: try: if 1 <= int(ttl) <= 21600: now = datetime.datetime.now() next = now + datetime.timedelta(seconds=int(ttl)) payload = {"ttl": ttl, "expires": next.timestamp()} return base64.b64encode(pickle.dumps(payload)) else:
# _*_ coding: utf-8 _*_ from bottle import Bottle, run, template # Bottle指定对象分配指定网址,可以不引入route(),引入模板 app = Bottle() # 给app变量分配一个网址,创建框架 @app.route('/hello') # 给app创建URL path def hello(): return "Hello World!" if __name__ == '__main__': run(app, host='localhost', port=8080, debug=True) #注意运行要添加app变量
from Raspi import System elif True is CheckWindows(): from Win import Network from Win import VideoInfo from Win import HDMI from Win import Video from Win import System pass path = None # playing file path user = None # playing file user comment = None # playing file comment duration = None # playing file duration audioNum = 0 # playing file audio stream vol = -4500 # current volume app = Bottle() # bottle instance pause = False # pause video = None # video instance videoInfo = None # videoInfo instance network = None # network Instance hdmi = None # hdmi instance system = None # system Instance lock = threading.Lock() # Lock Object enter = False # Enter-Key State def callback(event): global enter if event.event_type == keyboard.KEY_DOWN: if 28 == event.scan_code or 96 == event.scan_code: enter = True
def __init__(self, host='', porta=8080): self._h = host self._p = porta self._a = Bottle() self._rota() self._g = core
def dummy_xmlrpc_app(): app = Bottle() return app
def __init__(self, root): self.root = root self.app = Bottle() self.db = j.sal.bcdbfs # Valid token until thousand of years # Generated from jwt.iousing # { # "user": { # "id": 1, # "locale": "en", # "viewMode": "mosaic", # "perm": { # "admin": true, # "execute": true, # "create": true, # "rename": true, # "modify": true, # "delete": true, # "share": false, # "download": true # }, # "commands": [], # "lockPassword": false # }, # "exp": 156691277633, # "iat": 1566905576, # "iss": "File Browser" # } self.TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoxLCJsb2NhbGUiOiJlbiIsInZpZXdNb2RlIjoibW9zYWljIiwicGVybSI6eyJhZG1pbiI6dHJ1ZSwiZXhlY3V0ZSI6dHJ1ZSwiY3JlYXRlIjp0cnVlLCJyZW5hbWUiOnRydWUsIm1vZGlmeSI6dHJ1ZSwiZGVsZXRlIjp0cnVlLCJzaGFyZSI6ZmFsc2UsImRvd25sb2FkIjp0cnVlfSwiY29tbWFuZHMiOltdLCJsb2NrUGFzc3dvcmQiOmZhbHNlfSwiZXhwIjoxNTY2OTEyNzc2MzMsImlhdCI6MTU2NjkwNTU3NiwiaXNzIjoiRmlsZSBCcm93c2VyIn0.GaBiL_MeqDev0695MRqE3RhmGatouIT4BtlvpTI4P1A" @self.app.route("/fileserver/api/login", method="post") def login(): response.set_header("Content-Type", "cty") return self.TOKEN @self.app.route("/fileserver/api/renew", method="post") def renew(): response.set_header("X-Renew-Token", "true") response.set_header("Content-Type", "cty") return self.TOKEN @self.app.route("/static/<path:path>") def static(path): return static_file(path, root="%s/static" % self.root) @self.app.route("/fileserver/api/resources/<dir:path>/", method="post") def create_dir(dir): dir = j.sal.fs.joinPaths("/", dir).rstrip("/") override = request.GET.get("override") == "true" if not j.sal.bcdbfs.dir_exists(dir): self.db.dir_create(dir) elif j.sal.bcdbfs.dir_exists(dir) and override: self.db.dir_create(dir) obj = self.db._dir_model.get_by_name(name=dir) obj.epoch = int(time.time()) obj.save() response.set_header("X-Content-Type-Options", "nosniff") response.set_header("X-Renew-Token", "true") response.set_header("Content-Type", "text/plain; charset=utf-8") return "200 OK" @self.app.route("/fileserver/api/resources/<dir:path>/", method="delete") def delete_dir(dir): dir = j.sal.fs.joinPaths("/", dir).rstrip("/") if j.sal.bcdbfs.dir_exists(dir): self.db.dir_remove(dir) response.set_header("Content-Type", "text/plain; charset=utf-8") response.set_header("X-Content-Type-Options", "nosniff") response.set_header("X-Renew-Token", "true") return "200 OK" response.set_header("X-Content-Type-Options", "nosniff") response.set_header("X-Renew-Token", "true") response.set_header("Content-Type", "text/plain; charset=utf-8") return "409 Conflict" @self.app.route("/fileserver/api/resources/<path:re:.*>", method="post") def upload_file(path): file = j.sal.fs.joinPaths("/", path) override = request.GET.get("override") == "true" def create(file): content_type = "text/plain" if request.body.seek(0, 2) == 0: self.db.file_create_empty(file) else: request.body.seek(0) buff = request.body.read(1024) request.body.seek(0) mtype = filetype.guess(buff) if mtype: content_type = mtype.mime else: x = mimetypes.MimeTypes() types = {} for l in x.types_map: types.update(l) ct = types.get("." + j.sal.fs.getFileExtension(file)) if ct: content_type = ct self.db.file_write(file, request.body, append=True, create=True) obj = self.db._file_model.get_by_name(name=file) obj.content_type = content_type obj.epoch = int(time.time()) obj.save() if not j.sal.bcdbfs.file_exists(file): create(file) elif j.sal.bcdbfs.file_exists(file) and override: create(file) else: response.set_header("X-Content-Type-Options", "nosniff") response.set_header("X-Renew-Token", "true") response.set_header("Content-Type", "text/plain; charset=utf-8") return "409 Conflict" response.set_header("X-Content-Type-Options", "nosniff") response.set_header("X-Renew-Token", "true") response.set_header("Etag", "15bed3cb4c34f4360") response.set_header("Content-Type", "text/plain; charset=utf-8") return "200 OK" @self.app.route("/fileserver/api/threetransfer/<path:re:.*>", method="post") def upload_threetransfer(path): file = j.sal.fs.joinPaths("/", path) def create(file): content_type = "text/plain" if request.body.seek(0, 2) == 0: self.db.file_create_empty(file) else: request.body.seek(0) buff = request.body.read(1024) request.body.seek(0) mtype = filetype.guess(buff) if mtype: content_type = mtype.mime else: x = mimetypes.MimeTypes() types = {} for l in x.types_map: types.update(l) ct = types.get("." + j.sal.fs.getFileExtension(file)) if ct: content_type = ct filename = "{}".format(file) self.db.file_write(filename, request.body, append=True, create=True) obj = self.db._file_model.get_by_name(name=filename) obj.content_type = content_type obj.epoch = int(time.time()) obj.save() # if exists do nothing create(file) response.set_header("X-Content-Type-Options", "nosniff") response.set_header("X-Renew-Token", "true") response.set_header("Etag", "15bed3cb4c34f4360") response.set_header("Content-Type", "text/plain; charset=utf-8") return "200 OK" @self.app.route( "/fileserver/api/threetransferdownload/<identifier:re:.*>") def threetransfer_download(identifier): """ single file or single dir """ bcdb = j.data.bcdb.get("threetransfer") shortlink_model = bcdb.model_get(url="threetransfer.shortlink.1") files = shortlink_model.find(identifier=identifier) file = "" if files: file = files[0].url else: raise j.exception.Value("The identifier %s does not exist" % identifier) path = j.sal.fs.joinPaths("/", file) # download single file inline = request.GET.get("inline") == "true" obj = self.db._file_model.get_by_name(name=path) response.set_header("X-Renew-Token", "true") filename = obj.name if filename[0] == "/": filename = filename[1:] response.set_header("filename", filename) response.set_header("Content-Type", "application/octet-stream") filetype = obj.content_type response.set_header("Content-Type", filetype) if inline: response.set_header("Content-Disposition", "inline") response.set_header("Accept-Ranges", "bytes") else: # response.set_header("Content-Disposition", "attachment; filename=utf-8" "%s" % j.sal.fs.getBaseName(file)) response.set_header("Content-Disposition", 'attachment; filename="myfile.txt"') return self.db.file_read(path) @self.app.route("/fileserver/api/resources/<path:re:.*>", method="put") def create_file(path): def create(file): buff = request.body.read(1024) request.body.seek(0) content_type = "text/plain" mtype = filetype.guess(buff) if mtype: content_type = mtype.mime else: x = mimetypes.MimeTypes() types = {} for l in x.types_map: types.update(l) ct = types.get("." + j.sal.fs.getFileExtension(file)) if ct: content_type = ct for line in request.body: self.db.file_write(file, line.decode(), append=True, create=True) obj = self.db._file_model.get_by_name(name=file) obj.content_type = content_type obj.epoch = int(time.time()) obj.save() file = j.sal.fs.joinPaths("/", path) override = request.GET.get("override") == "true" obj = self.db._file_model.get_by_name(name=file) if obj.size_bytes == 0: override = True if j.sal.bcdbfs.file_exists(file) and override: self.db.file_delete(file) create(file) elif not j.sal.bcdbfs.file_exists(file): create(file) else: response.set_header("X-Content-Type-Options", "nosniff") response.set_header("X-Renew-Token", "true") response.set_header("Content-Type", "text/plain; charset=utf-8") return "409 Conflict" response.set_header("X-Content-Type-Options", "nosniff") response.set_header("X-Renew-Token", "true") response.set_header("Etag", "15bed3cb4c34f4360") response.set_header("Content-Type", "text/plain; charset=utf-8") return "200 OK" @self.app.route("/fileserver/api/resources/<path:re:.*>", method="delete") def delete_file(path): file = j.sal.fs.joinPaths("/", path) if j.sal.bcdbfs.file_exists(file): self.db.file_delete(file) response.set_header("X-Content-Type-Options", "nosniff") response.set_header("X-Renew-Token", "true") response.set_header("Etag", "15bed3cb4c34f4360") response.set_header("Content-Type", "text/plain; charset=utf-8") return "200 OK" response.set_header("X-Content-Type-Options", "nosniff") response.set_header("X-Renew-Token", "true") response.set_header("Content-Type", "text/plain; charset=utf-8") return "409 Conflict" @self.app.route("/fileserver/api/resources/<dir:path>/", method="patch") def dir_copy_rename_move(dir): src = j.sal.fs.joinPaths("/", dir) action = request.GET.get("action") destination = request.GET.get("destination") def copy_dir(src, dest): self.db.dir_copy_from_bcdbfs(src, dest) def move_dir(src, dest): self.db.dir_copy_from_bcdbfs(src, dest) self.db.dir_remove(src) if action == "copy": copy_dir(src, destination) if action in ["move", "rename"]: move_dir(src, destination) response.set_header("Content-Type", "text/plain; charset=utf-8") response.set_header("X-Content-Type-Options", "nosniff") response.set_header("X-Renew-Token", "true") return "200 OK" @self.app.route("/fileserver/api/resources/<path:re:.*>", method="patch") def file_copy_rename_move(path): file = j.sal.fs.joinPaths("/", path) action = request.GET.get("action") destination = request.GET.get("destination") def copy_file(src, dest): self.db.file_copy_form_bcdbfs(src, dest) def move_file(src, dest): self.db.file_copy_form_bcdbfs(src, dest) self.db.file_delete(src) if action == "copy": copy_file(file, destination) if action in ["move", "rename"]: move_file(file, destination) response.set_header("Content-Type", "text/plain; charset=utf-8") response.set_header("X-Content-Type-Options", "nosniff") response.set_header("X-Renew-Token", "true") return "200 OK" @self.app.route("/fileserver/api/resources/<path:re:.*>", method="get", name="list") def resources(path=""): def get_type(content_type): if "text" in content_type: return "text" if "image" in content_type: return "image" if "video" in content_type: return "video" return "blob" list = True if not path: path = "/" # root if not path.endswith("/"): list = False path = j.sal.fs.joinPaths("/", path).rstrip("/") or "/" response.set_header("X-Renew-Token", "true") response.set_header("Content-Type", "application/json; charset=utf-8") items = [] if list: dirs = self.db.list_dirs(path) files = self.db.list_files(path) for file in files: path_ = j.sal.fs.joinPaths(path, file) obj = self.db._file_model.get_by_name(name=path_) item = { "path": path_, "name": j.sal.fs.getBaseName(file), "size": obj.size_bytes, "extension": ".{}".format( j.sal.fs.getFileExtension(path)).rstrip("."), "modified": datetime.datetime.fromtimestamp( obj.epoch).strftime("%Y-%m-%dT%H:%M:%S.%f%Z"), "mode": 420, "isDir": False, "type": get_type(obj.content_type), } items.append(item) for dir in dirs: path_ = j.sal.fs.joinPaths(path, dir) obj = self.db._dir_model.get_by_name(name=path_) item = { "path": path_, "name": j.sal.fs.getBaseName(dir), "size": 4096, "extension": "", "modified": datetime.datetime.fromtimestamp( obj.epoch).strftime("%Y-%m-%dT%H:%M:%S.%f%Z"), "mode": 2147484141, "isDir": True, "type": "", } items.append(item) response.set_header("X-Renew-Token", "true") parent_obj = self.db._dir_model.get_by_name(name=path) return json.dumps({ "items": items, "numDirs": len(dirs), "numFiles": len(files), "sorting": { "by": "name", "asc": False }, "path": path, "name": "filemanager", "size": 4096, "extension": "", "modified": datetime.datetime.fromtimestamp( parent_obj.epoch).strftime("%Y-%m-%dT%H:%M:%S.%f%Z"), "mode": 2147484141, "isDir": True, "type": "", }) # file info modified = time.time() size = 0 content = "" if self.db.file_exists(path): obj = self.db._file_model.get_by_name(name=path) modified = obj.epoch size = obj.size_bytes content = obj.content return json.dumps({ "content": content, "checksums": { "md5": "N/A", "sha1": "N/A", "sha256": "N/A", "sha512": "N/A" }, "path": path, "name": j.sal.fs.getBaseName(path), "size": size, "extension": ".{}".format(j.sal.fs.getFileExtension(path)).rstrip("."), "modified": modified, "mode": 420, "isDir": False, "type": get_type(obj.content_type), }) @self.app.route("/fileserver/api/users") def users(): return json.dumps([{ "id": 1, "username": "******", "password": "", "scope": ".", "locale": "en", "lockPassword": False, "viewMode": "mosaic", "perm": { "admin": True, "execute": True, "create": True, "rename": True, "modify": True, "delete": True, "share": False, "download": True, }, "commands": [], "sorting": { "by": "name", "asc": False }, "rules": [], }]) @self.app.route("/fileserver/api/raw/<file:path>") def download_single(file): """ single file or single dir """ path = j.sal.fs.joinPaths("/", file) if path.endswith( "/"): # download_dir (this is a multi file downlad) # locate download_many action and call it route = [ r for r in self.app.routes if r.name == "download_many" ][0] return route.call(files=path) # download single file inline = request.GET.get("inline") == "true" obj = self.db._file_model.get_by_name(name=path) response.set_header("X-Renew-Token", "true") response.set_header("Content-Type", "application/octet-stream") if inline: response.set_header("Content-Disposition", "inline") response.set_header("Accept-Ranges", "bytes") else: response.set_header( "Content-Disposition", "attachment; filename**=utf-8" "%s" % j.sal.fs.getBaseName(file)) return self.db.file_read(path) @self.app.route("/fileserver/api/raw/", name="download_many") def download_many(files=None): """ full directory (recursive) or many files """ def list_files_recursively(dir): dir = dir.rstrip("/") res = self.db.list_files(dir) for d in self.db.list_dirs(dir): res.extend(list_files_recursively(d)) return res def zip(files, archive_name): with ZipFile("/tmp/%s" % archive_name, "w", ZIP_DEFLATED) as z: for file in files: c = self.db.file_read(file) z.writestr(file, c) def tar(files, archive_name, mode=""): tar = tarfile.open("/tmp/%s" % archive_name, "w:%s" % mode) for file in files: c = self.db.file_read(file) file_obj = BytesIO(c) info = tarfile.TarInfo(name=file) info.size = len(c) tar.addfile(tarinfo=info, fileobj=file_obj) tar.close() files = files or request.GET.get("files") requested_files = files.split(",") algorithm = request.GET.get("algo") files = [] for file in requested_files: if self.db.is_file(file): files.append(file) else: files.extend(list_files_recursively(file)) name = str(uuid.uuid4()) content_type = "application/octet-stream" if algorithm == "zip": file_name = "filemanager.zip" content_type = "application/zip" response.set_header("Transfer-Encoding", "chunked") zip(files, name) elif algorithm == "tar": file_name = "filemanager.tar" tar(files, name, mode="") elif algorithm == "targz": file_name = "filemanager.tar.gz" tar(files, name, mode="gz") elif algorithm == "tarbz2": file_name = "filemanager.tar.bz2" tar(files, name, mode="bz2") elif algorithm == "tarxz": file_name = "filemanager.tar.xz" tar(files, name, mode="xz") response.set_header("Content-Disposition", "attachment; filename**=utf-8''%s" % file_name) response.set_header("X-Renew-Token", "true") response.set_header("Content-Type", content_type) return open("/tmp/%s" % name, "rb") @self.app.route("/") def home(): return static_file("index.html", root="%s/static" % self.root) @self.app.route("/files/") def home(): return static_file("index.html", root="%s/static" % self.root) @self.app.route("/files") def home2(): return static_file("index.html", root="%s/static" % self.root) @self.app.route("/files/<path:path>") def home3(path): return static_file("index.html", root="%s/static" % self.root) @self.app.route("/opendocs/file/<path:re:.*>", method="get") def onlyoffice(path): title = j.sal.fs.getBaseName(path) key = hashlib.md5(path.encode("utf-8")).hexdigest() extension = j.sal.fs.getFileExtension(path) return template("%s/static/onlyoffice.html" % self.root, { "title": title, "key": key, "extension": extension })
#!env/bin/python import builtins from bottle import Bottle builtins.app = Bottle() app = builtins.app import lists.views import users.views if __name__ == "__main__": app.run(reloader=True, debug=True)
#!/usr/bin/env python # -*- coding: utf-8 -*- import json from bottle import Bottle, request, HTTPResponse from config.models import Sistema, VWUsuarioSistema from sqlalchemy.sql import select from config.middleware import enable_cors, headers, check_csrf from config.database import engine, session_db from config.constants import constants sistema_view = Bottle() @sistema_view.route('/listar', method='GET') @enable_cors @headers @check_csrf def listar(): rpta = None status = 200 try: conn = engine.connect() stmt = select([Sistema]) rs = conn.execute(stmt) rpta = [dict(r) for r in conn.execute(stmt)] except Exception as e: rpta = { 'tipo_mensaje': 'error', 'mensaje': ['Se ha producido un error en listar los sistemas', str(e)],
from bottle import Bottle, run, HTTPResponse HOST = "0.0.0.0" PORT = 80 BACK_END_SERVER = "tornado" HTTP_STATUS_OK = 200 proxy_app = Bottle() @proxy_app.route("/<url:re:.*>", method=['GET', 'POST'], name='proxy_request_handler') def proxy_request_handler(url): return HTTPResponse(status=HTTP_STATUS_OK) if __name__ == "__main__": run(app=proxy_app, host=HOST, port=int(PORT), server=BACK_END_SERVER)
#!/usr/bin/env python # -*- coding: utf-8 -*- import json from bottle import Bottle, request from sqlalchemy.sql import select from config.models import UnidadMedida from config.database import engine, session_db unidad_medida_view = Bottle() @unidad_medida_view.route('/listar', method='GET') def listar(): conn = engine.connect() stmt = select([UnidadMedida]) return json.dumps([dict(r) for r in conn.execute(stmt)]) @unidad_medida_view.route('/listar_select', method='GET') def listar_select(): conn = engine.connect() stmt = select([UnidadMedida]) rpta = [] for r in conn.execute(stmt): t = {'id': r[0], 'nombre': r[1] + ', ' + r[2]} rpta.append(t) return json.dumps(rpta) @unidad_medida_view.route('/guardar', method='POST') def guardar():
#!/usr/bin/env python # coding:utf-8 # pip install bottle-redis # pip install bottle-mongo import bottle from bottle import Bottle, run, request, response boy = Bottle() @boy.hook('before_request') def before_request(): request.user = {'name': 'boy'} print('boy request={}'.format(request.user)) @boy.get("/hello") def hello(): return "boy hello = {}".format(request.user.get('name')) girl = Bottle() @girl.hook('before_request') def before_request(): request.user = {'name': 'girl'} print('girl request={}'.format(request.user))
from bottle import Bottle, request import time httpserver = Bottle() @httpserver.get('/stuff') def do_stuff(): ''' Method that does stuff. ''' stuff = {'data': 'some data'} time.sleep(5) # Return the environment info as Json data return stuff
import os import sys import json import bottle import inject from bottle import route, run, request, Bottle from webapp.services.timeservice import TimeService time = Bottle() @time.get("/") @inject.autoparams() def get_time(time_service: TimeService) -> dict: return {"time": time_service.get_time()}
def app(setup_routers='routes.cfg'): app = Bottle() for build_action in builder_actions(routers(setup_routers)): app.route(build_action[0], build_action[1], build_action[2]) return app
def get_bottle_app(self): """Returns bottle instance""" self.app = Bottle() self.dispatch_views() self.app.hook('after_request')(self.after_request) return self.app
def serverStart(kwargs={}): app = Bottle() appConfig = AppConfig() bottle.TEMPLATES.clear() # register routes for appRoute in appConfig.registerRoutes(): app.route(appRoute[0], appRoute[1], appRoute[2]) # start system cleaner SystemCleaner().startCleaner() # init the session Session() serverOptions = appConfig.serverOptions() host = serverOptions.get('host') if not kwargs.get('host') else kwargs.get('host') port = serverOptions.get('port') if not kwargs.get('port') else kwargs.get('port') reloader = serverOptions.get('reloader') if not kwargs.get('reloader') else kwargs.get('reloader') debug = serverOptions.get('debug') if not kwargs.get('debug') else kwargs.get('debug') server = serverOptions.get('server') if not kwargs.get('server') else kwargs.get('server') interval = serverOptions.get('interval') if not kwargs.get('interval') else kwargs.get('interval') certfile = serverOptions.get('ssl').get('certfile') if not kwargs.get('certfile') else kwargs.get('certfile') keyfile = serverOptions.get('ssl').get('keyfile') if not kwargs.get('keyfile') else kwargs.get('keyfile') if os.access(os.getcwd(), os.W_OK) or (os.is_file(appserverPIDFile) and os.access(appserverPIDFile, os.W_OK)): # try to check the address already bind or not s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) alreadyRun = False try: s.bind((host, port)) writePID(str(os.getpid())) except Exception as ex: alreadyRun = True print('server already running or address already in used {}:{} -> {}'.format(host, port, ex)) # if in debug mode try kill the server and force alradyRun to false if reloader and debug: if serverStop(kwargs) == 0: alreadyRun = False finally: s.close() if not alreadyRun: overrideBuiltinPrint() if certfile is None or keyfile is None: run(app=app, host=host, port=port, reloader=reloader, debug=debug, server=server, interval=interval) else: run(app=app, host=host, port=port, reloader=reloader, debug=debug, server=server, interval=interval, certfile=certfile, keyfile=keyfile) else: print('----------') print('| server already running or address already in used {}:{} |'.format(host, port)) print('----------') else: print('''You don't have write access to {}, need read write access!'''.format(os.getcwd()))
http_range = env['HTTP_RANGE'].replace('bytes=', '').split('-', 1) start_at = int(http_range[0]) #end_at = http_range[1] and int(http_range[1]) or None if start_at > 0: response.status = 416 return response.status_line length = size_mb*1024**2 response.set_header('Content-Disposition', 'filename="{}mb.bin"'.format(size_mb)) response.set_header('Content-Length', length) return func() http = Bottle(catchall=False) @http.route("/{}mb.bin".format(size_mb)) def route_default(): return _default() @http.route("/resume/{}mb.bin".format(size_mb)) def route_resume(): return _resume() @http.route("/resume_fake/{}mb.bin".format(size_mb)) def route_resume_fake(): return _resume_fake() @http.route("/noresume/{}mb.bin".format(size_mb)) def route_noresume():
def make_wsgi_app(dbcontext, imgserver, dbapi, paymentapi, jinja_env, auth_decorator, imagefiles, invapi): w = Bottle() @w.get('/app/resumen_form') @dbcontext @auth_decorator def resume_form(): temp = jinja_env.get_template('invoice/resumen_form.html') stores = dbapi.search(Store) users = dbapi.search(User) return temp.render(almacenes=stores, users=users) @w.get('/app/resumen') @dbcontext @auth_decorator def get_resumen(): user = request.query.get('user') store = request.query.get('almacen_id') start, end = parse_start_end_date(request.query) if user is None or store is None: abort(400, 'Escoje usuario y almacen') if start is None or end is None: abort(400, 'Hay que ingresar las fechas') store = int(store) report = payment_report(dbapi, end, start, store) temp = jinja_env.get_template('invoice/resumen_nuevo.html') return temp.render(start=start, end=end, user=user, store=dbapi.search(Store), report=report) @w.get('/app/resumen_viejo') @dbcontext @auth_decorator def get_resumen_viejo(): user = request.query.get('user') store = request.query.get('almacen_id') start, end = parse_start_end_date(request.query) if user is None or store is None: abort(400, 'Escoje usuario y almacen') if start is None or end is None: abort(400, 'Hay que ingresar las fechas') store = int(store) result = get_notas_with_clients(dbapi.session, end, start, store) by_status = split_records(result, lambda x: x.status) deleted = by_status[Status.DELETED] committed = by_status[Status.COMITTED] ventas = split_records(committed, lambda x: x.payment_format) gtotal = sum((x.total for x in committed)) temp = jinja_env.get_template('invoice/resumen.html') return temp.render(start=start, end=end, user=user, store=dbapi.search(Store), ventas=ventas, gtotal=gtotal, eliminados=deleted) @w.get('/app/entregar_cuenta_form') @dbcontext @auth_decorator def entrega_de_cuenta(): temp = jinja_env.get_template('invoice/entregar_cuenta_form.html') return temp.render() @w.get('/app/crear_entrega_de_cuenta') @dbcontext @auth_decorator def crear_entrega_de_cuenta(): date = request.query.get('fecha') if date: date = parse_iso(date).date() else: date = datetime.date.today() report = generate_daily_report(dbapi, date) total_spent = sum((x.paid_from_cashier for x in report.spent)) checkimgs = { check.payment_id: os.path.split(check.imgcheck)[1] for check in report.checks if check.imgcheck } existing = dbapi.get(date, AccountStat) all_img = list( imgserver.getimg(objtype='entrega_cuenta', objid=date.isoformat())) temp = jinja_env.get_template( 'invoice/crear_entregar_cuenta_form.html') total_cash = sum(report.cash.values()) + report.other_cash return temp.render(cash=report.cash, others=report.other_by_client, total_cash=total_cash, deleted=report.deleted, date=date.isoformat(), pagos=report.payments, all_spent=report.spent, total_spent=total_spent, retension=report.retension, other_cash=report.other_cash, imgs=all_img, checkimgs=checkimgs, existing=existing) def get_cents_with_default(number, default=0): try: return int(float(number) * 100) except ValueError: return default @w.post('/app/crear_entrega_de_cuenta') @dbcontext @auth_decorator def post_crear_entrega_de_cuenta(): cash = request.forms.get('cash', 0) gastos = request.forms.get('gastos', 0) deposito = request.forms.get('deposito', 0) turned_cash = request.forms.get('valor', 0) diff = request.forms.get('diff', 0) date = request.forms.get('date') cash = get_cents_with_default(cash) gastos = get_cents_with_default(gastos) deposito = get_cents_with_default(deposito) turned_cash = get_cents_with_default(turned_cash) diff = get_cents_with_default(diff) date = parse_iso(date).date() userid = get_user(request)['username'] if request.forms.get('submit') == 'Crear': stat = AccountStat(date=date, total_spend=gastos, turned_cash=turned_cash, deposit=deposito, created_by=userid) dbapi.create(stat) dbapi.db_session.flush() else: dbapi.update( AccountStat(date=date), { 'revised_by': userid, 'turned_cash': turned_cash, 'deposit': deposito, 'diff': diff }) now = datetime.datetime.now() todo1 = Todo(objtype=ObjType.ACCOUNT, objid=date, status='PENDING', msg='Papeleta de deposito de {}: ${}'.format( date, Decimal(deposito) / 100), creation_date=now, due_date=now) todo2 = Todo(objtype=ObjType.ACCOUNT, objid=date, status='PENDING', msg='Papeleta de deposito de {}: ${}'.format( date, Decimal(turned_cash) / 100), creation_date=now, due_date=now) dbapi.create(todo1) dbapi.create(todo2) redirect('/app/crear_entrega_de_cuenta?fecha={}'.format( date.isoformat())) @w.get('/app/entrega_de_cuenta_list') @dbcontext @auth_decorator def ver_entrega_de_cuenta_list(): start, end = parse_start_end_date(request.query) if end is None: end = datetime.date.today() if start is None: start = datetime.date.today() - datetime.timedelta(days=7) accts = dbapi.db_session.query(NAccountStat).filter( NAccountStat.date >= start, NAccountStat.date <= end) temp = jinja_env.get_template('invoice/entrega_de_cuenta_list.html') return temp.render(accts=accts, start=start, end=end) def render_form_with_msg(path, title): msg = request.query.msg temp = jinja_env.get_template(path) return temp.render(msg=msg, title=title) @w.get('/app/crear_cuenta_form') @dbcontext @auth_decorator def create_cuenta(): return render_form_with_msg('invoice/crear_banco_form.html', title='Crear Cuenta') @w.get('/app/crear_banco_form') @dbcontext @auth_decorator def create_bank(): return render_form_with_msg('invoice/crear_banco_form.html', title='Crear Banco') @w.post('/app/crear_banco_form') @dbcontext @auth_decorator def post_create_bank(): name = request.forms.name bank = Bank(nombre=name) dbapi.create(bank) redirect('/app/crear_banco_form?msg=Cuenta+Creada') @w.post('/app/crear_cuenta_form') @dbcontext @auth_decorator def post_create_cuenta(): name = request.forms.name acc = DepositAccount(nombre=name) dbapi.create(acc) redirect('/app/crear_banco_form?msg=Cuenta+Creada') @w.post('/app/guardar_cheque_deposito') @dbcontext @auth_decorator def post_guardar_cheque_deposito(): nexturl = request.forms.get('next', '/app') for key, value in request.forms.items(): print key, value if key.startswith('acct-'): key = key.replace('acct-', '') print key, value dbapi.db_session.query(NCheck).filter_by(uid=key).update( {NCheck.deposit_account: value}) dbapi.db_session.flush() redirect(nexturl) @w.get('/app/ver_cheque/<cid>') @dbcontext @auth_decorator def ver_cheque(cid): check = paymentapi.get_check(cid) if check.imgcheck: _, check.imgcheck = os.path.split(check.imgcheck) if check.imgdeposit: _, check.imgdeposit = os.path.split(check.imgdeposit) temp = jinja_env.get_template('invoice/ver_cheque.html') comments = list( dbapi.db_session.query(NComment).filter_by(objtype=ObjType.CHECK, objid=str(cid))) return temp.render(check=check, comments=comments) @w.post('/app/postregar_cheque') @dbcontext @auth_decorator def postregar_cheque(): checkid = request.forms.checkid new_date = parse_iso(request.forms.new_date).date() session = dbapi.db_session check = session.query(NCheck).filter_by(uid=checkid).first() comment = NComment( timestamp=datetime.datetime.now(), user_id=get_user(request)['username'], comment='Cheque postponer desde {} hasta {}'.format( check.checkdate.isoformat(), new_date.isoformat()), objtype=ObjType.CHECK, objid=str(checkid), ) session.add(comment) check.checkdate = new_date session.flush() redirect('/app/ver_cheque/{}'.format(checkid)) @w.post('/app/save_check_img/<imgtype>/<cid>') @dbcontext @auth_decorator def save_check_image(cid, imgtype): upload = request.files.get('imgcheck') _, ext = os.path.splitext(upload.raw_filename) filename = uuid.uuid1().hex + ext filename = imagefiles.make_fullpath(filename) if save_check_image.image is None: try: from PIL import Image save_check_image.image = Image except ImportError: return 'Image module not installed' im = save_check_image.image.open(upload.file) if im.size[0] > 1024: im.resize((1024, 768)) im.save(filename) if imgtype == 'deposit': row = NCheck.imgdeposit newstatus = 'DEPOSITADO' else: row = NCheck.imgcheck newstatus = 'RECIBIDO' dbapi.db_session.query(NCheck).filter_by(uid=cid).update({ row: filename, NCheck.status: newstatus }) redirect('/app/ver_cheque/{}'.format(cid)) save_check_image.image = None @w.get('/app/imgcheck/<cid>') @dbcontext @auth_decorator def check_image_get(cid): check = paymentapi.get(cid) return static_file(check.imgcheck, root='.') @w.get('/app/guardar_deposito') @dbcontext @auth_decorator def guardar_deposito(): msg = request.query.msg temp = jinja_env.get_template('invoice/save_deposito_form.html') return temp.render(cuentas=dbapi.search(DepositAccount), stores=dbapi.search(Store), msg=msg) @w.get('/app/guardar_cheque') @dbcontext @auth_decorator def save_check_form(): msg = request.query.msg temp = jinja_env.get_template('invoice/save_check_form.html') return temp.render(banks=dbapi.search(Bank), stores=dbapi.search(Store), msg=msg) def parse_payment_from_request(form, clazz, url): date = datetime.date.today() if request.forms.ingresado == 'ayer': date = date - datetime.timedelta(days=1) payment = clazz.deserialize(request.forms) payment.note_id, payment.client_id = extract_nota_and_client( dbapi, form, url) payment.value = int(Decimal(payment.value) * 100) payment.date = date return payment @w.post('/app/guardar_cheque') @dbcontext @auth_decorator def save_check(): check = parse_payment_from_request(request.forms, Check, '/app/guardar_cheque') check.checkdate = parse_iso(check.checkdate) paymentapi.save_check(check) redirect('/app/guardar_cheque?msg=Cheque+Guardado') @w.get('/app/ver_cheques_guardados') @dbcontext @auth_decorator def list_checks(): today = datetime.date.today() start, end = parse_start_end_date_with_default( request.query, today, today - datetime.timedelta(hours=12)) result = paymentapi.list_checks(paymentdate=(start, end)) temp = jinja_env.get_template('invoice/list_cheque.html') return temp.render(start=start, end=end, checks=result, title='Cheques Guardados', accounts=dbapi.search(DepositAccount), thisurl=request.url) @w.get('/app/ver_cheques_para_depositar') @dbcontext @auth_decorator def list_checks_deposit(): today = datetime.date.today() start, end = parse_start_end_date_with_default(request.query, today, today) if start.isoweekday() == 1: start = start - datetime.timedelta(days=2) result = paymentapi.list_checks(checkdate=(start, end)) temp = jinja_env.get_template('invoice/list_cheque.html') return temp.render(start=start, end=end, checks=result, title='Cheques para depositar', accounts=dbapi.search(Store), thisurl=request.url) @w.get('/app/ver_cheques_por_titular') @dbcontext @auth_decorator def ver_cheques_por_titular(): start, end = parse_start_end_date_with_default(request.query, None, None) titular = request.query.titular if titular: result = dbapi.db_session.query(NCheck).filter( NCheck.holder.contains(titular)) if start is not None: result = result.filter(NCheck.checkdate >= start) if end is not None: result = result.filter(NCheck.checkdate <= end) result = map(Check.from_db_instance, result) else: result = [] temp = jinja_env.get_template('invoice/list_cheque.html') return temp.render(start=start, end=end, checks=result, title='Cheques para depositar', accounts=dbapi.search(DepositAccount), thisurl=request.url, show_titular=True, titular=titular) @w.post('/app/guardar_deposito') @dbcontext @auth_decorator def post_guardar_deposito(): deposit = parse_payment_from_request(request.forms, Deposit, '/app/guardar_deposito') paymentapi.save_payment(deposit, PaymentFormat.DEPOSIT) redirect('/app/guardar_deposito?msg=Deposito+Guardado') @w.get('/app/guardar_abono') @dbcontext @auth_decorator def guardar_abono(): msg = request.query.msg temp = jinja_env.get_template('invoice/save_abono_form.html') return temp.render(stores=dbapi.search(Store), action='/app/guardar_abono', msg=msg, payment_type=PaymentFormat.CASH) @w.get('/app/guardar_retension') @dbcontext @auth_decorator def guardar_retension(): msg = request.query.msg temp = jinja_env.get_template('invoice/save_abono_form.html') return temp.render(stores=dbapi.search(Store), action='/app/guardar_abono', msg=msg, payment_type='retension') @w.post('/app/guardar_abono') @dbcontext @auth_decorator def post_guardar_abono(): payment = Payment() url = '/app/guardar_abono' payment_type = request.forms.payment_type if payment_type != PaymentFormat.CASH: url = '/app/guardar_retension' payment.note_id, payment.client_id = extract_nota_and_client( dbapi, request.forms, url) payment.value = int(Decimal(request.forms.value) * 100) payment.date = datetime.date.today() paymentapi.save_payment(payment, payment_type) url = '/app/guardar_abono?msg=Abono+Guardado' if payment_type != PaymentFormat.CASH: url = '/app/guardar_retension?msg=Retension+Guardado' redirect(url) @w.get('/app/guardar_gastos') @w.get('/app/guardar_gastos/<uid>') @dbcontext @auth_decorator def save_spent(msg='', uid=-1): spent = None if uid >= 0: spent = dbapi.db_session.query(NSpent).filter_by(uid=uid).first() if spent is None: msg = 'Gasto no encontrado' temp = jinja_env.get_template('invoice/guardar_gastos.html') return temp.render(msg=msg, spent=spent) @w.post('/app/guardar_gastos') @dbcontext @auth_decorator def post_save_spent(): uid = request.forms.get('uid') spent = None create = True if uid is not None: spent = dbapi.db_session.query(NSpent).filter_by(uid=uid).first() create = False if spent is None: redirect('/app/guardar_gastos/{}'.format(uid)) if spent is None: spent = NSpent() for x in ('seller', 'seller_ruc', 'invnumber', 'invdate', 'desc', 'total', 'tax', 'retension', 'paid_from_cashier', 'inputdate'): setattr(spent, x, request.forms.get(x)) spent.total = int(Decimal(spent.total) * 100) spent.tax = int(Decimal(spent.tax) * 100) spent.retension = int(Decimal(spent.retension) * 100) spent.paid_from_cashier = int(Decimal(spent.paid_from_cashier) * 100) spent.invdate = parse_iso(spent.invdate) spent.inputdate = parse_iso(spent.inputdate) if create: dbapi.db_session.add(spent) dbapi.db_session.commit() return save_spent('Gasto Guardado') @w.get('/app/ver_gastos') @dbcontext @auth_decorator def ver_gastos(): today = datetime.datetime.today() start, end = parse_start_end_date_with_default(request.query, today, today) all_spent = dbapi.db_session.query(NSpent).filter( NSpent.inputdate >= start, NSpent.inputdate <= end + datetime.timedelta(days=1)) temp = jinja_env.get_template('invoice/ver_gastos.html') return temp.render(start=start, end=end, all_spent=all_spent) class CustomerSell(object): def __init__(self): self.subtotal = 0 self.iva = 0 self.count = 0 self.total = 0 def group_by_customer(inv): result = defaultdict(CustomerSell) for i in inv: if i.client.codigo is None: i.client.codigo = 'NA' cliente_id = fix_id(i.client.codigo) if not i.discount: i.discount = 0 result[cliente_id].subtotal += (i.subtotal - i.discount) result[cliente_id].iva += i.tax result[cliente_id].total += i.total result[cliente_id].count += 1 return result @w.get('/app/accounting_form') @dbcontext def get_sells_xml_form(): temp = jinja_env.get_template('accounting/ats_form.html') stores = filter(lambda x: x.ruc, dbapi.search(Store)) return temp.render(stores=stores, title='ATS') class Meta(object): pass @w.get('/app/accounting.xml') @dbcontext def get_sells_xml(): start_date, end_date = parse_start_end_date(request.query) end_date = end_date + datetime.timedelta(days=1) - datetime.timedelta( seconds=1) form_type = request.query.get('form_type') ruc = request.query.get('alm') invs = invapi.search_metadata_by_date_range( start_date, end_date, other_filters={'almacen_ruc': ruc}) deleted, sold = split_records_binary( invs, lambda x: x.status == Status.DELETED) grouped = group_by_customer(sold) meta = Meta() meta.date = start_date meta.total = reduce(lambda acc, x: acc + x.subtotal, grouped.values(), 0) meta.almacen_ruc = ruc meta.almacen_name = [ x.nombre for x in dbapi.search(Store) if x.ruc == ruc ][0] temp = jinja_env.get_template('accounting/resumen_agrupado.html') if form_type == 'ats': temp = jinja_env.get_template('accounting/ats.xml') response.set_header('Content-disposition', 'attachment') response.set_header('Content-type', 'application/xml') return temp.render(vendidos=grouped, eliminados=deleted, meta=meta) @w.get('/app/img/<rest:path>') @dbcontext @auth_decorator def img(rest): if constants.ENV == 'test': return static_file(rest, root=constants.IMAGE_PATH) else: response.set_header('X-Accel-Redirect', '/image/{}'.format(rest)) response.set_header('Content-Type', '') def save_img_from_request(therequest): imgdata = therequest.files.get('img') objtype = therequest.forms.get('objtype') objid = therequest.forms.get('objid') do_replace = therequest.forms.get('replace') return imgserver.saveimg(objtype, objid, imgdata, do_replace) @w.post('/app/attachimg') @dbcontext @auth_decorator def post_img(): redirect_url = request.forms.get('redirect_url') save_img_from_request(request) redirect(redirect_url) @w.post('/app/api/attachimg') @dbcontext @auth_decorator def post_img(): img = save_img_from_request(request) url = imgserver.get_url_path(img.path) return {'url': url} return w
class terrariumWebserver(): app = Bottle() app.install(terrariumWebserverHeaders()) def __init__(self, terrariumEngine): self.__terrariumEngine = terrariumEngine self.__app = terrariumWebserver.app self.__config = self.__terrariumEngine.get_config('system') self.__caching_days = 30 terrariumWebserver.app.terrarium = self.__terrariumEngine # Load language gettext.translation('terrariumpi', 'locales/', languages=[ self.__terrariumEngine.config.get_language() ]).install(True) self.__translations = terrariumTranslations() self.__routes() # Custom HTTP authentication routine. This way there is an option to optional secure the hole web interface def __auth_basic2(self, check, required, realm="private", text="Access denied"): """ Callback decorator to require HTTP auth (basic). TODO: Add route(check_auth=...) parameter. """ def decorator(func): @functools.wraps(func) def wrapper(*a, **ka): user, password = request.auth or (None, None) if required or terrariumUtils.is_true( self.__terrariumEngine.config.get_system() ['always_authenticate']): if user is None or not check(user, password): err = HTTPError(401, text) err.add_header('WWW-Authenticate', 'Basic realm="%s"' % realm) return err return func(*a, **ka) return wrapper return decorator def __authenticate(self, required): return self.__auth_basic2(self.__terrariumEngine.authenticate, required, _('TerrariumPI') + ' ' + _('Authentication'), _('Authenticate to make any changes')) def __logout_authenticate(self, user, password): return True def __routes(self): self.__app.route('/', method="GET", callback=self.__render_page, apply=self.__authenticate(False)) self.__app.route('/<template_name:re:[^/]+\.html$>', method="GET", callback=self.__render_page, apply=self.__authenticate(False)) self.__app.route('/<filename:re:robots\.txt>', method="GET", callback=self.__static_file, apply=self.__authenticate(False)) self.__app.route( '/<root:re:(static|gentelella|webcam|audio|log)>/<filename:path>', method="GET", callback=self.__static_file, apply=self.__authenticate(False)) self.__app.route('/api/<path:path>', method=['GET'], callback=self.__get_api_call, apply=self.__authenticate(False)) self.__app.route('/api/switch/toggle/<switchid:path>', method=['POST'], callback=self.__toggle_switch, apply=self.__authenticate(True)) self.__app.route('/api/switch/state/<switchid:path>/<value:int>', method=['POST'], callback=self.__state_switch, apply=self.__authenticate(True)) self.__app.route( '/api/config/<path:re:(system|weather|switches|sensors|webcams|doors|audio|environment|profile)>', method=['PUT', 'POST', 'DELETE'], callback=self.__update_api_call, apply=self.__authenticate(True)) self.__app.route( '/api/audio/player/<action:re:(start|stop|volumeup|volumedown|mute|unmute)>', method=['POST'], callback=self.__player_commands, apply=self.__authenticate(True)) self.__app.route('/api/audio/file', method=['POST'], callback=self.__upload_audio_file, apply=self.__authenticate(True)) self.__app.route('/api/audio/file/<audiofileid:path>', method=['DELETE'], callback=self.__delete_audio_file, apply=self.__authenticate(True)) self.__app.route('/logout', method=['GET'], callback=self.__logout_url, apply=auth_basic( self.__logout_authenticate, _('TerrariumPI') + ' ' + _('Authentication'), _('Authenticate to make any changes'))) def __template_variables(self, template): variables = { 'lang': self.__terrariumEngine.config.get_language(), 'title': self.__config['title'], 'version': self.__config['version'], 'page_title': _(template.replace('_', ' ').capitalize()), 'temperature_indicator': self.__terrariumEngine.get_temperature_indicator(), 'distance_indicator': self.__terrariumEngine.get_distance_indicator(), 'translations': self.__translations, 'device': self.__terrariumEngine.device } if 'index' == template or 'profile' == template: variables['person_name'] = self.__terrariumEngine.get_profile_name( ) variables[ 'person_image'] = self.__terrariumEngine.get_profile_image() return variables def __render_page(self, template_name='index.html'): template_name = template_name[:-5] if not os.path.isfile('views/' + template_name + '.tpl'): template_name = '404' return template(template_name, **self.__template_variables(template_name)) def __static_file(self, filename, root='static'): if filename == 'js/terrariumpi.js': response.headers[ 'Content-Type'] = 'application/javascript; charset=UTF-8' response.headers['Expires'] = ( datetime.datetime.utcnow() + datetime.timedelta(days=self.__caching_days) ).strftime('%a, %d %b %Y %H:%M:%S GMT') return template(filename, template_lookup=[root]) staticfile = static_file(filename, root=root) if isinstance(staticfile, HTTPError): return staticfile if 'webcam' == root or 'log' == root: staticfile.add_header( 'Expires', datetime.datetime.utcnow().strftime( '%a, %d %b %Y %H:%M:%S GMT')) if 'log' == root: staticfile.add_header('Content-Type', 'text/text; charset=UTF-8') staticfile.add_header('Content-Disposition', 'Attachment;filename=' + filename) else: staticfile.add_header('Expires', (datetime.datetime.utcnow() + datetime.timedelta(days=self.__caching_days) ).strftime('%a, %d %b %Y %H:%M:%S GMT')) if staticfile.get_header('Last-Modified') is not None: staticfile.add_header( 'Etag', hashlib.md5( staticfile.get_header('Last-Modified')).hexdigest()) return staticfile def __player_commands(self, action): result = { 'ok': False, 'title': _('Error!'), 'message': _('Player command could ot be executed!') } if 'start' == action: self.__terrariumEngine.audio_player_start() elif 'stop' == action: self.__terrariumEngine.audio_player_stop() elif 'volumeup' == action: self.__terrariumEngine.audio_player_volume_up() result = { 'ok': True, 'title': _('OK!'), 'message': _('Player command executed!') } elif 'volumedown' == action: self.__terrariumEngine.audio_player_volume_down() result = { 'ok': True, 'title': _('OK!'), 'message': _('Player command executed!') } elif 'mute' == action: pass elif 'unmute' == action: pass return result def __upload_audio_file(self): result = { 'ok': False, 'title': _('Error!'), 'message': _('File is not uploaded!') } upload = request.files.get('file') try: upload.save(terrariumAudioPlayer.AUDIO_FOLDER) self.__terrariumEngine.reload_audio_files() result = { 'ok': True, 'title': _('Success!'), 'message': _('File \'%s\' is uploaded' % (upload.filename, )) } except IOError, message: result['message'] = _('Duplicate file \'%s\'' % (upload.filename, )) return result
def make_wsgi_api(dbapi, invapi, dbcontext, auth_decorator, paymentapi, imgserver): w = Bottle() @w.get('/app/api/sales') @dbcontext def get_sales(): """ start=<start>&end=<end> """ start_date, end_date = parse_start_end_date(request.query) if not end_date: end_date = datetime.date.today() end_date = end_date + datetime.timedelta(hours=23) query = dbapi.db_session.query(NNota.almacen_id, func.sum( NNota.total)).filter(NNota.timestamp >= start_date).filter( NNota.timestamp <= end_date).filter( NNota.status != Status.DELETED).group_by(NNota.almacen_id) result = [] for aid, total in query: result.append((aid, Decimal(total) / 100)) return json_dumps({'result': result}) @w.get('/app/api/payment') @dbcontext def get_all_payments(): start, end = parse_start_end_date(request.query) result = list(paymentapi.list_payments(start, end)) return json_dumps({'result': result}) @w.get('/app/api/gasto') @dbcontext def get_all_gastos(): day = parse_iso(request.query.get('date')) result = dbapi.search(Spent, inputdate=day) return json_dumps(result) @w.get('/app/api/account_transaction') @dbcontext def get_account_transactions_mult_days(): start, end = parse_start_end_date(request.query) result = get_transactions(dbapi, paymentapi, invapi, imgserver, start, end) return json_dumps(result) @w.get('/app/api/check') @dbcontext def get_checks(): save_date = request.query.get('save_date') save_date_end = request.query.get('save_date_end') deposit_date = request.query.get('deposit_date') deposit_date_end = request.query.get('deposit_date_end') if save_date: save_date = (save_date, save_date_end) if deposit_date: deposit_date = (deposit_date, deposit_date_end) checks = paymentapi.list_checks(save_date, deposit_date) for x in checks: x.imgdeposit = imgserver.get_url_path(x.imgdeposit) x.imgcheck = imgserver.get_url_path(x.imgcheck) x.value = Decimal(x.value) / 100 return json_dumps({'result': checks}) @w.post('/app/api/acct_transaction') @dbcontext def post_acct_transaction(): data = request.body.read() acct = AccountTransaction.deserialize(json.loads(data)) acct.input_timestamp = datetime.datetime.now() acct.deleted = False pkey = dbapi.create(acct) return {'pkey': pkey} @w.put('/app/api/acct_transaction/<uid>') @dbcontext def put_acct_transaction(uid): data = json.loads(request.body.read()) acct = AccountTransaction(uid=uid) count = dbapi.update(acct, data) return {'updated': count} @w.get('/app/api/noncash_sales_with_payments') @dbcontext @auth_decorator def ver_ventas_no_efectivos(): start, end = parse_start_end_date(request.query) end += datetime.timedelta(hours=23) sales = dbapi.db_session.query(NNota).filter( NNota.timestamp >= start).filter(NNota.timestamp <= end).filter( NNota.payment_format != PaymentFormat.CASH) sales = map(InvMetadata.from_db_instance, sales) payments = list(paymentapi.list_payments(start, end)) result = {} for x in sales: if x.client.codigo not in result: result[x.client.codigo] = {} result[x.client.codigo]['sales'] = [] result[x.client.codigo]['payments'] = [] result[x.client.codigo]['sales'].append(x) unused_payments = [] for x in payments: if x.client_id in result: result[x.client_id]['payments'].append(x) else: unused_payments.append(x) result['unused_payments'] = unused_payments return json_dumps({ 'unused_payments': unused_payments, 'sales': result.items() }) @w.get('/app/api/account_deposit_with_img') @dbcontext @auth_decorator def get_account_deposit_with_img(): today = datetime.datetime.today() thisyear = today - datetime.timedelta(days=365) turned_in = sorted(get_turned_in_cash(dbapi, thisyear, today, imgserver), key=lambda x: x.date, reverse=True) result = defaultdict(list) for x in turned_in: if getattr(x, 'img', None): if len(result['with_deposit']) < 10: result['with_deposit'].append(x) else: result['without_deposit'].append(x) return json_dumps(result) # account stat bind_dbapi_rest('/app/api/account_stat', dbapi, AccountStat, w) bind_dbapi_rest('/app/api/bank_account', dbapi, DepositAccount, w) bind_dbapi_rest('/app/api/account_deposit', dbapi, AccountTransaction, w) bind_dbapi_rest('/app/api/spent', dbapi, Spent, w, skips_method=('DELETE', )) @w.get('/app/api/pago/<uid>') @dbcontext def get_pago_with_id(uid): elm = dbapi.db_session.query(NPayment).filter_by(uid=uid).first() if elm is None: response.status = 404 return '' return json_dumps(Payment().merge_from(elm).serialize()) @w.delete('/app/api/pago/<uid>') @dbcontext def mark_pago_deleted(uid): success = dbapi.db_session.query(NPayment).filter_by(uid=uid).update( {'deleted': True}) dbapi.db_session.commit() return {'success': success > 0} @w.put('/app/api/pago/<uid>') @dbcontext def modify_payment(uid): data = json.loads(request.body.read()) success = dbapi.db_session.query(NPayment).filter_by( uid=uid).update(data) dbapi.db_session.commit() return {'success': success > 0} @w.delete('/app/api/spent/<uid>') @dbcontext def mark_pago_deleted(uid): spent = Spent(uid=uid) sucess = dbapi.update(spent, {'deleted': True}) dbapi.db_session.commit() return {'success': sucess > 0} return w
import api.controllers.notes as noteController from bottle import request, Bottle from api.middleware.cheack_auth import requiresAuth, jwt_token_from_header from api.middleware.corsUtil import enable_cors noteApp = Bottle() @noteApp.route('/', method=['OPTIONS', 'GET']) @enable_cors @requiresAuth def getAllNotes(*args): """ Route for getting all notes of a specific user. Require authentication """ userID = args[0]["userID"] notes = noteController.allNotes(userID) return notes @noteApp.route('/<noteID>', method=['OPTIONS', 'GET']) @enable_cors @requiresAuth def getNoteByID(*args, noteID): """ Route for getting a single note of a specific user. Require authentication """ userID = args[0]["userID"] note = noteController.singleNote(noteID, userID) return note
import doreah # technical import os import datetime import sys import unicodedata from collections import namedtuple from threading import Lock # url handling from importlib.machinery import SourceFileLoader import urllib dbserver = Bottle() dblock = Lock() #global database lock SCROBBLES = [] # Format: tuple(track_ref,timestamp,saved) ARTISTS = [] # Format: artist TRACKS = [] # Format: namedtuple(artists=frozenset(artist_ref,...),title=title) Track = namedtuple("Track",["artists","title"]) Scrobble = namedtuple("Scrobble",["track","timestamp","saved"]) ### OPTIMIZATION SCROBBLESDICT = {} # timestamps to scrobble mapping STAMPS = [] # sorted #STAMPS_SET = set() # as set for easier check if exists # we use the scrobbles dict for that now
def __init__(self, data_dir): self.data_dir = data_dir.rstrip("/") self.app = Bottle() self.setup_routes()
f"[{request_time}] {request.remote_addr} - {request.method} {request.fullpath}?{request.query_string} {response.status_code} - {duration * 1000:0.2f}ms") return actual_response return _timing_and_logger def record_request_stats(): """ Records stats for an http request in Redis """ try: app.config['translateapp.redis'].hincrby("requests_by_ip", request.remote_addr, 1) except redis.RedisError as redis_err: print(f"Error sending stats to Redis: {redis_err}") app: Bottle = Bottle() app.install(timing_and_logger) @app.route('/api/v1/translate') def translate() -> Dict[str, Union[str, List[str]]]: """ Translate a phrase from Orcish to English """ phrase: str = request.query.phrase or None response_body: Dict[str, Union[str, List[str]]] = {"phrase": phrase, "translation": None, "errors": []} if app.config.get('translateapp.redis'): record_request_stats() if not phrase: response.status = 400
from bottle import Bottle from app.api.return_api_messages import ReturnMessages from app.service.summoner_service import SummonerService summoner_api = Bottle() summoner_service = SummonerService() @summoner_api.get('/<summoner_name>') def get_summoner_info_by_name(summoner_name): result = summoner_service.get_summoner_by_name(summoner_name) return result if result.status_code == 200 else ReturnMessages.error_get_response( )
#!/usr/bin/env python # -*- coding: utf-8 -*- import json from bottle import Bottle, request from config.models import criadores from config.middleware import response_headers, enable_cors import time from tinydb import Query criador_view = Bottle() @criador_view.route('/traer/<criador_id>', method=['GET']) @response_headers @enable_cors def traer(criador_id): rpta = None try: Criador = Query() tmp = criadores.search(Criador.criador_id == int(criador_id)) return tmp[0] except TypeError: rpta = { 'tipo_mensaje': 'error', 'mensaje': [ 'Se ha producido un error en crear los comentarios del criador', str(e) ] } return json.dumps(rpta)
time = time.strftime("%d/%m/%Y %H:%M:%S" + "\n") # 设置id是为了方便后面提取,顺序或逆序也在其中 id = 'id' + str(count) record = {'time': time, 'record': newline} kv.set(id, record) # 读取数据库中的信息 def printhistory(): notelist = [] for item in kv.get_by_prefix('id'): notelist.append(item[1]) return notelist app = Bottle() @app.route('/') def home(): return ''' <form action="/index" method="POST"> <br/> Please input a new line: <br/> <input name="newline" type="text"/> <br/> <input value="save" type="submit" /> </form>'''
from bottle import Bottle, request, abort from models.movie import Movie, Base recommendation_app = Bottle() @recommendation_app.post('/recommendation') def recommendation(): cursor_about = request.json.get("cursorAbout") user_matrix = request.json.get("userMatrix", {}) selection = request.json.get('selection', []) clean_selection = [int(uid) for uid in selection] results = Movie.related_base(cursor_about, clean_selection) scoring = {} for index, row in enumerate(results): movie = Movie.inflate(row[0]) bases = [Base.inflate(b).name for b in row[1]] content = { 'title': movie.title, 'score': 0, 'relations': [], 'data': movie.serialize } for key, value in user_matrix.items(): if key in bases: