NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

campaign.py (26837B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\campaigns\client\v1\data_model\campaign.py
      2 import campaigns.client.v1.data_model.flatbuffer.campaigndefinition_generated as fb_campaign
      3 from campaigns.client.v1.data_model.career_paths import PROTO_CAREER_TO_FDS_CAREER
      4 from campaigns.client.v1.data_model.contribution_method import ContributionMethodConfiguration
      5 from campaigns.client.v1.data_model.objective import FutureObjective, Objective, ObjectiveID
      6 from datetimeutils import datetime_to_filetime, filetime_to_datetime
      7 from eve.common.script.sys.idCheckers import IsCorporation, IsCharacter, IsFaction
      8 from eveProto.generated.eve_public.campaign.campaign_pb2 import STATE_EXPIRED, STATE_CANCELLED, STATE_UNSPECIFIED, STATE_ACTIVE, STATE_COMPLETED, Identifier, Version
      9 from itertoolsext.Enum import Enum
     10 from semantic_version import SemanticVersion
     11 from uuid import UUID
     12 import logging
     13 logger = logging.getLogger('campaigns')
     14 
     15 def serialize_semantic_version(builder, version):
     16     prerelease_strings = [ builder.CreateString(tag) for tag in version.prerelease_tags ]
     17     build_strings = [ builder.CreateString(tag) for tag in version.build_tags ]
     18     fb_campaign.SemanticVersionStartPrereleaseTagsVector(builder, len(prerelease_strings))
     19     for prerelease_string in reversed(prerelease_strings):
     20         builder.PrependUOffsetTRelative(prerelease_string)
     21 
     22     prerelease_offset = builder.EndVector()
     23     fb_campaign.SemanticVersionStartBuildTagsVector(builder, len(build_strings))
     24     for build_string in reversed(build_strings):
     25         builder.PrependUOffsetTRelative(build_string)
     26 
     27     build_offset = builder.EndVector()
     28     fb_campaign.SemanticVersionStart(builder)
     29     fb_campaign.SemanticVersionAddMajor(builder, version.major)
     30     fb_campaign.SemanticVersionAddMinor(builder, version.minor)
     31     fb_campaign.SemanticVersionAddPatch(builder, version.patch)
     32     fb_campaign.SemanticVersionAddPrereleaseTags(builder, prerelease_offset)
     33     fb_campaign.SemanticVersionAddBuildTags(builder, build_offset)
     34     return fb_campaign.SemanticVersionEnd(builder)
     35 
     36 
     37 def deserialize_semantic_version(version_flatbuffer):
     38     major = version_flatbuffer.Major()
     39     minor = version_flatbuffer.Minor()
     40     patch = version_flatbuffer.Patch()
     41     prerelease_tags = []
     42     for i in range(version_flatbuffer.PrereleaseTagsLength()):
     43         prerelease_tags.append(version_flatbuffer.PrereleaseTags(i).decode('utf-8'))
     44 
     45     build_tags = []
     46     for i in range(version_flatbuffer.BuildTagsLength()):
     47         build_tags.append(version_flatbuffer.BuildTags(i).decode('utf-8'))
     48 
     49     return SemanticVersion(major, minor, patch, prerelease_tags, build_tags)
     50 
     51 
     52 class CampaignID(object):
     53 
     54     def __init__(self, campaign_uuid):
     55         self._campaign_uuid = campaign_uuid
     56 
     57     @property
     58     def uuid(self):
     59         return self._campaign_uuid
     60 
     61     @classmethod
     62     def from_proto(cls, proto):
     63         return CampaignID(UUID(bytes=proto.uuid))
     64 
     65     def to_proto(self):
     66         return Identifier(uuid=self._campaign_uuid.bytes)
     67 
     68     def __eq__(self, other):
     69         if not isinstance(other, CampaignID):
     70             return NotImplemented
     71         return self._campaign_uuid == other._campaign_uuid
     72 
     73     def __ne__(self, other):
     74         return not self.__eq__(other)
     75 
     76     def __repr__(self):
     77         return '<%s %r>' % (self.__class__.__name__, self.__dict__)
     78 
     79     def __hash__(self):
     80         return hash(self.uuid)
     81 
     82 
     83 class Campaign(object):
     84 
     85     def __init__(self, campaign_id, version, title, subtitle, goal_description, success_description, failure_description, icon, logo, dashboard_background, ao_feature_page, objective_background, issuer, presenting_character, annotations, total_objectives, scheduled_start_datetime, finished_datetime, target_progress, contribution_method_configuration, current_objectives, future_objectives, campaign_state, scheduled_expiry_datetime, definition_name):
     86         self._campaign_id = campaign_id
     87         self._version = version
     88         self._title = title
     89         self._subtitle = subtitle
     90         self._goal_description = goal_description
     91         self._success_description = success_description
     92         self._failure_description = failure_description
     93         self._icon = icon
     94         self._logo = logo
     95         self._dashboard_background = dashboard_background
     96         self._ao_feature_page = ao_feature_page
     97         self._objective_background = objective_background
     98         self._issuer = issuer
     99         self._presenting_character = presenting_character
    100         self._annotations = annotations
    101         self._total_objectives = total_objectives
    102         self._scheduled_start_datetime = scheduled_start_datetime
    103         self._finished_datetime = finished_datetime
    104         self._target_progress = target_progress
    105         self._contribution_method_configuration = contribution_method_configuration
    106         self._current_objectives = current_objectives
    107         self._future_objectives = future_objectives
    108         self._campaign_state = campaign_state
    109         self._scheduled_expiry_datetime = scheduled_expiry_datetime
    110         self._definition_name = definition_name
    111 
    112     @property
    113     def id(self):
    114         return self._campaign_id
    115 
    116     @property
    117     def version(self):
    118         return self._version
    119 
    120     @property
    121     def title(self):
    122         return self._title
    123 
    124     @property
    125     def subtitle(self):
    126         return self._subtitle
    127 
    128     @property
    129     def goal_description(self):
    130         return self._goal_description
    131 
    132     @property
    133     def success_description(self):
    134         return self._success_description
    135 
    136     @property
    137     def failure_description(self):
    138         return self._failure_description
    139 
    140     @property
    141     def icon(self):
    142         return self._icon
    143 
    144     @property
    145     def logo(self):
    146         return self._logo
    147 
    148     @property
    149     def issuer(self):
    150         return self._issuer
    151 
    152     @property
    153     def is_character_issuer(self):
    154         return IsCharacter(self.issuer)
    155 
    156     @property
    157     def is_corporation_issuer(self):
    158         return IsCorporation(self.issuer)
    159 
    160     @property
    161     def is_faction_issuer(self):
    162         return IsFaction(self.issuer)
    163 
    164     @property
    165     def dashboard_background(self):
    166         return self._dashboard_background
    167 
    168     @property
    169     def ao_feature_page(self):
    170         return self._ao_feature_page
    171 
    172     @property
    173     def objective_background(self):
    174         return self._objective_background
    175 
    176     @property
    177     def presenting_character(self):
    178         return self._presenting_character
    179 
    180     @property
    181     def annotations(self):
    182         return self._annotations
    183 
    184     @property
    185     def total_objectives(self):
    186         return self._total_objectives
    187 
    188     @property
    189     def scheduled_start_datetime(self):
    190         return self._scheduled_start_datetime
    191 
    192     @property
    193     def scheduled_expiry_datetime(self):
    194         return self._scheduled_expiry_datetime
    195 
    196     @property
    197     def finished_datetime(self):
    198         return self._finished_datetime
    199 
    200     @property
    201     def is_finished(self):
    202         return self._finished_datetime is not None
    203 
    204     @property
    205     def target_progress(self):
    206         return self._target_progress
    207 
    208     @property
    209     def contribution_method_configuration(self):
    210         return self._contribution_method_configuration
    211 
    212     @property
    213     def current_objectives(self):
    214         return self._current_objectives
    215 
    216     @property
    217     def future_objectives(self):
    218         return self._future_objectives
    219 
    220     @property
    221     def campaign_state(self):
    222         return self._campaign_state
    223 
    224     @property
    225     def definition_name(self):
    226         return self._definition_name
    227 
    228     def __repr__(self):
    229         return '<%s %r>' % (self.__class__.__name__, self.__dict__)
    230 
    231     @classmethod
    232     def from_proto(cls, campaign_identifier, campaign_attributes, available_objectives, restricted_objectives):
    233         campaign_id = CampaignID.from_proto(campaign_identifier)
    234         future_objectives = []
    235         for objective in restricted_objectives:
    236             obj = FutureObjective(objective.scheduled_start_time.ToDatetime(), PROTO_CAREER_TO_FDS_CAREER[objective.career], objective.contribution_method.name)
    237             obj.campaign_id = campaign_id
    238             future_objectives.append(obj)
    239 
    240         current_objectives = []
    241         for available_objective in available_objectives:
    242             obj = Objective.from_proto(available_objective.objective, available_objective.attributes)
    243             obj.campaign_id = campaign_id
    244             current_objectives.append(obj)
    245 
    246         if campaign_attributes.issuer.WhichOneof('issuer') == 'character':
    247             issuer = campaign_attributes.issuer.character.sequential
    248         elif campaign_attributes.issuer.WhichOneof('issuer') == 'corporation':
    249             issuer = campaign_attributes.issuer.corporation.sequential
    250         else:
    251             issuer = campaign_attributes.issuer.faction.sequential
    252         annotations = {annotation.key:annotation.value for annotation in campaign_attributes.annotations}
    253         finished_time = None if campaign_attributes.WhichOneof('finished') == 'not_finished' else campaign_attributes.finish_time.ToDatetime()
    254         logo = ImageDefinition.from_proto(campaign_attributes.logo.image, campaign_attributes.logo.attributes)
    255         return Campaign(campaign_id=campaign_id, future_objectives=future_objectives, current_objectives=current_objectives, title=campaign_attributes.title.sequential, subtitle=campaign_attributes.subtitle.sequential, goal_description=campaign_attributes.goal_description.sequential, success_description=campaign_attributes.success_description.sequential, failure_description=campaign_attributes.failure_description.sequential, icon=campaign_attributes.icon.name, logo=logo, dashboard_background=campaign_attributes.dashboard_background.path, ao_feature_page=campaign_attributes.ao_feature_page.path, objective_background=campaign_attributes.objective_background.path, presenting_character=campaign_attributes.presenting_character.sequential, issuer=issuer, annotations=annotations, total_objectives=campaign_attributes.total_objectives, campaign_state=CampaignState.from_proto(campaign_attributes.state), scheduled_start_datetime=campaign_attributes.scheduled_start_time.ToDatetime(), scheduled_expiry_datetime=campaign_attributes.scheduled_expiry_time.ToDatetime(), finished_datetime=finished_time, target_progress=campaign_attributes.target_progress, contribution_method_configuration=ContributionMethodConfiguration.from_proto(campaign_attributes.contribution_method_configuration), version=CampaignVersion.from_proto(campaign_attributes.version), definition_name=campaign_attributes.definition_name)
    256 
    257     def to_flatbuffer(self, builder):
    258         uuid_bytes = [ ord(byte) for byte in self.id.uuid.bytes ]
    259         definition_version_fb = serialize_semantic_version(builder, self.version.definition_semantic_verison)
    260         definition_name = self.definition_name if self.definition_name is not None else ''
    261         definition_name_fb = builder.CreateString(definition_name)
    262         fb_campaign.CampaignVersionStart(builder)
    263         fb_campaign.CampaignVersionAddDefinitionVersion(builder, definition_version_fb)
    264         fb_campaign.CampaignVersionAddEtag(builder, self.version.etag)
    265         version_fb = fb_campaign.CampaignVersionEnd(builder)
    266         icon_fb = builder.CreateString(self.icon)
    267         dashboard_background_fb = builder.CreateString(self.dashboard_background)
    268         ao_feature_page_fb = builder.CreateString(self.ao_feature_page)
    269         objective_background_fb = builder.CreateString(self.objective_background)
    270         logo_fb = self.logo.to_flatbuffer(builder)
    271         annotations_list = []
    272         for key, value in self.annotations.iteritems():
    273             key_fb = builder.CreateString(key)
    274             value_fb = builder.CreateString(value)
    275             fb_campaign.AnnotationStart(builder)
    276             fb_campaign.AnnotationAddKey(builder, key_fb)
    277             fb_campaign.AnnotationAddValue(builder, value_fb)
    278             annotation_fb = fb_campaign.AnnotationEnd(builder)
    279             annotations_list.append(annotation_fb)
    280 
    281         fb_campaign.CampaignStartAnnotationsVector(builder, len(annotations_list))
    282         for annotation in reversed(annotations_list):
    283             builder.PrependUOffsetTRelative(annotation)
    284 
    285         annotations_fb = builder.EndVector()
    286         if self.finished_datetime is not None:
    287             finished_type = fb_campaign.FinishedTime.FinishedTime
    288         else:
    289             finished_type = fb_campaign.FinishedTime.NONE
    290         finished_time_fb = None
    291         if self.finished_datetime is not None:
    292             fb_campaign.FinishedStart(builder)
    293             fb_campaign.FinishedAddTimestamp(builder, datetime_to_filetime(self.finished_datetime))
    294             finished_time_fb = fb_campaign.FinishedEnd(builder)
    295         future_objective_offsets = []
    296         for future_objective in self.future_objectives:
    297             contribution_method_fb = builder.CreateString(future_objective.contribution_method_name)
    298             fb_campaign.FutureObjectiveStart(builder)
    299             fb_campaign.FutureObjectiveAddContributionMethod(builder, contribution_method_fb)
    300             fb_campaign.FutureObjectiveAddScheduledStartTime(builder, datetime_to_filetime(future_objective.start_datetime))
    301             fb_campaign.FutureObjectiveAddCareer(builder, future_objective.career_path)
    302             future_objective_offsets.append(fb_campaign.FutureObjectiveEnd(builder))
    303 
    304         fb_campaign.CampaignStartFutureObjectivesVector(builder, len(future_objective_offsets))
    305         for future_objective in reversed(future_objective_offsets):
    306             builder.PrependUOffsetTRelative(future_objective)
    307 
    308         future_objectives_fb = builder.EndVector()
    309         current_objective_offsets = []
    310         for current_objective in self.current_objectives:
    311             current_objective_offsets.append(current_objective.to_flatbuffer(builder))
    312 
    313         fb_campaign.CampaignStartCurrentObjectivesVector(builder, len(current_objective_offsets))
    314         for current_objective in reversed(current_objective_offsets):
    315             builder.PrependUOffsetTRelative(current_objective)
    316 
    317         current_objectives_fb = builder.EndVector()
    318         contribution_method_fb = self.contribution_method_configuration.to_flatbuffer(builder)
    319         fb_campaign.CampaignStart(builder)
    320         fb_campaign.CampaignAddUuid(builder, fb_campaign.CreateUuid(builder, uuid_bytes))
    321         fb_campaign.CampaignAddVersion(builder, version_fb)
    322         fb_campaign.CampaignAddTitle(builder, self.title)
    323         fb_campaign.CampaignAddSubtitle(builder, self.subtitle)
    324         fb_campaign.CampaignAddBriefingGoalDescription(builder, self.goal_description)
    325         fb_campaign.CampaignAddBriefingSuccessDescription(builder, self.success_description)
    326         fb_campaign.CampaignAddBriefingFailureDescription(builder, self.failure_description)
    327         fb_campaign.CampaignAddIcon(builder, icon_fb)
    328         fb_campaign.CampaignAddLogo(builder, logo_fb)
    329         fb_campaign.CampaignAddDashboardBackground(builder, dashboard_background_fb)
    330         fb_campaign.CampaignAddAoFeaturePage(builder, ao_feature_page_fb)
    331         fb_campaign.CampaignAddObjectiveBackground(builder, objective_background_fb)
    332         fb_campaign.CampaignAddIssuer(builder, self.issuer)
    333         fb_campaign.CampaignAddPresentingCharacter(builder, self.presenting_character)
    334         fb_campaign.CampaignAddAnnotations(builder, annotations_fb)
    335         fb_campaign.CampaignAddTotalObjectives(builder, self.total_objectives)
    336         fb_campaign.CampaignAddState(builder, self.campaign_state)
    337         fb_campaign.CampaignAddScheduledStartTime(builder, datetime_to_filetime(self.scheduled_start_datetime))
    338         fb_campaign.CampaignAddScheduledExpiryTime(builder, datetime_to_filetime(self.scheduled_expiry_datetime))
    339         fb_campaign.CampaignAddFinishedTimeType(builder, finished_type)
    340         if finished_time_fb is not None:
    341             fb_campaign.CampaignAddFinishedTime(builder, finished_time_fb)
    342         fb_campaign.CampaignAddTargetProgress(builder, self.target_progress)
    343         fb_campaign.CampaignAddContributionMethodConfig(builder, contribution_method_fb)
    344         fb_campaign.CampaignAddFutureObjectives(builder, future_objectives_fb)
    345         fb_campaign.CampaignAddCurrentObjectives(builder, current_objectives_fb)
    346         fb_campaign.CampaignAddDefinitionName(builder, definition_name_fb)
    347         return fb_campaign.CampaignEnd(builder)
    348 
    349     @classmethod
    350     def from_flatbuffer(cls, campaign_fb):
    351         campaign_id_bytes = [ chr(byte) for byte in campaign_fb.Uuid().Bytes() ]
    352         campaign_id = CampaignID(UUID(bytes=campaign_id_bytes))
    353         definition_version = deserialize_semantic_version(campaign_fb.Version().DefinitionVersion())
    354         definition_name = campaign_fb.DefinitionName()
    355         if definition_name is not None:
    356             definition_name = definition_name.decode('utf-8')
    357         annotations = {}
    358         for i in range(campaign_fb.AnnotationsLength()):
    359             annotation = campaign_fb.Annotations(i)
    360             annotations[annotation.Key().decode('utf-8')] = annotation.Value().decode('utf-8')
    361 
    362         if campaign_fb.FinishedTimeType() == fb_campaign.FinishedTime.NONE:
    363             finished_time = None
    364         else:
    365             union_data = campaign_fb.FinishedTime()
    366             finished_time = fb_campaign.Finished()
    367             finished_time.Init(union_data.Bytes, union_data.Pos)
    368             finished_time = filetime_to_datetime(finished_time.Timestamp())
    369         future_objectives = []
    370         for i in range(campaign_fb.FutureObjectivesLength()):
    371             objective = campaign_fb.FutureObjectives(i)
    372             future_objective = FutureObjective(start_datetime=filetime_to_datetime(objective.ScheduledStartTime()), career_path=objective.Career(), contribution_method_name=objective.ContributionMethod().decode('utf-8'), campaign_id=campaign_id)
    373             future_objectives.append(future_objective)
    374 
    375         current_objectives = []
    376         for i in range(campaign_fb.CurrentObjectivesLength()):
    377             objective = campaign_fb.CurrentObjectives(i)
    378             current_objective = Objective.from_flatbuffer(objective)
    379             current_objective.campaign_id = campaign_id
    380             current_objectives.append(current_objective)
    381 
    382         return Campaign(campaign_id=campaign_id, version=CampaignVersion(definition_semantic_version=definition_version, etag=campaign_fb.Version().Etag()), title=campaign_fb.Title(), subtitle=campaign_fb.Subtitle(), goal_description=campaign_fb.BriefingGoalDescription(), success_description=campaign_fb.BriefingSuccessDescription(), failure_description=campaign_fb.BriefingFailureDescription(), icon=campaign_fb.Icon().decode('utf-8'), logo=ImageDefinition.from_flatbuffer(campaign_fb.Logo()), dashboard_background=campaign_fb.DashboardBackground().decode('utf-8'), ao_feature_page=campaign_fb.AoFeaturePage().decode('utf-8'), objective_background=campaign_fb.ObjectiveBackground().decode('utf-8'), issuer=campaign_fb.Issuer(), presenting_character=campaign_fb.PresentingCharacter(), annotations=annotations, total_objectives=campaign_fb.TotalObjectives(), campaign_state=campaign_fb.State(), scheduled_start_datetime=filetime_to_datetime(campaign_fb.ScheduledStartTime()), scheduled_expiry_datetime=filetime_to_datetime(campaign_fb.ScheduledExpiryTime()), finished_datetime=finished_time, target_progress=campaign_fb.TargetProgress(), contribution_method_configuration=ContributionMethodConfiguration.from_flatbuffer(campaign_fb.ContributionMethodConfig()), future_objectives=future_objectives, current_objectives=current_objectives, definition_name=definition_name)
    383 
    384     def __eq__(self, other):
    385         if not isinstance(other, Campaign):
    386             return False
    387         return self.id == other.id and self.title == other.title and self.subtitle == other.subtitle and self.goal_description == other.goal_description and self.success_description == other.success_description and self.failure_description == other.failure_description and self.icon == other.icon and self.logo == other.logo and self.dashboard_background == other.dashboard_background and self.ao_feature_page == other.ao_feature_page and self.objective_background == other.objective_background and self.presenting_character == other.presenting_character and self.issuer == other.issuer and self.annotations == other.annotations and self.total_objectives == other.total_objectives and self.campaign_state == other.campaign_state and self.scheduled_start_datetime == other.scheduled_start_datetime and self.scheduled_expiry_datetime == other.scheduled_expiry_datetime and self.finished_datetime == other.finished_datetime and self.target_progress == other.target_progress and self.contribution_method_configuration == other.contribution_method_configuration and self.version == other.version and self.future_objectives == other.future_objectives and self.current_objectives == other.current_objectives and self.definition_name == other.definition_name
    388 
    389     def __ne__(self, other):
    390         result = self.__eq__(other)
    391         return not result
    392 
    393 
    394 @Enum
    395 
    396 class CampaignState(object):
    397     UNSPECIFIED = 0
    398     ACTIVE = 1
    399     COMPLETED = 2
    400     EXPIRED = 3
    401     CANCELLED = 4
    402 
    403     @classmethod
    404     def from_proto(cls, campaign_state):
    405         enum_value = _campaign_state_proto_to_enum.get(campaign_state, None)
    406         if enum_value is None:
    407             raise ValueError('Campaign State: Conversion to enum failed with unrecognized value: %s' % campaign_state)
    408         return enum_value
    409 
    410 
    411 _campaign_state_proto_to_enum = {STATE_UNSPECIFIED: CampaignState.UNSPECIFIED,
    412  STATE_ACTIVE: CampaignState.ACTIVE,
    413  STATE_COMPLETED: CampaignState.COMPLETED,
    414  STATE_EXPIRED: CampaignState.EXPIRED,
    415  STATE_CANCELLED: CampaignState.CANCELLED}
    416 
    417 class CampaignVersion(object):
    418 
    419     def __init__(self, definition_semantic_version, etag):
    420         self._definition_semantic_version = definition_semantic_version
    421         self._etag = etag
    422 
    423     @property
    424     def definition_semantic_verison(self):
    425         return self._definition_semantic_version
    426 
    427     @property
    428     def etag(self):
    429         return self._etag
    430 
    431     @classmethod
    432     def from_proto(cls, version):
    433         return CampaignVersion(SemanticVersion.from_proto(version.definition_version), version.etag)
    434 
    435     def to_proto(self):
    436         return Version(definition_version=self._definition_semantic_version.to_eve_public_proto(), etag=self._etag)
    437 
    438     def __repr__(self):
    439         return '<CampaignVersion>' + self.__dict__.__repr__()
    440 
    441     def __eq__(self, other):
    442         if not isinstance(other, CampaignVersion):
    443             return NotImplemented
    444         return self.definition_semantic_verison == other.definition_semantic_verison and self.etag == other.etag
    445 
    446     def __ne__(self, other):
    447         return not self.__eq__(other)
    448 
    449 
    450 class CampaignStats(object):
    451 
    452     def __init__(self, campaign_id, current_campaign_progress, total_contributors):
    453         self._campaign_id = campaign_id
    454         self._current_campaign_progress = current_campaign_progress
    455         self._total_contributors = total_contributors
    456 
    457     @property
    458     def id(self):
    459         return self._campaign_id
    460 
    461     @property
    462     def current_campaign_progress(self):
    463         return self._current_campaign_progress
    464 
    465     @property
    466     def total_contributors(self):
    467         return self._total_contributors
    468 
    469     def __repr__(self):
    470         return '<%s %r>' % (self.__class__.__name__, self.__dict__)
    471 
    472     @classmethod
    473     def from_proto(cls, campaign_id, proto):
    474         return CampaignStats(campaign_id=CampaignID.from_proto(campaign_id), current_campaign_progress=proto.current_campaign_progress, total_contributors=proto.total_contributors)
    475 
    476     def __eq__(self, other):
    477         if not isinstance(other, CampaignStats):
    478             return NotImplemented
    479         return self.id == other.id and self.current_campaign_progress == other.current_campaign_progress and self.total_contributors == other.total_contributors
    480 
    481     def __ne__(self, other):
    482         return not self == other
    483 
    484 
    485 class ImageDefinition(object):
    486 
    487     def __init__(self, path, width, height):
    488         self._path = path
    489         self._width = width
    490         self._height = height
    491 
    492     @property
    493     def path(self):
    494         return self._path
    495 
    496     @property
    497     def display_width(self):
    498         return self._width
    499 
    500     @property
    501     def display_height(self):
    502         return self._height
    503 
    504     @classmethod
    505     def from_proto(cls, identifier, attributes):
    506         return ImageDefinition(path=identifier.path, width=attributes.display_width, height=attributes.display_height)
    507 
    508     @classmethod
    509     def from_flatbuffer(cls, imagedef_fb):
    510         return ImageDefinition(path=imagedef_fb.Path().decode('utf-8'), width=imagedef_fb.Width(), height=imagedef_fb.Height())
    511 
    512     def to_flatbuffer(self, builder):
    513         path_fb = builder.CreateString(self._path)
    514         fb_campaign.ImageDefinitionStart(builder)
    515         fb_campaign.ImageDefinitionAddPath(builder, path_fb)
    516         fb_campaign.ImageDefinitionAddWidth(builder, self.display_width)
    517         fb_campaign.ImageDefinitionAddHeight(builder, self.display_height)
    518         return fb_campaign.ImageDefinitionEnd(builder)
    519 
    520     def __repr__(self):
    521         return '<%s %r>' % (self.__class__.__name__, self.__dict__)
    522 
    523     def __eq__(self, other):
    524         if not isinstance(other, ImageDefinition):
    525             return NotImplemented
    526         return self.path == other.path and self.display_width == other.display_width and self.display_height == other.display_height
    527 
    528     def __ne__(self, other):
    529         return not self.__eq__(other)
    530 
    531 
    532 class UnredeemedReward(object):
    533 
    534     def __init__(self, objective_id, isk_intervals, lp_intervals):
    535         self._objective_id = objective_id
    536         self._isk_intervals = isk_intervals
    537         self._lp_intervals = lp_intervals
    538 
    539     @property
    540     def objective_id(self):
    541         return self._objective_id
    542 
    543     @property
    544     def isk_intervals(self):
    545         return self._isk_intervals
    546 
    547     @property
    548     def lp_intervals(self):
    549         return self._lp_intervals
    550 
    551     def __repr__(self):
    552         return '<%s %r>' % (self.__class__.__name__, self.__dict__)
    553 
    554     @classmethod
    555     def from_proto(cls, reward):
    556         isk_intervals = 0 if reward.WhichOneof('isk') == 'no_isk_unredeemed' else reward.isk_intervals_unredeemed
    557         lp_intervals = 0 if reward.WhichOneof('lp') == 'no_lp_unredeemed' else reward.lp_intervals_unredeemed
    558         return UnredeemedReward(objective_id=ObjectiveID.from_proto(reward.objective), isk_intervals=isk_intervals, lp_intervals=lp_intervals)
    559 
    560     def __eq__(self, other):
    561         if not isinstance(other, UnredeemedReward):
    562             return NotImplemented
    563         return self.objective_id == other.objective_id and self.isk_intervals == other.isk_intervals and self.lp_intervals == other.lp_intervals
    564 
    565     def __ne__(self, other):
    566         return not self.__eq__(other)