Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ docker-compose exec app ./manage.py migrate
- Miguel Báez https://github.com/migueljoba
- Osbarge https://github.com/osbarge
- Pablo Santa Cruz https://github.com/pablo
- Roque Vera https://github.com/roquegv

## TODO

Expand Down
4 changes: 4 additions & 0 deletions conf/api_urls.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from rest_framework import routers
from core import api as core_api
from org import api as org_api
from ollas import api as ollas_api
from django.urls import include, path

PREFIX = "api/v1"
Expand All @@ -13,6 +14,9 @@
# ORG
router.register(r'donationcenters', org_api.DonationCenterViewSet)
router.register(r'donationcentersgeo', org_api.DonationCenterGeoViewSet)
# Ollas Populares
router.register(r'ollaspopulares', ollas_api.OllaPopularViewSet, 'ollaspopulares')
router.register(r'ollaspopularesgeo', ollas_api.OllaPopularGeoViewSet)

urlpatterns = [
path(f"{PREFIX}/", include(router.urls)),
Expand Down
7 changes: 7 additions & 0 deletions conf/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
'django.contrib.gis',
'core',
'org',
'ollas',
'widget_tweaks',
'rest_framework',
'rest_framework_gis',
Expand Down Expand Up @@ -203,6 +204,12 @@
),
'output_filename': 'scripts/list-donation.min.js',
},
'list-ollas.js': {
'source_filenames': (
'scripts/list-ollas.js',
),
'output_filename': 'scripts/list-ollas.min.js',
},
'leaflet-patch.js': {
'source_filenames': (
'scripts/leaflet-patch.js',
Expand Down
7 changes: 7 additions & 0 deletions conf/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

from conf import api_urls
from core import views as core_views
from ollas import views as ollas_views
from org import views as org_views
from org.views import RestrictedView

Expand Down Expand Up @@ -39,6 +40,12 @@
path('voluntario', TemplateView.as_view(template_name="volunteer/form.html"), name='voluntario'),
# login/logout
path('accounts/', include('django.contrib.auth.urls')),
# ollas populares
path('olla', TemplateView.as_view(template_name="olla_popular/info.html")),
path('nueva-olla', ollas_views.olla_form, name="olla-form"),
path('ollas/<int:id>', ollas_views.view_olla, name="olla-detail"),
path('ollas_ciudad/<slug:city>', ollas_views.list_by_city, name='ollas-by-city'),
path('ollas', ollas_views.list_ollas, name="olla-list"),
]
urlpatterns += api_urls.urlpatterns
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Expand Down
Empty file added ollas/__init__.py
Empty file.
44 changes: 44 additions & 0 deletions ollas/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from django.contrib import admin
from leaflet.admin import LeafletGeoAdmin

from ollas.models import OllaPopular


def unresolve(modeladmin, request, queryset):
queryset.update(resolved=False)


def resolve(modeladmin, request, queryset):
queryset.update(resolved=True)


def deactivate(modeladmin, request, queryset):
queryset.update(active=False)


def activate(modeladmin, request, queryset):
queryset.update(active=True)

resolve.short_description = "Marcar ollas populares seleccionadas como resueltas"
unresolve.short_description = "Marcar ollas populares seleccionadas como NO resueltas"
deactivate.short_description = "Marcar ollas populares seleccionadas como inactivas"
activate.short_description = "Marcar ollas populares seleccionadas como activas"

# Register your models here.
class OllaPopularAdmin(LeafletGeoAdmin):
list_display = (
"__str__",
"id",
"name",
"phone",
"resolved",
"active",
"title",
"message",
"upvotes",
"downvotes",
)
search_fields = ["title", "message", "name", "phone"]
actions = [resolve, unresolve, deactivate, activate]

admin.site.register(OllaPopular, OllaPopularAdmin)
44 changes: 44 additions & 0 deletions ollas/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters
from rest_framework import viewsets, status, mixins
from rest_framework.response import Response
from rest_framework_gis.filters import InBBoxFilter

from core.middleware import USER_TYPE_DEVICE
from core.serializers import DeviceSerializer
from core.models import Device, User

from ollas.models import OllaPopular
from ollas.serializers import OllaPopularSerializer, OllaPopularGeoJSONSerializer

"""
API endpoints that allows search queries on OllaPopular 0
"""


# SEARCH OLLAS POPULARES
class DynamicSearchFilter(filters.SearchFilter):
def get_search_fields(self, view, request):
return request.GET.getlist('search_fields', [])


class OllaPopularViewSet(viewsets.ModelViewSet):
queryset = OllaPopular.objects.filter(active=True, resolved=False).order_by('-id')
serializer_class = OllaPopularSerializer
filter_backends = [InBBoxFilter, DjangoFilterBackend, DynamicSearchFilter, ]
search_fields = ['title', 'phone',]
filterset_fields = {
'added': ['gte', 'lte'],
'city': ['exact'],
}
bbox_filter_field = 'location'
bbox_filter_include_overlapping = True


class OllaPopularGeoViewSet(viewsets.ReadOnlyModelViewSet):
queryset = OllaPopular.objects.filter(active=True, resolved=False).order_by('-pk')
pagination_class = None
serializer_class = OllaPopularGeoJSONSerializer
bbox_filter_field = 'location'
filter_backends = (InBBoxFilter, DynamicSearchFilter,)
bbox_filter_include_overlapping = True
5 changes: 5 additions & 0 deletions ollas/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.apps import AppConfig


class OllasConfig(AppConfig):
name = 'ollas'
50 changes: 50 additions & 0 deletions ollas/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from django import forms
from leaflet.forms.fields import PointField
from django.core.exceptions import NON_FIELD_ERRORS
from django.utils.safestring import mark_safe

from .models import OllaPopular


class OllaPopularForm(forms.ModelForm):
location = PointField(
label="Ubicación",
error_messages={'required': mark_safe('Te olvidaste de marcar tu ubicación en el mapita\n <br>Si tenés problemas con este paso <a href="#" class="is-link modal-button" data-target="#myModal" aria-haspopup="true">mirá esta ayuda</a></p><p id="div_direccion" style="font-size: 10px; margin-bottom: 5px;"></p>')},
help_text=mark_safe('<p style="margin-bottom:5px;font-size:10px;">Seleccioná tu ubicación para que la gente pueda encontrarte, si no querés marcar tu casa una buena opción puede ser la comisaría más cercana o algún otro sitio público cercano.\
<br>Si tenés problemas con este paso <a href="#" class="is-link modal-button" data-target="#myModal" aria-haspopup="true">mirá esta ayuda</a></p><p id="div_direccion" style="font-size: 10px; margin-bottom: 5px;"></p>'),
)

class Meta:
model = OllaPopular
fields = (
"title",
"message",
"name",
"phone",
"location",
"address",
"picture"
)
widgets = {
"title": forms.TextInput(
attrs={
"class": "input",
"placeholder": "Ejemplo: Olla Popular del barrio Caacupemi del Bañado Sur",
}
),
"message": forms.Textarea(
attrs={
"class": "textarea",
"rows": 4,
"placeholder": "Ejemplo: Somos un grupo de mujeres que nos organizamos para dar de comer a más de 220 personas, entre niños/as y adultos/as. Necesitamos alimentos para seguir dando de comer a nuestra gente: frutas, verduras, poroto, maiz, arroz, harina, aceite, carne, huevo... cualquier cosa ayuda.\nMuchas Gracias!",
}
),
"name": forms.TextInput(attrs={"class": "input"}),
"phone": forms.TextInput(attrs={"class": "input", "type": "tel"}),
"address": forms.TextInput(attrs={"class": "input"}),
}
error_messages = {
NON_FIELD_ERRORS: {
'unique_together': "Registro ya ingresado, no puede duplicar la misma olla popular.",
}
}
74 changes: 74 additions & 0 deletions ollas/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Generated by Django 2.2.12 on 2020-04-24 23:03

import core.utils
from django.conf import settings
import django.contrib.gis.db.models.fields
import django.contrib.postgres.search
from django.db import migrations, models
import django.db.models.deletion
import simple_history.models


class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name='OllaPopular',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(db_index=True, help_text='Escribe un nombre para identificar a la Olla Popular', max_length=200, verbose_name='Nombre de la olla popular')),
('message', models.TextField(db_index=True, help_text='Acá podés contar detalladamente lo que necesitás para tu olla popular, <b>cuanto mejor cuentes tu situación es más probable que te quieran ayudar</b>', max_length=2000, null=True, verbose_name='Descripción del pedido')),
('name', models.CharField(max_length=200, verbose_name='Nombre y Apellido del responsable')),
('phone', models.CharField(max_length=30, verbose_name='Teléfono de contacto')),
('address', models.CharField(help_text='Para ayudar a quien quiera ayudarte saber la dirección, ciudad, barrio, referencias, o cómo llegar', max_length=400, null=True, verbose_name='Dirección')),
('location', django.contrib.gis.db.models.fields.PointField(help_text='<p style="margin-bottom:5px;font-size:10px;">Seleccioná tu ubicación para que la gente pueda encontrarte, si no querés marcar tu casa una buena opción puede ser la comisaría más cercana o algún otro sitio público cercano. <br>Si tenés problemas con este paso <a href="#" class="is-link modal-button" data-target="#myModal" aria-haspopup="true">mirá esta ayuda</a></p><p id="div_direccion" style="font-size: 10px; margin-bottom: 5px;"></p>', srid=4326, verbose_name='Ubicación')),
('picture', models.ImageField(blank=True, help_text='Si querés podés adjuntar una foto relacionada con tu pedido, es opcional pero puede ayudar a que la gente entienda mejor tu situación', null=True, upload_to=core.utils.rename_img, verbose_name='Foto')),
('resolved', models.BooleanField(db_index=True, default=False)),
('active', models.BooleanField(db_index=True, default=True)),
('added', models.DateTimeField(auto_now_add=True, db_index=True, null=True, verbose_name='Agregado')),
('upvotes', models.IntegerField(blank=True, default=0)),
('downvotes', models.IntegerField(blank=True, default=0)),
('city', models.CharField(blank=True, default='', editable=False, max_length=50)),
('city_code', models.CharField(blank=True, default='', editable=False, max_length=50)),
('search_vector', django.contrib.postgres.search.SearchVectorField()),
],
),
migrations.CreateModel(
name='HistoricalOllaPopular',
fields=[
('id', models.IntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
('title', models.CharField(db_index=True, help_text='Escribe un nombre para identificar a la Olla Popular', max_length=200, verbose_name='Nombre de la olla popular')),
('message', models.TextField(db_index=True, help_text='Acá podés contar detalladamente lo que necesitás para tu olla popular, <b>cuanto mejor cuentes tu situación es más probable que te quieran ayudar</b>', max_length=2000, null=True, verbose_name='Descripción del pedido')),
('name', models.CharField(max_length=200, verbose_name='Nombre y Apellido del responsable')),
('phone', models.CharField(max_length=30, verbose_name='Teléfono de contacto')),
('address', models.CharField(help_text='Para ayudar a quien quiera ayudarte saber la dirección, ciudad, barrio, referencias, o cómo llegar', max_length=400, null=True, verbose_name='Dirección')),
('location', django.contrib.gis.db.models.fields.PointField(help_text='<p style="margin-bottom:5px;font-size:10px;">Seleccioná tu ubicación para que la gente pueda encontrarte, si no querés marcar tu casa una buena opción puede ser la comisaría más cercana o algún otro sitio público cercano. <br>Si tenés problemas con este paso <a href="#" class="is-link modal-button" data-target="#myModal" aria-haspopup="true">mirá esta ayuda</a></p><p id="div_direccion" style="font-size: 10px; margin-bottom: 5px;"></p>', srid=4326, verbose_name='Ubicación')),
('picture', models.TextField(blank=True, help_text='Si querés podés adjuntar una foto relacionada con tu pedido, es opcional pero puede ayudar a que la gente entienda mejor tu situación', max_length=100, null=True, verbose_name='Foto')),
('resolved', models.BooleanField(db_index=True, default=False)),
('active', models.BooleanField(db_index=True, default=True)),
('added', models.DateTimeField(blank=True, db_index=True, editable=False, null=True, verbose_name='Agregado')),
('upvotes', models.IntegerField(blank=True, default=0)),
('downvotes', models.IntegerField(blank=True, default=0)),
('city', models.CharField(blank=True, default='', editable=False, max_length=50)),
('city_code', models.CharField(blank=True, default='', editable=False, max_length=50)),
('search_vector', django.contrib.postgres.search.SearchVectorField()),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'historical olla popular',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
]
Empty file added ollas/migrations/__init__.py
Empty file.
Loading