def test_longitude_field(self): field = LongitudeField() name, path, args, kwargs = field.deconstruct() self.assertIsNone(name) self.assertEqual(path, 'osm_field.fields.LongitudeField') self.assertEqual(args, []) self.assertEqual(kwargs, {'validators': [validate_longitude]})
def test_longitude_field_with_validator(self): field = LongitudeField(validators=[foo_validator]) name, path, args, kwargs = field.deconstruct() self.assertIsNone(name) self.assertEqual(path, 'osm_field.fields.LongitudeField') self.assertEqual(args, []) self.assertEqual(kwargs, {'validators': [foo_validator, validate_longitude]})
def test_longitude_field_with_validator(self): field = LongitudeField(validators=[foo_validator]) name, path, args, kwargs = field.deconstruct() self.assertIsNone(name) self.assertEqual(path, "osm_field.fields.LongitudeField") self.assertEqual(args, []) self.assertEqual(kwargs, {"validators": [foo_validator, validate_longitude]})
class MultipleNamingModel(models.Model): default_location = OSMField() default_location_lat = LatitudeField() default_location_lon = LongitudeField() custom_location = OSMField(lat_field='custom_latitude', lon_field='custom_longitude') custom_latitude = LatitudeField() custom_longitude = LongitudeField()
class ExampleModel(models.Model): location = OSMField() location_lat = LatitudeField() location_lon = LongitudeField() another = OSMField(lat_field='some_lat_field', lon_field='other_lon_field') some_lat_field = LatitudeField() other_lon_field = LongitudeField() def __str__(self): return str(self.get_location_info()) def get_absolute_url(self): return reverse('detail', kwargs={'pk': self.pk})
class ChildModel(models.Model): parent = models.ForeignKey(ParentModel, related_name="children", on_delete=models.CASCADE) location = OSMField() location_lat = LatitudeField() location_lon = LongitudeField()
class LocationWithDataModel(models.Model): location = OSMField(lat_field='latitude', lon_field='longitude', data_field='location_data') latitude = LatitudeField() longitude = LongitudeField() location_data = models.TextField()
class MyOsm(models.Model): location = OSMField() email = models.EmailField(blank=True) phone = models.IntegerField(null=True, blank=True) location_lat = LatitudeField() location_lon = LongitudeField() def __str__(self): return self.location
class Location(models.Model): # location=models.CharField(max_length=255) # location_lat = models.CharField(max_length=22) # location_lon = models.CharField(max_length=22) location = OSMField() location_lat = LatitudeField() location_lon = LongitudeField() def __str__(self): return self.location
class Listing(models.Model): user = models.ForeignKey(User,on_delete=models.DO_NOTHING,default=2) realtor = models.ForeignKey(Realtor, on_delete=models.DO_NOTHING) title = models.CharField(max_length=200) address = models.CharField(max_length=200) city = models.CharField(max_length=100) state = models.CharField(max_length=100) zipcode = models.CharField(max_length=20) description = models.TextField(blank=True) price = models.IntegerField() bedrooms = models.IntegerField() bathrooms = models.DecimalField(max_digits=2, decimal_places=1) garage = models.IntegerField() sqft = models.IntegerField() sqft_living = models.IntegerField() lot_size = models.DecimalField(max_digits=5, decimal_places=1) floors = models.IntegerField() waterfront = models.IntegerField(choices=Waterfront_Choices) view = models.IntegerField(choices=View_Choices) condition = models.IntegerField(choices=Condition_Choices) grade = models.IntegerField(choices=Grade_Choices) sqft_above = models.IntegerField() sqft_basement = models.IntegerField() yr_built = models.IntegerField() yr_renovated = models.IntegerField() sqft_living15 = models.IntegerField() sqft_lot15 = models.IntegerField() photo_main = models.ImageField(upload_to='photos/%Y/%m/%d/') photo_1 = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True) photo_2 = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True) photo_3 = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True) photo_4 = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True) photo_5 = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True) photo_6 = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True) is_published = models.BooleanField(default=True) is_verified = models.BooleanField(default=False) list_date = models.DateTimeField(default=datetime.now, blank=True) likes = models.ManyToManyField(User,related_name='adz_posts') location = OSMField() location_lat = LatitudeField() location_lon = LongitudeField() def total_likes(self): return self.likes.count() def __str__(self): return self.title
class CosinnusOrganizationLocation(models.Model): location = OSMField(_('Location'), blank=True, null=True) location_lat = LatitudeField(_('Latitude'), blank=True, null=True) location_lon = LongitudeField(_('Longitude'), blank=True, null=True) organization = models.ForeignKey( CosinnusOrganization, verbose_name=_('Organization'), on_delete=models.CASCADE, related_name='locations', ) class Meta(object): verbose_name = _('CosinnusOrganizationLocation') verbose_name_plural = _('CosinnusOrganizationLocations') @property def location_url(self): if not self.location_lat or not self.location_lon: return None return 'http://www.openstreetmap.org/?mlat=%s&mlon=%s&zoom=15&layers=M' % ( self.location_lat, self.location_lon)
class Event(models.Model): start_time = models.DateTimeField(db_index=True, verbose_name="Start wydarzenia") end_time = models.DateTimeField(db_index=True, verbose_name="Koniec wydarzenia") title = models.CharField(max_length=120, verbose_name="Tytuł") description = RichTextField(verbose_name="Opis wydarzenia") image = models.ImageField(upload_to='event/%Y/%m/%d/', blank=True, null=True, verbose_name="Plakat") place = models.CharField(max_length=120, verbose_name="Miejsce") #point = models.PointField(blank=True, null=True, verbose_name="Miejsce na mapie") orgs = models.ManyToManyField('Organizer', blank=True, related_name='events', verbose_name="Organizator") user = models.ForeignKey(User, blank=True, null=True, related_name='event', verbose_name='Użytkownik', on_delete=models.SET_NULL) categories = models.ManyToManyField('Category', blank=True, verbose_name="Kategoria") url = models.URLField(blank=True, null=True, verbose_name="Adres www") location = OSMField(default='Oświęcim', verbose_name="Położenie na mapie", lat_field='latitude', lon_field='longitude') latitude = LatitudeField(default=50.038, verbose_name="Długość geograficzna") longitude = LongitudeField(default=19.221, verbose_name="Szerokość geograficzna") def __str__(self): return self.title
class Model(models.Model): location = OSMField(lat_field="latitude", lon_field="longitude") latitude = LatitudeField() longitude = LongitudeField()
class Model(models.Model): location = OSMField() location_lat = LatitudeField() location_lon = LongitudeField()
class OpenStreetMaps(models.Model): location = OSMField(lat_field='latitude', lon_field='longitude') latitude = LatitudeField() longitude = LongitudeField()
class ChildModel(models.Model): parent = models.ForeignKey(ParentModel, related_name='children') location = OSMField() location_lat = LatitudeField() location_lon = LongitudeField()
class CustomNamingModel(models.Model): location = OSMField(lat_field='latitude', lon_field='longitude') latitude = LatitudeField() longitude = LongitudeField()
class Event(models.Model): name = models.CharField(max_length=300) organizer = models.ForeignKey(User, on_delete=models.CASCADE) events_or_task = models.BooleanField(default=True) events_type = models.ForeignKey(EventsType, on_delete=models.CASCADE) date_event = models.DateField (null=True, blank=True, verbose_name='Дата') time_event = models.TimeField(null=True, blank=True, verbose_name='Час') city = models.ForeignKey(City, on_delete=models.CASCADE, null=True, blank=True) address = models.CharField(max_length=300, null=True, blank=True) status = models.ForeignKey(Status, on_delete=models.CASCADE, verbose_name='Статус', default=Status.DEFAULT_STATUS) # null=True, blank=True max_part = models.IntegerField(null=True, blank=True) min_part = models.IntegerField(null=True, blank=True) recommended_points = models.IntegerField() contact = models.EmailField(null=True, blank=True) publication_date = models.DateField(auto_now_add=True) description = models.TextField(null=True, blank=True) geom = PointField(null=True, blank=True) calendar_event = models.ForeignKey(CalendarEvent, on_delete=models.SET_NULL, null=True, blank=True) location = OSMField(lat_field='latitude', lon_field='longitude',null=True, blank=True) latitude = LatitudeField(null=True, blank=True) longitude = LongitudeField(null=True, blank=True) fb_page = models.URLField(null=True, blank=True) @property def get_events_type_url(self): return self.events_type.image.url @property def get_events_type_marker_url(self): return self.events_type.marker_image.url @property def get_event_url(self): return reverse('volunteer_event', args=(self.id,)) def save(self, *args, **kwargs): # if self.city: # if self.city.city == "Вінницька": # view_box = [(49.3921, 28.3079), (49.072, 28.6219)] # elif self.city.city == "Житомирська": # view_box = [(52.276012, 25.605223), (50.23924, 28.715773)] # else: # khmel # view_box = [(49.4770, 26.9048), (49.3631, 27.0995)] # nom = Nominatim(user_agent="changer.in.ua", view_box=view_box, bounded=True) if self.longitude and self.latitude: self.geom = {'coordinates': [self.longitude, self.latitude], 'type': 'Point'} # if self.address: # point = nom.geocode(self.address) # if point: # self.geom = {'coordinates':[point.longitude, point.latitude], 'type':'Point'} # else: # print('coordinates for address not found') # elif self.location: # point = nom.geocode(self.location) # if point: # self.geom = {'coordinates':[point.longitude, point.latitude], 'type':'Point'} # else: # print('coordinates for address not found') # elif self.longitude and self.latitude: # self.geom = {'coordinates': [self.longitude, self.latitude], 'type': 'Point'} # else: # print('coordinates for address not found') # calendar part if self.calendar_event: self.calendar_event.delete() if self.date_event: calendar_name = 'volunteer_calendar' calendar_slug = 'volunteer_calendar_slug' if Calendar.objects.filter(name=calendar_name, slug='volunteer_calendar_slug').exists(): calendar = Calendar.objects.filter(name=calendar_name, slug='volunteer_calendar_slug')[0] else: calendar = Calendar.objects.create(name=calendar_name, slug=calendar_slug) if self.time_event: start = datetime.datetime.combine(self.date_event, self.time_event) else: start = self.date_event data = { 'title': self.name, 'start': start , 'end': datetime.datetime(self.date_event.year, self.date_event.month, self.date_event.day, 23, 59), # 'end_recurring_period': datetime.datetime(today.year + 30, 6, 1, 0, 0), # 'rule': rule, 'calendar': calendar, 'color_event': self.events_type.color_event, } new_calendar_event = CalendarEvent.objects.create(**data) self.calendar_event = new_calendar_event # end calendar_part is_new_event = False if self.pk is None: is_new_event = True else: old_instance = Event.objects.get(pk = self.pk) old_status = old_instance.status.id old_type = old_instance.events_type.id currency = Currency.objects.get(type_event__id=old_type) super(Event, self).save(*args, **kwargs) if not is_new_event and self.status.id == 3 and old_status!=self.status.id: part = list(EventsParticipant.objects.filter(event = Event.objects.get(pk = self.pk)).values_list('user__id', flat = True)) part_user = User.objects.filter(id__in = part) if self.events_or_task == True: for user in part_user: points_list = PointsList.objects.create(user = user, currency = currency, points_quantity = self.recommended_points) IncreasePointsInfo.objects.create(increase = points_list, increase_type_id = 1, event_id = self.id) user_points = UserPoint.objects.get(user = user, currency = currency) user_points.quantity += self.recommended_points user_points.save() notify_good_job(sender=self.organizer.django_user_id, recipient=user.django_user_id, event_instance=self, currency_quantity=self.recommended_points, currency_type=currency.currency) else: user = TaskApplication.objects.get(event__id = self.id, executor = True).user points_list = PointsList.objects.create(user=user, currency=currency, points_quantity=self.recommended_points) IncreasePointsInfo.objects.create(increase=points_list, increase_type_id=1, event_id=self.id) user_points = UserPoint.objects.get(user=user, currency=currency) user_points.quantity += self.recommended_points user_points.save() notify_good_job(sender=self.organizer.django_user_id, recipient=user.django_user_id, event_instance=self, currency_quantity=self.recommended_points, currency_type=currency.currency) if len(part_user)>=3 and self.events_or_task == True: organizer_points = 30 points_list = PointsList.objects.create(user = self.organizer, currency = currency, points_quantity = self.recommended_points) IncreasePointsInfo.objects.create(increase=points_list, increase_type_id=2, event_id=self.id) user_points = UserPoint.objects.get(user=self.organizer, currency=currency) user_points.quantity += organizer_points user_points.save() notify_good_job(sender=self.organizer.django_user_id, recipient=self.organizer.django_user_id, event_instance=self, currency_quantity=organizer_points, currency_type=currency.currency) elif self.events_or_task == False: organizer_points = 30 points_list = PointsList.objects.create(user=self.organizer, currency=currency,points_quantity=self.recommended_points) IncreasePointsInfo.objects.create(increase=points_list, increase_type_id=2, event_id=self.id) user_points = UserPoint.objects.get(user=self.organizer, currency=currency) user_points.quantity += organizer_points user_points.save() notify_good_job(sender=self.organizer.django_user_id, recipient=self.organizer.django_user_id, event_instance=self, currency_quantity=organizer_points, currency_type=currency.currency) print('It is victory!') if is_new_event and self.status.id == 1: # потребує допомоги в підготовці notify_event_needs_help(self) def __str__(self): return '%s %s %s' % (self.name, '|', self.date_event) def as_dict(self): return model_to_dict(self)
class EcobasaCommunityProfile(models.Model): group = models.OneToOneField(CosinnusGroup, editable=False, related_name='profile') # mandatory name! network = models.BooleanField(_('Is this a regional network?'), default=False, blank=True) COMMUNITY_STATUS_STARTING = 's' COMMUNITY_STATUS_ESTABLISHED = 'e' COMMUNITY_STATUS_LAND = 'l' COMMUNITY_STATUS_CHOICES = ( (COMMUNITY_STATUS_STARTING, _('Starting Project (first years)')), (COMMUNITY_STATUS_ESTABLISHED, _('Established (+4 years)')), (COMMUNITY_STATUS_LAND, _('Land Offer')), ) community_status = models.CharField(_('Project status'), max_length=2, blank=True, choices=COMMUNITY_STATUS_CHOICES, default=COMMUNITY_STATUS_ESTABLISHED) COMMUNITY_TYPE_ECOVILLAGE = 'e' COMMUNITY_TYPE_COMUNE = 'c' COMMUNITY_TYPE_HOUSEPROJECT = 'h' COMMUNITY_TYPE_FARM = 'f' COMMUNITY_TYPE_CHOICES = ( (COMMUNITY_TYPE_ECOVILLAGE, _('Ecovillage')), (COMMUNITY_TYPE_COMUNE, _('Commune')), (COMMUNITY_TYPE_HOUSEPROJECT, _('Houseproject')), (COMMUNITY_TYPE_FARM, _('Permaculture Farm')), ) community_type = models.CharField(_('Type of community'), max_length=2, blank=True, choices=COMMUNITY_TYPE_CHOICES, default=COMMUNITY_TYPE_ECOVILLAGE) name = models.CharField(_('name of community'), max_length=255) website = models.URLField(_('link of your communities website'), max_length=250, blank=True, null=True) image = ThumbnailerImageField( verbose_name=_('image'), help_text= _('Header image for the community-profile, minimum resolution 1200x400' ), upload_to='community_images', max_length=255, blank=True, null=True) video = models.URLField( verbose_name=_('Video'), help_text=_('Link to a video showing your community'), max_length=255, blank=True, null=True) # contact info contact_telephone = models.CharField(_('telephone'), max_length=255, blank=True, null=True) contact_street = models.CharField(_('street'), max_length=255, blank=True, null=True) contact_location = OSMField(_('Location'), blank=True, null=True) contact_location_lat = LatitudeField(blank=True, null=True) contact_location_lon = LongitudeField(blank=True, null=True) contact_city = models.CharField(_('city'), max_length=255, blank=True, null=True) contact_zipcode = models.CharField(_('zipcode'), max_length=255, blank=True, null=True) contact_country = models.CharField(_('country'), max_length=2, blank=True, choices=COUNTRY_CHOICES, default='ZZ') contact_show = models.BooleanField(_('show address in profile'), default=False, blank=True) # visitors visitors_num = models.PositiveIntegerField( _('maximum number of people you can host'), blank=True, null=True, default=0) visitors_accommodation = models.TextField( _('accommodation for guests'), blank=True, null=True, help_text= _('Where can your visitors sleep? Do you have space for a bus, tents? How is the indoor sleeping situation? Do you have matresses, a couch? Do you have a donations or a pricing model? Required daily working amount or epxeriences?' )) # wishlist wishlist_projects = models.TextField(_( 'Do you have any construction projects? List and describe them together with needed materials, tools, experts, time and knowledge.' ), blank=True, null=True) wishlist_materials = TaggableManager( _('What materials do you need?'), through=TaggedWishMaterial, related_name='_wishlist_material', blank=True, help_text= _('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.' )) wishlist_materials_info = models.TextField(_( 'Do you have any additional info about materials, or details to your request (like condition, when you need them)?' ), blank=True, null=True) wishlist_tools = TaggableManager( _('What tools or machines do you need?'), through=TaggedWishTool, related_name='_wishlist_tool', blank=True, help_text= _('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.' )) wishlist_tools_info = models.TextField(_( 'Do you have any additional info about tools, or details to your request (like condition, when you need them)?' ), blank=True, null=True) wishlist_skills = TaggableManager( _('Are you looking for some experts that could help you with a project or problem? Tag their desired skills here:' ), through=TaggedWishSkill, related_name='_wishlist_skill', blank=True, help_text= _('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.' )) wishlist_special_needs = models.TextField( _('Special needs (knowledge, information)'), blank=True, null=True) # offers offers_services = TaggableManager( _('Services offered in your community'), through=TaggedOffersService, related_name='_offers_service', blank=True, help_text= _('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.' )) offers_skills = TaggableManager( _('Skills people can learn in your community'), through=TaggedOffersSkill, related_name='_offers_skill', blank=True) offers_creations = TaggableManager( _('Creations/Products'), through=TaggedOffersCreation, related_name='_offers_creation', blank=True, help_text= _('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.' )) offers_materials = TaggableManager( _('Do you have any materials that you produce or that you dont need anymore? (What you throw away, might be useful to somebody else..)' ), through=TaggedOffersMaterial, related_name='_offers_material', blank=True, help_text= _('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.' )) offers_tools = TaggableManager( _('Do you have any tools that you produce or that you dont need anymore?' ), through=TaggedOffersTool, related_name='_offers_tool', blank=True, help_text= _('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.' )) offers_workshop_spaces = models.TextField(_( 'Do you have workshop spaces, where people can build/construct/manufacture things?' ), blank=True, null=True) offers_learning_seminars = models.TextField( _('Do you offer any seminars that visitors could attend?'), blank=True, null=True) # basic info basic_description = models.TextField(_('Describe your community'), blank=True, null=True) basic_inhabitants = models.CharField( _('how many people live in your community?'), max_length=255, null=True, blank=True) basic_inhabitants_underage = models.PositiveIntegerField( _('how many of them are under 18?'), null=True, blank=True, default=0) basic_brings_together = models.TextField( _('what brings your community together'), blank=True, null=True) MEMBERSHIP_OPEN = 'o' MEMBERSHIP_LOOKING = 'l' MEMBERSHIP_CLOSED = 'c' MEMBERSHIP_CHOICES = ( (MEMBERSHIP_OPEN, _('looking for members')), (MEMBERSHIP_LOOKING, _('looking for volunteers')), (MEMBERSHIP_CLOSED, _('closed for the moment')), ) basic_membership_status = models.CharField(_('member status'), max_length=2, blank=True, choices=MEMBERSHIP_CHOICES, default=MEMBERSHIP_OPEN) class Meta: app_label = 'ecobasa' def __str__(self): return self.name def save(self, *args, **kwargs): # copy profile name to cosinnus group name self.group.name = self.name # ensure the CosinnusGroup is always public! self.group.public = True self.group.save() return super(EcobasaCommunityProfile, self).save(*args, **kwargs)
class DefaultNamingModel(models.Model): location = OSMField() location_lat = LatitudeField() location_lon = LongitudeField()
class MixedNamingModel(models.Model): location = OSMField(lon_field='longitude') location_lat = LatitudeField() longitude = LongitudeField()
class OpenStreetMaps(models.Model): location = OSMField() location_lat = LatitudeField() location_lon = LongitudeField()
class Event(BaseTaggableObjectModel): SORT_FIELDS_ALIASES = [ ('title', 'title'), ('from_date', 'from_date'), ('to_date', 'to_date'), ('city', 'city'), ('state', 'state'), ] STATE_SCHEDULED = 1 STATE_VOTING_OPEN = 2 STATE_CANCELED = 3 STATE_ARCHIVED_DOODLE = 4 STATE_CHOICES = ( (STATE_SCHEDULED, _('Scheduled')), (STATE_VOTING_OPEN, _('Voting open')), (STATE_CANCELED, _('Canceled')), (STATE_ARCHIVED_DOODLE, _('Archived Event Poll')), ) from_date = models.DateTimeField(_('Start'), default=None, blank=True, null=True, editable=True) to_date = models.DateTimeField(_('End'), default=None, blank=True, null=True, editable=True) state = models.PositiveIntegerField( _('State'), choices=STATE_CHOICES, default=STATE_VOTING_OPEN, ) __state = None # pre-save purpose note = models.TextField(_('Note'), blank=True, null=True) suggestion = models.ForeignKey( 'Suggestion', verbose_name=_('Event date'), on_delete=models.SET_NULL, null=True, blank=True, related_name='selected_name', ) location = OSMField(_('Location'), blank=True, null=True) location_lat = LatitudeField(_('Latitude'), blank=True, null=True) location_lon = LongitudeField(_('Longitude'), blank=True, null=True) street = models.CharField(_('Street'), blank=True, max_length=50, null=True) zipcode = models.PositiveIntegerField(_('ZIP code'), blank=True, null=True) city = models.CharField(_('City'), blank=True, max_length=50, null=True) public = models.BooleanField(_('Is public (on website)'), default=False) image = models.ImageField(_('Image'), upload_to=get_event_image_filename, blank=True, null=True) url = models.URLField(_('URL'), blank=True, null=True) original_doodle = models.OneToOneField( "self", verbose_name=_('Original Event Poll'), related_name='scheduled_event', null=True, blank=True, on_delete=models.SET_NULL) objects = EventManager() class Meta(BaseTaggableObjectModel.Meta): ordering = ['from_date', 'to_date'] verbose_name = _('Event') verbose_name_plural = _('Events') def __init__(self, *args, **kwargs): super(Event, self).__init__(*args, **kwargs) self.__state = self.state def __str__(self): if self.state == Event.STATE_SCHEDULED: if self.single_day: readable = _('%(event)s (%(date)s - %(end)s)') % { 'event': self.title, 'date': localize(self.from_date, 'd. F Y h:i'), 'end': localize(self.to_date, 'h:i'), } else: readable = _('%(event)s (%(from)s - %(to)s)') % { 'event': self.title, 'from': localize(self.from_date, 'd. F Y h:i'), 'to': localize(self.to_date, 'd. F Y h:i'), } elif self.state == Event.STATE_CANCELED: readable = _('%(event)s (canceled)') % {'event': self.title} elif self.state == Event.STATE_VOTING_OPEN: readable = _('%(event)s (pending)') % {'event': self.title} else: readable = _('%(event)s (archived)') % {'event': self.title} return readable def save(self, created_from_doodle=False, *args, **kwargs): created = bool(self.pk) == False super(Event, self).save(*args, **kwargs) if created and not created_from_doodle: # event/doodle was created if self.state == Event.STATE_SCHEDULED: cosinnus_notifications.event_created.send( sender=self, user=self.creator, obj=self, audience=get_user_model().objects.filter( id__in=self.group.members).exclude(id=self.creator.pk)) else: cosinnus_notifications.doodle_created.send( sender=self, user=self.creator, obj=self, audience=get_user_model().objects.filter( id__in=self.group.members).exclude(id=self.creator.pk)) if created and created_from_doodle: # event went from being a doodle to being a real event, so fire event created cosinnus_notifications.event_created.send( sender=self, user=self.creator, obj=self, audience=get_user_model().objects.filter( id__in=self.group.members).exclude(id=self.creator.pk)) # create a "going" attendance for the event's creator if created and self.state == Event.STATE_SCHEDULED: EventAttendance.objects.get_or_create( event=self, user=self.creator, defaults={'state': EventAttendance.ATTENDANCE_GOING}) self.__state = self.state def get_absolute_url(self): kwargs = {'group': self.group, 'slug': self.slug} if self.state == Event.STATE_VOTING_OPEN: return group_aware_reverse('cosinnus:event:doodle-vote', kwargs=kwargs) elif self.state == Event.STATE_ARCHIVED_DOODLE: return group_aware_reverse('cosinnus:event:doodle-archived', kwargs=kwargs) return group_aware_reverse('cosinnus:event:event-detail', kwargs=kwargs) def set_suggestion( self, sugg=None, update_fields=['from_date', 'to_date', 'state', 'suggestion']): if sugg is None: # No suggestion selected or remove selection self.from_date = None self.to_date = None self.state = Event.STATE_VOTING_OPEN self.suggestion = None elif sugg.event.pk == self.pk: # Make sure to not assign a suggestion belonging to another event. self.from_date = sugg.from_date self.to_date = sugg.to_date self.state = Event.STATE_SCHEDULED self.suggestion = sugg else: return self.save(update_fields=update_fields) @property def single_day(self): return localtime(self.from_date).date() == localtime( self.to_date).date() def get_period(self): if self.single_day: return localize(self.from_date, "d.m.Y") else: return "%s - %s" % (localize( self.from_date, "d.m."), localize(self.to_date, "d.m.Y")) @classmethod def get_current(self, group, user): """ Returns a queryset of the current upcoming events """ qs = Event.objects.filter(group=group).filter( state__in=[Event.STATE_SCHEDULED, Event.STATE_VOTING_OPEN]) if user: qs = filter_tagged_object_queryset_for_user(qs, user) return upcoming_event_filter(qs) @classmethod def get_current_for_portal(self): """ Returns a queryset of the current upcoming events in this portal """ qs = Event.objects.filter( group__portal=CosinnusPortal.get_current()).filter( state__in=[Event.STATE_SCHEDULED]) return upcoming_event_filter(qs) @property def is_same_day(self): return localtime(self.from_date).date() == localtime( self.to_date).date() @property def is_same_time(self): return self.from_date.time() == self.to_date.time() def get_voters_pks(self): """ Gets the pks of all Users that have voted for this event. Returns an empty list if nobody has voted or the event isn't a doodle. """ return self.suggestions.all().values_list('votes__voter__id', flat=True).distinct()
class Location(models.Model): location = OSMField() location_lat = LatitudeField() location_lon = LongitudeField() details = models.TextField(blank=True)
def test_longitude_field(self): field = LongitudeField() field.set_attributes_from_name("location_lon") formfield = field.formfield() self.assertEqual(formfield.max_value, 180) self.assertEqual(formfield.min_value, -180)
class Event(LikeableObjectMixin, BaseTaggableObjectModel): SORT_FIELDS_ALIASES = [ ('title', 'title'), ('from_date', 'from_date'), ('to_date', 'to_date'), ('city', 'city'), ('state', 'state'), ] STATE_SCHEDULED = 1 STATE_VOTING_OPEN = 2 STATE_CANCELED = 3 STATE_ARCHIVED_DOODLE = 4 STATE_CHOICES = ( (STATE_SCHEDULED, _('Scheduled')), (STATE_VOTING_OPEN, _('Voting open')), (STATE_CANCELED, _('Canceled')), (STATE_ARCHIVED_DOODLE, _('Archived Event Poll')), ) from_date = models.DateTimeField(_('Start'), default=None, blank=True, null=True, editable=True) to_date = models.DateTimeField(_('End'), default=None, blank=True, null=True, editable=True) state = models.PositiveIntegerField( _('State'), choices=STATE_CHOICES, default=STATE_VOTING_OPEN, ) __state = None # pre-save purpose # used as special flag for a hidden conference event # that mimics the conference and can be used in normal Event querysets as proxy for the conference # the logic for this is in `cosinnus_event.hooks` is_hidden_group_proxy = models.BooleanField( _('Is hidden proxy'), help_text= 'If set, this event is hidden in its own group, acting as a proxy for the group with from_date and to_date synced, to be able to be shown in other groups.', default=False) note = models.TextField(_('Note'), blank=True, null=True) suggestion = models.ForeignKey( 'Suggestion', verbose_name=_('Event date'), on_delete=models.SET_NULL, null=True, blank=True, related_name='selected_name', ) location = OSMField(_('Location'), blank=True, null=True) location_lat = LatitudeField(_('Latitude'), blank=True, null=True) location_lon = LongitudeField(_('Longitude'), blank=True, null=True) street = models.CharField(_('Street'), blank=True, max_length=50, null=True) zipcode = models.PositiveIntegerField(_('ZIP code'), blank=True, null=True) city = models.CharField(_('City'), blank=True, max_length=50, null=True) public = models.BooleanField(_('Is public (on website)'), default=False) image = models.ImageField(_('Image'), upload_to=get_event_image_filename, blank=True, null=True) url = models.URLField(_('URL'), blank=True, null=True) original_doodle = models.OneToOneField( "self", verbose_name=_('Original Event Poll'), related_name='scheduled_event', null=True, blank=True, on_delete=models.SET_NULL) objects = EventQuerySet.as_manager() timeline_template = 'cosinnus_event/v2/dashboard/timeline_item.html' class Meta(BaseTaggableObjectModel.Meta): ordering = ['from_date', 'to_date', 'title'] verbose_name = _('Event') verbose_name_plural = _('Events') def __init__(self, *args, **kwargs): super(Event, self).__init__(*args, **kwargs) self.__state = self.state def __str__(self): if self.is_hidden_group_proxy: readable = _('%(event)s (hidden proxy)') % {'event': self.title} elif self.state == Event.STATE_SCHEDULED: if self.single_day: readable = _('%(event)s (%(date)s - %(end)s)') % { 'event': self.title, 'date': localize(self.from_date, 'd. F Y h:i'), 'end': localize(self.to_date, 'h:i'), } else: readable = _('%(event)s (%(from)s - %(to)s)') % { 'event': self.title, 'from': localize(self.from_date, 'd. F Y h:i'), 'to': localize(self.to_date, 'd. F Y h:i'), } elif self.state == Event.STATE_CANCELED: readable = _('%(event)s (canceled)') % {'event': self.title} elif self.state == Event.STATE_VOTING_OPEN: readable = _('%(event)s (pending)') % {'event': self.title} elif self.state == Event.STATE_ARCHIVED_DOODLE: readable = _('%(event)s (archived)') % {'event': self.title} else: readable = _('%(event)s (state unknown)') % {'event': self.title} return readable def get_icon(self): """ Returns the font-awesome icon specific to this object type """ if self.state == 2: return 'fa-calendar-check-o' else: return 'fa-calendar' def save(self, created_from_doodle=False, *args, **kwargs): created = bool(self.pk) == False super(Event, self).save(*args, **kwargs) if created and not self.is_hidden_group_proxy: # event/doodle was created or # event went from being a doodle to being a real event, so fire event created session_id = uuid1().int audience = get_user_model().objects.filter( id__in=self.group.members) if self.creator: audience = audience.exclude(id=self.creator.pk) group_followers_except_creator_ids = [ pk for pk in self.group.get_followed_user_ids() if not pk in [self.creator_id] ] group_followers_except_creator = get_user_model().objects.filter( id__in=group_followers_except_creator_ids) if self.state == Event.STATE_SCHEDULED: # followers for the group cosinnus_notifications.followed_group_event_created.send( sender=self, user=self.creator, obj=self, audience=group_followers_except_creator, session_id=session_id) # regular members cosinnus_notifications.event_created.send( sender=self, user=self.creator, obj=self, audience=audience, session_id=session_id, end_session=True) else: # followers for the group cosinnus_notifications.followed_group_doodle_created.send( sender=self, user=self.creator, obj=self, audience=group_followers_except_creator, session_id=session_id) # regular members cosinnus_notifications.doodle_created.send( sender=self, user=self.creator, obj=self, audience=audience, session_id=session_id, end_session=True) # create a "going" attendance for the event's creator if settings.COSINNUS_EVENT_MARK_CREATOR_AS_GOING and created and self.state == Event.STATE_SCHEDULED: EventAttendance.objects.get_or_create( event=self, user=self.creator, defaults={'state': EventAttendance.ATTENDANCE_GOING}) self.__state = self.state def get_absolute_url(self): kwargs = {'group': self.group, 'slug': self.slug} if self.state == Event.STATE_VOTING_OPEN: return group_aware_reverse('cosinnus:event:doodle-vote', kwargs=kwargs) elif self.state == Event.STATE_ARCHIVED_DOODLE: return group_aware_reverse('cosinnus:event:doodle-archived', kwargs=kwargs) elif self.is_hidden_group_proxy: # hidden proxy events redirect to the group return self.group.get_absolute_url() return group_aware_reverse('cosinnus:event:event-detail', kwargs=kwargs) def get_edit_url(self): kwargs = {'group': self.group, 'slug': self.slug} if self.state == Event.STATE_VOTING_OPEN or self.state == Event.STATE_ARCHIVED_DOODLE: return group_aware_reverse('cosinnus:event:doodle-edit', kwargs=kwargs) elif self.is_hidden_group_proxy: # hidden proxy events redirect to the group return self.group.get_edit_url() return group_aware_reverse('cosinnus:event:event-edit', kwargs=kwargs) def get_delete_url(self): kwargs = {'group': self.group, 'slug': self.slug} if self.state == Event.STATE_VOTING_OPEN or self.state == Event.STATE_ARCHIVED_DOODLE: return group_aware_reverse('cosinnus:event:doodle-delete', kwargs=kwargs) elif self.is_hidden_group_proxy: # hidden proxy events redirect to the group return self.group.get_delete_url() return group_aware_reverse('cosinnus:event:event-delete', kwargs=kwargs) def is_user_attending(self, user): """ For notifications, statecheck if a user is attending this event """ return self.attendances.filter( user=user, state__in=[ EventAttendance.ATTENDANCE_GOING, EventAttendance.ATTENDANCE_MAYBE_GOING ]).count() >= 1 def special_alert_check(self, user): """ Can override checking whether this user wants this alert """ return self.is_user_attending(user) @property def sort_key(self): """ Overriding this sort key so re-ordering won't happen for widgets using events (because all event querysets are already well-sorted.) """ return 0 @property def stream_sort_key(self): """ Sort key for activity streams returns the created date instead of the event date """ return self.created def set_suggestion( self, sugg=None, update_fields=['from_date', 'to_date', 'state', 'suggestion']): if sugg is None: # No suggestion selected or remove selection self.from_date = None self.to_date = None self.state = Event.STATE_VOTING_OPEN self.suggestion = None elif sugg.event.pk == self.pk: # Make sure to not assign a suggestion belonging to another event. self.from_date = sugg.from_date self.to_date = sugg.to_date self.state = Event.STATE_SCHEDULED self.suggestion = sugg else: return self.save(update_fields=update_fields) @property def single_day(self): return localtime(self.from_date).date() == localtime( self.to_date).date() def get_humanized_event_time_html(self): return mark_safe( render_to_string('cosinnus_event/common/humanized_event_time.html', {'event': self})).strip() def get_period(self): if self.single_day: return localize(self.from_date, "d.m.Y") else: return "%s - %s" % (localize( self.from_date, "d.m."), localize(self.to_date, "d.m.Y")) @classmethod def get_current(self, group, user, include_sub_projects=False): """ Returns a queryset of the current upcoming events """ groups = [group] if include_sub_projects: groups = groups + list(group.get_children()) qs = Event.objects.filter(group__in=groups).filter(state__in=[ Event.STATE_SCHEDULED, Event.STATE_VOTING_OPEN, ]) if not include_sub_projects: # mix in reflected objects, not needed if we are sub-grouping anyways for onegroup in groups: if "%s.%s" % (self._meta.app_label, self._meta.model_name ) in settings.COSINNUS_REFLECTABLE_OBJECTS: mixin = MixReflectedObjectsMixin() qs = mixin.mix_queryset(qs, self._meta.model, onegroup) if user: qs = filter_tagged_object_queryset_for_user(qs, user) return upcoming_event_filter(qs).distinct() @classmethod def get_current_for_portal(self): """ Returns a queryset of the current upcoming events in this portal """ qs = Event.objects.filter( group__portal=CosinnusPortal.get_current()).filter( state__in=[Event.STATE_SCHEDULED]) return upcoming_event_filter(qs) @property def is_same_day(self): if not self.from_date or not self.to_date: return True return localtime(self.from_date).date() == localtime( self.to_date).date() @property def is_same_time(self): if not self.from_date or not self.to_date: return True return self.from_date.time() == self.to_date.time() @property def is_all_day(self): if not self.from_date or not self.to_date: return False return (localize(self.from_date, "H:i") == '00:00') and (localize( self.to_date, "H:i") == '23:59') def get_voters_pks(self): """ Gets the pks of all Users that have voted for this event. Returns an empty list if nobody has voted or the event isn't a doodle. """ return self.suggestions.all().values_list('votes__voter__id', flat=True).distinct() def get_suggestions_hash(self): """ Returns a hashable string containing all suggestions with their time. Useful to compare equality of suggestions for two doodles. """ return ','.join([ str(time.mktime(dt.timetuple())) for dt in self.suggestions.all().values_list('from_date', flat=True) ]) def get_comment_post_url(self): return group_aware_reverse('cosinnus:event:comment', kwargs={ 'group': self.group, 'event_slug': self.slug }) def get_attendants_count(self): all_attendants = EventAttendance.objects.filter(event=self) attendants_going = all_attendants.filter( state=EventAttendance.ATTENDANCE_GOING) return attendants_going.count()
class BaseTagObject(models.Model): VISIBILITY_USER = 0 # for Users, this setting means: "Only Group Members can see me" VISIBILITY_GROUP = 1 # for Users, this setting means: "Only Logged in Users can see me" VISIBILITY_ALL = 2 # for Users, this setting means: "Everyone can see me" #: Choices for :attr:`visibility`: ``(int, str)`` # Empty first choice must be included for select2 placeholder compatibility! VISIBILITY_CHOICES = ( ('', ''), (VISIBILITY_USER, _('Only me')), (VISIBILITY_GROUP, _('Team members only')), (VISIBILITY_ALL, _('Public (visible without login)')), ) group = models.ForeignKey(settings.COSINNUS_GROUP_OBJECT_MODEL, verbose_name=_('Team'), related_name='+', null=True, on_delete=models.CASCADE) persons = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, null=True, verbose_name=_('Persons'), related_name='+') tags = TaggableManager(_('Tags'), blank=True) visibility = models.PositiveSmallIntegerField(_('Permissions'), blank=True, default=VISIBILITY_GROUP, choices=VISIBILITY_CHOICES) #: Choices for :attr:`approach`: ``(str, str)`` # Empty first choice must be included for select2 placeholder compatibility! APPROACH_CHOICES = ( ('', ''), ('zivilgesellschaft', 'Zivilgesellschaft'), ('politik', 'Politik'), ('forschung', 'Forschung'), ('unternehmen', 'Unternehmen'), ) location = OSMField(_('Location'), blank=True, null=True) location_lat = LatitudeField(_('Latitude'), blank=True, null=True) location_lon = LongitudeField(_('Longitude'), blank=True, null=True) place = models.CharField(_('Place'), max_length=100, default='', blank=True) valid_start = models.DateTimeField(_('Valid from'), blank=True, null=True) valid_end = models.DateTimeField(_('Valid to'), blank=True, null=True) approach = models.CharField(_('Approach'), blank=True, null=True, choices=APPROACH_CHOICES, max_length=255) #: Choices for :attr:`topics`: ``(int, str)`` # Empty first choice must be included for select2 placeholder compatibility! TOPIC_CHOICES = getattr(settings, 'COSINNUS_TOPIC_CHOICES', []) topics = models.CommaSeparatedIntegerField( _('Topics'), blank=True, null=True, max_length=255) # We cannot add choices here as this would # fail validation text_topics = models.ManyToManyField(CosinnusTopicCategory, verbose_name=_('Text Topics'), related_name='tagged_objects', blank=True, null=True) likes = models.PositiveSmallIntegerField(_('Likes'), blank=True, default=0) likers = models.ManyToManyField( settings.AUTH_USER_MODEL, blank=True, null=True, related_name='likes+') # no reverse relation on model def save(self, *args, **kwargs): # update like count if self.pk: self.likes = self.likers.count() super(BaseTagObject, self).save(*args, **kwargs) def get_all_language_topics_rendered(self): """ Returns a single string with all assigned topic strings for each language """ if not self.topics: return '' renders = [] cur_language = translation.get_language() try: for lang in settings.LANGUAGES: translation.activate(lang[0]) topi = self.get_topics_rendered() renders.append(topi) finally: if not cur_language: translation.deactivate() else: translation.activate(cur_language) return ', '.join([topic_str for topic_str in renders if topic_str]) def get_topics_rendered(self): ret = ', '.join([force_text(t) for t in self.get_topics()]) return ret def get_topics(self): ret = [] if self.topics: m = dict(BaseTagObject.TOPIC_CHOICES) for i in [ int(x.strip()) for x in [topic for topic in self.topics.split(',') if topic] ]: t = m.get(i, None) if t: ret.append(t) return ret @property def location_url(self): if not self.location_lat or not self.location_lon: return None return 'http://www.openstreetmap.org/?mlat=%s&mlon=%s&zoom=15&layers=M' % ( self.location_lat, self.location_lon) class Meta(object): abstract = True def __str__(self): return "Tag object {0}".format(self.pk)