# coding: utf-8
# +-------------------------------------------------------------------
# | 宝塔Windows面板
# +-------------------------------------------------------------------
# | Copyright (c) 2015-2016 宝塔软件(http://www.bt.cn) All rights reserved.
# +-------------------------------------------------------------------
# | Author: 沐落 <cjx@bt.cn>
# +-------------------------------------------------------------------

import sys, os

if not "/class/" in sys.path:
    sys.path.insert(0, "/class/")
import db, public, re
import json


class data:
    __ERROR_COUNT = 0
    # 自定义排序字段
    __SORT_DATA = ['site_ssl', 'php_version', 'backup_count']
    '''
     * 设置备注信息
     * @param String _GET['tab'] 数据库表名
     * @param String _GET['id'] 条件ID
     * @return Bool
    '''
    
    def setPs(self, get):
        if not hasattr(get, 'id'):
            return public.returnMsg(False, '缺少必要参数网站ID，请重新操作.');
        
        id = get.id
        if public.M(get.table).where("id=?", (id,)).setField('ps', get.ps):
            return public.returnMsg(True, 'EDIT_SUCCESS');
        return public.returnMsg(False, 'EDIT_ERROR')
    
    # 删除搜索记录
    def remove_search_history(self, get):
        table = get.table
        search_key = get.search_key
        search = get.search
        p_file = public.get_panel_path()
        d_file = p_file + '/data/search.json'
        result = {}
        try:
            result = json.loads(public.readFile(d_file))
        except:
            pass
        if result:
            if table in result:
                if search_key in result[table]:
                    for i in result[table][search_key]:
                        if i['val'] == search:
                            result[table][search_key].remove(i)
                            public.writeFile(d_file, json.dumps(result))
                            break
        return public.returnMsg(True, '')
    
    def remove_all_search_history(self, get):
        table = get.table
        search_key = get.search_key
        p_file = public.get_panel_path()
        d_file = p_file + '/data/search.json'
        result = {}
        try:
            result = json.loads(public.readFile(d_file))
        except:
            pass
        if result:
            if table in result:
                if search_key in result[table]:
                    result[table][search_key] = []
                    public.writeFile(d_file, json.dumps(result))
        return public.returnMsg(True, '')
    
    
    # 端口扫描
    def CheckPort(self, port):
        import socket
        localIP = '127.0.0.1'
        temp = {}
        temp['port'] = int(port)
        temp['local'] = True
        try:
            s = socket.socket()
            s.settimeout(0.01)
            s.connect((localIP, temp['port']))
            s.close()
        except:
            temp['local'] = False
        
        result = 0
        if temp['local']: result += 2
        return result
    
    '''
     * 取数据列表
     * @param String _GET['tab'] 数据库表名
     * @param Int _GET['count'] 每页的数据行数
     * @param Int _GET['p'] 分页号  要取第几页数据
     * @return Json  page.分页数 , count.总行数   data.取回的数据
    '''
    
    def getData(self, get):
        
        table = get.table;
        if table == 'databases':
            public.M('databases').execute("alter TABLE databases add type TEXT DEFAULT MySQL", ());
        elif table == 'sites':
            public.M('sites').execute("alter TABLE sites add type TEXT DEFAULT PHP", ());
        
        data = self.GetSql(get)
        SQL = public.M(table)
        if table == 'backup':
            import os
            for i in range(len(data['data'])):
                if data['data'][i]['size'] == 0:
                    if os.path.exists(data['data'][i]['filename']): data['data'][i]['size'] = os.path.getsize(data['data'][i]['filename'])
        
        elif table == 'sites' or table == 'databases':
            ttype = '0'
            if table == 'databases': ttype = '1'
            for sdata in data['data']:
                sdata['backup_count'] = SQL.table('backup').where("pid=? AND type=?", (sdata['id'], ttype)).count()
                if table == 'databases': sdata['conn_config'] = json.loads(sdata['conn_config'])
            
            if table == 'sites':
                import panelSite
                siteObj = panelSite.panelSite()
                webType = public.get_webserver()
                for site in data['data']:
                    site['domain'] = SQL.table('domain').where("pid=?", (site['id'],)).count()
                    
                    if site['type'] == 'PHP' and len(site['type_version']) == 0:
                        site['type_version'] = siteObj.get_site_stype(site['name'], site['type'])
                        if site['type_version'] != -1:
                            public.M('sites').where('id=?', (site['id'],)).setField('type_version', site['type_version']);
                    site['ssl'] = ""
                    
                    if webType in ['nginx', 'apache']:
                        site['ssl'] = self.get_site_ssl_info(webType, site['name'])
        
        elif table == 'firewall':
            for i in range(len(data['data'])):
                if data['data'][i]['port'].find(':') != -1 or data['data'][i]['port'].find('.') != -1 or data['data'][i]['port'].find('-') != -1:
                    data['data'][i]['status'] = -1
                else:
                    data['data'][i]['status'] = self.CheckPort(data['data'][i]['port']);
        # 返回
        return self.get_sort_data(data)
    
    def get_site_ssl_info(self, webType, siteName):
        """
        获取SSL详细信息
        """
        setup_path = os.getenv("BT_SETUP")
        if webType == 'apache':
            path = setup_path + '/apache/conf/ssl/' + siteName
            if not os.path.exists(path): os.makedirs(path)
            
            file = '{}/apache/conf/vhost/{}.conf'.format(setup_path, siteName)
            conf = public.readFile(file)
            if conf:
                if conf.find('SSLCertificateFile') >= 0:
                    certPath = path + "/fullchain.pem"
                    if os.path.exists(certPath):
                        cert_data = public.get_cert_data(certPath)
                        return cert_data
        elif webType == 'nginx':
            
            path = setup_path + '/nginx/conf/ssl/' + siteName
            if not os.path.exists(path): os.makedirs(path)
            
            file = '{}/nginx/conf/vhost/{}.conf'.format(setup_path, siteName)
            conf = public.readFile(file)
            if conf:
                if conf.find('ssl_certificate') >= 0:
                    certPath = path + "/fullchain.pem"
                    if os.path.exists(certPath):
                        cert_data = public.get_cert_data(certPath)
                        return cert_data
        return -1
    
    '''
     * 取数据库行
     * @param String _GET['tab'] 数据库表名
     * @param Int _GET['id'] 索引ID
     * @return Json
    '''
    
    def getFind(self, get):
        tableName = get.table
        id = get.id
        field = self.GetField(get.table)
        SQL = public.M(tableName)
        where = "id=?"
        find = SQL.where(where, (id,)).field(field).find()
        return find
    
    '''
     * 取字段值
     * @param String _GET['tab'] 数据库表名
     * @param String _GET['key'] 字段
     * @param String _GET['id'] 条件ID
     * @return String
    '''
    
    def getKey(self, get):
        tableName = get.table
        keyName = get.key
        id = get.id
        SQL = db.Sql().table(tableName)
        where = "id=?"
        retuls = SQL.where(where, (id,)).getField(keyName);
        return retuls
    
    '''
     * 获取数据与分页
     * @param string table 表
     * @param string where 查询条件
     * @param int limit 每页行数
     * @param mixed result 定义分页数据结构
     * @return array
    '''
    
    def GetSql(self, get, result='1,2,3,4,5,8'):
        # 判断前端是否传入参数
        order = "id desc"
        if hasattr(get, 'order'):
            order = get.order
        
        limit = 20
        if hasattr(get, 'limit'):
            limit = int(get.limit)
        
        if hasattr(get, 'result'):
            result = get.result
        
        search_key = 'get_list'
        SQL = db.Sql()
        data = {}
        # 取查询条件
        where = ''
        search = ''
        if hasattr(get, 'search'):
            search = get.search
            
            where = self.GetWhere(get.table, get.search)
            if get.table == 'backup':
                where += " and type='" + get.type + "'"
            
            if get.table == 'sites' and get.search:
                pid = SQL.table('domain').where("name LIKE '%" + get.search + "%'", ()).getField('pid')
                if pid:
                    if where:
                        where += " or id=" + str(pid)
                    else:
                        where += "id=" + str(pid)
        
        if get.table == 'sites':
            search_key = 'php'
            if where:
                where = "({}) AND project_type='PHP'".format(where)
            else:
                where = "project_type='PHP'"
            
            if hasattr(get, 'type'):
                if get.type != '-1':
                    where += " AND type_id={}".format(get.type)
        
        if get.table == 'databases':
            if hasattr(get, 'db_type'):
                if where:
                    where += " AND db_type='{}'".format(get.db_type)
                else:
                    where = "db_type='{}'".format(get.db_type)
            if hasattr(get, 'sid'):
                if where:
                    where += " AND sid='{}'".format(get.sid)
                else:
                    where = "sid='{}'".format(get.sid)
        
        public.set_search_history(get.table, search_key, search)  # 记录搜索历史
        
        field = self.GetField(get.table)
        # 实例化数据库对象
        
        # 是否直接返回所有列表
        if hasattr(get, 'list'):
            data = SQL.table(get.table).where(where, ()).field(field).order(order).select()
            return data
        
        # 取总行数
        count = SQL.table(get.table).where(where, ()).count();
        # get.uri = get
        # 包含分页类
        import page
        # 实例化分页类
        page = page.Page()
        
        info = {}
        info['count'] = count
        info['row'] = limit
        
        info['p'] = 1
        if hasattr(get, 'p'):
            info['p'] = int(get['p'])
        info['uri'] = get
        info['return_js'] = ''
        if hasattr(get, 'tojs'):
            info['return_js'] = get.tojs
        
        data['where'] = where
        data['page'] = page.GetPage(info, result)  # 获取分页数据
        o_list = order.split(' ')
        if o_list[0] in self.__SORT_DATA:
            data['data'] = SQL.table(get.table).where(where, ()).field(field).select()
            data['plist'] = {'shift': page.SHIFT, 'row': page.ROW * info['p'], 'order': order}
        else:
            data['data'] = SQL.table(get.table).where(where, ()).order(order).field(field).limit(str(page.SHIFT) + ',' + str(page.ROW)).select()  # 取出数据
        data['search_history'] = public.get_search_history(get.table, search_key)
        return data
    
    def get_sort_data(self, data):
        """
        @获取自定义排序数据
        @param data: 数据
        """
        if 'plist' in data:
            plist = data['plist']
            o_list = plist['order'].split(' ')
            
            reverse = False
            sort_key = o_list[0].strip()
            
            if o_list[1].strip() == 'desc':
                reverse = True
            
            if sort_key in ['site_ssl']:
                for info in data['data']:
                    if type(info['ssl']) == int:
                        info[sort_key] = info['ssl']
                    else:
                        try:
                            info[sort_key] = info['ssl']['endtime']
                        except:
                            info[sort_key] = ''
            data['data'] = sorted(data['data'], key=lambda x: x[sort_key], reverse=reverse)
            data['data'] = data['data'][plist['shift']: plist['row']]
        return data
    
    # 获取条件
    def GetWhere(self, tableName, search):
        if not search: return ""
        
        if type(search) == bytes: search = search.encode('utf-8').strip()
        try:
            search = re.search(r"[\w\x80-\xff\.]+", search).group()
        except:
            pass
        
        wheres = {
            'sites': "name like '%" + search + "%' or ps like '%" + search + "%'",
            'ftps': "name like '%" + search + "%' or ps like '%" + search + "%'",
            'databases': "(name like '%" + search + "%' or ps like '%" + search + "%')",
            'logs': "type like '%" + search + "%' or log like '%" + search + "%'",
            'backup': "pid=" + search + "",
            'users': "id='" + search + "' or username='" + search + "'",
            'domain': "pid='" + search + "' or name='" + search + "'",
            'tasks': "status='" + search + "' or type='" + search + "'",
            'crontab': "name like '%" + search + "%' or sBody like '%" + search + "%'"
        }
        try:
            return wheres[tableName]
        except:
            return ''
    
    def GetField(self, tableName):
        fields = {
            'sites': "id,name,path,status,ps,addtime,edate,type,type_version",
            'ftps': "id,pid,name,password,status,ps,addtime,path",
            'databases': "id,sid,pid,name,username,password,accept,ps,addtime,type,db_type,conn_config",
            'logs': "id,uid,username,type,log,addtime",
            'backup': "id,pid,name,filename,addtime,size",
            'users': "id,username,phone,email,login_ip,login_time",
            'firewall': "id,port,ps,addtime",
            'domain': "id,pid,name,port,addtime",
            'tasks': "id,name,type,status,addtime,start,end"
        }
        try:
            return fields[tableName]
        except:
            return ''
