| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558 | import timeimport pytzimport jsonfrom datetime import datetimefrom datetime import time as Timefrom Model.models import AppAdvertiseCampaign, DeviceTypeModel, CountryModel, Device_User, OpenScreenCampaignfrom Ansjer.config import AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, SERVER_TYPEfrom django.core.paginator import Paginatorfrom django.views import Viewfrom django.db.models import Prefetchfrom django.db.models import Q, Ffrom Object.AWS.AmazonS3Util import AmazonS3Utilfrom Object.ResponseObject import ResponseObjectfrom Object.TokenObject import TokenObjectclass AppCampaignView(View):    def get(self, request, *args, **kwargs):        request.encoding = 'utf-8'        operation = kwargs.get('operation')        request_dict = request.GET        return self.validation(request_dict, request, operation)    def post(self, request, *args, **kwargs):        request.encoding = 'utf-8'        operation = kwargs.get('operation')        request_dict = request.POST        return self.validation(request_dict, request, operation)    def validation(self, request_dict, request, operation):        language = request_dict.get('language', 'en')        response = ResponseObject(language, 'pc')        if operation == 'getCampaignList':  # 获取广告活动列表            return self.get_campaign_list(request_dict, response)        elif operation == 'getCountryList':  # 查询国家列表            return self.get_country_list(response)        elif operation == 'addCampaign':  # 添加广告活动            return self.add_campaign(request, request_dict, response)        elif operation == 'updateCampaign':  # 更新广告活动            return self.update_campaign(request, request_dict, response)        elif operation == 'deleteCampaign':  # 删除广告活动            return self.delete_campaign(request_dict, response)        elif operation == 'switchCampaign':  # 广告活动开关            return self.switch_campaign(request_dict, response)        elif operation == 'appGetCampaigns':            return self.app_get_campaigns(request_dict)        elif operation == 'recordUserBehavior':            return self.record_user_behavior(request_dict)        elif operation == 'getUserBehaviorLog':            return self.get_user_behavior_log(request_dict, response)        else:            return response.json(414)    def get_campaign_list(self, request_dict, response):        """        查询广告活动列表        @param request_dict: 请求参数        @param response: 响应对象        @return: 响应对象包含广告活动列表        """        campaign_name = request_dict.get('campaign_name', None)        campaign_country = request_dict.get('campaign_country', None)        status = request_dict.get('status', None)        pageNo = request_dict.get('pageNo', 1)        pageSize = request_dict.get('pageSize', 20)        unknown_country = 0        # 连接并获取国家和设备类型        country_prefetch = Prefetch('country', queryset=CountryModel.objects.only('country_name'),                                    to_attr='country_list')        device_type_prefetch = Prefetch('device_type', queryset=DeviceTypeModel.objects.only('name'),                                        to_attr='device_type_list')        app_advertise_campaign_qs = AppAdvertiseCampaign.objects.prefetch_related(country_prefetch,                                                                                  device_type_prefetch)        # 过滤        if campaign_name:            app_advertise_campaign_qs = app_advertise_campaign_qs.filter(campaign_name=campaign_name)        if status:            app_advertise_campaign_qs = app_advertise_campaign_qs.filter(status=status)        if campaign_country:            campaign_country_list = campaign_country.split(',')            if "未知地区" in campaign_country_list:                unknown_country = 1            app_advertise_campaign_qs = app_advertise_campaign_qs.filter(                Q(country__country_name__in=campaign_country_list) | Q(unknown_country=unknown_country)).distinct()        app_advertise_campaign_qs = app_advertise_campaign_qs.filter(~Q(status=2))        # 分页        paginator = Paginator(app_advertise_campaign_qs.order_by('id'), pageSize)        campaigns = paginator.page(pageNo)        if SERVER_TYPE == 'Ansjer.cn_config.formal_settings' or SERVER_TYPE == 'Ansjer.cn_config.test_settings':            s3_url = "https://ansjerfilemanager.s3.cn-northwest-1.amazonaws.com.cn/app/campaign/"        else:            s3_url = "https://ansjerfilemanager.s3.amazonaws.com/app/campaign/"        # 添加设备名和地区返回        campaign_list = []        for campaign in campaigns.object_list:            if campaign.unknown_country == 0:                countries = ",".join([country.country_name for country in campaign.country_list])            else:                country_list = campaign.country_list                country_names = []                for country in country_list:                    country_names.append(country.country_name)                country_names.append("未知地区")                countries = ",".join(country_names)            campaign_data = {                'id': campaign.id,                'image_url': s3_url + campaign.image_url,                'campaign_name': campaign.campaign_name,                'campaign_url': campaign.campaign_url,                'campaign_type': campaign.campaign_type,                'status': campaign.status,                'campaign_start_date': campaign.campaign_start_date,                'campaign_end_date': campaign.campaign_end_date,                'campaign_show_stime': campaign.campaign_show_stime,                'campaign_show_etime': campaign.campaign_show_etime,                'countries': countries,                'device_types': ",".join([device.name for device in campaign.device_type_list]),            }            campaign_list.append(campaign_data)        data = {            'list': campaign_list,            'total': paginator.count,        }        return response.json(0, data)    def add_campaign(self, request, request_dict, response):        """        添加新的广告活动        @param request_dict: 包含所有请求参数的字典        @param response: 响应对象        @return: 响应对象        """        file = request.FILES.get('posterFile', None)        campaign_name = request_dict.get('campaign_name', None)        campaign_url = request_dict.get('campaign_url', None)        campaign_type = request_dict.get('campaign_type', None)        status = request_dict.get('status', None)        device_type_names = json.loads(request_dict.get('device_type_list', None))  # 设备类型名称列表        country_name_list = json.loads(request_dict.get('country_name_list', None))  # 地区列表        campaign_start_time = request_dict.get('campaign_start_time', None)        campaign_end_time = request_dict.get('campaign_end_time', None)        campaign_show_stime = request_dict.get('campaign_show_stime', 0)        campaign_show_etime = request_dict.get('campaign_show_etime', 86399)        if not all([campaign_name, campaign_type, device_type_names, campaign_url,                    country_name_list, campaign_start_time, campaign_end_time, file]):            return response.json(444)        # 针对特殊地区的处理,表没设计好用这个处理挽救一下        unknown_country = 0        if "未知地区" in country_name_list:            unknown_country = 1            country_name_list.remove("未知地区")        if SERVER_TYPE == 'Ansjer.cn_config.formal_settings' or SERVER_TYPE == 'Ansjer.cn_config.test_settings':            regin = 0            AWS_SES_ACCESS_REGION = "cn-northwest-1"        else:            regin = 1            AWS_SES_ACCESS_REGION = 'us-east-1'        fileName = file.name        try:            create_time = int(time.time())            update_time = int(time.time())            # 保存图片到存储桶            bucket_name = 'ansjerfilemanager'            file_key = f'app/campaign/OpenScreenAdvertise/{update_time}_{fileName}'            s3 = AmazonS3Util(AWS_ACCESS_KEY_ID[regin], AWS_SECRET_ACCESS_KEY[regin], AWS_SES_ACCESS_REGION)            # 地址:https://ansjerfilemanager.s3.amazonaws.com/app/campaign/OpenScreenAdvertise/XXX.jpg            s3.upload_file_obj(                bucket_name,                file_key,                file,                {'ContentType': file.content_type, 'ACL': 'public-read'})            # 创建 AppAdvertiseCampaign 实例            new_campaign = AppAdvertiseCampaign.objects.create(                image_url=f"OpenScreenAdvertise/{update_time}_{fileName}",                campaign_name=campaign_name,                campaign_url=campaign_url,                campaign_type=campaign_type,                status=status,                unknown_country=unknown_country,                campaign_start_date=campaign_start_time,                campaign_end_date=campaign_end_time,                campaign_show_stime=campaign_show_stime,                campaign_show_etime=campaign_show_etime,                create_time=create_time,                update_time=update_time,            )            # 根据名称查找 DeviceTypeModel 的实例并建立关系            device_type_instances = DeviceTypeModel.objects.filter(name__in=device_type_names)            for device_type_instance in device_type_instances:                new_campaign.device_type.add(device_type_instance)            # 根据 ID 关联 CountryModel 实例            country_instances = CountryModel.objects.filter(country_name__in=country_name_list)            for country_instance in country_instances:                new_campaign.country.add(country_instance)        except Exception as e:            return response.json(178)        return response.json(0)    def update_campaign(self, request, request_dict, response):        campaign_id = request_dict.get('id', None)        campaign_name = request_dict.get('campaign_name', None)        campaign_url = request_dict.get('campaign_url', None)        campaign_type = request_dict.get('campaign_type', None)        device_type_names = json.loads(request_dict.get('device_type_list', '[]'))  # 设备类型名称列表        country_name_list = json.loads(request_dict.get('country_name_list', '[]'))  # 地区列表        campaign_start_time = request_dict.get('campaign_start_time', None)        campaign_end_time = request_dict.get('campaign_end_time', None)        campaign_show_stime = request_dict.get('campaign_show_stime', None)        campaign_show_etime = request_dict.get('campaign_show_etime', None)        file = request.FILES.get('posterFile', None)        if not campaign_id:            return response.json(444)        if SERVER_TYPE == 'Ansjer.cn_config.formal_settings' or SERVER_TYPE == 'Ansjer.cn_config.test_settings':            regin = 0            AWS_SES_ACCESS_REGION = "cn-northwest-1"        else:            regin = 1            AWS_SES_ACCESS_REGION = 'us-east-1'        try:            update_time = int(time.time())            campaign = AppAdvertiseCampaign.objects.get(id=campaign_id)            if country_name_list is not None:                if "未知地区" in country_name_list:                    campaign.unknown_country = 1                    country_name_list.remove("未知地区")                else:                    campaign.unknown_country = 0            if file is not None:                # 删除存储桶原来的图片                s3 = AmazonS3Util(AWS_ACCESS_KEY_ID[regin], AWS_SECRET_ACCESS_KEY[regin], AWS_SES_ACCESS_REGION)                bucket_name = 'ansjerfilemanager'                if campaign.image_url:                    s3.delete_obj(bucket_name, f"app/campaign/{campaign.image_url}")                # 添加新的图片                file_key = f'app/campaign/OpenScreenAdvertise/{update_time}_{file.name}'                s3.upload_file_obj(                    bucket_name,                    file_key,                    file,                    {'ContentType': file.content_type, 'ACL': 'public-read'}                )                campaign.image_url = f'OpenScreenAdvertise/{update_time}_{file.name}'            if campaign_name is not None:                campaign.campaign_name = campaign_name            if campaign_url is not None:                campaign.campaign_url = campaign_url            if campaign_type is not None:                campaign.campaign_type = campaign_type            if campaign_start_time is not None:                campaign.campaign_start_date = campaign_start_time            if campaign_end_time is not None:                campaign.campaign_end_date = campaign_end_time            if campaign_show_stime is not None:                campaign.campaign_show_stime = campaign_show_stime            if campaign_show_etime is not None:                campaign.campaign_show_etime = campaign_show_etime            # 更新多对多字段 - 设备类型            if device_type_names:                device_types = DeviceTypeModel.objects.filter(name__in=device_type_names)                campaign.device_type.set(device_types)            # 更新多对多字段 - 国家/地区            if country_name_list:                countries = CountryModel.objects.filter(country_name__in=country_name_list)                campaign.country.set(countries)            campaign.update_time = update_time            # 保存更新            campaign.save()        except Exception as e:            return response.json(177)        return response.json(0)    def switch_campaign(self, request_dict, response):        campaign_id = request_dict.get('id')        status = request_dict.get('status')        if not campaign_id:            return response.json(444)        try:            AppAdvertiseCampaign.objects.filter(pk=campaign_id).update(status=status, update_time=int(time.time()))            return response.json(0)        except Exception as e:            return response.json(444)    def delete_campaign(self, request_dict, response):        campaign_id = request_dict.get('id')        if SERVER_TYPE == 'Ansjer.cn_config.formal_settings' or SERVER_TYPE == 'Ansjer.cn_config.test_settings':            regin = 0            AWS_SES_ACCESS_REGION = "cn-northwest-1"        else:            regin = 1            AWS_SES_ACCESS_REGION = 'us-east-1'        if not campaign_id:            return response.json(444)        try:            campaign = AppAdvertiseCampaign.objects.get(pk=campaign_id)            s3 = AmazonS3Util(AWS_ACCESS_KEY_ID[regin], AWS_SECRET_ACCESS_KEY[regin], AWS_SES_ACCESS_REGION)            bucket_name = 'ansjerfilemanager'            if campaign.image_url:                s3.delete_obj(bucket_name, f"app/campaign/{campaign.image_url}")            # 清除多对多关系            campaign.device_type.clear()            campaign.country.clear()            # 保留在广告表中            campaign.status = 2            campaign.update_time = int(time.time())            campaign.save()            return response.json(0)        except Exception as e:            return response.json(176)    def get_timezone_offset(self, tz):        """        将 "+8:00" 格式的时区字符串转换为包含分钟偏移的时区。        """        sign = tz[0]  # " " 或 "-"        hours, minutes = map(int, tz[1:].split('.'))  # 分离小时和分钟        # 计算总分钟数        total_minutes = hours * 60 + minutes        if sign == '-':            total_minutes = -total_minutes        # 使用 pytz.FixedOffset 创建时区        return pytz.FixedOffset(total_minutes)    def app_get_campaigns(cls, request_dict):        """        APP获取广告活动列表        @param request_dict: 请求参数        @param response: 响应对象        @return: 响应对象        """        language = request_dict.get('language', 'en')        tz = request_dict.get('tz', '+0:00')        token = request_dict.get('token', None)        response = ResponseObject(language)        if not token:            return response.json(444)        token = TokenObject(token)        if token.code != 0:            return response.json(token.code)        user_id = token.userID        if SERVER_TYPE == 'Ansjer.cn_config.formal_settings' or SERVER_TYPE == 'Ansjer.cn_config.test_settings':            s3_url = "https://ansjerfilemanager.s3.cn-northwest-1.amazonaws.com.cn/app/campaign/"        else:            s3_url = "https://ansjerfilemanager.s3.amazonaws.com/app/campaign/"        # 当日时间戳区间获取        timezone = cls.get_timezone_offset(tz)        current_date = datetime.now().date()        start_of_day = datetime.combine(current_date, Time.min)        end_of_day = datetime.combine(current_date, Time.max)        start_timestamp = int(start_of_day.timestamp())        end_timestamp = int(end_of_day.timestamp())        open_screen_campaign_qs = OpenScreenCampaign.objects.filter(            user_id=user_id,            create_time__gt=start_timestamp,            create_time__lt=end_timestamp        )        if not open_screen_campaign_qs.exists():            OpenScreenCampaign.objects.create(user_id=user_id,                                              update_time=int(time.time()),                                              create_time=int(time.time()))        try:            country_prefetch = Prefetch('country', queryset=CountryModel.objects.only('id'), to_attr='country_list')            device_type_prefetch = Prefetch('device_type', queryset=DeviceTypeModel.objects.only('type'),                                            to_attr='device_type_list')            app_advertise_campaign_qs = AppAdvertiseCampaign.objects.prefetch_related(country_prefetch,                                                                                      device_type_prefetch)            device_info_qs = Device_User.objects.filter(userID=user_id).values("region_country").first()            country_id = device_info_qs.get('region_country')            if country_id != 0:                app_advertise_campaign_qs = app_advertise_campaign_qs.filter(country__id=country_id, status=1)            else:                app_advertise_campaign_qs = app_advertise_campaign_qs.filter(status=1, unknown_country=1)            # 返回 广告名称、广告类型、开始时间、结束时间、广告图片、活动链接            campaigns_list = []            for campaign in app_advertise_campaign_qs:                # campaign_end_date = (datetime.utcfromtimestamp(campaign.campaign_end_date) # 日期版本                #                      .replace(tzinfo=pytz.utc).astimezone(timezone).strftime('%Y-%m-%d'))                # 日期范围                campaigns_start_date = datetime.fromtimestamp(campaign.campaign_start_date, pytz.utc).astimezone(                    timezone).replace(hour=0, minute=0, second=0, microsecond=0).timestamp()  # 时间戳版本                campaign_end_date = datetime.fromtimestamp(campaign.campaign_end_date, pytz.utc).astimezone(                    timezone).replace(hour=0, minute=0, second=0, microsecond=0).timestamp()  # 时间戳版本                # 时间范围                campaign_start_firstday = sum(int(x) * 60 ** i for i, x in enumerate(reversed(                    datetime.utcfromtimestamp(campaign.campaign_start_date + campaign.campaign_show_stime).replace(                        tzinfo=pytz.utc).astimezone(timezone).strftime('%H:%M').split(':')))) * 60  # 秒数版本                campaign_end_firstday = sum(int(x) * 60 ** i for i, x in enumerate(reversed(                    datetime.utcfromtimestamp(campaign.campaign_start_date + campaign.campaign_show_etime).replace(                        tzinfo=pytz.utc).astimezone(timezone).strftime('%H:%M').split(':')))) * 60  # 秒数版本                # campaign_end_firstday = (                #     datetime.utcfromtimestamp(campaign.campaign_start_date + campaign.campaign_show_etime)                #     .replace(tzinfo=pytz.utc).astimezone(timezone).strftime('%H:%M')) # 时间版本                campaigns_list.append({                    'campaign_id': campaign.id,                    'image_url': s3_url + campaign.image_url,                    'campaign_url': campaign.campaign_url,                    'campaign_name': campaign.campaign_name,                    'campaign_type': campaign.campaign_type,                    'start_date': campaigns_start_date,                    'end_date': campaign_end_date,                    'start_time': campaign_start_firstday,                    'end_time': campaign_end_firstday,                    'device_types': [device.type for device in campaign.device_type_list],                })            return response.json(0, {                'interval_time': 86400,                'campaigns': campaigns_list            })        except Exception as e:            return response.json(173)    def record_user_behavior(cls, request_dict):        """        记录用户行为        @param request_dict: 请求参数        @param response: 响应对象        @return: 响应对象        """        language = request_dict.get('language', 'en')        status = request_dict.get('status', None)  # 1.未跳过 2.已跳过 3.点击广告        campaign_id = request_dict.get('campaign_id', None)        token = request_dict.get('token', None)        response = ResponseObject(language)        if not token:            return response.json(444)        token = TokenObject(token)        if token.code != 0:            return response.json(token.code)        user_id = token.userID        if not all([status, campaign_id]):            return response.json(444)        # 当日时间戳区间获取        current_date = datetime.now().date()        start_of_day = datetime.combine(current_date, Time.min)        end_of_day = datetime.combine(current_date, Time.max)        start_timestamp = int(start_of_day.timestamp())        end_timestamp = int(end_of_day.timestamp())        try:            # 筛选符合条件的记录            open_screen_campaigns = OpenScreenCampaign.objects.filter(                user_id=user_id,                create_time__gt=start_timestamp,                create_time__lt=end_timestamp,                status=0,            )            # 检查是否存在记录            if not open_screen_campaigns.exists():                # 如果不存在,则创建新记录                OpenScreenCampaign.objects.create(                    user_id=user_id,                    status=status,                    campaign_id_id=campaign_id,                    create_time=int(time.time()),                    update_time=int(time.time())                )            else:                # 如果存在,则更新最新的记录                latest_campaign = open_screen_campaigns.latest("create_time")                latest_campaign.status = status                latest_campaign.campaign_id_id = campaign_id                latest_campaign.update_time = int(time.time())                latest_campaign.save()        except Exception as e:            return response.json(177, {'error': '更新错误'})        return response.json(0)    def get_user_behavior_log(self, request_dict, response):        campaign_ids = request_dict.get('campaign_ids', None)        start_time = request_dict.get('start_time', None)        end_time = request_dict.get('end_time', None)        if not all([start_time, end_time]):            return response.json(444)        try:            open_screen_campaign_qs = OpenScreenCampaign.objects.filter(update_time__range=[int(start_time), int(end_time)])            if campaign_ids is not None:                open_screen_campaign_qs = open_screen_campaign_qs.filter(                    Q(campaign_id_id__isnull=True) | Q(campaign_id_id__in=json.loads(campaign_ids)))            open_screen_campaign_qs = open_screen_campaign_qs.select_related('campaign_id').annotate(                campaign_name=F('campaign_id__campaign_name'),                campaign_type=F('campaign_id__campaign_type'),                campaign_status=F('campaign_id__status'),                start_date=F('campaign_id__campaign_start_date'),                end_date=F('campaign_id__campaign_end_date'),                start_time=F('campaign_id__campaign_show_stime'),                end_time=F('campaign_id__campaign_show_etime')            ).values('id', 'user_id', 'status', 'update_time', 'create_time', 'campaign_id', 'campaign_name',                     'campaign_type', 'campaign_status', 'start_date', 'end_date', 'start_time', 'end_time')            if not open_screen_campaign_qs.exists():                return response.json(0, {'list': []})            campaigns_list = list(open_screen_campaign_qs)            return response.json(0, {'list': campaigns_list})        except Exception as e:            return response.json(173)    def get_country_list(self, response):        try:            if SERVER_TYPE == 'Ansjer.us_config.formal_settings':                region_api = 'https://www.dvema.com/'            elif SERVER_TYPE == 'Ansjer.eur_config.formal_settings':                region_api = 'https://api.zositeche.com/'            elif SERVER_TYPE == 'Ansjer.cn_config.formal_settings':                region_api = 'https://www.zositechc.cn/'            else:                region_api = 'https://test.zositechc.cn/'            country_qs = CountryModel.objects.filter(region__api=region_api).values('country_name')            if not country_qs.exists():                return response.json(173)            country_list = []            for country in country_qs:                country_list.append(country['country_name'])            return response.json(0, {'list': country_list})        except Exception as e:            return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
 |