diff --git a/.gitignore b/.gitignore index db4561eaa1d4f3ed01af114a315a0053776ffed0..1af6787ec0b72af7a58ecd8bfd57051a60508677 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +source/data + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -52,3 +54,15 @@ docs/_build/ # PyBuilder target/ + +# Django test database +source/test_db.sqlite3 + +# linux trash +*.*~ + +# vagrant +.vagrant + +# IDE trash +.idea/* diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000000000000000000000000000000000..6aac37d3972b3a8e9e2505f69d7a8ee1170377f4 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "source/excerptexport/static/excerptexport/libraries/leaflet-locationfilter"] + path = source/excerptexport/static/excerptexport/libraries/leaflet-locationfilter + url = https://github.com/kajic/leaflet-locationfilter.git diff --git a/README.md b/README.md index fd3b7786d7bed7deaedf5f3ba5dc5c4c9fa81fb8..f9659ce9df3caa08aba7595fe412124cc9801956 100644 --- a/README.md +++ b/README.md @@ -4,3 +4,12 @@ Short project name for "<strong>O</strong>pen<strong>S</strong>treet<strong>M</s Cuts out OpenStreetMap data, processes it to geodata and converts it to typical GIS fileformats before being prepared for download. Website: http://osmaxx.hsr.ch/ + + +## Development +See `developmentEnvironment/` for instructions. + + +# Documentation + +See Wiki: https://github.com/geometalab/osmaxx/wiki diff --git a/data/150310-osmaxx-data.sql b/data/150310-osmaxx-data.sql new file mode 100644 index 0000000000000000000000000000000000000000..726f3dad01473c7a8ccc33b711e6d1a83d93b337 --- /dev/null +++ b/data/150310-osmaxx-data.sql @@ -0,0 +1,305 @@ +-- +-- PostgreSQL database dump +-- + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SET check_function_bodies = false; +SET client_min_messages = warning; + +SET search_path = public, pg_catalog; + +-- +-- Data for Name: auth_group; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY auth_group (id, name) FROM stdin; +\. + + +-- +-- Name: auth_group_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('auth_group_id_seq', 1, false); + + +-- +-- Data for Name: django_content_type; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY django_content_type (id, name, app_label, model) FROM stdin; +1 log entry admin logentry +2 permission auth permission +3 group auth group +4 user auth user +5 content type contenttypes contenttype +6 session sessions session +7 post gis geometry columns gis postgisgeometrycolumns +8 post gis spatial ref sys gis postgisspatialrefsys +9 excerpt excerptexport excerpt +10 bounding geometry excerptexport boundinggeometry +11 extraction order excerptexport extractionorder +12 output file excerptexport outputfile +\. + + +-- +-- Data for Name: auth_permission; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY auth_permission (id, name, content_type_id, codename) FROM stdin; +1 Can add log entry 1 add_logentry +2 Can change log entry 1 change_logentry +3 Can delete log entry 1 delete_logentry +4 Can add permission 2 add_permission +5 Can change permission 2 change_permission +6 Can delete permission 2 delete_permission +7 Can add group 3 add_group +8 Can change group 3 change_group +9 Can delete group 3 delete_group +10 Can add user 4 add_user +11 Can change user 4 change_user +12 Can delete user 4 delete_user +13 Can add content type 5 add_contenttype +14 Can change content type 5 change_contenttype +15 Can delete content type 5 delete_contenttype +16 Can add session 6 add_session +17 Can change session 6 change_session +18 Can delete session 6 delete_session +19 Can add post gis geometry columns 7 add_postgisgeometrycolumns +20 Can change post gis geometry columns 7 change_postgisgeometrycolumns +21 Can delete post gis geometry columns 7 delete_postgisgeometrycolumns +22 Can add post gis spatial ref sys 8 add_postgisspatialrefsys +23 Can change post gis spatial ref sys 8 change_postgisspatialrefsys +24 Can delete post gis spatial ref sys 8 delete_postgisspatialrefsys +25 Can add excerpt 9 add_excerpt +26 Can change excerpt 9 change_excerpt +27 Can delete excerpt 9 delete_excerpt +28 Can add bounding geometry 10 add_boundinggeometry +29 Can change bounding geometry 10 change_boundinggeometry +30 Can delete bounding geometry 10 delete_boundinggeometry +31 Can add extraction order 11 add_extractionorder +32 Can change extraction order 11 change_extractionorder +33 Can delete extraction order 11 delete_extractionorder +34 Can add output file 12 add_outputfile +35 Can change output file 12 change_outputfile +36 Can delete output file 12 delete_outputfile +\. + + +-- +-- Data for Name: auth_group_permissions; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY auth_group_permissions (id, group_id, permission_id) FROM stdin; +\. + + +-- +-- Name: auth_group_permissions_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('auth_group_permissions_id_seq', 1, false); + + +-- +-- Name: auth_permission_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('auth_permission_id_seq', 36, true); + + +-- +-- Data for Name: auth_user; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY auth_user (id, password, last_login, is_superuser, username, first_name, last_name, email, is_staff, is_active, date_joined) FROM stdin; +1 pbkdf2_sha256$15000$g6ka3dz4xWs2$dnrccGcgQYNXYpYUIIGSfA31+2wMt4qFIa/vOwzXmDY= 2015-03-10 14:21:30.210686+00 t admin t t 2015-03-10 14:21:12.39213+00 +\. + + +-- +-- Data for Name: auth_user_groups; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY auth_user_groups (id, user_id, group_id) FROM stdin; +\. + + +-- +-- Name: auth_user_groups_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('auth_user_groups_id_seq', 1, false); + + +-- +-- Name: auth_user_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('auth_user_id_seq', 1, true); + + +-- +-- Data for Name: auth_user_user_permissions; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY auth_user_user_permissions (id, user_id, permission_id) FROM stdin; +\. + + +-- +-- Name: auth_user_user_permissions_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('auth_user_user_permissions_id_seq', 1, false); + + +-- +-- Data for Name: django_admin_log; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) FROM stdin; +\. + + +-- +-- Name: django_admin_log_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('django_admin_log_id_seq', 1, false); + + +-- +-- Name: django_content_type_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('django_content_type_id_seq', 12, true); + + +-- +-- Data for Name: django_migrations; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY django_migrations (id, app, name, applied) FROM stdin; +1 contenttypes 0001_initial 2015-03-10 14:20:32.99273+00 +2 auth 0001_initial 2015-03-10 14:20:33.099779+00 +3 admin 0001_initial 2015-03-10 14:20:33.149468+00 +4 excerptexport 0001_initial 2015-03-10 14:20:33.276293+00 +5 sessions 0001_initial 2015-03-10 14:20:33.300442+00 +\. + + +-- +-- Name: django_migrations_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('django_migrations_id_seq', 5, true); + + +-- +-- Data for Name: django_session; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY django_session (session_key, session_data, expire_date) FROM stdin; +3pteq1w1mu5t441ch61ga288rgvixjse YzJmN2I5ZjMyMGRhYWRjMjAzN2I1ZTc2ODdhZmE1MjE3MzIwN2QxMDp7Il9hdXRoX3VzZXJfaWQiOjEsIl9hdXRoX3VzZXJfYmFja2VuZCI6ImRqYW5nby5jb250cmliLmF1dGguYmFja2VuZHMuTW9kZWxCYWNrZW5kIiwiX2F1dGhfdXNlcl9oYXNoIjoiNjdlYTJlMzg3ZTQyOGIyMWI5NWRjNmQzMTI4ODM1YmI3ZDE3Yjg1YyJ9 2015-03-24 14:21:30.212299+00 +\. + + +-- +-- Data for Name: excerptexport_excerpt; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY excerptexport_excerpt (id, name, is_public, is_active, owner_id) FROM stdin; +1 Neverland f t 1 +2 Rappi t t 1 +\. + + +-- +-- Data for Name: excerptexport_boundinggeometry; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY excerptexport_boundinggeometry (id, type, geometry, excerpt_id) FROM stdin; +1 0 0103000020E610000001000000050000000000000000FC52401F11A3BE66E34B400000000000FC5240BC5F5442D9A05040FFFFFFFFFF955E40BC5F5442D9A05040FFFFFFFFFF955E401F11A3BE66E34B400000000000FC52401F11A3BE66E34B40 1 +2 0 0103000020E6100000010000000500000000000080B9962140F99FD751A499474000000080B99621403AD5CAA5E6A04740000000003EBF21403AD5CAA5E6A04740000000003EBF2140F99FD751A499474000000080B9962140F99FD751A4994740 2 +\. + + +-- +-- Name: excerptexport_boundinggeometry_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('excerptexport_boundinggeometry_id_seq', 2, true); + + +-- +-- Name: excerptexport_excerpt_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('excerptexport_excerpt_id_seq', 2, true); + + +-- +-- Data for Name: excerptexport_extractionorder; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY excerptexport_extractionorder (id, state, process_start_date, process_reference, excerpt_id, orderer_id) FROM stdin; +\. + + +-- +-- Name: excerptexport_extractionorder_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('excerptexport_extractionorder_id_seq', 1, false); + + +-- +-- Data for Name: excerptexport_outputfile; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY excerptexport_outputfile (id, mime_type, path, create_date, deleted_on_filesystem, extraction_order_id) FROM stdin; +\. + + +-- +-- Name: excerptexport_outputfile_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('excerptexport_outputfile_id_seq', 1, false); + + +-- +-- Data for Name: spatial_ref_sys; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY spatial_ref_sys (srid, auth_name, auth_srid, srtext, proj4text) FROM stdin; +\. + + +SET search_path = topology, pg_catalog; + +-- +-- Data for Name: layer; Type: TABLE DATA; Schema: topology; Owner: postgres +-- + +COPY layer (topology_id, layer_id, schema_name, table_name, feature_column, feature_type, level, child_id) FROM stdin; +\. + + +-- +-- Data for Name: topology; Type: TABLE DATA; Schema: topology; Owner: postgres +-- + +COPY topology (id, name, srid, "precision", hasz) FROM stdin; +\. + + +-- +-- PostgreSQL database dump complete +-- + diff --git a/data/testdata-osmaxx.sql b/data/testdata-osmaxx.sql new file mode 100644 index 0000000000000000000000000000000000000000..7fde0a493757e8323977e1b74c6d3bc537d9cd73 --- /dev/null +++ b/data/testdata-osmaxx.sql @@ -0,0 +1,1369 @@ +-- +-- PostgreSQL database dump +-- + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SET check_function_bodies = false; +SET client_min_messages = warning; + +-- +-- Name: topology; Type: SCHEMA; Schema: -; Owner: postgres +-- + +CREATE SCHEMA topology; + + +ALTER SCHEMA topology OWNER TO postgres; + +-- +-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: +-- + +CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; + + +-- +-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: +-- + +COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; + + +-- +-- Name: postgis; Type: EXTENSION; Schema: -; Owner: +-- + +CREATE EXTENSION IF NOT EXISTS postgis WITH SCHEMA public; + + +-- +-- Name: EXTENSION postgis; Type: COMMENT; Schema: -; Owner: +-- + +COMMENT ON EXTENSION postgis IS 'PostGIS geometry, geography, and raster spatial types and functions'; + + +-- +-- Name: postgis_topology; Type: EXTENSION; Schema: -; Owner: +-- + +CREATE EXTENSION IF NOT EXISTS postgis_topology WITH SCHEMA topology; + + +-- +-- Name: EXTENSION postgis_topology; Type: COMMENT; Schema: -; Owner: +-- + +COMMENT ON EXTENSION postgis_topology IS 'PostGIS topology spatial types and functions'; + + +SET search_path = public, pg_catalog; + +SET default_tablespace = ''; + +SET default_with_oids = false; + +-- +-- Name: auth_group; Type: TABLE; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE TABLE auth_group ( + id integer NOT NULL, + name character varying(80) NOT NULL +); + + +ALTER TABLE public.auth_group OWNER TO osmaxx; + +-- +-- Name: auth_group_id_seq; Type: SEQUENCE; Schema: public; Owner: osmaxx +-- + +CREATE SEQUENCE auth_group_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.auth_group_id_seq OWNER TO osmaxx; + +-- +-- Name: auth_group_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: osmaxx +-- + +ALTER SEQUENCE auth_group_id_seq OWNED BY auth_group.id; + + +-- +-- Name: auth_group_permissions; Type: TABLE; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE TABLE auth_group_permissions ( + id integer NOT NULL, + group_id integer NOT NULL, + permission_id integer NOT NULL +); + + +ALTER TABLE public.auth_group_permissions OWNER TO osmaxx; + +-- +-- Name: auth_group_permissions_id_seq; Type: SEQUENCE; Schema: public; Owner: osmaxx +-- + +CREATE SEQUENCE auth_group_permissions_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.auth_group_permissions_id_seq OWNER TO osmaxx; + +-- +-- Name: auth_group_permissions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: osmaxx +-- + +ALTER SEQUENCE auth_group_permissions_id_seq OWNED BY auth_group_permissions.id; + + +-- +-- Name: auth_permission; Type: TABLE; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE TABLE auth_permission ( + id integer NOT NULL, + name character varying(50) NOT NULL, + content_type_id integer NOT NULL, + codename character varying(100) NOT NULL +); + + +ALTER TABLE public.auth_permission OWNER TO osmaxx; + +-- +-- Name: auth_permission_id_seq; Type: SEQUENCE; Schema: public; Owner: osmaxx +-- + +CREATE SEQUENCE auth_permission_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.auth_permission_id_seq OWNER TO osmaxx; + +-- +-- Name: auth_permission_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: osmaxx +-- + +ALTER SEQUENCE auth_permission_id_seq OWNED BY auth_permission.id; + + +-- +-- Name: auth_user; Type: TABLE; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE TABLE auth_user ( + id integer NOT NULL, + password character varying(128) NOT NULL, + last_login timestamp with time zone NOT NULL, + is_superuser boolean NOT NULL, + username character varying(30) NOT NULL, + first_name character varying(30) NOT NULL, + last_name character varying(30) NOT NULL, + email character varying(75) NOT NULL, + is_staff boolean NOT NULL, + is_active boolean NOT NULL, + date_joined timestamp with time zone NOT NULL +); + + +ALTER TABLE public.auth_user OWNER TO osmaxx; + +-- +-- Name: auth_user_groups; Type: TABLE; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE TABLE auth_user_groups ( + id integer NOT NULL, + user_id integer NOT NULL, + group_id integer NOT NULL +); + + +ALTER TABLE public.auth_user_groups OWNER TO osmaxx; + +-- +-- Name: auth_user_groups_id_seq; Type: SEQUENCE; Schema: public; Owner: osmaxx +-- + +CREATE SEQUENCE auth_user_groups_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.auth_user_groups_id_seq OWNER TO osmaxx; + +-- +-- Name: auth_user_groups_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: osmaxx +-- + +ALTER SEQUENCE auth_user_groups_id_seq OWNED BY auth_user_groups.id; + + +-- +-- Name: auth_user_id_seq; Type: SEQUENCE; Schema: public; Owner: osmaxx +-- + +CREATE SEQUENCE auth_user_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.auth_user_id_seq OWNER TO osmaxx; + +-- +-- Name: auth_user_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: osmaxx +-- + +ALTER SEQUENCE auth_user_id_seq OWNED BY auth_user.id; + + +-- +-- Name: auth_user_user_permissions; Type: TABLE; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE TABLE auth_user_user_permissions ( + id integer NOT NULL, + user_id integer NOT NULL, + permission_id integer NOT NULL +); + + +ALTER TABLE public.auth_user_user_permissions OWNER TO osmaxx; + +-- +-- Name: auth_user_user_permissions_id_seq; Type: SEQUENCE; Schema: public; Owner: osmaxx +-- + +CREATE SEQUENCE auth_user_user_permissions_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.auth_user_user_permissions_id_seq OWNER TO osmaxx; + +-- +-- Name: auth_user_user_permissions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: osmaxx +-- + +ALTER SEQUENCE auth_user_user_permissions_id_seq OWNED BY auth_user_user_permissions.id; + + +-- +-- Name: django_admin_log; Type: TABLE; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE TABLE django_admin_log ( + id integer NOT NULL, + action_time timestamp with time zone NOT NULL, + object_id text, + object_repr character varying(200) NOT NULL, + action_flag smallint NOT NULL, + change_message text NOT NULL, + content_type_id integer, + user_id integer NOT NULL, + CONSTRAINT django_admin_log_action_flag_check CHECK ((action_flag >= 0)) +); + + +ALTER TABLE public.django_admin_log OWNER TO osmaxx; + +-- +-- Name: django_admin_log_id_seq; Type: SEQUENCE; Schema: public; Owner: osmaxx +-- + +CREATE SEQUENCE django_admin_log_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.django_admin_log_id_seq OWNER TO osmaxx; + +-- +-- Name: django_admin_log_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: osmaxx +-- + +ALTER SEQUENCE django_admin_log_id_seq OWNED BY django_admin_log.id; + + +-- +-- Name: django_content_type; Type: TABLE; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE TABLE django_content_type ( + id integer NOT NULL, + name character varying(100) NOT NULL, + app_label character varying(100) NOT NULL, + model character varying(100) NOT NULL +); + + +ALTER TABLE public.django_content_type OWNER TO osmaxx; + +-- +-- Name: django_content_type_id_seq; Type: SEQUENCE; Schema: public; Owner: osmaxx +-- + +CREATE SEQUENCE django_content_type_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.django_content_type_id_seq OWNER TO osmaxx; + +-- +-- Name: django_content_type_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: osmaxx +-- + +ALTER SEQUENCE django_content_type_id_seq OWNED BY django_content_type.id; + + +-- +-- Name: django_migrations; Type: TABLE; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE TABLE django_migrations ( + id integer NOT NULL, + app character varying(255) NOT NULL, + name character varying(255) NOT NULL, + applied timestamp with time zone NOT NULL +); + + +ALTER TABLE public.django_migrations OWNER TO osmaxx; + +-- +-- Name: django_migrations_id_seq; Type: SEQUENCE; Schema: public; Owner: osmaxx +-- + +CREATE SEQUENCE django_migrations_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.django_migrations_id_seq OWNER TO osmaxx; + +-- +-- Name: django_migrations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: osmaxx +-- + +ALTER SEQUENCE django_migrations_id_seq OWNED BY django_migrations.id; + + +-- +-- Name: django_session; Type: TABLE; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE TABLE django_session ( + session_key character varying(40) NOT NULL, + session_data text NOT NULL, + expire_date timestamp with time zone NOT NULL +); + + +ALTER TABLE public.django_session OWNER TO osmaxx; + +-- +-- Name: excerptExport_boundinggeometry; Type: TABLE; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE TABLE "excerptExport_boundinggeometry" ( + id integer NOT NULL, + type integer NOT NULL, + excerpt_id integer, + geometry geometry(Geometry,4326) +); + + +ALTER TABLE public."excerptExport_boundinggeometry" OWNER TO osmaxx; + +-- +-- Name: excerptExport_boundinggeometry_id_seq; Type: SEQUENCE; Schema: public; Owner: osmaxx +-- + +CREATE SEQUENCE "excerptExport_boundinggeometry_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public."excerptExport_boundinggeometry_id_seq" OWNER TO osmaxx; + +-- +-- Name: excerptExport_boundinggeometry_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: osmaxx +-- + +ALTER SEQUENCE "excerptExport_boundinggeometry_id_seq" OWNED BY "excerptExport_boundinggeometry".id; + + +-- +-- Name: excerptExport_excerpt; Type: TABLE; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE TABLE "excerptExport_excerpt" ( + id integer NOT NULL, + name character varying(128) NOT NULL, + is_public boolean NOT NULL, + is_active boolean NOT NULL, + owner_id integer NOT NULL +); + + +ALTER TABLE public."excerptExport_excerpt" OWNER TO osmaxx; + +-- +-- Name: excerptExport_excerpt_id_seq; Type: SEQUENCE; Schema: public; Owner: osmaxx +-- + +CREATE SEQUENCE "excerptExport_excerpt_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public."excerptExport_excerpt_id_seq" OWNER TO osmaxx; + +-- +-- Name: excerptExport_excerpt_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: osmaxx +-- + +ALTER SEQUENCE "excerptExport_excerpt_id_seq" OWNED BY "excerptExport_excerpt".id; + + +-- +-- Name: excerptExport_extractionorder; Type: TABLE; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE TABLE "excerptExport_extractionorder" ( + id integer NOT NULL, + state integer NOT NULL, + process_start_date timestamp with time zone NOT NULL, + process_reference character varying(128) NOT NULL, + excerpt_id integer NOT NULL, + orderer_id integer NOT NULL +); + + +ALTER TABLE public."excerptExport_extractionorder" OWNER TO osmaxx; + +-- +-- Name: excerptExport_extractionorder_id_seq; Type: SEQUENCE; Schema: public; Owner: osmaxx +-- + +CREATE SEQUENCE "excerptExport_extractionorder_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public."excerptExport_extractionorder_id_seq" OWNER TO osmaxx; + +-- +-- Name: excerptExport_extractionorder_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: osmaxx +-- + +ALTER SEQUENCE "excerptExport_extractionorder_id_seq" OWNED BY "excerptExport_extractionorder".id; + + +-- +-- Name: excerptExport_outputfile; Type: TABLE; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE TABLE "excerptExport_outputfile" ( + id integer NOT NULL, + mime_type character varying(64) NOT NULL, + path character varying(512) NOT NULL, + create_date timestamp with time zone NOT NULL, + deleted_on_filesystem boolean NOT NULL, + extraction_order_id integer NOT NULL +); + + +ALTER TABLE public."excerptExport_outputfile" OWNER TO osmaxx; + +-- +-- Name: excerptExport_outputfile_id_seq; Type: SEQUENCE; Schema: public; Owner: osmaxx +-- + +CREATE SEQUENCE "excerptExport_outputfile_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public."excerptExport_outputfile_id_seq" OWNER TO osmaxx; + +-- +-- Name: excerptExport_outputfile_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: osmaxx +-- + +ALTER SEQUENCE "excerptExport_outputfile_id_seq" OWNED BY "excerptExport_outputfile".id; + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY auth_group ALTER COLUMN id SET DEFAULT nextval('auth_group_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY auth_group_permissions ALTER COLUMN id SET DEFAULT nextval('auth_group_permissions_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY auth_permission ALTER COLUMN id SET DEFAULT nextval('auth_permission_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY auth_user ALTER COLUMN id SET DEFAULT nextval('auth_user_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY auth_user_groups ALTER COLUMN id SET DEFAULT nextval('auth_user_groups_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY auth_user_user_permissions ALTER COLUMN id SET DEFAULT nextval('auth_user_user_permissions_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY django_admin_log ALTER COLUMN id SET DEFAULT nextval('django_admin_log_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY django_content_type ALTER COLUMN id SET DEFAULT nextval('django_content_type_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY django_migrations ALTER COLUMN id SET DEFAULT nextval('django_migrations_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY "excerptExport_boundinggeometry" ALTER COLUMN id SET DEFAULT nextval('"excerptExport_boundinggeometry_id_seq"'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY "excerptExport_excerpt" ALTER COLUMN id SET DEFAULT nextval('"excerptExport_excerpt_id_seq"'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY "excerptExport_extractionorder" ALTER COLUMN id SET DEFAULT nextval('"excerptExport_extractionorder_id_seq"'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY "excerptExport_outputfile" ALTER COLUMN id SET DEFAULT nextval('"excerptExport_outputfile_id_seq"'::regclass); + + +-- +-- Data for Name: auth_group; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY auth_group (id, name) FROM stdin; +\. + + +-- +-- Name: auth_group_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('auth_group_id_seq', 1, false); + + +-- +-- Data for Name: auth_group_permissions; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY auth_group_permissions (id, group_id, permission_id) FROM stdin; +\. + + +-- +-- Name: auth_group_permissions_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('auth_group_permissions_id_seq', 1, false); + + +-- +-- Data for Name: auth_permission; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY auth_permission (id, name, content_type_id, codename) FROM stdin; +1 Can add log entry 1 add_logentry +2 Can change log entry 1 change_logentry +3 Can delete log entry 1 delete_logentry +4 Can add permission 2 add_permission +5 Can change permission 2 change_permission +6 Can delete permission 2 delete_permission +7 Can add group 3 add_group +8 Can change group 3 change_group +9 Can delete group 3 delete_group +10 Can add user 4 add_user +11 Can change user 4 change_user +12 Can delete user 4 delete_user +13 Can add content type 5 add_contenttype +14 Can change content type 5 change_contenttype +15 Can delete content type 5 delete_contenttype +16 Can add session 6 add_session +17 Can change session 6 change_session +18 Can delete session 6 delete_session +19 Can add post gis geometry columns 7 add_postgisgeometrycolumns +20 Can change post gis geometry columns 7 change_postgisgeometrycolumns +21 Can delete post gis geometry columns 7 delete_postgisgeometrycolumns +22 Can add post gis spatial ref sys 8 add_postgisspatialrefsys +23 Can change post gis spatial ref sys 8 change_postgisspatialrefsys +24 Can delete post gis spatial ref sys 8 delete_postgisspatialrefsys +25 Can add excerpt 9 add_excerpt +26 Can change excerpt 9 change_excerpt +27 Can delete excerpt 9 delete_excerpt +28 Can add bounding geometry 10 add_boundinggeometry +29 Can change bounding geometry 10 change_boundinggeometry +30 Can delete bounding geometry 10 delete_boundinggeometry +31 Can add extraction order 11 add_extractionorder +32 Can change extraction order 11 change_extractionorder +33 Can delete extraction order 11 delete_extractionorder +34 Can add output file 12 add_outputfile +35 Can change output file 12 change_outputfile +36 Can delete output file 12 delete_outputfile +\. + + +-- +-- Name: auth_permission_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('auth_permission_id_seq', 36, true); + + +-- +-- Data for Name: auth_user; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY auth_user (id, password, last_login, is_superuser, username, first_name, last_name, email, is_staff, is_active, date_joined) FROM stdin; +2 pbkdf2_sha256$15000$eRPNPVQ7axe6$MBilaqID/YK9isxjx1dLM1ObyiQgCl0kM+I3qZFSQXg= 2015-02-27 12:33:59.87765+00 f test f t 2015-02-27 12:33:59.877691+00 +1 pbkdf2_sha256$15000$JNgfrf5fGxn9$DwTDPL/7buiekQhqG3bCk2mwgHdWEJ+6x53Mvn8Ge7I= 2015-02-27 13:53:23.941818+00 t admin admin@osmaxx.ch t t 2015-02-27 08:57:51.303567+00 +\. + + +-- +-- Data for Name: auth_user_groups; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY auth_user_groups (id, user_id, group_id) FROM stdin; +\. + + +-- +-- Name: auth_user_groups_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('auth_user_groups_id_seq', 1, false); + + +-- +-- Name: auth_user_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('auth_user_id_seq', 2, true); + + +-- +-- Data for Name: auth_user_user_permissions; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY auth_user_user_permissions (id, user_id, permission_id) FROM stdin; +\. + + +-- +-- Name: auth_user_user_permissions_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('auth_user_user_permissions_id_seq', 1, false); + + +-- +-- Data for Name: django_admin_log; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) FROM stdin; +1 2015-02-27 12:34:00.001253+00 2 test 1 4 1 +2 2015-02-27 13:46:16.717167+00 7 Excerpt {name: Neverland} 1 9 1 +3 2015-02-27 14:04:27.050712+00 5 BoundingGeometry{} 1 10 1 +4 2015-02-27 14:25:43.025932+00 6 orderer: test, excerpt: Neverland 1 11 1 +5 2015-02-27 14:29:36.530231+00 1 /path /to/neverland 1 12 1 +\. + + +-- +-- Name: django_admin_log_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('django_admin_log_id_seq', 5, true); + + +-- +-- Data for Name: django_content_type; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY django_content_type (id, name, app_label, model) FROM stdin; +1 log entry admin logentry +2 permission auth permission +3 group auth group +4 user auth user +5 content type contenttypes contenttype +6 session sessions session +7 post gis geometry columns gis postgisgeometrycolumns +8 post gis spatial ref sys gis postgisspatialrefsys +9 excerpt excerptExport excerpt +10 bounding geometry excerptExport boundinggeometry +11 extraction order excerptExport extractionorder +12 output file excerptExport outputfile +\. + + +-- +-- Name: django_content_type_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('django_content_type_id_seq', 12, true); + + +-- +-- Data for Name: django_migrations; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY django_migrations (id, app, name, applied) FROM stdin; +1 contenttypes 0001_initial 2015-02-27 08:57:28.447577+00 +2 auth 0001_initial 2015-02-27 08:57:28.552313+00 +3 admin 0001_initial 2015-02-27 08:57:28.596216+00 +4 excerptExport 0001_initial 2015-02-27 08:57:28.698472+00 +5 excerptExport 0002_auto_20150224_1627 2015-02-27 08:57:28.791073+00 +6 excerptExport 0003_auto_20150224_1703 2015-02-27 08:57:28.879449+00 +7 excerptExport 0004_boundinggeometry_geometry 2015-02-27 08:57:28.953421+00 +8 excerptExport 0005_auto_20150227_0748 2015-02-27 08:57:29.063244+00 +9 sessions 0001_initial 2015-02-27 08:57:29.080875+00 +10 excerptExport 0006_auto_20150227_1427 2015-02-27 14:28:06.420669+00 +\. + + +-- +-- Name: django_migrations_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('django_migrations_id_seq', 10, true); + + +-- +-- Data for Name: django_session; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY django_session (session_key, session_data, expire_date) FROM stdin; +i6hk03rj76yys919y9jlik2whlkily9h YWY4NmRlMmMwMTdjOThlZDBiYThmNDZlZWQxYzM1Yjc5Njg2M2Y0OTp7Il9hdXRoX3VzZXJfYmFja2VuZCI6ImRqYW5nby5jb250cmliLmF1dGguYmFja2VuZHMuTW9kZWxCYWNrZW5kIiwiX2F1dGhfdXNlcl9oYXNoIjoiNjVmN2IwNzlmZGY5ODIyYzFjNDcyMjJkZGMxZTc3OTZjOWVmNzk1MSIsIl9hdXRoX3VzZXJfaWQiOjF9 2015-03-13 12:44:04.911484+00 +17g48i79t4znwu3wlwttraimtha3w4mo ZjEyN2VlZTg5NzQ3MzI3MTBjMmZmZTg5ZThjODdjZTE5ZGM1YjA5OTp7Il9hdXRoX3VzZXJfYmFja2VuZCI6ImRqYW5nby5jb250cmliLmF1dGguYmFja2VuZHMuTW9kZWxCYWNrZW5kIiwiX2F1dGhfdXNlcl9pZCI6MSwiX2F1dGhfdXNlcl9oYXNoIjoiNjVmN2IwNzlmZGY5ODIyYzFjNDcyMjJkZGMxZTc3OTZjOWVmNzk1MSJ9 2015-03-13 13:53:23.944227+00 +\. + + +-- +-- Data for Name: excerptExport_boundinggeometry; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY "excerptExport_boundinggeometry" (id, type, excerpt_id, geometry) FROM stdin; +5 0 7 \N +\. + + +-- +-- Name: excerptExport_boundinggeometry_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('"excerptExport_boundinggeometry_id_seq"', 5, true); + + +-- +-- Data for Name: excerptExport_excerpt; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY "excerptExport_excerpt" (id, name, is_public, is_active, owner_id) FROM stdin; +7 Neverland t t 2 +\. + + +-- +-- Name: excerptExport_excerpt_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('"excerptExport_excerpt_id_seq"', 7, true); + + +-- +-- Data for Name: excerptExport_extractionorder; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY "excerptExport_extractionorder" (id, state, process_start_date, process_reference, excerpt_id, orderer_id) FROM stdin; +6 1 2015-02-27 14:25:36+00 5 7 2 +\. + + +-- +-- Name: excerptExport_extractionorder_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('"excerptExport_extractionorder_id_seq"', 6, true); + + +-- +-- Data for Name: excerptExport_outputfile; Type: TABLE DATA; Schema: public; Owner: osmaxx +-- + +COPY "excerptExport_outputfile" (id, mime_type, path, create_date, deleted_on_filesystem, extraction_order_id) FROM stdin; +1 text /path /to/neverland 2015-02-27 14:29:32+00 t 6 +\. + + +-- +-- Name: excerptExport_outputfile_id_seq; Type: SEQUENCE SET; Schema: public; Owner: osmaxx +-- + +SELECT pg_catalog.setval('"excerptExport_outputfile_id_seq"', 1, true); + + +-- +-- Data for Name: spatial_ref_sys; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY spatial_ref_sys (srid, auth_name, auth_srid, srtext, proj4text) FROM stdin; +\. + + +SET search_path = topology, pg_catalog; + +-- +-- Data for Name: layer; Type: TABLE DATA; Schema: topology; Owner: postgres +-- + +COPY layer (topology_id, layer_id, schema_name, table_name, feature_column, feature_type, level, child_id) FROM stdin; +\. + + +-- +-- Data for Name: topology; Type: TABLE DATA; Schema: topology; Owner: postgres +-- + +COPY topology (id, name, srid, "precision", hasz) FROM stdin; +\. + + +SET search_path = public, pg_catalog; + +-- +-- Name: auth_group_name_key; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY auth_group + ADD CONSTRAINT auth_group_name_key UNIQUE (name); + + +-- +-- Name: auth_group_permissions_group_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY auth_group_permissions + ADD CONSTRAINT auth_group_permissions_group_id_permission_id_key UNIQUE (group_id, permission_id); + + +-- +-- Name: auth_group_permissions_pkey; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY auth_group_permissions + ADD CONSTRAINT auth_group_permissions_pkey PRIMARY KEY (id); + + +-- +-- Name: auth_group_pkey; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY auth_group + ADD CONSTRAINT auth_group_pkey PRIMARY KEY (id); + + +-- +-- Name: auth_permission_content_type_id_codename_key; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY auth_permission + ADD CONSTRAINT auth_permission_content_type_id_codename_key UNIQUE (content_type_id, codename); + + +-- +-- Name: auth_permission_pkey; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY auth_permission + ADD CONSTRAINT auth_permission_pkey PRIMARY KEY (id); + + +-- +-- Name: auth_user_groups_pkey; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY auth_user_groups + ADD CONSTRAINT auth_user_groups_pkey PRIMARY KEY (id); + + +-- +-- Name: auth_user_groups_user_id_group_id_key; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY auth_user_groups + ADD CONSTRAINT auth_user_groups_user_id_group_id_key UNIQUE (user_id, group_id); + + +-- +-- Name: auth_user_pkey; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY auth_user + ADD CONSTRAINT auth_user_pkey PRIMARY KEY (id); + + +-- +-- Name: auth_user_user_permissions_pkey; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY auth_user_user_permissions + ADD CONSTRAINT auth_user_user_permissions_pkey PRIMARY KEY (id); + + +-- +-- Name: auth_user_user_permissions_user_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY auth_user_user_permissions + ADD CONSTRAINT auth_user_user_permissions_user_id_permission_id_key UNIQUE (user_id, permission_id); + + +-- +-- Name: auth_user_username_key; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY auth_user + ADD CONSTRAINT auth_user_username_key UNIQUE (username); + + +-- +-- Name: django_admin_log_pkey; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY django_admin_log + ADD CONSTRAINT django_admin_log_pkey PRIMARY KEY (id); + + +-- +-- Name: django_content_type_app_label_6d1d692a86c60fa3_uniq; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY django_content_type + ADD CONSTRAINT django_content_type_app_label_6d1d692a86c60fa3_uniq UNIQUE (app_label, model); + + +-- +-- Name: django_content_type_pkey; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY django_content_type + ADD CONSTRAINT django_content_type_pkey PRIMARY KEY (id); + + +-- +-- Name: django_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY django_migrations + ADD CONSTRAINT django_migrations_pkey PRIMARY KEY (id); + + +-- +-- Name: django_session_pkey; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY django_session + ADD CONSTRAINT django_session_pkey PRIMARY KEY (session_key); + + +-- +-- Name: excerptExport_boundinggeometry_excerpt_id_key; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY "excerptExport_boundinggeometry" + ADD CONSTRAINT "excerptExport_boundinggeometry_excerpt_id_key" UNIQUE (excerpt_id); + + +-- +-- Name: excerptExport_boundinggeometry_pkey; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY "excerptExport_boundinggeometry" + ADD CONSTRAINT "excerptExport_boundinggeometry_pkey" PRIMARY KEY (id); + + +-- +-- Name: excerptExport_excerpt_pkey; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY "excerptExport_excerpt" + ADD CONSTRAINT "excerptExport_excerpt_pkey" PRIMARY KEY (id); + + +-- +-- Name: excerptExport_extractionorder_pkey; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY "excerptExport_extractionorder" + ADD CONSTRAINT "excerptExport_extractionorder_pkey" PRIMARY KEY (id); + + +-- +-- Name: excerptExport_outputfile_pkey; Type: CONSTRAINT; Schema: public; Owner: osmaxx; Tablespace: +-- + +ALTER TABLE ONLY "excerptExport_outputfile" + ADD CONSTRAINT "excerptExport_outputfile_pkey" PRIMARY KEY (id); + + +-- +-- Name: auth_group_name_7e02d7ed75bc062_like; Type: INDEX; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE INDEX auth_group_name_7e02d7ed75bc062_like ON auth_group USING btree (name varchar_pattern_ops); + + +-- +-- Name: auth_group_permissions_0e939a4f; Type: INDEX; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE INDEX auth_group_permissions_0e939a4f ON auth_group_permissions USING btree (group_id); + + +-- +-- Name: auth_group_permissions_8373b171; Type: INDEX; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE INDEX auth_group_permissions_8373b171 ON auth_group_permissions USING btree (permission_id); + + +-- +-- Name: auth_permission_417f1b1c; Type: INDEX; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE INDEX auth_permission_417f1b1c ON auth_permission USING btree (content_type_id); + + +-- +-- Name: auth_user_groups_0e939a4f; Type: INDEX; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE INDEX auth_user_groups_0e939a4f ON auth_user_groups USING btree (group_id); + + +-- +-- Name: auth_user_groups_e8701ad4; Type: INDEX; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE INDEX auth_user_groups_e8701ad4 ON auth_user_groups USING btree (user_id); + + +-- +-- Name: auth_user_user_permissions_8373b171; Type: INDEX; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE INDEX auth_user_user_permissions_8373b171 ON auth_user_user_permissions USING btree (permission_id); + + +-- +-- Name: auth_user_user_permissions_e8701ad4; Type: INDEX; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE INDEX auth_user_user_permissions_e8701ad4 ON auth_user_user_permissions USING btree (user_id); + + +-- +-- Name: auth_user_username_64abb5217a0c0b32_like; Type: INDEX; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE INDEX auth_user_username_64abb5217a0c0b32_like ON auth_user USING btree (username varchar_pattern_ops); + + +-- +-- Name: django_admin_log_417f1b1c; Type: INDEX; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE INDEX django_admin_log_417f1b1c ON django_admin_log USING btree (content_type_id); + + +-- +-- Name: django_admin_log_e8701ad4; Type: INDEX; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE INDEX django_admin_log_e8701ad4 ON django_admin_log USING btree (user_id); + + +-- +-- Name: django_session_de54fa62; Type: INDEX; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE INDEX django_session_de54fa62 ON django_session USING btree (expire_date); + + +-- +-- Name: django_session_session_key_25d1a855625e1585_like; Type: INDEX; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE INDEX django_session_session_key_25d1a855625e1585_like ON django_session USING btree (session_key varchar_pattern_ops); + + +-- +-- Name: excerptExport_boundinggeometry_geometry_id; Type: INDEX; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE INDEX "excerptExport_boundinggeometry_geometry_id" ON "excerptExport_boundinggeometry" USING gist (geometry); + + +-- +-- Name: excerptExport_excerpt_5e7b1936; Type: INDEX; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE INDEX "excerptExport_excerpt_5e7b1936" ON "excerptExport_excerpt" USING btree (owner_id); + + +-- +-- Name: excerptExport_extractionorder_230c0360; Type: INDEX; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE INDEX "excerptExport_extractionorder_230c0360" ON "excerptExport_extractionorder" USING btree (orderer_id); + + +-- +-- Name: excerptExport_extractionorder_28999874; Type: INDEX; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE INDEX "excerptExport_extractionorder_28999874" ON "excerptExport_extractionorder" USING btree (excerpt_id); + + +-- +-- Name: excerptExport_outputfile_245ededb; Type: INDEX; Schema: public; Owner: osmaxx; Tablespace: +-- + +CREATE INDEX "excerptExport_outputfile_245ededb" ON "excerptExport_outputfile" USING btree (extraction_order_id); + + +-- +-- Name: D53fef9ace6a08d93bf5bf3539521bd9; Type: FK CONSTRAINT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY "excerptExport_outputfile" + ADD CONSTRAINT "D53fef9ace6a08d93bf5bf3539521bd9" FOREIGN KEY (extraction_order_id) REFERENCES "excerptExport_extractionorder"(id) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: auth_content_type_id_34a3b14bf0e48a00_fk_django_content_type_id; Type: FK CONSTRAINT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY auth_permission + ADD CONSTRAINT auth_content_type_id_34a3b14bf0e48a00_fk_django_content_type_id FOREIGN KEY (content_type_id) REFERENCES django_content_type(id) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: auth_group_permissio_group_id_51423762a574e157_fk_auth_group_id; Type: FK CONSTRAINT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY auth_group_permissions + ADD CONSTRAINT auth_group_permissio_group_id_51423762a574e157_fk_auth_group_id FOREIGN KEY (group_id) REFERENCES auth_group(id) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: auth_group_permission_id_53959fb43e1969da_fk_auth_permission_id; Type: FK CONSTRAINT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY auth_group_permissions + ADD CONSTRAINT auth_group_permission_id_53959fb43e1969da_fk_auth_permission_id FOREIGN KEY (permission_id) REFERENCES auth_permission(id) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: auth_user__permission_id_6c139150877f2afe_fk_auth_permission_id; Type: FK CONSTRAINT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY auth_user_user_permissions + ADD CONSTRAINT auth_user__permission_id_6c139150877f2afe_fk_auth_permission_id FOREIGN KEY (permission_id) REFERENCES auth_permission(id) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: auth_user_groups_group_id_48ee1c83ebf45d6b_fk_auth_group_id; Type: FK CONSTRAINT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY auth_user_groups + ADD CONSTRAINT auth_user_groups_group_id_48ee1c83ebf45d6b_fk_auth_group_id FOREIGN KEY (group_id) REFERENCES auth_group(id) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: auth_user_groups_user_id_d589d48ade01d45_fk_auth_user_id; Type: FK CONSTRAINT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY auth_user_groups + ADD CONSTRAINT auth_user_groups_user_id_d589d48ade01d45_fk_auth_user_id FOREIGN KEY (user_id) REFERENCES auth_user(id) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: auth_user_user_permiss_user_id_3c839064ab836e99_fk_auth_user_id; Type: FK CONSTRAINT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY auth_user_user_permissions + ADD CONSTRAINT auth_user_user_permiss_user_id_3c839064ab836e99_fk_auth_user_id FOREIGN KEY (user_id) REFERENCES auth_user(id) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: djan_content_type_id_1cea6f0a5c4e5f9f_fk_django_content_type_id; Type: FK CONSTRAINT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY django_admin_log + ADD CONSTRAINT djan_content_type_id_1cea6f0a5c4e5f9f_fk_django_content_type_id FOREIGN KEY (content_type_id) REFERENCES django_content_type(id) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: django_admin_log_user_id_55e32449a5a1c63a_fk_auth_user_id; Type: FK CONSTRAINT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY django_admin_log + ADD CONSTRAINT django_admin_log_user_id_55e32449a5a1c63a_fk_auth_user_id FOREIGN KEY (user_id) REFERENCES auth_user(id) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: excerptE_excerpt_id_bcae1215ca879e0_fk_excerptExport_excerpt_id; Type: FK CONSTRAINT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY "excerptExport_boundinggeometry" + ADD CONSTRAINT "excerptE_excerpt_id_bcae1215ca879e0_fk_excerptExport_excerpt_id" FOREIGN KEY (excerpt_id) REFERENCES "excerptExport_excerpt"(id) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: excerptExport_excerpt_owner_id_61b50617b4ae557f_fk_auth_user_id; Type: FK CONSTRAINT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY "excerptExport_excerpt" + ADD CONSTRAINT "excerptExport_excerpt_owner_id_61b50617b4ae557f_fk_auth_user_id" FOREIGN KEY (owner_id) REFERENCES auth_user(id) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: excerptExport_extra_orderer_id_6d8dc67c41045671_fk_auth_user_id; Type: FK CONSTRAINT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY "excerptExport_extractionorder" + ADD CONSTRAINT "excerptExport_extra_orderer_id_6d8dc67c41045671_fk_auth_user_id" FOREIGN KEY (orderer_id) REFERENCES auth_user(id) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: excerpt_excerpt_id_65d1bfbd6f6e17e3_fk_excerptExport_excerpt_id; Type: FK CONSTRAINT; Schema: public; Owner: osmaxx +-- + +ALTER TABLE ONLY "excerptExport_extractionorder" + ADD CONSTRAINT "excerpt_excerpt_id_65d1bfbd6f6e17e3_fk_excerptExport_excerpt_id" FOREIGN KEY (excerpt_id) REFERENCES "excerptExport_excerpt"(id) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: public; Type: ACL; Schema: -; Owner: postgres +-- + +REVOKE ALL ON SCHEMA public FROM PUBLIC; +REVOKE ALL ON SCHEMA public FROM postgres; +GRANT ALL ON SCHEMA public TO postgres; +GRANT ALL ON SCHEMA public TO PUBLIC; + + +-- +-- PostgreSQL database dump complete +-- + diff --git a/developmentEnvironment/Link to Osmaxx Administration Development.desktop b/developmentEnvironment/Link to Osmaxx Administration Development.desktop new file mode 100644 index 0000000000000000000000000000000000000000..85c0a83f6dd9079592703d3d72e747953b8eb5f0 --- /dev/null +++ b/developmentEnvironment/Link to Osmaxx Administration Development.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Link to Site administration | Django site admin +Type=Link +URL=http://osmax.dev:8000/admin/ +Icon=text-html +Name[en_US]=Link to Osmaxx Administration Development diff --git a/developmentEnvironment/Link to Osmaxx Development.desktop b/developmentEnvironment/Link to Osmaxx Development.desktop new file mode 100644 index 0000000000000000000000000000000000000000..f11c31e10935cce8ea4dd41df9503707025e2abc --- /dev/null +++ b/developmentEnvironment/Link to Osmaxx Development.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Link to Osmaxx +Type=Link +URL=http://osmaxx.dev:8000/excerptExport/ +Icon=text-html +Name[en_US]=Link to Osmaxx Development diff --git a/developmentEnvironment/README.md b/developmentEnvironment/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d5a210587abc7fd5ddbb2012172661c5ab5461d2 --- /dev/null +++ b/developmentEnvironment/README.md @@ -0,0 +1,170 @@ +# Git repository + +For developers with write access to this repository: + +1. Clone this GitHub repository to your local machine and change into the local repo + ```shell + git clone git@github.com:geometalab/osmaxx.git osmaxx && cd osmaxx + ``` + You can specify the name of the remote origin by adding param -o. Example: -o 'gitHub' + +2. Enable [git-flow](https://github.com/nvie/gitflow) for the local repo + + git flow init -d + + (This project uses git-flow's default branch names and branch name prefixes, which `-d` automatically accepts.) +3. (You should now be on the `develop` branch.) + + Clone the third party repositories we use through [git submodules](http://www.git-scm.com/book/en/v2/Git-Tools-Submodules) + + git submodule init + git submodule update + +4. Create a feature branch for your contribution + + git flow feature start my-awesome-contribution + +5. Make your commits as usual +6. Once you're finished, push the feature branch back to this GitHub repo + + git flow feature publish + + **and** create a pull request against branch `develop`. (Do **not** use `git flow feature finish`, as we use pull requests for review purposes.) + +# Project Development Environment (Vagrant Box) + +A vagrant box is provided as part of this project's repository. + +## Features + +* Ubuntu 14.04 http://www.ubuntu.com/download/server +* Python3 / pip-3 +* Django https://docs.djangoproject.com/en/1.7/ +* Postgresql http://wiki.ubuntuusers.de/PostgreSQL +* OSM Tools +* Postgis + + + +## Setup + +1. Download and install newest Version of Virtualbox: https://www.virtualbox.org/wiki/Downloads + * Ubuntu: Do not use the older version from sources because of incompatibility with new Vagrant +2. Download and install newest Version of Vagrant: https://www.vagrantup.com/downloads.html + * Ubuntu: Do not use the older version from sources, because of different syntax of vagrant files for older versions +3. Navigate to "developmentEnvironment", run "vagrant up" to start bring up the machine +4. On first start up, Vagrant will download the box. This can take some minutes. +5. Add 'localhost osmaxx.dev' to your /etc/hosts file +6. Use the configured Apache or start development server (live update after file change) + 1. Live simulation with Apache + * Open http://osmax.dev:8080/excerptExport/ in your local browser + 2. Development + * Log into vagrant machine: `vagrant ssh` + * Run development start script: `/var/www/eda/projects/runDevelopmentServer.sh` + * Open http://osmax.dev:8000/excerptExport/ in your local browser + + +### Reset the box + +```shell +vagrant destroy -f +``` + + +### Log into the box + +```shell +vagrant ssh +``` +or +```shell +ssh -l 'vagrant' -p '2222' 'localhost' +``` + + + +## Access + +Add + + 127.0.0.1 osmaxx.dev + +to your local /etc/hosts file. + +| Feature | URL | Username | Password | +| --- | --- | --- | --- | +| Database osmaxx | | osmaxx | osmaxx | +| App frontend | http://osmaxx.dev:8080/excerptexport | | | +| App frontend development | http://osmaxx.dev:8000/excerptexport | | | +| App backend development | http://osmaxx.dev:8000/admin | admin | osmaxx | + + +## Development + +### Run application using Django built in server (see runDevelopmentServer.sh) + +You need to specify the ip. Otherwise you are not able to reach the application from outside of the vm. + +```shell +#!/bin/bash + +CURRENTDIR=`dirname $0` +cd "$CURRENTDIR" +# activate environment +source "../environment/bin/activate" +# get local ip +LOCALIP=`ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'` +echo "$LOCALIP" +python ./manage.py runserver "$LOCALIP:8000" +``` + +### Clear Django cache + +```shell +python manage.py shell + +# (InteractiveConsole) +from django.core.cache import cache +cache.clear() +``` + + +### Update persistence + +#### 1. Update migration information + +```shell +cd /path/to/projects/folder +source ../environment/bin/activate +python manage.py makemigrations +``` + +#### 2. See domain specific migrations (e.g. sql) + +```shell +python manage.py sqlmigrate excerptExport {number, e.g. 0001} +``` + +#### 3. Run migrations on database +```shell +python manage.py migrate +``` + + +### Use backend + +#### Create superuser + +```shell +python manage.py createsuperuser +``` + + +### Backup & restore the database +```shell +# backup +sudo -u postgres pg_dump osmaxx --data-only > /var/www/eda/data/{yymmdd}-osmaxx-data.sql + +# restore +sudo -u postgres psql osmaxx < /var/www/eda/data/{yymmdd}-osmaxx-data.sql +``` diff --git a/developmentEnvironment/Vagrantfile b/developmentEnvironment/Vagrantfile new file mode 100644 index 0000000000000000000000000000000000000000..f6721b661d9f70bccc0b8e9960a8651afec2f888 --- /dev/null +++ b/developmentEnvironment/Vagrantfile @@ -0,0 +1,83 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# All Vagrant configuration is done below. The "2" in Vagrant.configure +# configures the configuration version (we support older styles for +# backwards compatibility). Please don't change it unless you know what +# you're doing. +Vagrant.configure(2) do |config| + # The most common configuration options are documented and commented below. + # For a complete reference, please see the online documentation at + # https://docs.vagrantup.com. + + # Every Vagrant development environment requires a box. You can search for + # boxes at https://atlas.hashicorp.com/search. + config.vm.box = "ubuntu/trusty64" + + # Disable automatic box update checking. If you disable this, then + # boxes will only be checked for updates when the user runs + # `vagrant box outdated`. This is not recommended. + # config.vm.box_check_update = false + + # Create a forwarded port mapping which allows access to a specific port + # within the machine from a port on the host machine. In the example below, + # accessing "localhost:8080" will access port 80 on the guest machine. + config.vm.network "forwarded_port", guest: 80, host: 8080 + config.vm.network "forwarded_port", guest: 8000, host: 8000 + + # Create a private network, which allows host-only access to the machine + # using a specific IP. + # config.vm.network "private_network", ip: "192.168.33.10" + + # Create a public network, which generally matched to bridged network. + # Bridged networks make the machine appear as another physical device on + # your network. + # config.vm.network "public_network" + + # Share an additional folder to the guest VM. The first argument is + # the path on the host to the actual folder. The second argument is + # the path on the guest to mount the folder. And the optional third + # argument is a set of non-required options. + # config.vm.synced_folder "../data", "/vagrant_data" + config.vm.synced_folder "../source", "/var/www/eda/projects" + config.vm.synced_folder "../data", "/var/www/eda/data" + #, type: "rsync", + # rsync__exclude: [ ".DS_Store", ".directory", ".idea", "developmentEnvironment/" ], + # owner: "vagrant", + # group: "www-data" + + # Provider-specific configuration so you can fine-tune various + # backing providers for Vagrant. These expose provider-specific options. + # Example for VirtualBox: + # + # config.vm.provider "virtualbox" do |vb| + # # Display the VirtualBox GUI when booting the machine + # vb.gui = true + # + # # Customize the amount of memory on the VM: + # vb.memory = "1024" + # end + # + # View the documentation for the provider you are using for more + # information on available options. + + # Define a Vagrant Push strategy for pushing to Atlas. Other push strategies + # such as FTP and Heroku are also available. See the documentation at + # https://docs.vagrantup.com/v2/push/atlas.html for more information. + # config.push.define "atlas" do |push| + # push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME" + # end + + # Enable provisioning with a shell script. Additional provisioners such as + # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the + # documentation for more information about their specific syntax and use. + config.vm.provision "shell", run: "always", inline: <<-SHELL + if [ -f "/etc/init.d/apache2" ]; then + sudo service apache2 restart + fi + SHELL + config.vm.provision "shell", run: "always", inline: <<-SHELL + sudo chmod u+x /var/www/eda/projects/runDevelopmentServer.sh + SHELL + config.vm.provision "shell", path: "setup.sh" +end diff --git a/developmentEnvironment/osmaxx.vhost b/developmentEnvironment/osmaxx.vhost new file mode 100644 index 0000000000000000000000000000000000000000..7f5e5bbfebf882d23e688d32faf9cba74da314c1 --- /dev/null +++ b/developmentEnvironment/osmaxx.vhost @@ -0,0 +1,14 @@ +WSGIDaemonProcess osmaxx.dev python-path=/var/www/eda/environment/:/var/www/eda/environment/lib/python3.4/site-packages +WSGIProcessGroup osmaxx.dev + +ErrorLog /var/log/apache2/osmaxx.log +WSGIScriptAlias / /var/www/eda/projects/osmaxx/wsgi.py + +Alias "/static/admin" "/var/www/eda/environment/lib/python3.4/site-packages/django/contrib/admin/static/admin" +Alias "/static/excerptexport" "/var/www/eda/projects/excerptexport/static/excerptexport" + +<Directory /var/www/eda/projects> + <Files osmaxx/wsgi.py> + Require all granted + </Files> +</Directory> \ No newline at end of file diff --git a/developmentEnvironment/requirements.txt b/developmentEnvironment/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..12c0609832cda82a251d9051dc14584435606967 --- /dev/null +++ b/developmentEnvironment/requirements.txt @@ -0,0 +1,3 @@ +Django==1.7.4 +django-enumfield==1.2 +psycopg2==2.6 diff --git a/developmentEnvironment/setup.sh b/developmentEnvironment/setup.sh new file mode 100755 index 0000000000000000000000000000000000000000..ed8d8882f72e609ecca0391ad36c1a1ce4ddc1c1 --- /dev/null +++ b/developmentEnvironment/setup.sh @@ -0,0 +1,110 @@ +#!/bin/bash + +# improve bash prompt +echo 'parse_git_branch() {' >> ~/.bashrc +echo " git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'" >> ~/.bashrc +echo '}' >> ~/.bashrc +echo 'export PS1="\[$(tput bold)\]\[$(tput setaf 6)\]\u\[$(tput setaf 4)\]@\[$(tput setaf 6)\]\H\[$(tput setaf 4)\]:\[$(tput setaf 2)\]\$(pwd)\[$(tput setaf 3)\]\$(parse_git_branch)\[$(tput setaf 4)\]$ \[$(tput sgr0)\]"' >> ~/.bashrc + +echo "" +echo "[setup] configure host ..." +sudo sh -c "echo 'osmaxx-environment' > /etc/hostname" +sudo sh -c "echo '' >> /etc/hosts" +sudo sh -c "echo '127.0.0.1 osmaxx.dev' >> /etc/hosts" +sudo sh -c "echo '127.0.0.1 osmaxx-environment' >> /etc/hosts" + +echo "" +echo "------------ /etc/hosts ----------" +cat /etc/hosts +echo "----------------------------------" + +# prevent error message: "dpkg-reconfigure: unable to re-open stdin: No file or directory" +export LANGUAGE=en_US.UTF-8 +export LANG=en_US.UTF-8 +export LC_ALL=en_US.UTF-8 +sudo locale-gen en_US.UTF-8 +sudo dpkg-reconfigure locales + + +echo "" +echo "[setup] install software and clean up ..." +sudo apt-get update +sudo apt-get -y install rsync git git-flow +sudo apt-get -y autoremove + + +echo "" +echo "[setup] install python, tools and django ..." +sudo apt-get -y install python3 python3-doc python3-setuptools python3-pip python-dev libpq-dev +sudo pip3 install virtualenv + + +echo "" +echo "[setup] install postgresql and python driver ..." +sudo apt-get -y install postgresql postgresql-client +sudo apt-get -y install postgis osmctools apache2 postgresql-9.3-postgis-2.1 +sudo apt-get -y install python3-psycopg2 + + +echo"" +echo "[setup] install webserver ..." +sudo apt-get -y install apache2 apache2-utils libapache2-mod-wsgi-py3 +sudo a2enmod wsgi +sudo sh -c "echo 'ServerName localhost' >> /etc/apache2/apache2.conf" +sudo service apache2 restart + + +echo "" +echo "[setup] configure database ..." +sudo -u postgres psql -c "CREATE USER osmaxx WITH PASSWORD 'osmaxx';" +sudo -u postgres psql -c "CREATE DATABASE osmaxx ENCODING 'UTF8';" +sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE osmaxx TO osmaxx;" +echo "------------ available databases ------------" +sudo -u postgres psql -c "SELECT datname FROM pg_database WHERE datistemplate = false;" +echo "---------------------------------------------" + + +echo "[setup] install & configure geodata extensions ..." +sudo apt-get -y install binutils libgeos-3.4. # GEOS +sudo apt-get -y install libproj0 # PROJ.4 +sudo apt-get -y install python-gdal # GDAL +sudo apt-get -y install postgis +sudo -u postgres psql -c "CREATE EXTENSION postgis;" "osmaxx" +sudo -u postgres psql -c "CREATE EXTENSION postgis_topology;" "osmaxx" + + +echo "" +echo "[setup] setup application ..." +cd /var/www +if [ ! -d "eda" ]; then + mkdir "eda" +fi +cd "eda" + +if [ -d "projects" ]; then + virtualenv-3.4 environment + sudo chown -R vagrant:www-data environment + source environment/bin/activate + pip3 install -r /vagrant/requirements.txt + + + echo "[setup] run migrations & import test data ..." + cd "projects" + python manage.py migrate + echo "from django.contrib.auth.models import User; User.objects.create_superuser('admin', '', 'osmaxx')" | python manage.py shell +fi + +# link virtual host file from vagrant directory +sudo ln -s /vagrant/osmaxx.vhost /etc/apache2/sites-available/osmaxx.conf +sudo ln -s /etc/apache2/sites-available/osmaxx.conf /etc/apache2/sites-enabled/osmaxx.conf +sudo a2ensite osmaxx +service apache2 restart + +echo "" +echo ".----------------------------------------------------------------------." +echo "| |" +echo "| The vagrant box should be created successfully. |" +echo "| Please add 'osmaxx.dev localhost' to your local /etc/hosts file |" +echo "| Open 'osmaxx.dev:{applicationPort}' with a browser |" +echo "| |" +echo "'----------------------------------------------------------------------'" diff --git a/source/excerptexport/__init__.py b/source/excerptexport/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/source/excerptexport/admin.py b/source/excerptexport/admin.py new file mode 100644 index 0000000000000000000000000000000000000000..85a61c4cc3aafe7cbb91043c464938666c574012 --- /dev/null +++ b/source/excerptexport/admin.py @@ -0,0 +1,9 @@ +from django.contrib import admin + +from excerptexport.models import BoundingGeometry, Excerpt, ExtractionOrder, OutputFile + + +admin.site.register(BoundingGeometry) +admin.site.register(Excerpt) +admin.site.register(ExtractionOrder) +admin.site.register(OutputFile) diff --git a/source/excerptexport/migrations/0001_initial.py b/source/excerptexport/migrations/0001_initial.py new file mode 100644 index 0000000000000000000000000000000000000000..a6cc0ba52e74eb64744f69557e0bc8ab2b02f650 --- /dev/null +++ b/source/excerptexport/migrations/0001_initial.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import django.contrib.gis.db.models.fields +from django.conf import settings + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='BoundingGeometry', + fields=[ + ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)), + ('type', models.IntegerField(default=0)), + ('geometry', django.contrib.gis.db.models.fields.GeometryField(null=True, srid=4326, blank=True)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Excerpt', + fields=[ + ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=128)), + ('is_public', models.BooleanField(default=False)), + ('is_active', models.BooleanField(default=True)), + ('owner', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='excerpts')), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='ExtractionOrder', + fields=[ + ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)), + ('state', models.IntegerField(default=1)), + ('process_start_date', models.DateTimeField(verbose_name='process start date')), + ('process_reference', models.CharField(max_length=128)), + ('excerpt', models.ForeignKey(to='excerptexport.Excerpt', related_name='extraction_orders')), + ('orderer', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='extraction_orders')), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='OutputFile', + fields=[ + ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)), + ('mime_type', models.CharField(max_length=64)), + ('path', models.CharField(max_length=512)), + ('create_date', models.DateTimeField(verbose_name='create date')), + ('deleted_on_filesystem', models.BooleanField(default=False)), + ('extraction_order', models.ForeignKey(to='excerptexport.ExtractionOrder', related_name='output_files')), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.AddField( + model_name='boundinggeometry', + name='excerpt', + field=models.OneToOneField(to='excerptexport.Excerpt', null=True), + preserve_default=True, + ), + ] diff --git a/source/excerptexport/migrations/0002_auto_20150317_1330.py b/source/excerptexport/migrations/0002_auto_20150317_1330.py new file mode 100644 index 0000000000000000000000000000000000000000..83d24abe19caf7d51ada6f663924fbd00172e8fc --- /dev/null +++ b/source/excerptexport/migrations/0002_auto_20150317_1330.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('excerptexport', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='extractionorder', + name='process_reference', + field=models.CharField(null=True, max_length=128), + preserve_default=True, + ), + migrations.AlterField( + model_name='extractionorder', + name='process_start_date', + field=models.DateTimeField(verbose_name='process start date', null=True), + preserve_default=True, + ), + ] diff --git a/source/excerptexport/migrations/0002_auto_20150320_1421.py b/source/excerptexport/migrations/0002_auto_20150320_1421.py new file mode 100644 index 0000000000000000000000000000000000000000..1288e3c52bed216530a14e707332e5d845991c3c --- /dev/null +++ b/source/excerptexport/migrations/0002_auto_20150320_1421.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('excerptexport', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='outputfile', + name='path', + ), + migrations.AddField( + model_name='outputfile', + name='file', + field=models.FileField(upload_to='/var/www/eda/projects/data', null=True), + preserve_default=True, + ), + migrations.AddField( + model_name='outputfile', + name='public_identifier', + field=models.CharField(max_length=512, default='14268612701000000'), + preserve_default=True, + ), + migrations.AlterField( + model_name='extractionorder', + name='process_reference', + field=models.CharField(max_length=128, blank=True), + preserve_default=True, + ), + ] diff --git a/source/excerptexport/migrations/0003_merge.py b/source/excerptexport/migrations/0003_merge.py new file mode 100644 index 0000000000000000000000000000000000000000..edb831fe3a7f170faca9e7d28b0c276f17df3497 --- /dev/null +++ b/source/excerptexport/migrations/0003_merge.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('excerptexport', '0002_auto_20150317_1330'), + ('excerptexport', '0002_auto_20150320_1421'), + ] + + operations = [ + ] diff --git a/source/excerptexport/migrations/0004_auto_20150324_1637.py b/source/excerptexport/migrations/0004_auto_20150324_1637.py new file mode 100644 index 0000000000000000000000000000000000000000..beba5a8c527fba7c84fe5bd6ec4d39041b44038e --- /dev/null +++ b/source/excerptexport/migrations/0004_auto_20150324_1637.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import excerptexport.models.output_file + + +class Migration(migrations.Migration): + + dependencies = [ + ('excerptexport', '0003_merge'), + ] + + operations = [ + migrations.AlterField( + model_name='extractionorder', + name='process_reference', + field=models.CharField(null=True, max_length=128, blank=True), + preserve_default=True, + ), + migrations.AlterField( + model_name='outputfile', + name='create_date', + field=models.DateTimeField(auto_now_add=True), + preserve_default=True, + ), + migrations.AlterField( + model_name='outputfile', + name='file', + field=models.FileField(null=True, upload_to='/var/www/eda/projects/data', blank=True), + preserve_default=True, + ), + migrations.AlterField( + model_name='outputfile', + name='public_identifier', + field=models.CharField(default=excerptexport.models.output_file.default_public_identifier, max_length=512), + preserve_default=True, + ), + ] diff --git a/source/excerptexport/migrations/__init__.py b/source/excerptexport/migrations/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/source/excerptexport/models/__init__.py b/source/excerptexport/models/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..098860f199f158e5b4c38f8083db546d7f86f6e6 --- /dev/null +++ b/source/excerptexport/models/__init__.py @@ -0,0 +1,4 @@ +from .excerpt import Excerpt +from .bounding_geometry import BoundingGeometry +from .extraction_order import ExtractionOrder +from .output_file import OutputFile \ No newline at end of file diff --git a/source/excerptexport/models/bounding_geometry.py b/source/excerptexport/models/bounding_geometry.py new file mode 100644 index 0000000000000000000000000000000000000000..fbbc537612d3d53683665e022f3060391e6a2423 --- /dev/null +++ b/source/excerptexport/models/bounding_geometry.py @@ -0,0 +1,45 @@ +from django.db import models +from django.contrib.gis.db import models +from django.contrib.gis.geos import GEOSGeometry, Polygon + +from django_enumfield import enum + +from .excerpt import Excerpt + + +class BoundingGeometryType(enum.Enum): + BOUNDINGBOX = 0 + # POLYGON = 1 + + +class BoundingGeometry(models.Model): + @staticmethod + def create_from_bounding_box_coordinates(north, east, south, west): + bounding_geometry = BoundingGeometry() + bounding_geometry.type = BoundingGeometryType.BOUNDINGBOX + polygon = Polygon([ + GEOSGeometry('POINT(%s %s)' % (west, south)), + GEOSGeometry('POINT(%s %s)' % (west, north)), + GEOSGeometry('POINT(%s %s)' % (east, north)), + GEOSGeometry('POINT(%s %s)' % (east, south)), + GEOSGeometry('POINT(%s %s)' % (west, south)) + ]) + bounding_geometry.geometry = GEOSGeometry(polygon) + return bounding_geometry + + type = enum.EnumField(BoundingGeometryType, default=BoundingGeometryType.BOUNDINGBOX) + geometry = models.GeometryField(srid=4326, blank=True, null=True, spatial_index=True) + + # django admin inline mode needs relation from BoundingGeometry to Excerpt -> inverse relation does not work + excerpt = models.OneToOneField(Excerpt, null=True) + + # overriding the default manager with a GeoManager instance. + # required to perform spatial queries + objects = models.GeoManager() + + def __str__(self): + geometry_type = 'Bounding box' if (self.type == BoundingGeometryType.BOUNDINGBOX) else 'Polygon' + points = [] + for coordinates in self.geometry[0]: + points.append('(' + ', '.join(list(str(round(coordinate, 5)) for coordinate in coordinates)) + ')') + return geometry_type + ': ' + ', '.join(points) diff --git a/source/excerptexport/models/excerpt.py b/source/excerptexport/models/excerpt.py new file mode 100644 index 0000000000000000000000000000000000000000..09c06c76c4ac6e42574e0535c68751172f7fdbd4 --- /dev/null +++ b/source/excerptexport/models/excerpt.py @@ -0,0 +1,13 @@ +from django.db import models +from django.contrib.auth.models import User + + +class Excerpt(models.Model): + name = models.CharField(max_length=128) + is_public = models.BooleanField(default=False) + is_active = models.BooleanField(default=True) + + owner = models.ForeignKey(User, related_name='excerpts') + + def __str__(self): + return self.name diff --git a/source/excerptexport/models/extraction_order.py b/source/excerptexport/models/extraction_order.py new file mode 100644 index 0000000000000000000000000000000000000000..618db21800e1877299d40cda0ecb2ae8244dab5e --- /dev/null +++ b/source/excerptexport/models/extraction_order.py @@ -0,0 +1,28 @@ +from django.db import models +from django.contrib.auth.models import User + +from django_enumfield import enum + +from .excerpt import Excerpt + + +class ExtractionOrderState(enum.Enum): + UNDEFINED = 0 + INITIALIZED = 1 + WAITING = 2 + PROCESSING = 3 + FINISHED = 4 + CANCELED = 5 + + +class ExtractionOrder(models.Model): + state = enum.EnumField(ExtractionOrderState, default=ExtractionOrderState.INITIALIZED) + process_start_date = models.DateTimeField('process start date', null=True) + process_reference = models.CharField(max_length=128, blank=True, null=True) + + orderer = models.ForeignKey(User, related_name='extraction_orders') + excerpt = models.ForeignKey(Excerpt, related_name='extraction_orders') + + def __str__(self): + return '[' + str(self.id) + '] orderer: ' + self.orderer.get_username() + ', excerpt: ' + self.excerpt.name + ', state: ' + self.get_state_display() \ + + ', output files: ' + str(self.output_files.count()) diff --git a/source/excerptexport/models/output_file.py b/source/excerptexport/models/output_file.py new file mode 100644 index 0000000000000000000000000000000000000000..9717aeca941c6d0230029d6bbf927b3f7d522a64 --- /dev/null +++ b/source/excerptexport/models/output_file.py @@ -0,0 +1,33 @@ +import os +import uuid + +from django.db import models + +from excerptexport import settings + +from .extraction_order import ExtractionOrder + + +def default_public_identifier(): + return str(uuid.uuid4()) + + +class OutputFile(models.Model): + + mime_type = models.CharField(max_length=64) + file = models.FileField(upload_to=settings.APPLICATION_SETTINGS['data_directory'], blank=True, null=True) + create_date = models.DateTimeField(auto_now_add=True) + deleted_on_filesystem = models.BooleanField(default=False) + public_identifier = models.CharField(max_length=512, default=default_public_identifier) + + extraction_order = models.ForeignKey(ExtractionOrder, related_name='output_files') + + def __str__(self): + return \ + '[' + str(self.id) + '] ' \ + + ('file: ' + os.path.basename(self.file.name) + ', ' if (self.file and self.file.name) else '') \ + + 'identifier: ' + self.public_identifier + + + + diff --git a/source/excerptexport/services/__init__.py b/source/excerptexport/services/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/source/excerptexport/services/data_conversion_service.py b/source/excerptexport/services/data_conversion_service.py new file mode 100644 index 0000000000000000000000000000000000000000..bb04d9cd24ccb9141db3ceca481180d337a2d03a --- /dev/null +++ b/source/excerptexport/services/data_conversion_service.py @@ -0,0 +1,59 @@ +import subprocess +import os, sys +from datetime import datetime +from django.core.files import File +from excerptexport import settings +from excerptexport.models import OutputFile + + +def trigger_data_conversion(extraction_order, export_options): + """ + Run data conversion script + + :param export_options: dictionary + """ + export_formats_configuration = {} + for export_configuration_group_key, export_configuration_group in settings.EXPORT_OPTIONS.items(): + export_formats_configuration.update(export_configuration_group['formats']) + print(export_formats_configuration) + """ + 'gis': { + 'formats': { + 'file_gdb': { + 'name': 'FileGDB', + 'file_extension': 'gdb' + }, + 'geo_package': { + 'name': 'GeoPackage', + 'file_extension': 'geo' + } + } + }, + 'routing': { + 'name': 'Routing', + 'formats': { + 'img': { + 'name': 'IMG', + 'file_extension': 'img' + } + } + } + """ + for export_type_key, export_type in export_options.items(): + for format_key in export_type['formats']: + output_file = OutputFile.objects.create( + mime_type=export_formats_configuration[format_key]['mime_type'], + extraction_order=extraction_order + ) + + # TODO: if this service will be integrated permanent, check for directory existence + file_path = settings.APPLICATION_SETTINGS['data_directory'] + '/' \ + + output_file.public_identifier + '.' + export_formats_configuration[format_key]['file_extension'] + + with open(file_path, 'w') as file_reference: + new_file = File(file_reference) + new_file.write(output_file.public_identifier) + + # file must be committed, so reopen to attach to model + output_file.file = file_path + output_file.save() diff --git a/source/excerptexport/settings/__init__.py b/source/excerptexport/settings/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..720725674f333c185331257d805db13acfa543fb --- /dev/null +++ b/source/excerptexport/settings/__init__.py @@ -0,0 +1,3 @@ +from .export_options import EXPORT_OPTIONS +from .administrative_areas import ADMINISTRATIVE_AREAS +from .application_settings import APPLICATION_SETTINGS diff --git a/source/excerptexport/settings/administrative_areas.py b/source/excerptexport/settings/administrative_areas.py new file mode 100644 index 0000000000000000000000000000000000000000..ec6058b10a58e63b264326fb133832620d436deb --- /dev/null +++ b/source/excerptexport/settings/administrative_areas.py @@ -0,0 +1,11 @@ +ADMINISTRATIVE_AREAS = { + 'regions': { + 'eu': 'Europe', + 'af': 'Africa' + }, + 'countries': { + 'ch': 'Switzerland', + 'de': 'Germany', + 'us': 'USA' + } +} diff --git a/source/excerptexport/settings/application_settings.py b/source/excerptexport/settings/application_settings.py new file mode 100644 index 0000000000000000000000000000000000000000..89a1373e7d886de5ccc71c8f550ad4593874febe --- /dev/null +++ b/source/excerptexport/settings/application_settings.py @@ -0,0 +1,8 @@ +import os + +APPLICATION_SETTINGS = { + 'data_directory': os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), '../data/')), + 'download_file_name': '%(id)s-%(name)s', + 'download_chunk_size': 8192, + 'file_identifier_random_number_range': (1000000, 9999999) +} diff --git a/source/excerptexport/settings/export_options.py b/source/excerptexport/settings/export_options.py new file mode 100644 index 0000000000000000000000000000000000000000..94805cdcbaecc3b2e3a705dda166371f8c0c3ee2 --- /dev/null +++ b/source/excerptexport/settings/export_options.py @@ -0,0 +1,69 @@ +EXPORT_OPTIONS = { + 'gis': { + 'name': 'GIS', + 'formats': { + 'file_gdb': { + 'name': 'FileGDB', + 'file_extension': 'gdb', + 'mime_type': 'application/octet-stream' + }, + 'geo_package': { + 'name': 'GeoPackage', + 'file_extension': 'geo', # ??? + 'mime_type': 'application/octet-stream' # Not verified! + }, + 'shape_file': { + 'name': 'ShapeFile', + 'file_extension': 'shp', + 'mime_type': 'application/octet-stream' # Not verified! + } + }, + 'options': { + 'coordinate_reference_system': { + 'label': 'Coordinate reference system', + 'type': 'select', + 'select_multiple': False, + 'default': 'pseudomerkator', + 'groups': [ + { + 'name': 'Global coordinate reference systems', + 'values': [ + {'name': 'pseudomerkator', 'label': 'Pseudo merkator'}, + {'name': 'wgs72', 'label': 'WGS 72'}, + {'name': 'wgs84', 'label': 'WGS 84'} + ] + }, + { + 'name': 'UTM zones for your export', + 'values': [ + {'name': 'utm32', 'label': 'UTM zone 32'}, + {'name': 'utm33', 'label': 'UTM zone 33'} + ] + } + ] + }, + 'detail_level': { + 'label': 'Detail level', + 'type': 'radio', + 'default': 'verbatim', + 'values': [ + {'name': 'verbatim', 'label': 'Verbatim'}, + {'name': 'simplified', 'label': 'Simplified'} + ] + } + } + }, + 'routing': { + 'name': 'Routing', + 'formats': { + 'img': { + 'name': 'IMG (Garmin)', + 'file_extension': 'img', + 'mime_type': 'application/octet-stream' # Not verified! + } + }, + 'options': { + + } + } +} diff --git a/source/excerptexport/static/excerptexport/libraries/leaflet-locationfilter b/source/excerptexport/static/excerptexport/libraries/leaflet-locationfilter new file mode 160000 index 0000000000000000000000000000000000000000..fd3a095b2a589a1b488376d5c63c6dcd42757f10 --- /dev/null +++ b/source/excerptexport/static/excerptexport/libraries/leaflet-locationfilter @@ -0,0 +1 @@ +Subproject commit fd3a095b2a589a1b488376d5c63c6dcd42757f10 diff --git a/source/excerptexport/static/excerptexport/scripts/formModeSwitcher.js b/source/excerptexport/static/excerptexport/scripts/formModeSwitcher.js new file mode 100644 index 0000000000000000000000000000000000000000..6ed5fdca26233d53d7fe81ec7770e57aff3ea5a0 --- /dev/null +++ b/source/excerptexport/static/excerptexport/scripts/formModeSwitcher.js @@ -0,0 +1,32 @@ +(function() { + this.deactivateAllParts = function(formPartNodes) { + Array.prototype.forEach.call(formPartNodes,function(node) { + node.setAttribute('data-form-part-state', 'inactive'); + }); + }; + + this.activateSelectedPart = function(form, formPartsSwitcher, formPartsButtons) { + var formPartId = (formPartsButtons.item(formPartsSwitcher.selectedIndex)).getAttribute('data-form-part-for'); + form.querySelector('[data-form-part="'+formPartId+'"]').setAttribute('data-form-part-state', 'active'); + }; + + window.addEventListener('load', function() { + var formPartNodes = document.querySelectorAll('[data-form-part]'); + var form = formPartNodes.item(0).parentNode; + var formPartsSwitchers = document.querySelectorAll('select[data-form-part-switcher]'); + var formPartsButtons = document.querySelectorAll('[data-form-part-for]'); + + deactivateAllParts(formPartNodes); + + formPartsSwitchers.forEach = Array.prototype.forEach; + formPartsSwitchers.forEach(function(node) { + node.addEventListener('change',function(event) { + deactivateAllParts(formPartNodes); + activateSelectedPart(form, node, formPartsButtons); + }); + + activateSelectedPart(form, node, formPartsButtons); + }); + }); +})(); + diff --git a/source/excerptexport/static/excerptexport/scripts/map.js b/source/excerptexport/static/excerptexport/scripts/map.js new file mode 100644 index 0000000000000000000000000000000000000000..0527138fea7e7c49fd4c3b177b349bef9f837ec6 --- /dev/null +++ b/source/excerptexport/static/excerptexport/scripts/map.js @@ -0,0 +1,56 @@ +/** + * @author Raphael Das Gupta + */ +var map = L.map('map').setView([0, 0], 2); +// add an OpenStreetMap tile layer +L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', { + attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' +}).addTo(map); + + +var inputElementNorth = document.getElementById('new_excerpt.boundingBox.north'); +var inputElementWest = document.getElementById('new_excerpt.boundingBox.west'); +var inputElementEast = document.getElementById('new_excerpt.boundingBox.east'); +var inputElementSouth = document.getElementById('new_excerpt.boundingBox.south'); + + +var locationFilter = new L.LocationFilter({ + enable: true, + enableButton: false +}).addTo(map); + +function updateBboxTextInputsWith(bounds) { + inputElementNorth.value = bounds._northEast.lat; + inputElementWest.value = bounds._southWest.lng; + inputElementEast.value = bounds._northEast.lng; + inputElementSouth.value = bounds._southWest.lat; +} + + +// push initial values to text inputs +updateBboxTextInputsWith(locationFilter.getBounds()); + +// update text input values upon change on map +locationFilter.on("change", function (e) { + console.log(locationFilter); + console.log(locationFilter.getBounds()); + updateBboxTextInputsWith(e.bounds); +}); + + +/** + * update map on coordinate input field change + */ +function updateMapBoundingBox() { + var bounds = locationFilter.getBounds(); + bounds._northEast.lat = inputElementNorth.value; + bounds._southWest.lng = inputElementWest.value; + bounds._northEast.lng = inputElementEast.value; + bounds._southWest.lat = inputElementSouth.value; + locationFilter.setBounds(bounds); +} + +inputElementNorth.addEventListener('change', updateMapBoundingBox); +inputElementWest.addEventListener('change', updateMapBoundingBox); +inputElementEast.addEventListener('change', updateMapBoundingBox); +inputElementSouth.addEventListener('change', updateMapBoundingBox); \ No newline at end of file diff --git a/source/excerptexport/static/excerptexport/stylesheets/main.css b/source/excerptexport/static/excerptexport/stylesheets/main.css new file mode 100644 index 0000000000000000000000000000000000000000..0dedbd6b3955ac1044241c1eb6f2ac263b2371d5 --- /dev/null +++ b/source/excerptexport/static/excerptexport/stylesheets/main.css @@ -0,0 +1,139 @@ +* { box-sizing: border-box; } +body { padding: 0; margin: 0; } + +h1 { font-size: 2rem; margin: 0; } + + +/* container */ +header, .main, footer { padding: 1rem; } +header, footer { position: fixed; width: 100%; background: #286090; color: white; z-index: 10000; } +header { top: 0; } +.main { margin-top: 4rem; margin-bottom: 4rem; } +footer { bottom: 0; } +footer p { margin: 0; } + +.box-container { width: 100%; display: table; } +.box-container .container-row { display: table-row; height: 100%; } +.box-container .container-column { display: table-cell; height: 100%; padding: 1rem; } + +/*.row > .column { display: inline-block; }*/ +.container-column.stretch-2, .container-column.stretch-20 { width: 20%; } +.container-column.stretch-25 { width: 25%; } +.container-column.stretch-3, .container-column.stretch-30 { width: 30%; } +.container-column.stretch-333 { width: 33.3%; } +.container-column.stretch-4, .container-column.stretch-40 { width: 40%; } +.container-column.stretch-5, .container-column.stretch-50 { width: 50%; } +.container-column.stretch-6, .container-column.stretch-60 { width: 50%; } +.container-column.stretch-666 { width: 66.6%; } +.container-column.stretch-7, .container-column.stretch-70 { width: 70%; } +.container-column.stretch-8, .container-column.stretch-80 { width: 80%; } + + +/* font */ +p { word-wrap: break-word; } + + +/* icons */ +.icon { + background: rgb(40, 96, 144); + color: white; + padding: 0.5rem; + margin: 0.25rem; + display: inline-block; + width: 3rem; + height: 3rem; + border-radius: 1.5rem; + font-size: 2rem; + line-height: 2rem; + text-align: center; +} + + +/* navigation */ +nav ul { list-style-type: none; padding: 0; } + + +/* map */ +#map { height: 100%; z-index: 100; } + +.outerMapWrapper { + height: auto; + position: fixed; + width: 50%; + width: calc(50% - 1rem); + overflow: hidden; + top: 5rem; + bottom: 5rem; + right: 1rem; +} + + +/* form */ +select[multiple], select[size] { + padding: 0; +} +option, optgroup { + -moz-appearance: none; + -ms-appearance: none; + -webkit-appearance: none; + appearance: none; +} +option { + padding: 0.5rem; + padding-left: 1rem; + border: none; + background: white; + color: black; +} +optgroup { + border: none; + background: rgb(40, 96, 144); + color: white; + /*padding-top: 0.5rem;*/ +} +/* firefox: style optgroup header */ +optgroup:before { + border: none; + background: rgb(40, 96, 144); + color: white; + padding: 0.5rem; +} +/*optgroup > option:first-child { border-top: 0.5rem solid rgb(40, 96, 144); display: block; }*/ + +/* special select: shown as button group */ +.select-button-group { overflow-x: hidden; } +.select-button-group > select.btn-group { + display:inline-block; + border: none; + background: none; + background: none; + -moz-appearance: none; + -ms-appearance: none; + -webkit-appearance: none; + appearance: none; + overflow: hidden; + width: 100%; + width: calc(100% + 2rem); +} +select.btn-group > option { + padding: 0.75rem 1.5rem; +} +select.btn-group > option:checked { + box-shadow: 0 0 1rem rgba(0, 0, 0, 0.125) inset; + border-color: rgb(173, 173, 173); + background-color: rgb(230, 230, 230); +} +select.btn-group > option:active, select.btn-group > option:hover, select.btn-group > option:focus { + background-color: rgb(230, 230, 230); +} +[data-form-part-state="inactive"] { display: none; } + + +/* validation */ +input:invalid, textarea:invalid, select:invalid { + border-color: red; + background: lavenderblush; +} +input:invalid:focus, textarea:invalid:focus, select:invalid:focus { + border-color: maroon; +} diff --git a/source/excerptexport/templates/excerptexport/layouts/base.html b/source/excerptexport/templates/excerptexport/layouts/base.html new file mode 100644 index 0000000000000000000000000000000000000000..d0c59a628cebcb5ae3485b2228d4e0e17201221e --- /dev/null +++ b/source/excerptexport/templates/excerptexport/layouts/base.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +{% load staticfiles %} + +<html> +<head lang="en"> + <meta charset="UTF-8"> + <title>Osmaxx</title> + <style> + body { font-family: Arial, sans-serif; } + </style> + + <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" /> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" /> + <link rel="stylesheet" type="text/css" media="screen" href="https://silviomoreto.github.io/bootstrap-select/bootstrap-select.min.css" /> + <link rel='stylesheet' type='text/css' href='{% static "excerptexport/libraries/leaflet-locationfilter/src/locationfilter.css" %}' /> + + <link rel='stylesheet' type='text/css' href='{% static "excerptexport/stylesheets/main.css" %}' /> +</head> +<body> + <header> + <h1>Osmaxx</h1> + </header> + <div class="main"> + {% block main %} + <h2>Main block</h2> + {% endblock %} + </div> + <footer> + <p>© osmaxx.ch 2015</p> + </footer> +</body> +</html> diff --git a/source/excerptexport/templates/excerptexport/partials/export_options.html b/source/excerptexport/templates/excerptexport/partials/export_options.html new file mode 100644 index 0000000000000000000000000000000000000000..eee5750d4603de4f40cfb0f9064b4eb6dc80fb51 --- /dev/null +++ b/source/excerptexport/templates/excerptexport/partials/export_options.html @@ -0,0 +1,32 @@ +{% for export_option_key, export_option in export_options.items %} + <div class="form-group"> + <h3>{{ export_option.name }}</h3> + <fieldset class="form-group"> + <legend>Formats</legend> + {% for format_key, format in export_option.formats.items %} + <input type="checkbox" name="export_options.{{ export_option_key }}.formats" + id="export_options.{{ export_option_key }}.formats.{{ format_key }}" value="{{ format_key }}" /> + <label for="export_options.{{ export_option_key }}.formats.{{ format_key }}">{{ format.name }}</label> + {% endfor %} + </fieldset> + + {% for option_config_key, option_config in export_option.options.items %} + {% if option_config.type == 'select' %} + <div class="form-group"> + <label for="export_options.{{ export_option_key }}.options.{{ option_config_key }}">{{ option_config.label }}</label> + {% include 'excerptexport/partials/select.html' with element=option_config name="export_options."|add:export_option_key|add:".options."|add:option_config_key %} + </div> + {% elif option_config.type == 'radio' %} + <fieldset class="form-group"> + <legend>{{ option_config.label }}</legend> + {% for value in option_config.values %} + <input type="radio" name="export_options.{{ export_option_key }}.options.{{ option_config_key }}" value="{{ value.name }}" + id="export_options.{{ export_option_key }}.options.{{ option_config_key }}.{{ value.name }}" + {% if option_config.default == value.name %}checked="checked"{% endif %} /> + <label for="export_options.{{ export_option_key }}.options.{{ option_config_key }}.{{ value.name }}">{{ value.label }}</label> + {% endfor %} + </fieldset> + {% endif %} + {% endfor %} + </div> +{% endfor %} diff --git a/source/excerptexport/templates/excerptexport/partials/select.html b/source/excerptexport/templates/excerptexport/partials/select.html new file mode 100644 index 0000000000000000000000000000000000000000..9a91023d2a07b5d82ec4678298026bdca5335012 --- /dev/null +++ b/source/excerptexport/templates/excerptexport/partials/select.html @@ -0,0 +1,29 @@ +<select name="{{ name }}" id="{{ name }}"> + {% if element.groups %} + {% for group in element.groups %} + <optgroup label="{{ group.name }}"> + {% if group.groups %} + + {% for subgroup in group.groups %} + <optgroup label="{{ subgroup.name }}"> + {% for option in subgroup.values %} + <option value="{{ option.name }}">{{ option.label }}</option> + {% endfor %} + </optgroup> + {% endfor %} + + {% elif group.values %} + + {% for option in group.values %} + <option value="{{ option.name }}">{{ option.label }}</option> + {% endfor %} + + {% endif %} + </optgroup> + {% endfor %} + {% elif element.values %} + {% for option in element.values %} + <option value="{{ option.name }}">{{ option.label }}</option> + {% endfor %} + {% endif %} +</select> diff --git a/source/excerptexport/templates/excerptexport/templates/create_excerpt_export.html b/source/excerptexport/templates/excerptexport/templates/create_excerpt_export.html new file mode 100644 index 0000000000000000000000000000000000000000..17bc3710f5c8c2a630049caf898b0ab77306d09a --- /dev/null +++ b/source/excerptexport/templates/excerptexport/templates/create_excerpt_export.html @@ -0,0 +1,27 @@ +{% extends "excerptexport/layouts/base.html" %} + +{% block main %} + <a href="{% url 'excerptexport:new' %}">Back</a> + {% if use_existing %} + <dl> + <dt>id of existing excerpt</dt> + <dd>{{ excerpt }}</dd> + <dt>export options</dt> + <dd>{{ options }}</dd> + </dl> + {% else %} + <dl> + <dt>name of new excerpt</dt> + <dd>{{ excerpt.name }}</dd> + <dt>is public</dt> + <dd>{{ excerpt.is_public }}</dd> + <dt>owner</dt> + <dd>{{ excerpt.owner.username }}</dd> + <dt>bounding geometry</dt> + <dd>{{ bounding_geometry.geometry }}</dd> + <dt>export options</dt> + <dd>{{ options }}</dd> + </dl> + + {% endif %} +{% endblock %} diff --git a/source/excerptexport/templates/excerptexport/templates/index.html b/source/excerptexport/templates/excerptexport/templates/index.html new file mode 100644 index 0000000000000000000000000000000000000000..bfb70045dc92cde8fc2e1ca99eb5deaeaf8eb3da --- /dev/null +++ b/source/excerptexport/templates/excerptexport/templates/index.html @@ -0,0 +1,17 @@ +{% extends "excerptexport/layouts/base.html" %} + +{% block main %} + <h2>Overview</h2> + <nav> + <ul> + <li> + <span class="icon">✎</span> + <a href="{% url 'excerptexport:new' %}">New excerpt export</a> + </li> + <li> + <span class="icon">⇩</span> + <a href="{% url 'excerptexport:downloads' %}">Downloads</a> + </li> + </ul> + </nav> +{% endblock %} diff --git a/source/excerptexport/templates/excerptexport/templates/new_excerpt_export.html b/source/excerptexport/templates/excerptexport/templates/new_excerpt_export.html new file mode 100644 index 0000000000000000000000000000000000000000..b042173995abedee580c1daeaaf1f9eb3eeb91eb --- /dev/null +++ b/source/excerptexport/templates/excerptexport/templates/new_excerpt_export.html @@ -0,0 +1,144 @@ +{% extends "excerptexport/layouts/base.html" %} + +{% load staticfiles %} + +{% block main %} + <div class="box-container"> + <div class="container-row"><!-- + --><div class="container-column stretch-5"> + <form action="{% url 'excerptexport:create' %}" method="post" novalidate="novalidate"> + {% csrf_token %} + + <div class="form-group select-button-group"> + <select class="btn-group" role="group" name="form-mode" id="form-mode" size="2" data-form-part-switcher> + <option class="btn btn-default" value="existing_excerpt" selected="selected" data-form-part-for="existing_excerpt">Use existing excerpt</option> + <option class="btn btn-default" value="create_new_excerpt" data-form-part-for="create_new_excerpt">Create new excerpt</option> + </select> + </div> + + <div class="form-part" data-form-part="existing_excerpt"> + <h2>Existing excerpt</h2> + <div class="form-group"> + <label for="existing_excerpt.id">Excerpt</label> + <select class="form-control" name="existing_excerpt.id" id="existing_excerpt.id" size="10" required="required"> + <optgroup label=" Personal excerpts ({{ user.username }})"> + {% for excerpt in personal_excerpts %} + <option value="{{ excerpt.id }}">{{ excerpt.name }}</option> + {% endfor %} + </optgroup> + <optgroup label=" Public excerpts"> + {% for excerpt in public_excerpts %} + <option value="{{ excerpt.id }}">{{ excerpt.name }}</option> + {% endfor %} + </optgroup> + {% for administrative_areas_group_name, administrative_areas_group_regions in administrative_areas.items %} + <optgroup label=" {{ administrative_areas_group_name }}"> + {% for region_key, region_name in administrative_areas_group_regions.items %} + <option value="{{ region_key }}">{{ region_name }}</option> + {% endfor %} + </optgroup> + {% endfor %} + </select> + </div> + </div> + + + <div class="form-part" data-form-part="create_new_excerpt"> + <h2>Create excerpt</h2> + <div class="form-group"> + <label for="new_excerpt.name">Excerpt name</label> + <input type="text" class="form-control" id="new_excerpt.name" name="new_excerpt.name" required="required" /> + </div> + + <fieldset class="form-group"> + <legend>Bounding box</legend> + + <div class="form-group" id="bbox-values"> + <div class="row"> + <div class="col-sm-4 col-sm-offset-4"> + <label for="new_excerpt.boundingBox.north">North</label> + <input class="form-control" id="new_excerpt.boundingBox.north" name="new_excerpt.boundingBox.north" required="required" pattern="\-?[1-9][0-9]*(\.[0-9]*)?" /> + </div> + </div> + <div class="row"> + <div class="col-sm-4"> + <label for="new_excerpt.boundingBox.west">South</label> + <input class="form-control" id="new_excerpt.boundingBox.west" name="new_excerpt.boundingBox.west" required="required" pattern="\-?[1-9][0-9]*(\.[0-9]*)?" /> + </div> + <div class="col-sm-4 col-sm-offset-4"> + <label for="new_excerpt.boundingBox.east">West</label> + <input class="form-control " id="new_excerpt.boundingBox.east" name="new_excerpt.boundingBox.east" required="required" pattern="\-?[1-9][0-9]*(\.[0-9]*)?" /> + </div> + </div> + <div class="row"> + <div class="col-sm-4 col-sm-offset-4"> + <label for="new_excerpt.boundingBox.south">East</label> + <input class="form-control" id="new_excerpt.boundingBox.south" name="new_excerpt.boundingBox.south" required="required" pattern="\-?[1-9][0-9]*(\.[0-9]*)?" /> + </div> + </div> + </div> + </fieldset> + + <div class="form-group"> + <input type="checkbox" checked="checked" id="new_excerpt.isPublic" name="new_excerpt.isPublic"/> + <label for="new_excerpt.is_public">Public</label> + <span class="help-block">Others will see name and bounding box of this excerpt. They won't see that you created it or when you did so.</span> + </div> + </div> + + <div class="form-part"> + <h2>Export options</h2> + <fieldset class="form-group"> + {% include 'excerptexport/partials/export_options.html' with export_options=export_options %} + </fieldset> + </div> + + + <input type="submit" value="Create excerpt export request" class="btn btn-primary" /> + </form> + + </div><!-- + --><div class="container-column stretch-5"> + <div class="outerMapWrapper"> + <!--<div class="innerMapWrapper">--> + <div id="map" ></div> + <!--</div>--> + </div> + </div><!-- + --></div> + </div> + + + <!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> + <script type="text/javascript" src="https://code.jquery.com/jquery.js"></script> + + <script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script> + <script>L.Path.CLIP_PADDING = 1.0;</script> + + <!-- Leaflet plugins --> + <script src='{% static "excerptexport/libraries/leaflet-locationfilter/src/locationfilter.js" %}'></script> + + <!-- map --> + <script src='{% static "excerptexport/scripts/map.js" %}'></script> + + <!-- form --> + <script src='{% static "excerptexport/scripts/formModeSwitcher.js" %}'></script> + + <!-- Bootstrap --> + <script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script> + + <!-- Bootstrap plugins --> + <script type="text/javascript"> + $(function () { + $('[data-toggle="tooltip"]').tooltip(); + }); + </script> + <!-- Bootstrap select --> + <script type="text/javascript" + src="https://silviomoreto.github.io/bootstrap-select/bootstrap-select.min.js"></script> + <script type="text/javascript"> + $(document).ready(function (e) { + $('.selectpicker').selectpicker({}); + }); + </script> +{% endblock %} \ No newline at end of file diff --git a/source/excerptexport/templates/excerptexport/templates/show_downloads.html b/source/excerptexport/templates/excerptexport/templates/show_downloads.html new file mode 100644 index 0000000000000000000000000000000000000000..d1954b50484867ae58bfab457b011052d9bf4d1f --- /dev/null +++ b/source/excerptexport/templates/excerptexport/templates/show_downloads.html @@ -0,0 +1,15 @@ +{% extends "excerptexport/layouts/base.html" %} + +{% load filter_filename %} + +{% block main %} + <h2>Downloads</h2> + <ul> + {% for file in files %} + <li> + <a href="{% url 'excerptexport:download' %}?file={{ file.public_identifier }}">{{ file.public_identifier }}</a>: + {{ file.file|filter_filename }} + </li> + {% endfor %} + </ul> +{% endblock %} diff --git a/source/excerptexport/templatetags/filter_filename.py b/source/excerptexport/templatetags/filter_filename.py new file mode 100644 index 0000000000000000000000000000000000000000..80963b27763cbe0932685c06f18b61287ce2d69a --- /dev/null +++ b/source/excerptexport/templatetags/filter_filename.py @@ -0,0 +1,11 @@ +import os + +from django import template + + +register = template.Library() + + +@register.filter +def filter_filename(file_object): + return os.path.basename(file_object.name) if file_object and file_object.name else file_object diff --git a/source/excerptexport/tests/__init__.py b/source/excerptexport/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..38e696e5bb1644e41917b4c11b58c1484cb9a794 --- /dev/null +++ b/source/excerptexport/tests/__init__.py @@ -0,0 +1 @@ +# scripts with names of form 'test*.py' are autodiscovered diff --git a/source/excerptexport/tests/test_downloads.py b/source/excerptexport/tests/test_downloads.py new file mode 100644 index 0000000000000000000000000000000000000000..3d8a145ee31103370530d681d2f5d7af6e7d26de --- /dev/null +++ b/source/excerptexport/tests/test_downloads.py @@ -0,0 +1,46 @@ +import os + +from django.test import TestCase +from django.core.urlresolvers import reverse +from django.core.files import File +from django.contrib.auth.models import User + +from excerptexport.models import OutputFile, Excerpt, ExtractionOrder +from excerptexport import settings + + +class DownloadsTestCase(TestCase): + def setUp(self): + settings.APPLICATION_SETTINGS['data_directory'] = '/tmp/osmaxx-dev-data' + if not os.path.isdir(settings.APPLICATION_SETTINGS['data_directory']): + os.makedirs(settings.APPLICATION_SETTINGS['data_directory']) + settings.APPLICATION_SETTINGS['download_file_name'] = '%(name)s' + + def test_file_download(self): + user = User.objects.create_user('user', 'user@example.com', 'pw') + excerpt = Excerpt.objects.create(name='Neverland', is_active=True, is_public=True, owner=user) + extraction_order = ExtractionOrder.objects.create(excerpt=excerpt, orderer=user) + output_file = OutputFile.objects.create(mime_type='test/plain', extraction_order=extraction_order) + + file_path = settings.APPLICATION_SETTINGS['data_directory'] + '/' + output_file.public_identifier + '.txt' + + with open(file_path, 'w') as file_reference: + new_file = File(file_reference) + new_file.write('Test text') + + output_file.file = file_path + output_file.save() + + response = self.client.get( + reverse('excerptexport:download'), + {'file': output_file.public_identifier} + ) + + self.assertEqual(response['Content-Length'], str(os.path.getsize(file_path))) + self.assertEqual( + response['Content-Disposition'], + 'attachment; filename=%s' % os.path.basename(output_file.file.name) + ) + self.assertEqual(b''.join(response.streaming_content), b'Test text') + + os.remove(file_path) diff --git a/source/excerptexport/tests/test_partials.py b/source/excerptexport/tests/test_partials.py new file mode 100644 index 0000000000000000000000000000000000000000..cccc764669c7ac12c7cb026026db601405b6edec --- /dev/null +++ b/source/excerptexport/tests/test_partials.py @@ -0,0 +1,55 @@ +from django.core.urlresolvers import reverse +from django.contrib.auth.models import User +from django.shortcuts import render +from django.template import Context, Template +from django.test import TestCase + + +class PartialsTestCase(TestCase): + def test_rendering_select_with_groups(self): + context = Context({ + 'coordinate_reference_system': { + 'label': 'Coordinate reference system', + 'type': 'select', + 'select_multiple': False, + 'default': 'pseudomerkator', + 'groups': [ + { + 'name': 'Global coordinate reference systems', + 'values': [ + {'name': 'pseudomerkator', 'label': 'Pseudo merkator'}, + {'name': 'wgs72', 'label': 'WGS 72'}, + {'name': 'wgs84', 'label': 'WGS 84'} + ] + }, + { + 'name': 'UTM zones for your export', + 'values': [ + {'name': 'utm32', 'label': 'UTM zone 32'}, + {'name': 'utm33', 'label': 'UTM zone 33'} + ] + } + ] + } + }) + template = Template( + "{% spaceless %}{% include 'excerptexport/partials/select.html' with element=coordinate_reference_system name='coordinate_reference_system' %}{% endspaceless %}" + ) + rendered_view = template.render(context) + expected_rendered_template = Template( + """{% spaceless %} +<select name="coordinate_reference_system" id="coordinate_reference_system"> + <optgroup label="Global coordinate reference systems"> + <option value="pseudomerkator">Pseudo merkator</option> + <option value="wgs72">WGS 72</option> + <option value="wgs84">WGS 84</option> + </optgroup> + <optgroup label="UTM zones for your export"> + <option value="utm32">UTM zone 32</option> + <option value="utm33">UTM zone 33</option> + </optgroup> +</select> +{% endspaceless %}""" + ).render(Context({})) + + self.assertEqual(rendered_view, expected_rendered_template) diff --git a/source/excerptexport/tests/test_views.py b/source/excerptexport/tests/test_views.py new file mode 100644 index 0000000000000000000000000000000000000000..fd7dbc7a9e985d640a7e90923d1eb08d0bdd6957 --- /dev/null +++ b/source/excerptexport/tests/test_views.py @@ -0,0 +1,124 @@ +from django.core.urlresolvers import reverse +from django.contrib.auth.models import User +from django.test import TestCase + +from excerptexport.models import ExtractionOrder, Excerpt + + +class ExcerptExportViewTests(TestCase): + user = None + new_excerpt_post_data = None + existing_excerpt = None + existing_excerpt_post_data = None + + def setUp(self): + self.user = User.objects.create_user('user', 'user@example.com', 'pw') + self.new_excerpt_post_data = { + 'form-mode': 'create_new_excerpt', + 'new_excerpt.name': 'A very interesting region', + 'new_excerpt.is_public': 'True', + 'new_excerpt.boundingBox.north': '1.0', + 'new_excerpt.boundingBox.east': '2.0', + 'new_excerpt.boundingBox.south': '3.0', + 'new_excerpt.boundingBox.west': '4.0' + } + existing_excerpt = Excerpt.objects.create( + name='Some old Excerpt', + is_active=True, + is_public=False, + owner=self.user + ) + self.existing_excerpt_post_data = { + 'form-mode': 'existing_excerpt', + 'existing_excerpt.id': existing_excerpt.id + } + + def test_new_when_not_logged_in(self): + """ + When not logged in, we get redirected. + """ + response = self.client.get(reverse('excerptexport:new')) + self.assertEqual(response.status_code, 302) + + def test_new(self): + """ + When logged in, we get the excerpt choice form. + """ + self.client.login(username='user', password='pw') + response = self.client.get(reverse('excerptexport:new')) + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'Create new excerpt') + + def test_create_when_not_logged_in(self): + """ + When not logged in, we get redirected. + """ + response = self.client.post(reverse('excerptexport:create'), self.new_excerpt_post_data) + self.assertEqual(response.status_code, 302) + + def test_create_with_new_excerpt(self): + """ + When logged in, POSTing an export request with a new excerpt is successful. + """ + self.client.login(username='user', password='pw') + response = self.client.post(reverse('excerptexport:create'), self.new_excerpt_post_data) + self.assertEqual(response.status_code, 200) + + self.assertFalse(response.context['use_existing']) + self.assertEqual(response.context['excerpt'].name, 'A very interesting region') + self.assertEqual( + str(response.context['bounding_geometry']), + 'Bounding box: (4.0, 3.0), (4.0, 1.0), (2.0, 1.0), (2.0, 3.0), (4.0, 3.0)' + ) + self.assertEqual(response.context['options'], {'routing': {'formats': []}, 'gis': {'coordinate_reference_system': [], 'detail_level': [], 'formats': []}}) + + self.assertEqual( + Excerpt.objects.filter(name='A very interesting region', is_active=True, is_public=True).count(), + 1 + ) + + def test_create_with_existing_excerpt(self): + """ + When logged in, POSTing an export request using an existing excerpt is successful. + """ + self.client.login(username='user', password='pw') + response = self.client.post(reverse('excerptexport:create'), self.existing_excerpt_post_data) + self.assertEqual(response.status_code, 200) + + self.assertTrue(response.context['use_existing']) + self.assertEqual(response.context['excerpt'], str(self.existing_excerpt_post_data['existing_excerpt.id'])) + self.assertEqual(response.context['options'], {'routing': {'formats': []}, 'gis': {'coordinate_reference_system': [], 'detail_level': [], 'formats': []}}) + + def test_create_with_new_excerpt_persists_a_new_order(self): + """ + When logged in, POSTing an export request with a new excerpt persists a new ExtractionOrder. + """ + self.assertEqual(ExtractionOrder.objects.count(), 0) + self.client.login(username='user', password='pw') + response = self.client.post(reverse('excerptexport:create'), self.new_excerpt_post_data) + self.assertEqual(ExtractionOrder.objects.count(), 1) + + newly_created_order = ExtractionOrder.objects.first() # only reproducible because there is only 1 + from excerptexport.models.extraction_order import ExtractionOrderState + self.assertEqual(newly_created_order.state, ExtractionOrderState.INITIALIZED) + self.assertIsNone(newly_created_order.process_start_date) + self.assertIsNone(newly_created_order.process_reference) + self.assertEqual(newly_created_order.orderer, self.user) + self.assertEqual(newly_created_order.excerpt.name, 'A very interesting region') + + def test_create_with_existing_excerpt_persists_a_new_order(self): + """ + When logged in, POSTing an export request using an existing excerpt persists a new ExtractionOrder. + """ + self.assertEqual(ExtractionOrder.objects.count(), 0) + self.client.login(username='user', password='pw') + response = self.client.post(reverse('excerptexport:create'), self.existing_excerpt_post_data) + self.assertEqual(ExtractionOrder.objects.count(), 1) + + newly_created_order = ExtractionOrder.objects.first() # only reproducible because there is only 1 + from excerptexport.models.extraction_order import ExtractionOrderState + self.assertEqual(newly_created_order.state, ExtractionOrderState.INITIALIZED) + self.assertIsNone(newly_created_order.process_start_date) + self.assertIsNone(newly_created_order.process_reference) + self.assertEqual(newly_created_order.orderer, self.user) + self.assertEqual(newly_created_order.excerpt.name, 'Some old Excerpt') diff --git a/source/excerptexport/urls.py b/source/excerptexport/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..911810b1261558d9d1b83f160394f19ca614f70b --- /dev/null +++ b/source/excerptexport/urls.py @@ -0,0 +1,12 @@ +from django.conf.urls import patterns, url +from excerptexport import views + + +urlpatterns = patterns( + '', + url(r'^$', views.index, name='index'), + url(r'^new/$', views.new_excerpt_export, name='new'), + url(r'^downloads/$', views.show_downloads, name='downloads'), + url(r'^download/$', views.download_file, name='download'), + url(r'^create/$', views.create_excerpt_export, name='create'), +) diff --git a/source/excerptexport/views.py b/source/excerptexport/views.py new file mode 100644 index 0000000000000000000000000000000000000000..cf9e6c583022e9fa2f26d0f63290de640f353367 --- /dev/null +++ b/source/excerptexport/views.py @@ -0,0 +1,145 @@ +import os + +from django.shortcuts import render +from django.shortcuts import get_object_or_404 + +from django.http import HttpResponse, HttpResponseRedirect, StreamingHttpResponse, HttpResponseNotFound +from django.core.servers.basehttp import FileWrapper +from django.core.urlresolvers import reverse +from django.core.servers.basehttp import FileWrapper +from django.template import RequestContext, loader + +from django.contrib.auth.decorators import login_required +from django.contrib.auth.models import User + +from django.utils.encoding import smart_str + +from excerptexport.models import ExtractionOrder +from excerptexport.models import Excerpt +from excerptexport.models import OutputFile +from excerptexport.models import BoundingGeometry +from excerptexport.models.extraction_order import ExtractionOrderState +from excerptexport import settings +from excerptexport.services.data_conversion_service import trigger_data_conversion + + +def index(request): + return HttpResponse(loader.get_template('excerptexport/templates/index.html').render(RequestContext(request, {}))) + + +class NewExcerptExportViewModel: + def __init__(self, user): + self.user = user + self.personal_excerpts = Excerpt.objects.filter(is_active=True, is_public=False, owner=user) # .order_by('name') + self.public_excerpts = Excerpt.objects.filter(is_active=True, is_public=True) # .order_by('name') + + self.administrative_areas = settings.ADMINISTRATIVE_AREAS + self.export_options = settings.EXPORT_OPTIONS + + def get_context(self): + return self.__dict__ + + +@login_required(login_url='/admin/') +def new_excerpt_export(request): + view_model = NewExcerptExportViewModel(request.user) + return render(request, 'excerptexport/templates/new_excerpt_export.html', view_model.get_context()) + + +@login_required(login_url='/admin/') +def create_excerpt_export(request): + if request.POST['form-mode'] == 'existing_excerpt': + existing_excerpt_id = request.POST['existing_excerpt.id'] + view_context = {'excerpt': existing_excerpt_id} + extraction_order = ExtractionOrder.objects.create( + excerpt_id=existing_excerpt_id, + orderer=request.user + ) + + if request.POST['form-mode'] == 'create_new_excerpt': + excerpt = Excerpt( + name=request.POST['new_excerpt.name'], + is_active=True, + is_public=request.POST['new_excerpt.is_public'] if ('new_excerpt.is_public' in request.POST) else False + ) + excerpt.owner = request.user + excerpt.save() + + bounding_geometry = BoundingGeometry.create_from_bounding_box_coordinates( + request.POST['new_excerpt.boundingBox.north'], + request.POST['new_excerpt.boundingBox.east'], + request.POST['new_excerpt.boundingBox.south'], + request.POST['new_excerpt.boundingBox.west'] + ) + bounding_geometry.excerpt = excerpt + bounding_geometry.save() + + view_context = {'excerpt': excerpt, 'bounding_geometry': bounding_geometry} + extraction_order = ExtractionOrder.objects.create( + excerpt=excerpt, + orderer=request.user + ) + + view_context['use_existing'] = 'existing_excerpt_id' in vars() # TODO: The view should not have to know + export_options = get_export_options(request.POST, settings.EXPORT_OPTIONS) + view_context['options'] = export_options + + trigger_data_conversion(extraction_order, export_options) + + return render(request, 'excerptexport/templates/create_excerpt_export.html', view_context) + + +@login_required(login_url='/admin/') +def show_downloads(request): + view_context = {} + + files = OutputFile.objects.filter(extraction_order__orderer=request.user, extraction_order__state=ExtractionOrderState.FINISHED) + view_context['files'] = files + return render(request, 'excerptexport/templates/show_downloads.html', view_context) + + +def download_file(request): + + file_id = request.GET['file'] + output_file = get_object_or_404(OutputFile, public_identifier=file_id, deleted_on_filesystem=False) + if not output_file.file: + return HttpResponseNotFound('<p>No output file attached to output file record.</p>') + + download_file_name = settings.APPLICATION_SETTINGS['download_file_name'] % { + 'id': output_file.public_identifier, + 'name': os.path.basename(output_file.file.name) + + } + # abspath usage: settings.APPLICATION_SETTINGS['data_directory'] may contain '../', + # so use abspath to strip it + # basepath usage: django stores the absolute path of a file but if we use the location from settings, + # the files are more movable -> so we only use the name of the file + absolute_file_path = os.path.abspath(settings.APPLICATION_SETTINGS['data_directory'] + '/' + os.path.basename(output_file.file.name)) + + # stream file in chunks + response = StreamingHttpResponse( + FileWrapper(open(absolute_file_path), settings.APPLICATION_SETTINGS['download_chunk_size']), + content_type=output_file.mime_type + ) + response['Content-Length'] = os.path.getsize(absolute_file_path) + response['Content-Disposition'] = 'attachment; filename=%s' % download_file_name + return response + + +def get_export_options(requestPostValues, optionConfig): + # post values naming schema: + # formats: "export_options.{{ export_option_key }}.formats" + # options: "'export_options.{{ export_option_key }}.options.{{ export_option_config_key }}" + export_options = {} + for export_option_key, export_option in optionConfig.items(): + export_options[export_option_key] = {} + export_options[export_option_key]['formats'] = requestPostValues.getlist( + 'export_options.'+export_option_key+'.formats' + ) + + for export_option_config_key, export_option_config in export_option['options'].items(): + export_options[export_option_key][export_option_config_key] = requestPostValues.getlist( + 'export_options.'+export_option_key+'.options.'+export_option_config_key + ) + + return export_options diff --git a/source/manage.py b/source/manage.py new file mode 100755 index 0000000000000000000000000000000000000000..072246e6dae942f5b3b6d2d22932423082f0eff0 --- /dev/null +++ b/source/manage.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python +import os +import sys + + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "osmaxx.settings") + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv) diff --git a/source/osmaxx/__init__.py b/source/osmaxx/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/source/osmaxx/settings.py b/source/osmaxx/settings.py new file mode 100644 index 0000000000000000000000000000000000000000..3ebedb0e386b63e18d32bf5d77f9a49ce84da397 --- /dev/null +++ b/source/osmaxx/settings.py @@ -0,0 +1,113 @@ +""" +Django settings for osmaxx project. + +For more information on this file, see +https://docs.djangoproject.com/en/1.7/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.7/ref/settings/ +""" + +import os + + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(__file__)) + +TEMPLATE_DIRS = ( + os.path.join(BASE_DIR, 'resources/private/'), +) + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'w%uc3xg!elspz-3!g@j7-^7@^g1-a-3%-+u39$4=vueb_p5p_6' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +TEMPLATE_DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = ( + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django.contrib.gis', + 'excerptexport' +) + +MIDDLEWARE_CLASSES = ( + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +) + +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', + } +} + +ROOT_URLCONF = 'osmaxx.urls' + +WSGI_APPLICATION = 'osmaxx.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/1.7/ref/settings/#databases + +DATABASES = { + 'default': { + # 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'ENGINE': 'django.contrib.gis.db.backends.postgis', + 'NAME': 'osmaxx', + 'USER': 'osmaxx', + 'PASSWORD': 'osmaxx', + 'HOST': '127.0.0.1', + 'PORT': '5432' + } +} + +import sys +if 'test' in sys.argv or 'test_coverage' in sys.argv: # Covers regular testing and django-coverage + DATABASES = { + 'default': { + 'ENGINE': 'django.contrib.gis.db.backends.spatialite', + 'NAME': os.path.join(BASE_DIR, 'test_db.sqlite3'), + } + } + +# Internationalization +# https://docs.djangoproject.com/en/1.7/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.7/howto/static-files/ + +STATIC_URL = '/static/' +# STATICFILES_DIRS = ( +# os.path.join(BASE_DIR, 'resources/public/'), +# ) diff --git a/source/osmaxx/urls.py b/source/osmaxx/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..e863f657daafc86c62c710e61489f27d3bbf76aa --- /dev/null +++ b/source/osmaxx/urls.py @@ -0,0 +1,13 @@ +from django.conf.urls import patterns, include, url +from django.contrib import admin + + +urlpatterns = patterns( + '', + # Examples: + # url(r'^$', 'osmaxx.views.home', name='home'), + # url(r'^blog/', include('blog.urls')), + + url(r'^excerptexport/', include('excerptexport.urls', namespace='excerptexport')), + url(r'^admin/', include(admin.site.urls)), +) diff --git a/source/osmaxx/wsgi.py b/source/osmaxx/wsgi.py new file mode 100644 index 0000000000000000000000000000000000000000..c1967f3ac194b733d9c12b2d0745c709bd1f917c --- /dev/null +++ b/source/osmaxx/wsgi.py @@ -0,0 +1,19 @@ +""" +WSGI config for osmaxx project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/ +""" + +import os +import sys + + +sys.path.append('/var/www/eda') +sys.path.append('/var/www/eda/projects') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "osmaxx.settings") + +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() diff --git a/source/runDevelopmentServer.sh b/source/runDevelopmentServer.sh new file mode 100755 index 0000000000000000000000000000000000000000..0189d7842f383454921147a60b7e15bbc5e6a940 --- /dev/null +++ b/source/runDevelopmentServer.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +CURRENTDIR=`dirname $0` +cd "$CURRENTDIR" +source "../environment/bin/activate" +LOCALIP=`ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'` +echo "$LOCALIP" +python ./manage.py runserver "$LOCALIP:8000" \ No newline at end of file