From b80bd744ad873f6fc43018bc4bfb90677de167bd Mon Sep 17 00:00:00 2001 From: Stefan Wintermeyer Date: Mon, 17 Dec 2012 12:01:45 +0100 Subject: Start of GS5. --- .gitignore | 88 + Gemfile | 78 + Gemfile.lock | 209 + Guardfile | 13 + README.md | 14 +- Rakefile | 7 + app/assets/images/amooma-logo.png | Bin 0 -> 1314 bytes app/assets/images/bg-body.png | Bin 0 -> 1768 bytes .../images/gradients/light-to-dark-blue-x63.png | Bin 0 -> 187 bytes .../images/gradients/white-gray-x29-reverse.png | Bin 0 -> 123 bytes app/assets/images/gradients/white-gray-x29.png | Bin 0 -> 126 bytes app/assets/images/gradients/white-texture-x63.png | Bin 0 -> 6927 bytes app/assets/images/icons/cellphone-32x.png | Bin 0 -> 1938 bytes app/assets/images/icons/clock-32x.png | Bin 0 -> 5968 bytes app/assets/images/icons/cross-16x.png | Bin 0 -> 3350 bytes app/assets/images/icons/facebook-32x.png | Bin 0 -> 402 bytes app/assets/images/icons/fax-32x.png | Bin 0 -> 5762 bytes app/assets/images/icons/headphones-16x.png | Bin 0 -> 3285 bytes app/assets/images/icons/headphones-32x.png | Bin 0 -> 5906 bytes app/assets/images/icons/house-32x.png | Bin 0 -> 5741 bytes app/assets/images/icons/mic-32x.png | Bin 0 -> 5837 bytes app/assets/images/icons/microphone-16x.png | Bin 0 -> 3239 bytes app/assets/images/icons/microphone-32x.png | Bin 0 -> 5837 bytes app/assets/images/icons/mute-16x.png | Bin 0 -> 3349 bytes app/assets/images/icons/phone-down-32x.png | Bin 0 -> 5879 bytes app/assets/images/icons/phone-mobile-32x.png | Bin 0 -> 5509 bytes app/assets/images/icons/phone-up-32x.png | Bin 0 -> 5861 bytes app/assets/images/icons/search-13x16.png | Bin 0 -> 849 bytes app/assets/images/icons/skype-32x.png | Bin 0 -> 625 bytes app/assets/images/icons/star-16x.png | Bin 0 -> 3379 bytes app/assets/images/icons/suitcase-32x.png | Bin 0 -> 5550 bytes app/assets/images/icons/tag-16x.png | Bin 0 -> 3286 bytes app/assets/images/icons/twitter-32x.png | Bin 0 -> 397 bytes app/assets/images/icons/unmute-16x.png | Bin 0 -> 3373 bytes app/assets/images/icons/user-16x.png | Bin 0 -> 3287 bytes app/assets/images/icons/user-female-16x.png | Bin 0 -> 1680 bytes app/assets/images/icons/user-male-16x.png | Bin 0 -> 1559 bytes app/assets/images/logo.png | Bin 0 -> 7490 bytes app/assets/images/rails.png | Bin 0 -> 6646 bytes app/assets/images/stubs/user-36x.jpg | Bin 0 -> 2093 bytes app/assets/images/user.png | Bin 0 -> 4800 bytes app/assets/javascripts/api/rows.js.coffee | 3 + app/assets/javascripts/application.js | 13 + app/assets/javascripts/config_siemens.js.coffee | 3 + app/assets/javascripts/core.coffee | 5 + app/assets/javascripts/page.js.coffee | 3 + app/assets/javascripts/softkeys.js.coffee | 25 + app/assets/javascripts/vendor/autoresize.jquery.js | 94 + .../vendor/fancybox/jquery.easing-1.3.pack.js | 205 + .../vendor/fancybox/jquery.fancybox-1.3.4.pack.js | 46 + .../fancybox/jquery.mousewheel-3.0.4.pack.js | 14 + app/assets/javascripts/vendor/html5boilerplate.js | 20 + app/assets/javascripts/vendor/jquery-1.6.2.min.js | 18 + app/assets/javascripts/vendor/jquery.condom.js | 52 + .../javascripts/vendor/jquery.easy-slider-1.7.js | 225 + .../javascripts/vendor/jquery.survival-kit.coffee | 36 + app/assets/javascripts/vendor/jquery.tmpl.js | 486 ++ .../javascripts/vendor/modernizr-2.0.6.min.js | 1116 +++++ app/assets/stylesheets/api/rows.css.scss | 3 + app/assets/stylesheets/app/layouts/_app.scss | 24 + .../stylesheets/app/layouts/_conference.scss | 136 + .../stylesheets/app/layouts/_phone-book-entry.scss | 176 + app/assets/stylesheets/app/pages/_phone_book.scss | 25 + app/assets/stylesheets/app/shared/_contents.scss | 374 ++ app/assets/stylesheets/app/shared/_footers.scss | 90 + app/assets/stylesheets/app/shared/_handheld.scss | 25 + app/assets/stylesheets/app/shared/_headers.scss | 145 + app/assets/stylesheets/app/shared/_ie.scss | 7 + app/assets/stylesheets/app/shared/_media.scss | 16 + app/assets/stylesheets/app/shared/_print.scss | 17 + app/assets/stylesheets/application.css.scss | 117 + app/assets/stylesheets/scaffolds.css.scss | 56 + app/assets/stylesheets/vendor/README | 1 + .../stylesheets/vendor/boilerplate-1.0/README | 15 + .../stylesheets/vendor/boilerplate-1.0/_reset.scss | 37 + .../vendor/boilerplate-1.0/_styles.scss | 171 + .../stylesheets/vendor/boilerplate-2.0/README | 16 + .../vendor/boilerplate-2.0/_styles.scss | 209 + .../stylesheets/vendor/easy-slider/_numeric.scss | 44 + .../stylesheets/vendor/facebox/_facebox.scss | 85 + app/assets/stylesheets/vendor/fancy-box/README | 4 + .../stylesheets/vendor/fancy-box/_fancy-box.scss | 336 ++ app/assets/stylesheets/vendor/fancy-buttons/README | 3 + .../vendor/fancy-buttons/_fancy-buttons.scss | 195 + .../vendor/fancy-buttons/_fancy-gradient.scss | 28 + .../stylesheets/vendor/survival-kit/_blog.scss | 99 + .../stylesheets/vendor/survival-kit/_effects.scss | 97 + .../stylesheets/vendor/survival-kit/_forms.scss | 313 ++ .../stylesheets/vendor/survival-kit/_headers.scss | 36 + .../stylesheets/vendor/survival-kit/_images.scss | 121 + .../stylesheets/vendor/survival-kit/_lists.scss | 37 + .../stylesheets/vendor/survival-kit/_loader.scss | 11 + .../vendor/survival-kit/_navigation.scss | 230 + .../stylesheets/vendor/survival-kit/_secure.scss | 3 + .../stylesheets/vendor/survival-kit/_tools.scss | 267 + .../access_authorizations_controller.rb | 68 + app/controllers/acd_agents_controller.rb | 73 + app/controllers/acd_callers_controller.rb | 41 + app/controllers/addresses_controller.rb | 41 + app/controllers/api/rows_controller.rb | 91 + app/controllers/application_controller.rb | 161 + .../automatic_call_distributors_controller.rb | 100 + app/controllers/call_forwards_controller.rb | 127 + app/controllers/call_histories_controller.rb | 100 + app/controllers/calls_controller.rb | 6 + app/controllers/callthroughs_controller.rb | 75 + app/controllers/conference_invitees_controller.rb | 93 + app/controllers/conferences_controller.rb | 82 + app/controllers/config_polycom_controller.rb | 330 ++ app/controllers/config_siemens_controller.rb | 1239 +++++ app/controllers/config_siemens_sort_controller.rb | 371 ++ app/controllers/config_snom_controller.rb | 1169 +++++ app/controllers/fax_accounts_controller.rb | 82 + app/controllers/fax_documents_controller.rb | 82 + .../freeswitch_voicemail_msgs_controller.rb | 7 + app/controllers/gemeinschaft_setups_controller.rb | 61 + .../gs_cluster_sync_log_entries_controller.rb | 25 + app/controllers/gs_nodes_controller.rb | 170 + app/controllers/gui_functions_controller.rb | 73 + app/controllers/hunt_group_members_controller.rb | 67 + app/controllers/hunt_groups_controller.rb | 55 + app/controllers/manufacturers_controller.rb | 49 + app/controllers/page_controller.rb | 24 + app/controllers/phone_book_entries_controller.rb | 135 + app/controllers/phone_books_controller.rb | 105 + app/controllers/phone_models_controller.rb | 52 + app/controllers/phone_number_ranges_controller.rb | 56 + app/controllers/phone_numbers_controller.rb | 226 + app/controllers/phone_sip_accounts_controller.rb | 60 + app/controllers/phones_controller.rb | 72 + app/controllers/ringtones_controller.rb | 67 + app/controllers/sessions_controller.rb | 44 + app/controllers/sip_accounts_controller.rb | 98 + app/controllers/sip_domains_controller.rb | 41 + app/controllers/softkeys_controller.rb | 91 + app/controllers/system_messages_controller.rb | 30 + app/controllers/tenants_controller.rb | 91 + .../user_group_memberships_controller.rb | 48 + app/controllers/user_groups_controller.rb | 69 + app/controllers/users_controller.rb | 85 + app/controllers/voicemail_messages_controller.rb | 140 + app/controllers/voicemail_settings_controller.rb | 91 + app/controllers/whitelists_controller.rb | 61 + app/helpers/access_authorizations_helper.rb | 2 + app/helpers/acd_agents_helper.rb | 2 + app/helpers/acd_callers_helper.rb | 2 + app/helpers/addresses_helper.rb | 2 + app/helpers/api/rows_helper.rb | 2 + app/helpers/application_helper.rb | 2 + app/helpers/automatic_call_distributors_helper.rb | 2 + app/helpers/call_forward_cases_helper.rb | 2 + app/helpers/call_forwards_helper.rb | 2 + app/helpers/callthroughs_helper.rb | 2 + app/helpers/conference_invitees_helper.rb | 2 + app/helpers/conferences_helper.rb | 2 + app/helpers/config_siemens_helper.rb | 2 + app/helpers/error_messages_helper.rb | 23 + app/helpers/fax_accounts_helper.rb | 2 + app/helpers/fax_documents_helper.rb | 2 + app/helpers/gemeinschaft_setups_helper.rb | 2 + app/helpers/gs_cluster_sync_log_entries_helper.rb | 2 + app/helpers/gs_nodes_helper.rb | 2 + app/helpers/gui_functions_helper.rb | 2 + app/helpers/hunt_group_members_helper.rb | 2 + app/helpers/hunt_groups_helper.rb | 2 + app/helpers/layout_helper.rb | 70 + app/helpers/manufacturers_helper.rb | 2 + app/helpers/page_helper.rb | 2 + app/helpers/phone_book_entries_helper.rb | 2 + app/helpers/phone_books_helper.rb | 2 + app/helpers/phone_models_helper.rb | 2 + app/helpers/phone_number_ranges_helper.rb | 2 + app/helpers/phone_numbers_helper.rb | 2 + app/helpers/phone_sip_accounts_helper.rb | 2 + app/helpers/phones_helper.rb | 2 + app/helpers/phones_sip_accounts_helper.rb | 2 + app/helpers/ringtones_helper.rb | 2 + app/helpers/sessions_helper.rb | 2 + app/helpers/sip_accounts_helper.rb | 2 + app/helpers/sip_domains_helper.rb | 2 + app/helpers/softkeys_helper.rb | 2 + app/helpers/system_messages_helper.rb | 2 + app/helpers/tenants_helper.rb | 2 + app/helpers/user_groups_helper.rb | 2 + app/helpers/users_helper.rb | 2 + app/helpers/whitelists_helper.rb | 2 + app/mailers/.gitkeep | 0 app/mailers/notifications.rb | 110 + app/models/.gitkeep | 0 app/models/ability.rb | 170 + app/models/access_authorization.rb | 41 + app/models/acd_agent.rb | 39 + app/models/acd_caller.rb | 6 + app/models/address.rb | 8 + app/models/api.rb | 5 + app/models/api/row.rb | 152 + app/models/area_code.rb | 22 + app/models/automatic_call_distributor.rb | 21 + app/models/call.rb | 36 + app/models/call_forward.rb | 262 + app/models/call_forward_case.rb | 13 + app/models/call_history.rb | 199 + app/models/callthrough.rb | 60 + app/models/conference.rb | 63 + app/models/conference_invitee.rb | 39 + app/models/country.rb | 21 + app/models/dial_in_number_store.rb | 16 + app/models/fax_account.rb | 77 + app/models/fax_document.rb | 82 + app/models/fax_resolution.rb | 15 + app/models/fax_thumbnail.rb | 8 + app/models/freeswitch_alias.rb | 23 + app/models/freeswitch_call.rb | 24 + app/models/freeswitch_cdr.rb | 4 + app/models/freeswitch_channel.rb | 24 + app/models/freeswitch_complete.rb | 23 + app/models/freeswitch_fifo_bridge.rb | 23 + app/models/freeswitch_fifo_caller.rb | 23 + app/models/freeswitch_fifo_outbound.rb | 23 + app/models/freeswitch_interface.rb | 23 + app/models/freeswitch_nat.rb | 23 + app/models/freeswitch_registration.rb | 23 + app/models/freeswitch_task.rb | 23 + app/models/freeswitch_voicemail_pref.rb | 23 + app/models/gemeinschaft_setup.rb | 8 + app/models/gs_cluster_sync_log_entry.rb | 99 + app/models/gs_node.rb | 30 + app/models/gui_function.rb | 40 + app/models/gui_function_membership.rb | 7 + app/models/hunt_group.rb | 43 + app/models/hunt_group_member.rb | 67 + app/models/language.rb | 11 + app/models/manufacturer.rb | 46 + app/models/oui.rb | 17 + app/models/phone.rb | 240 + app/models/phone_book.rb | 33 + app/models/phone_book_entry.rb | 109 + app/models/phone_model.rb | 56 + app/models/phone_number.rb | 304 ++ app/models/phone_number_range.rb | 16 + app/models/phone_sip_account.rb | 17 + .../remote_gs_node/gs_cluster_sync_log_entry.rb | 9 + app/models/ringtone.rb | 15 + app/models/sip_account.rb | 221 + app/models/sip_domain.rb | 16 + app/models/softkey.rb | 100 + app/models/softkey_function.rb | 13 + app/models/system_message.rb | 7 + app/models/tenant.rb | 243 + app/models/tenant_membership.rb | 25 + app/models/user.rb | 208 + app/models/user_group.rb | 33 + app/models/user_group_membership.rb | 26 + app/models/voicemail_message.rb | 52 + app/models/voicemail_setting.rb | 12 + app/models/whitelist.rb | 23 + app/uploaders/audio_uploader.rb | 49 + app/uploaders/document_uploader.rb | 49 + app/uploaders/image_uploader.rb | 63 + app/uploaders/thumbnail_uploader.rb | 62 + app/uploaders/tiff_uploader.rb | 49 + app/views/access_authorizations/_form.html.haml | 7 + .../access_authorizations/_form_core.html.haml | 11 + .../access_authorizations/_index_core.html.haml | 21 + app/views/access_authorizations/edit.html.haml | 3 + app/views/access_authorizations/index.html.haml | 6 + app/views/access_authorizations/new.html.haml | 3 + app/views/access_authorizations/show.html.haml | 22 + app/views/acd_agents/_form.html.haml | 7 + app/views/acd_agents/_form_core.html.haml | 7 + app/views/acd_agents/_index_core.html.haml | 18 + app/views/acd_agents/_listing.html.haml | 8 + app/views/acd_agents/edit.html.haml | 3 + app/views/acd_agents/index.html.haml | 6 + app/views/acd_agents/new.html.haml | 3 + app/views/acd_agents/show.html.haml | 28 + app/views/acd_callers/_index_core.html.haml | 21 + app/views/acd_callers/index.html.haml | 6 + app/views/acd_callers/show.html.haml | 25 + app/views/addresses/_form.html.haml | 7 + app/views/addresses/_form_core.html.haml | 9 + app/views/addresses/_index_core.html.haml | 23 + app/views/addresses/edit.html.haml | 9 + app/views/addresses/index.html.haml | 6 + app/views/addresses/new.html.haml | 3 + app/views/addresses/show.html.haml | 28 + app/views/api/rows/_form.html.erb | 21 + app/views/api/rows/edit.html.erb | 3 + app/views/api/rows/index.html.erb | 29 + app/views/api/rows/new.html.erb | 3 + app/views/api/rows/show.html.erb | 56 + .../automatic_call_distributors/_form.html.haml | 8 + .../_form_core.html.haml | 16 + .../_index_core.html.haml | 39 + .../automatic_call_distributors/edit.html.haml | 3 + .../automatic_call_distributors/index.html.haml | 6 + .../automatic_call_distributors/new.html.haml | 3 + .../automatic_call_distributors/show.html.haml | 59 + app/views/call_forwards/_form.html.haml | 7 + app/views/call_forwards/_form_core.html.haml | 15 + app/views/call_forwards/_index_core.html.haml | 31 + app/views/call_forwards/edit.html.haml | 3 + app/views/call_forwards/index.html.haml | 6 + app/views/call_forwards/new.html.haml | 3 + app/views/call_forwards/show.html.haml | 33 + app/views/call_histories/_index_core.html.haml | 65 + app/views/call_histories/_navigation.html.haml | 11 + app/views/call_histories/index.html.haml | 6 + app/views/calls/_index_core.html.haml | 9 + app/views/calls/index.html.haml | 6 + app/views/callthroughs/_form.html.haml | 7 + app/views/callthroughs/_form_core.html.haml | 24 + app/views/callthroughs/_index_core.html.haml | 17 + app/views/callthroughs/edit.html.haml | 3 + app/views/callthroughs/index.html.haml | 6 + app/views/callthroughs/new.html.haml | 3 + app/views/callthroughs/show.html.haml | 27 + app/views/conference_invitees/_form.html.haml | 7 + app/views/conference_invitees/_form_core.html.haml | 7 + .../conference_invitees/_index_core.html.haml | 17 + app/views/conference_invitees/edit.html.haml | 3 + app/views/conference_invitees/index.html.haml | 6 + app/views/conference_invitees/new.html.haml | 3 + app/views/conference_invitees/show.html.haml | 20 + app/views/conferences/_form.html.haml | 7 + app/views/conferences/_form_core.html.haml | 11 + app/views/conferences/_index_core.html.haml | 53 + app/views/conferences/edit.html.haml | 3 + app/views/conferences/index.html.haml | 6 + app/views/conferences/new.html.haml | 3 + app/views/conferences/show.html.haml | 43 + app/views/config_polycom/_call_history.xml.haml | 18 + .../config_polycom/_call_history_menu.xml.haml | 13 + app/views/config_polycom/_phone_book.xml.haml | 18 + app/views/config_polycom/config_files.xml.builder | 12 + app/views/config_polycom/idle_screen.xml.haml | 7 + app/views/config_polycom/settings.xml.erb | 8 + .../config_polycom/settings_directory.xml.haml | 16 + app/views/config_siemens/_menu_list.xml.haml | 33 + app/views/config_siemens/clean-up.xml.erb | 5 + app/views/config_siemens/index.xml.erb | 5 + app/views/config_siemens/write.xml.erb | 10 + .../config_snom/_snom_phone_directory.xml.haml | 19 + app/views/config_snom/_snom_phone_input.xml.haml | 19 + app/views/config_snom/_snom_phone_menu.xml.haml | 17 + app/views/config_snom/_snom_phone_text.xml.haml | 16 + app/views/config_snom/call_history.xml.haml | 2 + app/views/config_snom/idle_screen.xml.haml | 33 + app/views/config_snom/log_in.xml.haml | 3 + app/views/config_snom/show.xml.haml | 151 + app/views/config_snom/state_settings.xml.haml | 49 + app/views/config_snom/switch_protocol.xml.builder | 18 + app/views/fax_accounts/_form.html.haml | 7 + app/views/fax_accounts/_form_core.html.haml | 11 + app/views/fax_accounts/_index_core.html.haml | 35 + app/views/fax_accounts/edit.html.haml | 3 + app/views/fax_accounts/index.html.haml | 6 + app/views/fax_accounts/new.html.haml | 3 + app/views/fax_accounts/show.html.haml | 21 + app/views/fax_documents/_form.html.haml | 7 + app/views/fax_documents/_form_core.html.haml | 7 + app/views/fax_documents/_index_core.html.haml | 33 + app/views/fax_documents/edit.html.haml | 9 + app/views/fax_documents/index.html.haml | 5 + app/views/fax_documents/new.html.haml | 3 + app/views/fax_documents/show.html.haml | 36 + .../_index_core.html.haml | 12 + .../freeswitch_voicemail_msgs/index.html.haml | 3 + app/views/gemeinschaft_setups/new.de.html.haml | 25 + app/views/gemeinschaft_setups/new.html.haml | 25 + .../gs_cluster_sync_log_entries/_form.html.haml | 7 + .../_form_core.html.haml | 6 + .../_index_core.html.haml | 17 + .../gs_cluster_sync_log_entries/edit.html.haml | 3 + .../gs_cluster_sync_log_entries/index.html.haml | 6 + .../gs_cluster_sync_log_entries/new.html.haml | 3 + .../gs_cluster_sync_log_entries/show.html.haml | 19 + app/views/gs_nodes/_form.html.haml | 7 + app/views/gs_nodes/_form_core.html.haml | 7 + app/views/gs_nodes/_index_core.html.haml | 19 + app/views/gs_nodes/edit.html.haml | 3 + app/views/gs_nodes/index.html.haml | 6 + app/views/gs_nodes/new.html.haml | 3 + app/views/gs_nodes/show.html.haml | 22 + app/views/gs_nodes/sync.xml.haml | 88 + app/views/gui_functions/_form.html.haml | 7 + app/views/gui_functions/_form_core.html.haml | 10 + app/views/gui_functions/_index_core.html.haml | 26 + app/views/gui_functions/edit.html.haml | 3 + app/views/gui_functions/index.html.haml | 6 + app/views/gui_functions/new.html.haml | 3 + app/views/gui_functions/show.html.haml | 18 + app/views/hunt_group_members/_form.html.haml | 7 + app/views/hunt_group_members/_form_core.html.haml | 4 + app/views/hunt_group_members/_index_core.html.haml | 20 + app/views/hunt_group_members/_listing.html.haml | 8 + app/views/hunt_group_members/edit.html.haml | 3 + app/views/hunt_group_members/index.html.haml | 6 + app/views/hunt_group_members/new.html.haml | 3 + app/views/hunt_group_members/show.html.haml | 19 + app/views/hunt_groups/_form.html.haml | 7 + app/views/hunt_groups/_form_core.html.haml | 4 + app/views/hunt_groups/_index_core.html.haml | 34 + app/views/hunt_groups/edit.html.haml | 3 + app/views/hunt_groups/index.html.haml | 6 + app/views/hunt_groups/new.html.haml | 3 + app/views/hunt_groups/show.html.haml | 26 + app/views/layouts/application.html.haml | 46 + app/views/manufacturers/_form.html.haml | 7 + app/views/manufacturers/_form_core.html.haml | 4 + app/views/manufacturers/_index_core.html.haml | 18 + app/views/manufacturers/edit.html.haml | 3 + app/views/manufacturers/index.html.haml | 5 + app/views/manufacturers/new.html.haml | 3 + app/views/manufacturers/show.html.haml | 18 + app/views/notifications/new_fax.text.erb | 8 + app/views/notifications/new_password.text.erb | 3 + app/views/notifications/new_pin.text.erb | 7 + app/views/notifications/new_voicemail.text.erb | 9 + app/views/page/conference.html.haml | 80 + app/views/page/index.de.html.haml | 16 + app/views/page/index.html.haml | 16 + app/views/phone_book_entries/_form.html.haml | 7 + app/views/phone_book_entries/_form_core.html.haml | 27 + .../phone_book_entries/_index_core.de.html.haml | 36 + app/views/phone_book_entries/_index_core.html.haml | 36 + app/views/phone_book_entries/_navigation.html.haml | 8 + app/views/phone_book_entries/edit.html.haml | 9 + app/views/phone_book_entries/index.html.haml | 19 + app/views/phone_book_entries/new.html.haml | 3 + app/views/phone_book_entries/show.html.haml | 146 + .../phone_book_entries/show.html.haml.examlple | 194 + app/views/phone_books/_form.html.haml | 7 + app/views/phone_books/_form_core.html.haml | 3 + app/views/phone_books/_index_core.html.haml | 16 + app/views/phone_books/edit.html.haml | 3 + app/views/phone_books/index.html.haml | 6 + app/views/phone_books/new.html.haml | 3 + app/views/phone_books/show.html.haml | 13 + app/views/phone_models/_form.html.haml | 7 + app/views/phone_models/_form_core.html.haml | 4 + app/views/phone_models/_index_core.html.haml | 19 + app/views/phone_models/edit.html.haml | 3 + app/views/phone_models/index.html.haml | 6 + app/views/phone_models/new.html.haml | 3 + app/views/phone_models/show.html.haml | 18 + app/views/phone_number_ranges/_form.html.haml | 7 + app/views/phone_number_ranges/_form_core.html.haml | 3 + .../phone_number_ranges/_index_core.html.haml | 21 + app/views/phone_number_ranges/edit.html.haml | 3 + app/views/phone_number_ranges/index.html.haml | 6 + app/views/phone_number_ranges/new.html.haml | 3 + app/views/phone_number_ranges/show.html.haml | 18 + app/views/phone_numbers/_form.html.haml | 7 + app/views/phone_numbers/_form_core.html.haml | 10 + app/views/phone_numbers/_index_core.html.haml | 13 + app/views/phone_numbers/_listing.html.haml | 8 + app/views/phone_numbers/edit.html.haml | 3 + app/views/phone_numbers/index.html.haml | 6 + app/views/phone_numbers/new.html.haml | 3 + app/views/phone_numbers/show.html.haml | 27 + app/views/phone_sip_accounts/_form.html.haml | 7 + app/views/phone_sip_accounts/_form_core.html.haml | 2 + app/views/phone_sip_accounts/_index_core.html.haml | 13 + app/views/phone_sip_accounts/index.html.haml | 6 + app/views/phone_sip_accounts/new.html.haml | 3 + app/views/phone_sip_accounts/show.html.haml | 13 + app/views/phones/_form.html.haml | 7 + app/views/phones/_form_core.html.haml | 8 + app/views/phones/_index_core.html.haml | 15 + app/views/phones/edit.html.haml | 3 + app/views/phones/index.html.haml | 6 + app/views/phones/new.html.haml | 3 + app/views/phones/show.html.haml | 31 + app/views/ringtones/_form.html.haml | 7 + app/views/ringtones/_form_core.html.haml | 3 + app/views/ringtones/_index_core.html.haml | 11 + app/views/ringtones/edit.html.haml | 3 + app/views/ringtones/index.html.haml | 6 + app/views/ringtones/new.html.haml | 3 + app/views/ringtones/show.html.haml | 12 + app/views/sessions/new.html.haml | 8 + app/views/shared/_create_link.html.haml | 11 + app/views/shared/_flash.html.haml | 19 + app/views/shared/_header.de.html.haml | 41 + app/views/shared/_header.html.haml | 41 + .../shared/_index_view_edit_destroy_part.html.haml | 29 + app/views/shared/_show_edit_destroy_part.html.haml | 16 + app/views/shared/_system_message.html.haml | 10 + app/views/sip_accounts/_form.html.haml | 7 + app/views/sip_accounts/_form_core.html.haml | 12 + app/views/sip_accounts/_index_core.html.haml | 28 + app/views/sip_accounts/edit.html.haml | 3 + app/views/sip_accounts/index.html.haml | 6 + app/views/sip_accounts/new.html.haml | 3 + app/views/sip_accounts/show.html.haml | 50 + app/views/sip_domains/_form.html.haml | 7 + app/views/sip_domains/_form_core.html.haml | 3 + app/views/sip_domains/_index_core.html.haml | 11 + app/views/sip_domains/edit.html.haml | 3 + app/views/sip_domains/index.html.haml | 6 + app/views/sip_domains/new.html.haml | 3 + app/views/sip_domains/show.html.haml | 10 + app/views/softkeys/_form.html.haml | 7 + app/views/softkeys/_form_core.html.haml | 12 + app/views/softkeys/_index_core.html.haml | 14 + app/views/softkeys/edit.html.haml | 3 + app/views/softkeys/index.html.haml | 6 + app/views/softkeys/new.html.haml | 3 + app/views/softkeys/show.html.haml | 7 + app/views/system_messages/_form.html.haml | 7 + app/views/system_messages/_form_core.html.haml | 2 + app/views/system_messages/_index_core.html.haml | 11 + app/views/system_messages/index.html.haml | 3 + app/views/system_messages/new.html.haml | 3 + app/views/system_messages/show.html.haml | 8 + app/views/tenants/_admin_area.de.html.haml | 118 + app/views/tenants/_admin_area.html.haml | 116 + app/views/tenants/_form.html.haml | 24 + app/views/tenants/_form_core.html.haml | 3 + app/views/tenants/_index_core.html.haml | 17 + app/views/tenants/edit.html.haml | 3 + app/views/tenants/index.html.haml | 6 + app/views/tenants/new.html.haml | 3 + app/views/tenants/show.html.haml | 14 + app/views/user_group_memberships/_form.html.haml | 7 + .../user_group_memberships/_form_core.html.haml | 2 + .../user_group_memberships/_index_core.html.haml | 13 + app/views/user_group_memberships/edit.html.haml | 3 + app/views/user_group_memberships/index.html.haml | 7 + app/views/user_group_memberships/new.html.haml | 3 + app/views/user_group_memberships/show.html.haml | 7 + app/views/user_groups/_form.html.haml | 7 + app/views/user_groups/_form_core.html.haml | 3 + app/views/user_groups/_index_core.html.haml | 24 + app/views/user_groups/edit.html.haml | 3 + app/views/user_groups/index.html.haml | 6 + app/views/user_groups/new.html.haml | 3 + app/views/user_groups/show.html.haml | 20 + app/views/users/_form.html.haml | 16 + app/views/users/_form_core.html.haml | 27 + app/views/users/_index_core.html.haml | 18 + app/views/users/_listing.html.haml | 8 + app/views/users/edit.html.haml | 3 + app/views/users/index.html.haml | 6 + app/views/users/new.html.haml | 3 + app/views/users/show.html.haml | 96 + app/views/voicemail_messages/_index_core.html.haml | 44 + app/views/voicemail_messages/_navigation.html.haml | 9 + app/views/voicemail_messages/index.html.haml | 6 + app/views/voicemail_settings/_form.html.haml | 7 + app/views/voicemail_settings/_form_core.html.haml | 11 + app/views/voicemail_settings/edit.html.haml | 3 + app/views/voicemail_settings/show.html.haml | 26 + app/views/whitelists/_form.html.haml | 7 + app/views/whitelists/_form_core.html.haml | 8 + app/views/whitelists/_index_core.html.haml | 15 + app/views/whitelists/edit.html.haml | 3 + app/views/whitelists/index.html.haml | 6 + app/views/whitelists/new.html.haml | 3 + app/views/whitelists/show.html.haml | 7 + config.ru | 4 + config/application.rb | 65 + config/boot.rb | 6 + config/database.yml | 22 + config/environment.rb | 5 + config/environments/development.rb | 45 + config/environments/production.rb | 65 + config/environments/test.rb | 37 + config/hirb.yml | 201 + config/initializers/backtrace_silencers.rb | 7 + config/initializers/connectivity_check.rb | 23 + config/initializers/gemeinschaft_parameters.rb | 81 + config/initializers/inflections.rb | 10 + config/initializers/load_extensions.rb | 1 + config/initializers/mime_types.rb | 9 + config/initializers/secret_token.rb | 7 + config/initializers/session_store.rb | 8 + config/initializers/simple_form.rb | 19 + config/initializers/validators.rb | 242 + config/initializers/wrap_parameters.rb | 14 + config/locales/carrierwave/de.yml | 5 + config/locales/carrierwave/en.yml | 5 + config/locales/de.yml | 196 + config/locales/en.yml | 6 + config/locales/simple_form.de.yml | 24 + config/locales/simple_form.en.yml | 24 + config/locales/views/access_authorizations/de.yml | 45 + config/locales/views/access_authorizations/en.yml | 48 + config/locales/views/acd_agents/de.yml | 76 + config/locales/views/acd_agents/en.yml | 76 + config/locales/views/acd_callers/de.yml | 70 + config/locales/views/acd_callers/en.yml | 70 + config/locales/views/addresses/de.yml | 72 + config/locales/views/addresses/en.yml | 72 + .../views/automatic_call_distributors/de.yml | 131 + .../views/automatic_call_distributors/en.yml | 136 + config/locales/views/call_forward_cases/de.yml | 7 + config/locales/views/call_forward_cases/en.yml | 7 + config/locales/views/call_forwards/de.yml | 77 + config/locales/views/call_forwards/en.yml | 77 + config/locales/views/call_histories/de.yml | 66 + config/locales/views/call_histories/en.yml | 67 + config/locales/views/callthroughs/de.yml | 58 + config/locales/views/callthroughs/en.yml | 58 + config/locales/views/conference_invitees/de.yml | 55 + config/locales/views/conference_invitees/en.yml | 54 + config/locales/views/conferences/de.yml | 81 + config/locales/views/conferences/en.yml | 81 + config/locales/views/fax_accounts/de.yml | 60 + config/locales/views/fax_accounts/en.yml | 60 + config/locales/views/fax_documents/de.yml | 148 + config/locales/views/fax_documents/en.yml | 148 + config/locales/views/gemeinschaft_setups/de.yml | 28 + config/locales/views/gemeinschaft_setups/en.yml | 28 + .../views/gs_cluster_sync_log_entries/de.yml | 60 + .../views/gs_cluster_sync_log_entries/en.yml | 60 + config/locales/views/gs_nodes/de.yml | 65 + config/locales/views/gs_nodes/en.yml | 65 + config/locales/views/gui_functions/de.yml | 50 + config/locales/views/gui_functions/en.yml | 50 + config/locales/views/hunt_group_members/de.yml | 48 + config/locales/views/hunt_group_members/en.yml | 48 + config/locales/views/hunt_groups/de.yml | 57 + config/locales/views/hunt_groups/en.yml | 57 + config/locales/views/manufacturers/de.yml | 49 + config/locales/views/manufacturers/en.yml | 49 + config/locales/views/notifications/de.yml | 4 + config/locales/views/notifications/en.yml | 4 + config/locales/views/pages/de.yml | 9 + config/locales/views/pages/en.yml | 9 + config/locales/views/phone_book_entries/de.yml | 161 + config/locales/views/phone_book_entries/en.yml | 161 + config/locales/views/phone_books/de.yml | 46 + config/locales/views/phone_books/en.yml | 46 + config/locales/views/phone_models/de.yml | 50 + config/locales/views/phone_models/en.yml | 49 + config/locales/views/phone_number_ranges/de.yml | 51 + config/locales/views/phone_number_ranges/en.yml | 51 + config/locales/views/phone_numbers/de.yml | 64 + config/locales/views/phone_numbers/en.yml | 64 + config/locales/views/phone_sip_accounts/de.yml | 37 + config/locales/views/phone_sip_accounts/en.yml | 37 + config/locales/views/phones/de.yml | 77 + config/locales/views/phones/en.yml | 77 + config/locales/views/ringtones/de.yml | 39 + config/locales/views/ringtones/en.yml | 39 + config/locales/views/sessions/de.yml | 15 + config/locales/views/sessions/en.yml | 15 + config/locales/views/sip_accounts/de.yml | 83 + config/locales/views/sip_accounts/en.yml | 83 + config/locales/views/sip_domains/de.yml | 38 + config/locales/views/sip_domains/en.yml | 38 + config/locales/views/softkeys/de.yml | 68 + config/locales/views/softkeys/en.yml | 64 + config/locales/views/system_messages/de.yml | 38 + config/locales/views/system_messages/en.yml | 38 + config/locales/views/tenants/de.yml | 73 + config/locales/views/tenants/en.yml | 73 + config/locales/views/user_group_memberships/de.yml | 35 + config/locales/views/user_group_memberships/en.yml | 35 + config/locales/views/user_groups/de.yml | 42 + config/locales/views/user_groups/en.yml | 42 + config/locales/views/users/de.yml | 95 + config/locales/views/users/en.yml | 95 + config/locales/views/voicemail_messages/de.yml | 34 + config/locales/views/voicemail_messages/en.yml | 35 + config/locales/views/voicemail_settings/de.yml | 52 + config/locales/views/voicemail_settings/en.yml | 52 + config/locales/views/whitelists/de.yml | 38 + config/locales/views/whitelists/en.yml | 38 + config/private_pub.yml | 10 + config/routes.rb | 375 ++ db/migrate/20111006073436_create_tenants.rb | 15 + db/migrate/20111006074623_create_users.rb | 20 + .../20111006081257_create_tenant_memberships.rb | 12 + db/migrate/20111006081936_create_user_groups.rb | 15 + ...20111006082944_create_user_group_memberships.rb | 11 + db/migrate/20111006082945_create_phone_books.rb | 17 + .../20111006101543_create_phone_book_entries.rb | 35 + db/migrate/20111007084820_add_image_to_user.rb | 5 + ...20111007092546_add_image_to_phone_book_entry.rb | 5 + ...111007110029_remove_position_from_phone_book.rb | 9 + .../20111007110258_remove_position_from_tenant.rb | 9 + ...23901_remove_position_from_tenant_membership.rb | 9 + ...0111008112922_add_current_tenant_id_to_users.rb | 5 + db/migrate/20111009184013_add_sessions_table.rb | 16 + db/migrate/20111009202027_create_phone_numbers.rb | 19 + db/migrate/20111009202500_create_countries.rb | 12 + db/migrate/20111009202910_create_area_codes.rb | 11 + .../20111009203233_add_country_id_to_tenant.rb | 5 + ...0232_add_phone_book_entry_id_to_phone_number.rb | 6 + ...0014_add_central_office_code_to_phone_number.rb | 5 + ...1181421_add_central_office_code_to_area_code.rb | 5 + db/migrate/20111012113547_create_ouis.rb | 11 + db/migrate/20111012121851_create_manufacturers.rb | 15 + db/migrate/20111012131652_create_phones.rb | 17 + db/migrate/20111012142952_add_state_to_phone.rb | 5 + db/migrate/20111012143922_create_phone_models.rb | 15 + .../20111013110804_add_state_to_phone_models.rb | 5 + db/migrate/20111013173838_create_sip_domains.rb | 13 + .../20111013173845_add_sip_domain_id_to_tenant.rb | 5 + db/migrate/20111013180505_create_sip_accounts.rb | 18 + db/migrate/20111031125955_create_addresses.rb | 19 + ...1101155754_add_phonetics_to_phone_book_entry.rb | 7 + ...20111101155952_add_index_to_phone_book_entry.rb | 10 + ...111104114634_add_polymorphic_to_phone_number.rb | 8 + db/migrate/20111104140800_create_calls.rb | 28 + db/migrate/20111104140900_create_channels.rb | 42 + db/migrate/20111104140901_create_interfaces.rb | 17 + db/migrate/20111104141000_create_aliases.rb | 15 + db/migrate/20111104141001_create_complete.rb | 33 + db/migrate/20111104141002_create_tasks.rb | 16 + db/migrate/20111104141100_create_nat.rb | 15 + db/migrate/20111104141101_create_registrations.rb | 20 + db/migrate/20111106081300_create_fifo_bridge.rb | 17 + db/migrate/20111106082100_create_fifo_callers.rb | 15 + db/migrate/20111106082500_create_fifo_outbound.rb | 36 + db/migrate/20111106083400_create_voicemail_msgs.rb | 30 + .../20111106084200_create_voicemail_prefs.rb | 17 + .../20111106162141_add_phoneable_to_phone.rb | 6 + .../20111119124303_add_hot_deskable_to_phone.rb | 5 + .../20111119153939_add_state_to_phone_number.rb | 5 + ...1120110056_add_value_of_to_s_to_phone_number.rb | 6 + ...112448_add_value_of_to_s_to_phone_book_entry.rb | 5 + .../20111120180010_create_call_forward_cases.rb | 21 + db/migrate/20111120180020_create_call_forwards.rb | 25 + ...1121105916_add_sip_domain_id_to_sip_accounts.rb | 5 + db/migrate/20111121152220_create_conferences.rb | 20 + .../20111122172513_create_conference_invitees.rb | 16 + .../20111123124113_create_phone_number_ranges.rb | 14 + db/migrate/20111123132658_create_languages.rb | 10 + .../20111123141120_create_gemeinschaft_setups.rb | 19 + ...3211631_rename_columns_of_phone_number_range.rb | 8 + ...25124957_add_phone_number_id_to_call_forward.rb | 9 + .../20111125150925_add_hops_to_call_forward.rb | 5 + .../20111126180826_add_depth_to_call_forward.rb | 5 + ...ernal_extension_ranges_to_gemeinschaft_setup.rb | 6 + db/migrate/20111128100949_add_pin_to_user.rb | 6 + .../20111203164007_add_tenant_id_to_sip_account.rb | 5 + ...124447_remove_sip_domain_id_from_sip_account.rb | 9 + ...20111211184853_remove_state_from_sip_account.rb | 9 + ...11211192350_add_sip_domain_id_to_sip_account.rb | 5 + db/migrate/20111212193532_create_faxes.rb | 19 + db/migrate/20111212201847_create_fax_pages.rb | 13 + ...3_add_external_numbers_to_gemeinschaft_setup.rb | 5 + .../20111213170837_add_language_id_to_tenant.rb | 7 + ...546_remove_tenant_id_from_gemeinschaft_setup.rb | 17 + ...20111214182903_add_max_members_to_conference.rb | 5 + db/migrate/20111215172021_create_fax_accounts.rb | 16 + .../20111216112614_add_information_to_fax.rb | 19 + db/migrate/20111217162506_add_fax_to_faxes.rb | 8 + db/migrate/20111218085222_create_fax_documents.rb | 32 + ...18100048_add_fax_account_id_to_fax_documents.rb | 5 + .../20111218143152_add_tenant_id_to_fax_account.rb | 6 + ...13_add_days_till_auto_delete_to_fax_accounts.rb | 6 + db/migrate/20111219131952_create_fax_thumbnails.rb | 11 + ...6_remove_fax_documentable_from_fax_documents.rb | 11 + ...151633_add_caller_id_number_to_fax_documents.rb | 8 + ...173947_remove_result_text_from_fax_documents.rb | 13 + .../20111222184203_add_tiff_to_fax_documents.rb | 5 + ...111222184912_add_resolution_to_fax_documents.rb | 5 + .../20111222185426_create_fax_resolutions.rb | 11 + db/migrate/20111226180221_create_delayed_jobs.rb | 21 + .../20111228194037_create_phone_sip_accounts.rb | 14 + db/migrate/20120104142556_create_ringtones.rb | 15 + ...d_announcement_of_a_new_member_to_conference.rb | 6 + db/migrate/20120118195740_create_softkeys.rb | 17 + .../20120119103852_add_sip_account_to_softkeys.rb | 6 + ...20119111944_add_call_waiting_to_sip_accounts.rb | 5 + ...d_clir_and_clip_phone_number_to_sip_accounts.rb | 6 + db/migrate/20120119154422_fax_defaults.rb | 15 + db/migrate/20120119154633_language_defaults.rb | 15 + db/migrate/20120119154759_country_defaults.rb | 254 + db/migrate/20120119154952_area_codes_germany.rb | 5245 ++++++++++++++++++++ db/migrate/20120119155619_area_codes_poland.rb | 69 + db/migrate/20120119161017_call_forward_cases.rb | 23 + db/migrate/20120119161152_snom_phones.rb | 63 + ...0120124131057_add_clip_number_to_sip_account.rb | 6 + ...4133950_add_clip_no_screening_to_sip_account.rb | 6 + .../20120124135953_add_clip_to_sip_account.rb | 5 + .../20120124142001_remove_name_from_softkey.rb | 9 + db/migrate/20120126090831_create_callthroughs.rb | 15 + .../20120127101726_create_system_messages.rb | 13 + db/migrate/20120128143538_openstage_phones.rb | 25 + .../20120128191113_create_access_authorizations.rb | 17 + db/migrate/20120129094444_create_whitelists.rb | 15 + ...1_add_sip_account_id_to_access_authorization.rb | 6 + db/migrate/20120203093048_create_hunt_groups.rb | 15 + .../20120203120739_create_hunt_group_members.rb | 16 + .../20120210121455_add_language_id_to_users.rb | 5 + .../20120215160448_create_softkey_functions.rb | 14 + ...20215160449_add_position_to_softkey_function.rb | 7 + ...215161054_add_softkey_function_id_to_softkey.rb | 5 + db/migrate/20120218182205_create_api_rows.rb | 21 + .../20120219210950_remove_state_from_user.rb | 9 + db/migrate/20120228154913_create_cdrs.rb | 33 + ...094049_add_voicemail_boolean_to_call_forward.rb | 6 + ...0312175918_add_hunt_group_id_to_call_forward.rb | 6 + ...120313121920_add_polymorphic_to_call_forward.rb | 9 + ...d_send_voicemail_as_email_attachment_to_user.rb | 6 + .../20120329133930_add_bleg_read_time_to_cdrs.rb | 6 + ...20120409092724_add_importer_checksum_to_user.rb | 6 + ...0120409160614_add_description_to_sip_account.rb | 6 + ...ard_rules_act_per_sip_account_to_sip_account.rb | 5 + ...120418194029_add_call_forward_id_to_softkeys.rb | 6 + .../20120421073538_add_position_to_call_forward.rb | 6 + .../20120421075735_populate_softkey_functions.rb | 9 + .../20120422072551_populate_softkey_function.rb | 18 + ...0120424062951_add_hotdeskable_to_sip_account.rb | 6 + .../20120425112414_add_nightly_reboot_to_phone.rb | 6 + .../20120509071426_add_from_field_to_tenant.rb | 8 + ...20510110311_add_forwarding_read_time_to_cdrs.rb | 6 + db/migrate/20120513154359_create_gui_functions.rb | 14 + ...120513155342_create_gui_function_memberships.rb | 12 + db/migrate/20120513185233_add_gui_functions.rb | 47 + .../20120515104749_add_hunt_group_function_key.rb | 14 + .../20120515124103_add_hold_softkey_function.rb | 14 + db/migrate/20120611093946_create_gs_nodes.rb | 14 + ...0120611150245_add_gs_node_id_to_phone_number.rb | 8 + ...120614113123_add_gs_node_information_to_user.rb | 8 + ...13931_add_gs_node_information_to_sip_account.rb | 8 + ...115938_add_gs_node_information_to_hunt_group.rb | 8 + ...617065247_create_gs_cluster_sync_log_entries.rb | 17 + db/migrate/20120617193636_add_site_to_gs_node.rb | 12 + .../20120626094238_add_uuid_to_phone_number.rb | 11 + db/migrate/20120626095730_add_uuid_to_users.rb | 6 + ...base_ip_address_to_gs_cluster_sync_log_entry.rb | 6 + ...ing_to_be_syned_to_gs_cluster_sync_log_entry.rb | 6 + ...add_association_to_gs_cluster_sync_log_entry.rb | 8 + db/migrate/20120723065038_add_uuid_to_tenants.rb | 6 + .../20120724131815_add_uuid_to_conferences.rb | 6 + .../20120724131905_add_uuid_to_callthroughs.rb | 6 + .../20120724131956_add_uuid_to_fax_accounts.rb | 6 + .../20120727102518_add_uuid_to_phone_book_entry.rb | 7 + ...20727105750_add_uuid_to_access_authorization.rb | 7 + ...access_authorization_user_id_to_phone_number.rb | 6 + db/migrate/20120728073802_add_is_native_to_user.rb | 6 + ...20120728073904_add_is_native_to_phone_number.rb | 6 + .../20120728091842_add_is_native_to_sip_account.rb | 6 + ...20120728113705_add_uuid_to_hunt_group_member.rb | 7 + ...0120728133144_add_uuid_to_phone_number_range.rb | 7 + .../20120728135133_add_uuid_to_fax_documents.rb | 6 + ...802132854_add_notification_to_voicemail_msgs.rb | 6 + ...0120813085708_add_uuid_to_conference_invitee.rb | 6 + ...821105942_create_automatic_call_distributors.rb | 22 + db/migrate/20120822094609_create_acd_callers.rb | 18 + db/migrate/20120822124716_create_acd_agents.rb | 19 + ...unce_position_to_automatic_call_distributors.rb | 6 + ...e_call_agents_to_automatic_call_distributors.rb | 6 + ..._add_greeting_to_automatic_call_distributors.rb | 6 + ...0_add_goodbye_to_automatic_call_distributors.rb | 6 + ...908_add_music_to_automatic_call_distributors.rb | 6 + ...40_change_data_type_for_announce_call_agents.rb | 13 + ..._add_automatic_call_distributor_function_key.rb | 14 + db/migrate/20121012071908_create_call_histories.rb | 29 + .../20121105123841_add_uuid_to_phone_books.rb | 6 + db/migrate/20121105123943_add_uuid_to_addresses.rb | 6 + .../20121105124208_add_uuid_to_call_forwards.rb | 6 + .../20121105124343_add_uuid_to_phone_models.rb | 6 + db/migrate/20121105124904_add_uuid_to_softkeys.rb | 6 + .../20121105125043_add_uuid_to_whitelists.rb | 6 + db/migrate/20121105125232_populate_uuid_field.rb | 138 + .../20121105144944_add_last_sync_to_gs_nodes.rb | 6 + .../20121107072526_add_bridge_stamp_to_cdrs.rb | 6 + ...20121121080400_add_notify_to_voicemail_prefs.rb | 6 + ...1121080548_add_attachment_to_voicemail_prefs.rb | 6 + ...21121080649_add_mark_read_to_voicemail_prefs.rb | 6 + .../20121121081552_add_purge_to_voicemail_prefs.rb | 6 + ...0121125084332_add_provisioning_key_to_phones.rb | 6 + ...084447_add_provisioning_key_active_to_phones.rb | 6 + db/schema.rb | 967 ++++ db/seeds.rb | 5 + .../20120119160732_emergency_numbers_germany.rb | 30 + .../20120223142004_add_more_german_area_codes.rb | 58 + install.sh | 214 + lib/activerecord_extensions.rb | 72 + lib/agi_server.rb | 123 + lib/assets/.gitkeep | 0 lib/freeswitch_event.rb | 133 + lib/generators/nifty.rb | 28 + lib/generators/nifty/authentication/USAGE | 50 + .../authentication/authentication_generator.rb | 154 + .../authentication/templates/authlogic_session.rb | 2 + .../templates/controller_authentication.rb | 60 + .../nifty/authentication/templates/fixtures.yml | 24 + .../nifty/authentication/templates/migration.rb | 20 + .../templates/sessions_controller.rb | 41 + .../authentication/templates/sessions_helper.rb | 2 + .../templates/tests/rspec/sessions_controller.rb | 39 + .../authentication/templates/tests/rspec/user.rb | 83 + .../templates/tests/rspec/users_controller.rb | 56 + .../templates/tests/shoulda/sessions_controller.rb | 40 + .../authentication/templates/tests/shoulda/user.rb | 85 + .../templates/tests/shoulda/users_controller.rb | 61 + .../tests/testunit/sessions_controller.rb | 36 + .../templates/tests/testunit/user.rb | 88 + .../templates/tests/testunit/users_controller.rb | 53 + .../nifty/authentication/templates/user.rb | 38 + .../authentication/templates/users_controller.rb | 32 + .../nifty/authentication/templates/users_helper.rb | 2 + .../templates/views/erb/_form.html.erb | 20 + .../templates/views/erb/edit.html.erb | 3 + .../templates/views/erb/login.html.erb | 30 + .../templates/views/erb/signup.html.erb | 5 + .../templates/views/haml/_form.html.haml | 16 + .../templates/views/haml/edit.html.haml | 3 + .../templates/views/haml/login.html.haml | 26 + .../templates/views/haml/signup.html.haml | 5 + lib/generators/nifty/config/USAGE | 23 + lib/generators/nifty/config/config_generator.rb | 24 + lib/generators/nifty/config/templates/config.yml | 8 + .../nifty/config/templates/load_config.rb | 2 + lib/generators/nifty/layout/USAGE | 25 + lib/generators/nifty/layout/layout_generator.rb | 29 + .../layout/templates/error_messages_helper.rb | 23 + .../nifty/layout/templates/layout.html.haml | 21 + .../nifty/layout/templates/layout_helper.rb | 38 + .../nifty/layout/templates/stylesheet.css | 83 + .../nifty/layout/templates/stylesheet.sass | 73 + lib/generators/nifty/scaffold/USAGE | 51 + .../nifty/scaffold/scaffold_generator.rb | 344 ++ .../nifty/scaffold/templates/actions/create.rb | 8 + .../nifty/scaffold/templates/actions/destroy.rb | 5 + .../nifty/scaffold/templates/actions/edit.rb | 3 + .../nifty/scaffold/templates/actions/index.rb | 3 + .../nifty/scaffold/templates/actions/new.rb | 3 + .../nifty/scaffold/templates/actions/show.rb | 3 + .../nifty/scaffold/templates/actions/update.rb | 8 + .../nifty/scaffold/templates/controller.rb | 3 + .../nifty/scaffold/templates/fixtures.yml | 9 + lib/generators/nifty/scaffold/templates/helper.rb | 2 + lib/generators/nifty/scaffold/templates/locale.yml | 46 + .../nifty/scaffold/templates/locale_de.yml | 46 + .../nifty/scaffold/templates/migration.rb | 16 + lib/generators/nifty/scaffold/templates/model.rb | 4 + .../templates/tests/rspec/actions/create.rb | 11 + .../templates/tests/rspec/actions/destroy.rb | 6 + .../scaffold/templates/tests/rspec/actions/edit.rb | 4 + .../templates/tests/rspec/actions/index.rb | 4 + .../scaffold/templates/tests/rspec/actions/new.rb | 4 + .../scaffold/templates/tests/rspec/actions/show.rb | 4 + .../templates/tests/rspec/actions/update.rb | 11 + .../scaffold/templates/tests/rspec/controller.rb | 8 + .../nifty/scaffold/templates/tests/rspec/model.rb | 7 + .../templates/tests/shoulda/actions/create.rb | 13 + .../templates/tests/shoulda/actions/destroy.rb | 8 + .../templates/tests/shoulda/actions/edit.rb | 6 + .../templates/tests/shoulda/actions/index.rb | 6 + .../templates/tests/shoulda/actions/new.rb | 6 + .../templates/tests/shoulda/actions/show.rb | 6 + .../templates/tests/shoulda/actions/update.rb | 13 + .../scaffold/templates/tests/shoulda/controller.rb | 5 + .../scaffold/templates/tests/shoulda/model.rb | 7 + .../templates/tests/testunit/actions/create.rb | 11 + .../templates/tests/testunit/actions/destroy.rb | 6 + .../templates/tests/testunit/actions/edit.rb | 4 + .../templates/tests/testunit/actions/index.rb | 4 + .../templates/tests/testunit/actions/new.rb | 4 + .../templates/tests/testunit/actions/show.rb | 4 + .../templates/tests/testunit/actions/update.rb | 11 + .../templates/tests/testunit/controller.rb | 49 + .../scaffold/templates/tests/testunit/model.rb | 7 + .../scaffold/templates/views/haml/_form.html.haml | 7 + .../templates/views/haml/_form_core.html.haml | 4 + .../templates/views/haml/_index_core.html.haml | 13 + .../scaffold/templates/views/haml/edit.html.haml | 3 + .../scaffold/templates/views/haml/index.html.haml | 6 + .../scaffold/templates/views/haml/new.html.haml | 3 + .../scaffold/templates/views/haml/show.html.haml | 9 + lib/phone_controllers/snom_phone.rb | 23 + lib/tasks/.gitkeep | 0 lib/tasks/cvs_user_import.rake | 331 ++ lib/tasks/fax.rake | 74 + lib/tasks/gs_cluster.rake | 333 ++ lib/tasks/originate.rake | 13 + lib/tasks/populate_area_codes_de.rake | 5211 +++++++++++++++++++ lib/tasks/populate_area_codes_pl.rake | 59 + lib/tasks/populate_country_codes.rake | 244 + lib/tasks/send_fax_notifications.rake | 49 + lib/tasks/send_voicemail_notifications.rake | 52 + lib/templates/erb/scaffold/_form.html.erb | 13 + lib/uacsta.rb | 83 + log/.gitkeep | 0 misc/TODO-Liste.txt | 0 misc/etc/cron.d/logout_phones | 3 + misc/etc/ssl/amooma/server.pem | 36 + misc/etc/ssl/amooma/server_cert.pem | 22 + misc/etc/ssl/amooma/server_key.pem | 16 + misc/example/apache-gs5.conf | 24 + misc/example/nginx | 73 + misc/example/xml-interface.txt | 25 + misc/freeswitch/conf/freeswitch.xml | 759 +++ misc/freeswitch/scripts/acd_wait.lua | 45 + misc/freeswitch/scripts/common/call_forwarding.lua | 47 + misc/freeswitch/scripts/common/call_history.lua | 140 + misc/freeswitch/scripts/common/conference.lua | 239 + .../scripts/common/configuration_file.lua | 70 + misc/freeswitch/scripts/common/database.lua | 151 + misc/freeswitch/scripts/common/fapi.lua | 80 + misc/freeswitch/scripts/common/ipcalc.lua | 27 + misc/freeswitch/scripts/common/log.lua | 69 + misc/freeswitch/scripts/common/node.lua | 73 + misc/freeswitch/scripts/common/phone_number.lua | 359 ++ misc/freeswitch/scripts/common/routing_tables.lua | 66 + misc/freeswitch/scripts/common/sip_account.lua | 137 + misc/freeswitch/scripts/common/str.lua | 136 + misc/freeswitch/scripts/common/sync_log.lua | 39 + misc/freeswitch/scripts/configuration.lua | 229 + .../scripts/configuration/freeswitch_xml.lua | 307 ++ misc/freeswitch/scripts/configuration/sip.lua | 37 + .../scripts/dialplan/access_authorizations.lua | 52 + misc/freeswitch/scripts/dialplan/acd.lua | 484 ++ misc/freeswitch/scripts/dialplan/callthrough.lua | 148 + misc/freeswitch/scripts/dialplan/cdr.lua | 71 + misc/freeswitch/scripts/dialplan/dialplan.lua | 996 ++++ misc/freeswitch/scripts/dialplan/fax.lua | 232 + misc/freeswitch/scripts/dialplan/functions.lua | 839 ++++ misc/freeswitch/scripts/dialplan/geo_number.lua | 89 + misc/freeswitch/scripts/dialplan/hunt_group.lua | 202 + misc/freeswitch/scripts/dialplan/phone_book.lua | 63 + misc/freeswitch/scripts/dialplan/presence.lua | 84 + misc/freeswitch/scripts/dialplan/route.lua | 265 + misc/freeswitch/scripts/dialplan/session.lua | 224 + misc/freeswitch/scripts/dialplan/sip_call.lua | 266 + misc/freeswitch/scripts/dialplan/tenant.lua | 51 + misc/freeswitch/scripts/dialplan/user.lua | 91 + misc/freeswitch/scripts/dialplan/voicemail.lua | 155 + misc/freeswitch/scripts/dialplan_default.lua | 64 + .../freeswitch/scripts/event/call_history_save.lua | 74 + misc/freeswitch/scripts/event/cdr_save.lua | 105 + misc/freeswitch/scripts/event/event.lua | 109 + misc/freeswitch/scripts/event/perimeter.lua | 106 + misc/freeswitch/scripts/event/presence_update.lua | 199 + misc/freeswitch/scripts/event_manager.lua | 39 + misc/freeswitch/scripts/fax_daemon.lua | 42 + misc/freeswitch/scripts/ini/conferences.ini | 27 + misc/freeswitch/scripts/ini/database.ini | 11 + misc/freeswitch/scripts/ini/dialplan.ini | 11 + misc/freeswitch/scripts/ini/events.ini | 8 + misc/freeswitch/scripts/ini/gateways.ini.example | 23 + misc/freeswitch/scripts/ini/perimeter.ini | 9 + misc/freeswitch/scripts/ini/routes.ini | 77 + misc/freeswitch/scripts/ini/sip_accounts.ini | 10 + misc/freeswitch/scripts/ini/sofia.ini | 55 + misc/freeswitch/scripts/phones/phone.lua | 114 + misc/freeswitch/scripts/phones/siemens.lua | 45 + misc/freeswitch/scripts/phones/snom.lua | 65 + misc/freeswitch/scripts/phones/uacsta.lua | 100 + misc/freeswitch/scripts/send_fax.lua | 170 + misc/mon_ami/asterisk.py | 299 ++ misc/mon_ami/freeswitch.py | 194 + misc/mon_ami/helper.py | 21 + misc/mon_ami/log.py | 71 + misc/mon_ami/mon-ami | 58 + misc/mon_ami/mon_ami | 10 + misc/mon_ami/mon_ami_handler.py | 434 ++ misc/mon_ami/mon_ami_main.py | 117 + misc/mon_ami/mon_ami_server.py | 85 + misc/mon_ami/sqliter.py | 132 + misc/mon_ami/tcp_server.py | 39 + misc/nginx/nginx.conf | 81 + private_pub.ru | 8 + public/404.html | 26 + public/422.html | 26 + public/500.html | 26 + public/favicon.ico | 0 public/images/fallback/mini_default.jpg | Bin 0 -> 3638 bytes public/images/fallback/mini_default_female.png | Bin 0 -> 1975 bytes public/images/fallback/mini_default_male.png | Bin 0 -> 1975 bytes public/images/fallback/profile_default.jpg | Bin 0 -> 6426 bytes public/images/fallback/profile_default.psd | Bin 0 -> 61058 bytes public/images/fallback/profile_default_female.png | Bin 0 -> 28145 bytes public/images/fallback/profile_default_male.png | Bin 0 -> 28742 bytes public/images/fallback/small_default.jpg | Bin 0 -> 4149 bytes public/images/fallback/small_default_female.png | Bin 0 -> 6620 bytes public/images/fallback/small_default_male.png | Bin 0 -> 6594 bytes .../fallback/snom_caller_picture_default.jpg | Bin 0 -> 5405 bytes .../snom_caller_picture_default_female.png | Bin 0 -> 14611 bytes .../fallback/snom_caller_picture_default_male.png | Bin 0 -> 14160 bytes public/images/snom/snom_300.jpg | Bin 0 -> 71634 bytes public/images/snom/snom_320.jpg | Bin 0 -> 53908 bytes public/images/snom/snom_360.jpg | Bin 0 -> 64418 bytes public/images/snom/snom_370.jpg | Bin 0 -> 77721 bytes public/images/snom/snom_820.jpg | Bin 0 -> 41398 bytes public/images/snom/snom_821.jpg | Bin 0 -> 41398 bytes public/images/snom/snom_870.jpg | Bin 0 -> 43835 bytes public/robots.txt | 6 + script/agi_server | 35 + script/delayed_job | 5 + script/erd | 38 + script/fax_new | 111 + script/fax_new.sh | 4 + script/logout_phones | 29 + script/logout_phones.sh | 4 + script/notes | 25 + script/rails | 68 + script/voicemail_new | 61 + script/voicemail_new.sh | 4 + test/factories/api_rows.rb | 17 + test/factories/area_codes.rb | 7 + test/factories/call_forwards.rb | 16 + test/factories/conference_invitees.rb | 8 + test/factories/conferences.rb | 8 + test/factories/countries.rb | 8 + test/factories/gemeinschaft_setups.rb | 8 + test/factories/gui_function_memberships.rb | 10 + test/factories/languages.rb | 6 + test/factories/manufacturers.rb | 6 + test/factories/ouis.rb | 6 + test/factories/phone_book_entries.rb | 7 + test/factories/phone_books.rb | 6 + test/factories/phone_models.rb | 6 + test/factories/phone_number_ranges.rb | 6 + test/factories/phone_numbers.rb | 7 + test/factories/phones.rb | 15 + test/factories/sip_accounts.rb | 17 + test/factories/sip_domains.rb | 6 + test/factories/softkey_functions.rb | 7 + test/factories/tenant_memberships.rb | 6 + test/factories/tenants.rb | 8 + test/factories/user_group_memberships.rb | 14 + test/factories/user_groups.rb | 6 + test/factories/users.rb | 11 + test/fixtures/.gitkeep | 0 test/functional/.gitkeep | 0 .../access_authorizations_controller_test.rb | 49 + test/functional/acd_agents_controller_test.rb | 49 + test/functional/acd_callers_controller_test.rb | 49 + test/functional/addresses_controller_test.rb | 49 + test/functional/api/rows_controller_test.rb | 49 + .../automatic_call_distributors_controller_test.rb | 49 + test/functional/call_forwards_controller_test.rb | 91 + test/functional/callthroughs_controller_test.rb | 49 + .../conference_invitees_controller_test.rb | 49 + test/functional/conferences_controller_test.rb | 49 + test/functional/config_siemens_controller_test.rb | 7 + test/functional/fax_accounts_controller_test.rb | 49 + test/functional/fax_documents_controller_test.rb | 49 + .../gemeinschaft_setups_controller_test.rb | 50 + .../gs_cluster_sync_log_entries_controller_test.rb | 49 + test/functional/gs_nodes_controller_test.rb | 49 + test/functional/gui_functions_controller_test.rb | 49 + .../hunt_group_members_controller_test.rb | 49 + test/functional/hunt_groups_controller_test.rb | 49 + test/functional/manufacturers_controller_test.rb | 77 + test/functional/notifications_test.rb | 12 + test/functional/page_controller_test.rb | 35 + .../phone_book_entries_controller_test.rb | 103 + test/functional/phone_books_controller_test.rb | 71 + test/functional/phone_models_controller_test.rb | 143 + .../phone_number_ranges_controller_test.rb | 78 + test/functional/phone_numbers_controller_test.rb | 115 + .../phone_sip_accounts_controller_test.rb | 49 + test/functional/phones_controller_test.rb | 55 + .../phones_sip_accounts_controller_test.rb | 49 + test/functional/ringtones_controller_test.rb | 49 + test/functional/sessions_controller_test.rb | 7 + test/functional/sip_accounts_controller_test.rb | 76 + test/functional/sip_domains_controller_test.rb | 49 + test/functional/softkeys_controller_test.rb | 49 + test/functional/system_messages_controller_test.rb | 49 + test/functional/tenants_controller_test.rb | 51 + test/functional/user_groups_controller_test.rb | 51 + test/functional/users_controller_test.rb | 65 + test/functional/whitelists_controller_test.rb | 49 + test/integration/.gitkeep | 0 test/performance/browsing_test.rb | 12 + test/test_helper.rb | 13 + test/unit/.gitkeep | 0 test/unit/access_authorization_test.rb | 7 + test/unit/acd_agent_test.rb | 7 + test/unit/acd_caller_test.rb | 7 + test/unit/address_test.rb | 7 + test/unit/api/row_test.rb | 7 + test/unit/area_code_test.rb | 7 + test/unit/automatic_call_distributor_test.rb | 7 + test/unit/call_forward_case_test.rb | 7 + test/unit/call_forward_test.rb | 9 + test/unit/callthrough_test.rb | 134 + test/unit/conference_invitee_test.rb | 17 + test/unit/conference_test.rb | 48 + test/unit/country_test.rb | 7 + test/unit/dial_in_number_store_test.rb | 7 + test/unit/fax_account_test.rb | 7 + test/unit/fax_document_test.rb | 7 + test/unit/fax_page_test.rb | 7 + test/unit/fax_resolution_test.rb | 7 + test/unit/fax_thumbnail_test.rb | 7 + test/unit/gemeinschaft_setup_test.rb | 7 + test/unit/gs_cluster_sync_log_entry_test.rb | 7 + test/unit/gs_node_test.rb | 7 + test/unit/gui_function_membership_test.rb | 7 + test/unit/gui_function_test.rb | 7 + test/unit/helpers/api/rows_helper_test.rb | 4 + test/unit/helpers/config_siemens_helper_test.rb | 4 + test/unit/helpers/page_helper_test.rb | 4 + test/unit/helpers/sessions_helper_test.rb | 4 + test/unit/hunt_group_member_test.rb | 7 + test/unit/hunt_group_test.rb | 7 + test/unit/language_test.rb | 7 + test/unit/manufacturer_test.rb | 27 + test/unit/oui_test.rb | 14 + test/unit/phone_book_entry_test.rb | 51 + test/unit/phone_book_test.rb | 119 + test/unit/phone_model_test.rb | 9 + test/unit/phone_number_range_test.rb | 9 + test/unit/phone_number_test.rb | 260 + test/unit/phone_sip_account_test.rb | 7 + test/unit/phone_test.rb | 49 + test/unit/ringtone_test.rb | 7 + test/unit/sip_account_test.rb | 34 + test/unit/sip_domain_test.rb | 9 + test/unit/softkey_function_test.rb | 7 + test/unit/softkey_test.rb | 7 + test/unit/system_message_test.rb | 7 + test/unit/tenant_membership_test.rb | 14 + test/unit/tenant_test.rb | 33 + test/unit/user_group_membership_test.rb | 39 + test/unit/user_group_test.rb | 38 + test/unit/user_test.rb | 82 + test/unit/whitelist_test.rb | 7 + vendor/assets/stylesheets/.gitkeep | 0 vendor/plugins/.gitkeep | 0 1224 files changed, 61085 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 Gemfile create mode 100644 Gemfile.lock create mode 100644 Guardfile create mode 100644 Rakefile create mode 100644 app/assets/images/amooma-logo.png create mode 100644 app/assets/images/bg-body.png create mode 100644 app/assets/images/gradients/light-to-dark-blue-x63.png create mode 100644 app/assets/images/gradients/white-gray-x29-reverse.png create mode 100644 app/assets/images/gradients/white-gray-x29.png create mode 100644 app/assets/images/gradients/white-texture-x63.png create mode 100644 app/assets/images/icons/cellphone-32x.png create mode 100644 app/assets/images/icons/clock-32x.png create mode 100644 app/assets/images/icons/cross-16x.png create mode 100644 app/assets/images/icons/facebook-32x.png create mode 100644 app/assets/images/icons/fax-32x.png create mode 100644 app/assets/images/icons/headphones-16x.png create mode 100644 app/assets/images/icons/headphones-32x.png create mode 100644 app/assets/images/icons/house-32x.png create mode 100644 app/assets/images/icons/mic-32x.png create mode 100644 app/assets/images/icons/microphone-16x.png create mode 100644 app/assets/images/icons/microphone-32x.png create mode 100644 app/assets/images/icons/mute-16x.png create mode 100644 app/assets/images/icons/phone-down-32x.png create mode 100644 app/assets/images/icons/phone-mobile-32x.png create mode 100644 app/assets/images/icons/phone-up-32x.png create mode 100644 app/assets/images/icons/search-13x16.png create mode 100644 app/assets/images/icons/skype-32x.png create mode 100644 app/assets/images/icons/star-16x.png create mode 100644 app/assets/images/icons/suitcase-32x.png create mode 100644 app/assets/images/icons/tag-16x.png create mode 100644 app/assets/images/icons/twitter-32x.png create mode 100644 app/assets/images/icons/unmute-16x.png create mode 100644 app/assets/images/icons/user-16x.png create mode 100644 app/assets/images/icons/user-female-16x.png create mode 100644 app/assets/images/icons/user-male-16x.png create mode 100644 app/assets/images/logo.png create mode 100644 app/assets/images/rails.png create mode 100644 app/assets/images/stubs/user-36x.jpg create mode 100644 app/assets/images/user.png create mode 100644 app/assets/javascripts/api/rows.js.coffee create mode 100644 app/assets/javascripts/application.js create mode 100644 app/assets/javascripts/config_siemens.js.coffee create mode 100644 app/assets/javascripts/core.coffee create mode 100644 app/assets/javascripts/page.js.coffee create mode 100644 app/assets/javascripts/softkeys.js.coffee create mode 100644 app/assets/javascripts/vendor/autoresize.jquery.js create mode 100755 app/assets/javascripts/vendor/fancybox/jquery.easing-1.3.pack.js create mode 100755 app/assets/javascripts/vendor/fancybox/jquery.fancybox-1.3.4.pack.js create mode 100755 app/assets/javascripts/vendor/fancybox/jquery.mousewheel-3.0.4.pack.js create mode 100644 app/assets/javascripts/vendor/html5boilerplate.js create mode 100755 app/assets/javascripts/vendor/jquery-1.6.2.min.js create mode 100644 app/assets/javascripts/vendor/jquery.condom.js create mode 100644 app/assets/javascripts/vendor/jquery.easy-slider-1.7.js create mode 100644 app/assets/javascripts/vendor/jquery.survival-kit.coffee create mode 100644 app/assets/javascripts/vendor/jquery.tmpl.js create mode 100755 app/assets/javascripts/vendor/modernizr-2.0.6.min.js create mode 100644 app/assets/stylesheets/api/rows.css.scss create mode 100644 app/assets/stylesheets/app/layouts/_app.scss create mode 100644 app/assets/stylesheets/app/layouts/_conference.scss create mode 100644 app/assets/stylesheets/app/layouts/_phone-book-entry.scss create mode 100644 app/assets/stylesheets/app/pages/_phone_book.scss create mode 100644 app/assets/stylesheets/app/shared/_contents.scss create mode 100644 app/assets/stylesheets/app/shared/_footers.scss create mode 100644 app/assets/stylesheets/app/shared/_handheld.scss create mode 100644 app/assets/stylesheets/app/shared/_headers.scss create mode 100644 app/assets/stylesheets/app/shared/_ie.scss create mode 100644 app/assets/stylesheets/app/shared/_media.scss create mode 100644 app/assets/stylesheets/app/shared/_print.scss create mode 100644 app/assets/stylesheets/application.css.scss create mode 100644 app/assets/stylesheets/scaffolds.css.scss create mode 100644 app/assets/stylesheets/vendor/README create mode 100644 app/assets/stylesheets/vendor/boilerplate-1.0/README create mode 100644 app/assets/stylesheets/vendor/boilerplate-1.0/_reset.scss create mode 100644 app/assets/stylesheets/vendor/boilerplate-1.0/_styles.scss create mode 100644 app/assets/stylesheets/vendor/boilerplate-2.0/README create mode 100644 app/assets/stylesheets/vendor/boilerplate-2.0/_styles.scss create mode 100644 app/assets/stylesheets/vendor/easy-slider/_numeric.scss create mode 100644 app/assets/stylesheets/vendor/facebox/_facebox.scss create mode 100644 app/assets/stylesheets/vendor/fancy-box/README create mode 100755 app/assets/stylesheets/vendor/fancy-box/_fancy-box.scss create mode 100644 app/assets/stylesheets/vendor/fancy-buttons/README create mode 100644 app/assets/stylesheets/vendor/fancy-buttons/_fancy-buttons.scss create mode 100644 app/assets/stylesheets/vendor/fancy-buttons/_fancy-gradient.scss create mode 100644 app/assets/stylesheets/vendor/survival-kit/_blog.scss create mode 100644 app/assets/stylesheets/vendor/survival-kit/_effects.scss create mode 100644 app/assets/stylesheets/vendor/survival-kit/_forms.scss create mode 100644 app/assets/stylesheets/vendor/survival-kit/_headers.scss create mode 100644 app/assets/stylesheets/vendor/survival-kit/_images.scss create mode 100644 app/assets/stylesheets/vendor/survival-kit/_lists.scss create mode 100644 app/assets/stylesheets/vendor/survival-kit/_loader.scss create mode 100644 app/assets/stylesheets/vendor/survival-kit/_navigation.scss create mode 100644 app/assets/stylesheets/vendor/survival-kit/_secure.scss create mode 100644 app/assets/stylesheets/vendor/survival-kit/_tools.scss create mode 100644 app/controllers/access_authorizations_controller.rb create mode 100644 app/controllers/acd_agents_controller.rb create mode 100644 app/controllers/acd_callers_controller.rb create mode 100644 app/controllers/addresses_controller.rb create mode 100644 app/controllers/api/rows_controller.rb create mode 100644 app/controllers/application_controller.rb create mode 100644 app/controllers/automatic_call_distributors_controller.rb create mode 100644 app/controllers/call_forwards_controller.rb create mode 100644 app/controllers/call_histories_controller.rb create mode 100644 app/controllers/calls_controller.rb create mode 100644 app/controllers/callthroughs_controller.rb create mode 100644 app/controllers/conference_invitees_controller.rb create mode 100644 app/controllers/conferences_controller.rb create mode 100644 app/controllers/config_polycom_controller.rb create mode 100644 app/controllers/config_siemens_controller.rb create mode 100644 app/controllers/config_siemens_sort_controller.rb create mode 100644 app/controllers/config_snom_controller.rb create mode 100644 app/controllers/fax_accounts_controller.rb create mode 100644 app/controllers/fax_documents_controller.rb create mode 100644 app/controllers/freeswitch_voicemail_msgs_controller.rb create mode 100644 app/controllers/gemeinschaft_setups_controller.rb create mode 100644 app/controllers/gs_cluster_sync_log_entries_controller.rb create mode 100644 app/controllers/gs_nodes_controller.rb create mode 100644 app/controllers/gui_functions_controller.rb create mode 100644 app/controllers/hunt_group_members_controller.rb create mode 100644 app/controllers/hunt_groups_controller.rb create mode 100644 app/controllers/manufacturers_controller.rb create mode 100644 app/controllers/page_controller.rb create mode 100644 app/controllers/phone_book_entries_controller.rb create mode 100644 app/controllers/phone_books_controller.rb create mode 100644 app/controllers/phone_models_controller.rb create mode 100644 app/controllers/phone_number_ranges_controller.rb create mode 100644 app/controllers/phone_numbers_controller.rb create mode 100644 app/controllers/phone_sip_accounts_controller.rb create mode 100644 app/controllers/phones_controller.rb create mode 100644 app/controllers/ringtones_controller.rb create mode 100644 app/controllers/sessions_controller.rb create mode 100644 app/controllers/sip_accounts_controller.rb create mode 100644 app/controllers/sip_domains_controller.rb create mode 100644 app/controllers/softkeys_controller.rb create mode 100644 app/controllers/system_messages_controller.rb create mode 100644 app/controllers/tenants_controller.rb create mode 100644 app/controllers/user_group_memberships_controller.rb create mode 100644 app/controllers/user_groups_controller.rb create mode 100644 app/controllers/users_controller.rb create mode 100644 app/controllers/voicemail_messages_controller.rb create mode 100644 app/controllers/voicemail_settings_controller.rb create mode 100644 app/controllers/whitelists_controller.rb create mode 100644 app/helpers/access_authorizations_helper.rb create mode 100644 app/helpers/acd_agents_helper.rb create mode 100644 app/helpers/acd_callers_helper.rb create mode 100644 app/helpers/addresses_helper.rb create mode 100644 app/helpers/api/rows_helper.rb create mode 100644 app/helpers/application_helper.rb create mode 100644 app/helpers/automatic_call_distributors_helper.rb create mode 100644 app/helpers/call_forward_cases_helper.rb create mode 100644 app/helpers/call_forwards_helper.rb create mode 100644 app/helpers/callthroughs_helper.rb create mode 100644 app/helpers/conference_invitees_helper.rb create mode 100644 app/helpers/conferences_helper.rb create mode 100644 app/helpers/config_siemens_helper.rb create mode 100644 app/helpers/error_messages_helper.rb create mode 100644 app/helpers/fax_accounts_helper.rb create mode 100644 app/helpers/fax_documents_helper.rb create mode 100644 app/helpers/gemeinschaft_setups_helper.rb create mode 100644 app/helpers/gs_cluster_sync_log_entries_helper.rb create mode 100644 app/helpers/gs_nodes_helper.rb create mode 100644 app/helpers/gui_functions_helper.rb create mode 100644 app/helpers/hunt_group_members_helper.rb create mode 100644 app/helpers/hunt_groups_helper.rb create mode 100644 app/helpers/layout_helper.rb create mode 100644 app/helpers/manufacturers_helper.rb create mode 100644 app/helpers/page_helper.rb create mode 100644 app/helpers/phone_book_entries_helper.rb create mode 100644 app/helpers/phone_books_helper.rb create mode 100644 app/helpers/phone_models_helper.rb create mode 100644 app/helpers/phone_number_ranges_helper.rb create mode 100644 app/helpers/phone_numbers_helper.rb create mode 100644 app/helpers/phone_sip_accounts_helper.rb create mode 100644 app/helpers/phones_helper.rb create mode 100644 app/helpers/phones_sip_accounts_helper.rb create mode 100644 app/helpers/ringtones_helper.rb create mode 100644 app/helpers/sessions_helper.rb create mode 100644 app/helpers/sip_accounts_helper.rb create mode 100644 app/helpers/sip_domains_helper.rb create mode 100644 app/helpers/softkeys_helper.rb create mode 100644 app/helpers/system_messages_helper.rb create mode 100644 app/helpers/tenants_helper.rb create mode 100644 app/helpers/user_groups_helper.rb create mode 100644 app/helpers/users_helper.rb create mode 100644 app/helpers/whitelists_helper.rb create mode 100644 app/mailers/.gitkeep create mode 100644 app/mailers/notifications.rb create mode 100644 app/models/.gitkeep create mode 100644 app/models/ability.rb create mode 100644 app/models/access_authorization.rb create mode 100644 app/models/acd_agent.rb create mode 100644 app/models/acd_caller.rb create mode 100644 app/models/address.rb create mode 100644 app/models/api.rb create mode 100644 app/models/api/row.rb create mode 100644 app/models/area_code.rb create mode 100644 app/models/automatic_call_distributor.rb create mode 100644 app/models/call.rb create mode 100644 app/models/call_forward.rb create mode 100644 app/models/call_forward_case.rb create mode 100644 app/models/call_history.rb create mode 100644 app/models/callthrough.rb create mode 100644 app/models/conference.rb create mode 100644 app/models/conference_invitee.rb create mode 100644 app/models/country.rb create mode 100644 app/models/dial_in_number_store.rb create mode 100644 app/models/fax_account.rb create mode 100644 app/models/fax_document.rb create mode 100644 app/models/fax_resolution.rb create mode 100644 app/models/fax_thumbnail.rb create mode 100644 app/models/freeswitch_alias.rb create mode 100644 app/models/freeswitch_call.rb create mode 100644 app/models/freeswitch_cdr.rb create mode 100644 app/models/freeswitch_channel.rb create mode 100644 app/models/freeswitch_complete.rb create mode 100644 app/models/freeswitch_fifo_bridge.rb create mode 100644 app/models/freeswitch_fifo_caller.rb create mode 100644 app/models/freeswitch_fifo_outbound.rb create mode 100644 app/models/freeswitch_interface.rb create mode 100644 app/models/freeswitch_nat.rb create mode 100644 app/models/freeswitch_registration.rb create mode 100644 app/models/freeswitch_task.rb create mode 100644 app/models/freeswitch_voicemail_pref.rb create mode 100644 app/models/gemeinschaft_setup.rb create mode 100644 app/models/gs_cluster_sync_log_entry.rb create mode 100644 app/models/gs_node.rb create mode 100644 app/models/gui_function.rb create mode 100644 app/models/gui_function_membership.rb create mode 100644 app/models/hunt_group.rb create mode 100644 app/models/hunt_group_member.rb create mode 100644 app/models/language.rb create mode 100644 app/models/manufacturer.rb create mode 100644 app/models/oui.rb create mode 100644 app/models/phone.rb create mode 100644 app/models/phone_book.rb create mode 100644 app/models/phone_book_entry.rb create mode 100644 app/models/phone_model.rb create mode 100644 app/models/phone_number.rb create mode 100644 app/models/phone_number_range.rb create mode 100644 app/models/phone_sip_account.rb create mode 100644 app/models/remote_gs_node/gs_cluster_sync_log_entry.rb create mode 100644 app/models/ringtone.rb create mode 100644 app/models/sip_account.rb create mode 100644 app/models/sip_domain.rb create mode 100644 app/models/softkey.rb create mode 100644 app/models/softkey_function.rb create mode 100644 app/models/system_message.rb create mode 100644 app/models/tenant.rb create mode 100644 app/models/tenant_membership.rb create mode 100644 app/models/user.rb create mode 100644 app/models/user_group.rb create mode 100644 app/models/user_group_membership.rb create mode 100644 app/models/voicemail_message.rb create mode 100644 app/models/voicemail_setting.rb create mode 100644 app/models/whitelist.rb create mode 100644 app/uploaders/audio_uploader.rb create mode 100644 app/uploaders/document_uploader.rb create mode 100644 app/uploaders/image_uploader.rb create mode 100644 app/uploaders/thumbnail_uploader.rb create mode 100644 app/uploaders/tiff_uploader.rb create mode 100644 app/views/access_authorizations/_form.html.haml create mode 100644 app/views/access_authorizations/_form_core.html.haml create mode 100644 app/views/access_authorizations/_index_core.html.haml create mode 100644 app/views/access_authorizations/edit.html.haml create mode 100644 app/views/access_authorizations/index.html.haml create mode 100644 app/views/access_authorizations/new.html.haml create mode 100644 app/views/access_authorizations/show.html.haml create mode 100644 app/views/acd_agents/_form.html.haml create mode 100644 app/views/acd_agents/_form_core.html.haml create mode 100644 app/views/acd_agents/_index_core.html.haml create mode 100644 app/views/acd_agents/_listing.html.haml create mode 100644 app/views/acd_agents/edit.html.haml create mode 100644 app/views/acd_agents/index.html.haml create mode 100644 app/views/acd_agents/new.html.haml create mode 100644 app/views/acd_agents/show.html.haml create mode 100644 app/views/acd_callers/_index_core.html.haml create mode 100644 app/views/acd_callers/index.html.haml create mode 100644 app/views/acd_callers/show.html.haml create mode 100644 app/views/addresses/_form.html.haml create mode 100644 app/views/addresses/_form_core.html.haml create mode 100644 app/views/addresses/_index_core.html.haml create mode 100644 app/views/addresses/edit.html.haml create mode 100644 app/views/addresses/index.html.haml create mode 100644 app/views/addresses/new.html.haml create mode 100644 app/views/addresses/show.html.haml create mode 100644 app/views/api/rows/_form.html.erb create mode 100644 app/views/api/rows/edit.html.erb create mode 100644 app/views/api/rows/index.html.erb create mode 100644 app/views/api/rows/new.html.erb create mode 100644 app/views/api/rows/show.html.erb create mode 100644 app/views/automatic_call_distributors/_form.html.haml create mode 100644 app/views/automatic_call_distributors/_form_core.html.haml create mode 100644 app/views/automatic_call_distributors/_index_core.html.haml create mode 100644 app/views/automatic_call_distributors/edit.html.haml create mode 100644 app/views/automatic_call_distributors/index.html.haml create mode 100644 app/views/automatic_call_distributors/new.html.haml create mode 100644 app/views/automatic_call_distributors/show.html.haml create mode 100644 app/views/call_forwards/_form.html.haml create mode 100644 app/views/call_forwards/_form_core.html.haml create mode 100644 app/views/call_forwards/_index_core.html.haml create mode 100644 app/views/call_forwards/edit.html.haml create mode 100644 app/views/call_forwards/index.html.haml create mode 100644 app/views/call_forwards/new.html.haml create mode 100644 app/views/call_forwards/show.html.haml create mode 100644 app/views/call_histories/_index_core.html.haml create mode 100644 app/views/call_histories/_navigation.html.haml create mode 100644 app/views/call_histories/index.html.haml create mode 100644 app/views/calls/_index_core.html.haml create mode 100644 app/views/calls/index.html.haml create mode 100644 app/views/callthroughs/_form.html.haml create mode 100644 app/views/callthroughs/_form_core.html.haml create mode 100644 app/views/callthroughs/_index_core.html.haml create mode 100644 app/views/callthroughs/edit.html.haml create mode 100644 app/views/callthroughs/index.html.haml create mode 100644 app/views/callthroughs/new.html.haml create mode 100644 app/views/callthroughs/show.html.haml create mode 100644 app/views/conference_invitees/_form.html.haml create mode 100644 app/views/conference_invitees/_form_core.html.haml create mode 100644 app/views/conference_invitees/_index_core.html.haml create mode 100644 app/views/conference_invitees/edit.html.haml create mode 100644 app/views/conference_invitees/index.html.haml create mode 100644 app/views/conference_invitees/new.html.haml create mode 100644 app/views/conference_invitees/show.html.haml create mode 100644 app/views/conferences/_form.html.haml create mode 100644 app/views/conferences/_form_core.html.haml create mode 100644 app/views/conferences/_index_core.html.haml create mode 100644 app/views/conferences/edit.html.haml create mode 100644 app/views/conferences/index.html.haml create mode 100644 app/views/conferences/new.html.haml create mode 100644 app/views/conferences/show.html.haml create mode 100644 app/views/config_polycom/_call_history.xml.haml create mode 100644 app/views/config_polycom/_call_history_menu.xml.haml create mode 100644 app/views/config_polycom/_phone_book.xml.haml create mode 100644 app/views/config_polycom/config_files.xml.builder create mode 100644 app/views/config_polycom/idle_screen.xml.haml create mode 100644 app/views/config_polycom/settings.xml.erb create mode 100644 app/views/config_polycom/settings_directory.xml.haml create mode 100644 app/views/config_siemens/_menu_list.xml.haml create mode 100644 app/views/config_siemens/clean-up.xml.erb create mode 100644 app/views/config_siemens/index.xml.erb create mode 100644 app/views/config_siemens/write.xml.erb create mode 100644 app/views/config_snom/_snom_phone_directory.xml.haml create mode 100644 app/views/config_snom/_snom_phone_input.xml.haml create mode 100644 app/views/config_snom/_snom_phone_menu.xml.haml create mode 100644 app/views/config_snom/_snom_phone_text.xml.haml create mode 100644 app/views/config_snom/call_history.xml.haml create mode 100644 app/views/config_snom/idle_screen.xml.haml create mode 100644 app/views/config_snom/log_in.xml.haml create mode 100644 app/views/config_snom/show.xml.haml create mode 100644 app/views/config_snom/state_settings.xml.haml create mode 100644 app/views/config_snom/switch_protocol.xml.builder create mode 100644 app/views/fax_accounts/_form.html.haml create mode 100644 app/views/fax_accounts/_form_core.html.haml create mode 100644 app/views/fax_accounts/_index_core.html.haml create mode 100644 app/views/fax_accounts/edit.html.haml create mode 100644 app/views/fax_accounts/index.html.haml create mode 100644 app/views/fax_accounts/new.html.haml create mode 100644 app/views/fax_accounts/show.html.haml create mode 100644 app/views/fax_documents/_form.html.haml create mode 100644 app/views/fax_documents/_form_core.html.haml create mode 100644 app/views/fax_documents/_index_core.html.haml create mode 100644 app/views/fax_documents/edit.html.haml create mode 100644 app/views/fax_documents/index.html.haml create mode 100644 app/views/fax_documents/new.html.haml create mode 100644 app/views/fax_documents/show.html.haml create mode 100644 app/views/freeswitch_voicemail_msgs/_index_core.html.haml create mode 100644 app/views/freeswitch_voicemail_msgs/index.html.haml create mode 100644 app/views/gemeinschaft_setups/new.de.html.haml create mode 100644 app/views/gemeinschaft_setups/new.html.haml create mode 100644 app/views/gs_cluster_sync_log_entries/_form.html.haml create mode 100644 app/views/gs_cluster_sync_log_entries/_form_core.html.haml create mode 100644 app/views/gs_cluster_sync_log_entries/_index_core.html.haml create mode 100644 app/views/gs_cluster_sync_log_entries/edit.html.haml create mode 100644 app/views/gs_cluster_sync_log_entries/index.html.haml create mode 100644 app/views/gs_cluster_sync_log_entries/new.html.haml create mode 100644 app/views/gs_cluster_sync_log_entries/show.html.haml create mode 100644 app/views/gs_nodes/_form.html.haml create mode 100644 app/views/gs_nodes/_form_core.html.haml create mode 100644 app/views/gs_nodes/_index_core.html.haml create mode 100644 app/views/gs_nodes/edit.html.haml create mode 100644 app/views/gs_nodes/index.html.haml create mode 100644 app/views/gs_nodes/new.html.haml create mode 100644 app/views/gs_nodes/show.html.haml create mode 100644 app/views/gs_nodes/sync.xml.haml create mode 100644 app/views/gui_functions/_form.html.haml create mode 100644 app/views/gui_functions/_form_core.html.haml create mode 100644 app/views/gui_functions/_index_core.html.haml create mode 100644 app/views/gui_functions/edit.html.haml create mode 100644 app/views/gui_functions/index.html.haml create mode 100644 app/views/gui_functions/new.html.haml create mode 100644 app/views/gui_functions/show.html.haml create mode 100644 app/views/hunt_group_members/_form.html.haml create mode 100644 app/views/hunt_group_members/_form_core.html.haml create mode 100644 app/views/hunt_group_members/_index_core.html.haml create mode 100644 app/views/hunt_group_members/_listing.html.haml create mode 100644 app/views/hunt_group_members/edit.html.haml create mode 100644 app/views/hunt_group_members/index.html.haml create mode 100644 app/views/hunt_group_members/new.html.haml create mode 100644 app/views/hunt_group_members/show.html.haml create mode 100644 app/views/hunt_groups/_form.html.haml create mode 100644 app/views/hunt_groups/_form_core.html.haml create mode 100644 app/views/hunt_groups/_index_core.html.haml create mode 100644 app/views/hunt_groups/edit.html.haml create mode 100644 app/views/hunt_groups/index.html.haml create mode 100644 app/views/hunt_groups/new.html.haml create mode 100644 app/views/hunt_groups/show.html.haml create mode 100644 app/views/layouts/application.html.haml create mode 100644 app/views/manufacturers/_form.html.haml create mode 100644 app/views/manufacturers/_form_core.html.haml create mode 100644 app/views/manufacturers/_index_core.html.haml create mode 100644 app/views/manufacturers/edit.html.haml create mode 100644 app/views/manufacturers/index.html.haml create mode 100644 app/views/manufacturers/new.html.haml create mode 100644 app/views/manufacturers/show.html.haml create mode 100644 app/views/notifications/new_fax.text.erb create mode 100644 app/views/notifications/new_password.text.erb create mode 100644 app/views/notifications/new_pin.text.erb create mode 100644 app/views/notifications/new_voicemail.text.erb create mode 100644 app/views/page/conference.html.haml create mode 100644 app/views/page/index.de.html.haml create mode 100644 app/views/page/index.html.haml create mode 100644 app/views/phone_book_entries/_form.html.haml create mode 100644 app/views/phone_book_entries/_form_core.html.haml create mode 100644 app/views/phone_book_entries/_index_core.de.html.haml create mode 100644 app/views/phone_book_entries/_index_core.html.haml create mode 100644 app/views/phone_book_entries/_navigation.html.haml create mode 100644 app/views/phone_book_entries/edit.html.haml create mode 100644 app/views/phone_book_entries/index.html.haml create mode 100644 app/views/phone_book_entries/new.html.haml create mode 100644 app/views/phone_book_entries/show.html.haml create mode 100644 app/views/phone_book_entries/show.html.haml.examlple create mode 100644 app/views/phone_books/_form.html.haml create mode 100644 app/views/phone_books/_form_core.html.haml create mode 100644 app/views/phone_books/_index_core.html.haml create mode 100644 app/views/phone_books/edit.html.haml create mode 100644 app/views/phone_books/index.html.haml create mode 100644 app/views/phone_books/new.html.haml create mode 100644 app/views/phone_books/show.html.haml create mode 100644 app/views/phone_models/_form.html.haml create mode 100644 app/views/phone_models/_form_core.html.haml create mode 100644 app/views/phone_models/_index_core.html.haml create mode 100644 app/views/phone_models/edit.html.haml create mode 100644 app/views/phone_models/index.html.haml create mode 100644 app/views/phone_models/new.html.haml create mode 100644 app/views/phone_models/show.html.haml create mode 100644 app/views/phone_number_ranges/_form.html.haml create mode 100644 app/views/phone_number_ranges/_form_core.html.haml create mode 100644 app/views/phone_number_ranges/_index_core.html.haml create mode 100644 app/views/phone_number_ranges/edit.html.haml create mode 100644 app/views/phone_number_ranges/index.html.haml create mode 100644 app/views/phone_number_ranges/new.html.haml create mode 100644 app/views/phone_number_ranges/show.html.haml create mode 100644 app/views/phone_numbers/_form.html.haml create mode 100644 app/views/phone_numbers/_form_core.html.haml create mode 100644 app/views/phone_numbers/_index_core.html.haml create mode 100644 app/views/phone_numbers/_listing.html.haml create mode 100644 app/views/phone_numbers/edit.html.haml create mode 100644 app/views/phone_numbers/index.html.haml create mode 100644 app/views/phone_numbers/new.html.haml create mode 100644 app/views/phone_numbers/show.html.haml create mode 100644 app/views/phone_sip_accounts/_form.html.haml create mode 100644 app/views/phone_sip_accounts/_form_core.html.haml create mode 100644 app/views/phone_sip_accounts/_index_core.html.haml create mode 100644 app/views/phone_sip_accounts/index.html.haml create mode 100644 app/views/phone_sip_accounts/new.html.haml create mode 100644 app/views/phone_sip_accounts/show.html.haml create mode 100644 app/views/phones/_form.html.haml create mode 100644 app/views/phones/_form_core.html.haml create mode 100644 app/views/phones/_index_core.html.haml create mode 100644 app/views/phones/edit.html.haml create mode 100644 app/views/phones/index.html.haml create mode 100644 app/views/phones/new.html.haml create mode 100644 app/views/phones/show.html.haml create mode 100644 app/views/ringtones/_form.html.haml create mode 100644 app/views/ringtones/_form_core.html.haml create mode 100644 app/views/ringtones/_index_core.html.haml create mode 100644 app/views/ringtones/edit.html.haml create mode 100644 app/views/ringtones/index.html.haml create mode 100644 app/views/ringtones/new.html.haml create mode 100644 app/views/ringtones/show.html.haml create mode 100644 app/views/sessions/new.html.haml create mode 100644 app/views/shared/_create_link.html.haml create mode 100644 app/views/shared/_flash.html.haml create mode 100644 app/views/shared/_header.de.html.haml create mode 100644 app/views/shared/_header.html.haml create mode 100644 app/views/shared/_index_view_edit_destroy_part.html.haml create mode 100644 app/views/shared/_show_edit_destroy_part.html.haml create mode 100644 app/views/shared/_system_message.html.haml create mode 100644 app/views/sip_accounts/_form.html.haml create mode 100644 app/views/sip_accounts/_form_core.html.haml create mode 100644 app/views/sip_accounts/_index_core.html.haml create mode 100644 app/views/sip_accounts/edit.html.haml create mode 100644 app/views/sip_accounts/index.html.haml create mode 100644 app/views/sip_accounts/new.html.haml create mode 100644 app/views/sip_accounts/show.html.haml create mode 100644 app/views/sip_domains/_form.html.haml create mode 100644 app/views/sip_domains/_form_core.html.haml create mode 100644 app/views/sip_domains/_index_core.html.haml create mode 100644 app/views/sip_domains/edit.html.haml create mode 100644 app/views/sip_domains/index.html.haml create mode 100644 app/views/sip_domains/new.html.haml create mode 100644 app/views/sip_domains/show.html.haml create mode 100644 app/views/softkeys/_form.html.haml create mode 100644 app/views/softkeys/_form_core.html.haml create mode 100644 app/views/softkeys/_index_core.html.haml create mode 100644 app/views/softkeys/edit.html.haml create mode 100644 app/views/softkeys/index.html.haml create mode 100644 app/views/softkeys/new.html.haml create mode 100644 app/views/softkeys/show.html.haml create mode 100644 app/views/system_messages/_form.html.haml create mode 100644 app/views/system_messages/_form_core.html.haml create mode 100644 app/views/system_messages/_index_core.html.haml create mode 100644 app/views/system_messages/index.html.haml create mode 100644 app/views/system_messages/new.html.haml create mode 100644 app/views/system_messages/show.html.haml create mode 100644 app/views/tenants/_admin_area.de.html.haml create mode 100644 app/views/tenants/_admin_area.html.haml create mode 100644 app/views/tenants/_form.html.haml create mode 100644 app/views/tenants/_form_core.html.haml create mode 100644 app/views/tenants/_index_core.html.haml create mode 100644 app/views/tenants/edit.html.haml create mode 100644 app/views/tenants/index.html.haml create mode 100644 app/views/tenants/new.html.haml create mode 100644 app/views/tenants/show.html.haml create mode 100644 app/views/user_group_memberships/_form.html.haml create mode 100644 app/views/user_group_memberships/_form_core.html.haml create mode 100644 app/views/user_group_memberships/_index_core.html.haml create mode 100644 app/views/user_group_memberships/edit.html.haml create mode 100644 app/views/user_group_memberships/index.html.haml create mode 100644 app/views/user_group_memberships/new.html.haml create mode 100644 app/views/user_group_memberships/show.html.haml create mode 100644 app/views/user_groups/_form.html.haml create mode 100644 app/views/user_groups/_form_core.html.haml create mode 100644 app/views/user_groups/_index_core.html.haml create mode 100644 app/views/user_groups/edit.html.haml create mode 100644 app/views/user_groups/index.html.haml create mode 100644 app/views/user_groups/new.html.haml create mode 100644 app/views/user_groups/show.html.haml create mode 100644 app/views/users/_form.html.haml create mode 100644 app/views/users/_form_core.html.haml create mode 100644 app/views/users/_index_core.html.haml create mode 100644 app/views/users/_listing.html.haml create mode 100644 app/views/users/edit.html.haml create mode 100644 app/views/users/index.html.haml create mode 100644 app/views/users/new.html.haml create mode 100644 app/views/users/show.html.haml create mode 100644 app/views/voicemail_messages/_index_core.html.haml create mode 100644 app/views/voicemail_messages/_navigation.html.haml create mode 100644 app/views/voicemail_messages/index.html.haml create mode 100644 app/views/voicemail_settings/_form.html.haml create mode 100644 app/views/voicemail_settings/_form_core.html.haml create mode 100644 app/views/voicemail_settings/edit.html.haml create mode 100644 app/views/voicemail_settings/show.html.haml create mode 100644 app/views/whitelists/_form.html.haml create mode 100644 app/views/whitelists/_form_core.html.haml create mode 100644 app/views/whitelists/_index_core.html.haml create mode 100644 app/views/whitelists/edit.html.haml create mode 100644 app/views/whitelists/index.html.haml create mode 100644 app/views/whitelists/new.html.haml create mode 100644 app/views/whitelists/show.html.haml create mode 100644 config.ru create mode 100644 config/application.rb create mode 100644 config/boot.rb create mode 100644 config/database.yml create mode 100644 config/environment.rb create mode 100644 config/environments/development.rb create mode 100644 config/environments/production.rb create mode 100644 config/environments/test.rb create mode 100644 config/hirb.yml create mode 100644 config/initializers/backtrace_silencers.rb create mode 100644 config/initializers/connectivity_check.rb create mode 100644 config/initializers/gemeinschaft_parameters.rb create mode 100644 config/initializers/inflections.rb create mode 100644 config/initializers/load_extensions.rb create mode 100644 config/initializers/mime_types.rb create mode 100644 config/initializers/secret_token.rb create mode 100644 config/initializers/session_store.rb create mode 100644 config/initializers/simple_form.rb create mode 100644 config/initializers/validators.rb create mode 100644 config/initializers/wrap_parameters.rb create mode 100644 config/locales/carrierwave/de.yml create mode 100644 config/locales/carrierwave/en.yml create mode 100644 config/locales/de.yml create mode 100644 config/locales/en.yml create mode 100644 config/locales/simple_form.de.yml create mode 100644 config/locales/simple_form.en.yml create mode 100644 config/locales/views/access_authorizations/de.yml create mode 100644 config/locales/views/access_authorizations/en.yml create mode 100644 config/locales/views/acd_agents/de.yml create mode 100644 config/locales/views/acd_agents/en.yml create mode 100644 config/locales/views/acd_callers/de.yml create mode 100644 config/locales/views/acd_callers/en.yml create mode 100644 config/locales/views/addresses/de.yml create mode 100644 config/locales/views/addresses/en.yml create mode 100644 config/locales/views/automatic_call_distributors/de.yml create mode 100644 config/locales/views/automatic_call_distributors/en.yml create mode 100644 config/locales/views/call_forward_cases/de.yml create mode 100644 config/locales/views/call_forward_cases/en.yml create mode 100644 config/locales/views/call_forwards/de.yml create mode 100644 config/locales/views/call_forwards/en.yml create mode 100644 config/locales/views/call_histories/de.yml create mode 100644 config/locales/views/call_histories/en.yml create mode 100644 config/locales/views/callthroughs/de.yml create mode 100644 config/locales/views/callthroughs/en.yml create mode 100644 config/locales/views/conference_invitees/de.yml create mode 100644 config/locales/views/conference_invitees/en.yml create mode 100644 config/locales/views/conferences/de.yml create mode 100644 config/locales/views/conferences/en.yml create mode 100644 config/locales/views/fax_accounts/de.yml create mode 100644 config/locales/views/fax_accounts/en.yml create mode 100644 config/locales/views/fax_documents/de.yml create mode 100644 config/locales/views/fax_documents/en.yml create mode 100644 config/locales/views/gemeinschaft_setups/de.yml create mode 100644 config/locales/views/gemeinschaft_setups/en.yml create mode 100644 config/locales/views/gs_cluster_sync_log_entries/de.yml create mode 100644 config/locales/views/gs_cluster_sync_log_entries/en.yml create mode 100644 config/locales/views/gs_nodes/de.yml create mode 100644 config/locales/views/gs_nodes/en.yml create mode 100644 config/locales/views/gui_functions/de.yml create mode 100644 config/locales/views/gui_functions/en.yml create mode 100644 config/locales/views/hunt_group_members/de.yml create mode 100644 config/locales/views/hunt_group_members/en.yml create mode 100644 config/locales/views/hunt_groups/de.yml create mode 100644 config/locales/views/hunt_groups/en.yml create mode 100644 config/locales/views/manufacturers/de.yml create mode 100644 config/locales/views/manufacturers/en.yml create mode 100644 config/locales/views/notifications/de.yml create mode 100644 config/locales/views/notifications/en.yml create mode 100644 config/locales/views/pages/de.yml create mode 100644 config/locales/views/pages/en.yml create mode 100644 config/locales/views/phone_book_entries/de.yml create mode 100644 config/locales/views/phone_book_entries/en.yml create mode 100644 config/locales/views/phone_books/de.yml create mode 100644 config/locales/views/phone_books/en.yml create mode 100644 config/locales/views/phone_models/de.yml create mode 100644 config/locales/views/phone_models/en.yml create mode 100644 config/locales/views/phone_number_ranges/de.yml create mode 100644 config/locales/views/phone_number_ranges/en.yml create mode 100644 config/locales/views/phone_numbers/de.yml create mode 100644 config/locales/views/phone_numbers/en.yml create mode 100644 config/locales/views/phone_sip_accounts/de.yml create mode 100644 config/locales/views/phone_sip_accounts/en.yml create mode 100644 config/locales/views/phones/de.yml create mode 100644 config/locales/views/phones/en.yml create mode 100644 config/locales/views/ringtones/de.yml create mode 100644 config/locales/views/ringtones/en.yml create mode 100644 config/locales/views/sessions/de.yml create mode 100644 config/locales/views/sessions/en.yml create mode 100644 config/locales/views/sip_accounts/de.yml create mode 100644 config/locales/views/sip_accounts/en.yml create mode 100644 config/locales/views/sip_domains/de.yml create mode 100644 config/locales/views/sip_domains/en.yml create mode 100644 config/locales/views/softkeys/de.yml create mode 100644 config/locales/views/softkeys/en.yml create mode 100644 config/locales/views/system_messages/de.yml create mode 100644 config/locales/views/system_messages/en.yml create mode 100644 config/locales/views/tenants/de.yml create mode 100644 config/locales/views/tenants/en.yml create mode 100644 config/locales/views/user_group_memberships/de.yml create mode 100644 config/locales/views/user_group_memberships/en.yml create mode 100644 config/locales/views/user_groups/de.yml create mode 100644 config/locales/views/user_groups/en.yml create mode 100644 config/locales/views/users/de.yml create mode 100644 config/locales/views/users/en.yml create mode 100644 config/locales/views/voicemail_messages/de.yml create mode 100644 config/locales/views/voicemail_messages/en.yml create mode 100644 config/locales/views/voicemail_settings/de.yml create mode 100644 config/locales/views/voicemail_settings/en.yml create mode 100644 config/locales/views/whitelists/de.yml create mode 100644 config/locales/views/whitelists/en.yml create mode 100644 config/private_pub.yml create mode 100644 config/routes.rb create mode 100644 db/migrate/20111006073436_create_tenants.rb create mode 100644 db/migrate/20111006074623_create_users.rb create mode 100644 db/migrate/20111006081257_create_tenant_memberships.rb create mode 100644 db/migrate/20111006081936_create_user_groups.rb create mode 100644 db/migrate/20111006082944_create_user_group_memberships.rb create mode 100644 db/migrate/20111006082945_create_phone_books.rb create mode 100644 db/migrate/20111006101543_create_phone_book_entries.rb create mode 100644 db/migrate/20111007084820_add_image_to_user.rb create mode 100644 db/migrate/20111007092546_add_image_to_phone_book_entry.rb create mode 100644 db/migrate/20111007110029_remove_position_from_phone_book.rb create mode 100644 db/migrate/20111007110258_remove_position_from_tenant.rb create mode 100644 db/migrate/20111007123901_remove_position_from_tenant_membership.rb create mode 100644 db/migrate/20111008112922_add_current_tenant_id_to_users.rb create mode 100644 db/migrate/20111009184013_add_sessions_table.rb create mode 100644 db/migrate/20111009202027_create_phone_numbers.rb create mode 100644 db/migrate/20111009202500_create_countries.rb create mode 100644 db/migrate/20111009202910_create_area_codes.rb create mode 100644 db/migrate/20111009203233_add_country_id_to_tenant.rb create mode 100644 db/migrate/20111010110232_add_phone_book_entry_id_to_phone_number.rb create mode 100644 db/migrate/20111011080014_add_central_office_code_to_phone_number.rb create mode 100644 db/migrate/20111011181421_add_central_office_code_to_area_code.rb create mode 100644 db/migrate/20111012113547_create_ouis.rb create mode 100644 db/migrate/20111012121851_create_manufacturers.rb create mode 100644 db/migrate/20111012131652_create_phones.rb create mode 100644 db/migrate/20111012142952_add_state_to_phone.rb create mode 100644 db/migrate/20111012143922_create_phone_models.rb create mode 100644 db/migrate/20111013110804_add_state_to_phone_models.rb create mode 100644 db/migrate/20111013173838_create_sip_domains.rb create mode 100644 db/migrate/20111013173845_add_sip_domain_id_to_tenant.rb create mode 100644 db/migrate/20111013180505_create_sip_accounts.rb create mode 100644 db/migrate/20111031125955_create_addresses.rb create mode 100644 db/migrate/20111101155754_add_phonetics_to_phone_book_entry.rb create mode 100644 db/migrate/20111101155952_add_index_to_phone_book_entry.rb create mode 100644 db/migrate/20111104114634_add_polymorphic_to_phone_number.rb create mode 100644 db/migrate/20111104140800_create_calls.rb create mode 100644 db/migrate/20111104140900_create_channels.rb create mode 100644 db/migrate/20111104140901_create_interfaces.rb create mode 100644 db/migrate/20111104141000_create_aliases.rb create mode 100644 db/migrate/20111104141001_create_complete.rb create mode 100644 db/migrate/20111104141002_create_tasks.rb create mode 100644 db/migrate/20111104141100_create_nat.rb create mode 100644 db/migrate/20111104141101_create_registrations.rb create mode 100644 db/migrate/20111106081300_create_fifo_bridge.rb create mode 100644 db/migrate/20111106082100_create_fifo_callers.rb create mode 100644 db/migrate/20111106082500_create_fifo_outbound.rb create mode 100644 db/migrate/20111106083400_create_voicemail_msgs.rb create mode 100644 db/migrate/20111106084200_create_voicemail_prefs.rb create mode 100644 db/migrate/20111106162141_add_phoneable_to_phone.rb create mode 100644 db/migrate/20111119124303_add_hot_deskable_to_phone.rb create mode 100644 db/migrate/20111119153939_add_state_to_phone_number.rb create mode 100644 db/migrate/20111120110056_add_value_of_to_s_to_phone_number.rb create mode 100644 db/migrate/20111120112448_add_value_of_to_s_to_phone_book_entry.rb create mode 100644 db/migrate/20111120180010_create_call_forward_cases.rb create mode 100644 db/migrate/20111120180020_create_call_forwards.rb create mode 100644 db/migrate/20111121105916_add_sip_domain_id_to_sip_accounts.rb create mode 100644 db/migrate/20111121152220_create_conferences.rb create mode 100644 db/migrate/20111122172513_create_conference_invitees.rb create mode 100644 db/migrate/20111123124113_create_phone_number_ranges.rb create mode 100644 db/migrate/20111123132658_create_languages.rb create mode 100644 db/migrate/20111123141120_create_gemeinschaft_setups.rb create mode 100644 db/migrate/20111123211631_rename_columns_of_phone_number_range.rb create mode 100644 db/migrate/20111125124957_add_phone_number_id_to_call_forward.rb create mode 100644 db/migrate/20111125150925_add_hops_to_call_forward.rb create mode 100644 db/migrate/20111126180826_add_depth_to_call_forward.rb create mode 100644 db/migrate/20111127112235_add_internal_extension_ranges_to_gemeinschaft_setup.rb create mode 100644 db/migrate/20111128100949_add_pin_to_user.rb create mode 100644 db/migrate/20111203164007_add_tenant_id_to_sip_account.rb create mode 100644 db/migrate/20111210124447_remove_sip_domain_id_from_sip_account.rb create mode 100644 db/migrate/20111211184853_remove_state_from_sip_account.rb create mode 100644 db/migrate/20111211192350_add_sip_domain_id_to_sip_account.rb create mode 100644 db/migrate/20111212193532_create_faxes.rb create mode 100644 db/migrate/20111212201847_create_fax_pages.rb create mode 100644 db/migrate/20111213122843_add_external_numbers_to_gemeinschaft_setup.rb create mode 100644 db/migrate/20111213170837_add_language_id_to_tenant.rb create mode 100644 db/migrate/20111213182546_remove_tenant_id_from_gemeinschaft_setup.rb create mode 100644 db/migrate/20111214182903_add_max_members_to_conference.rb create mode 100644 db/migrate/20111215172021_create_fax_accounts.rb create mode 100644 db/migrate/20111216112614_add_information_to_fax.rb create mode 100644 db/migrate/20111217162506_add_fax_to_faxes.rb create mode 100644 db/migrate/20111218085222_create_fax_documents.rb create mode 100644 db/migrate/20111218100048_add_fax_account_id_to_fax_documents.rb create mode 100644 db/migrate/20111218143152_add_tenant_id_to_fax_account.rb create mode 100644 db/migrate/20111218145713_add_days_till_auto_delete_to_fax_accounts.rb create mode 100644 db/migrate/20111219131952_create_fax_thumbnails.rb create mode 100644 db/migrate/20111219163426_remove_fax_documentable_from_fax_documents.rb create mode 100644 db/migrate/20111220151633_add_caller_id_number_to_fax_documents.rb create mode 100644 db/migrate/20111222173947_remove_result_text_from_fax_documents.rb create mode 100644 db/migrate/20111222184203_add_tiff_to_fax_documents.rb create mode 100644 db/migrate/20111222184912_add_resolution_to_fax_documents.rb create mode 100644 db/migrate/20111222185426_create_fax_resolutions.rb create mode 100644 db/migrate/20111226180221_create_delayed_jobs.rb create mode 100644 db/migrate/20111228194037_create_phone_sip_accounts.rb create mode 100644 db/migrate/20120104142556_create_ringtones.rb create mode 100644 db/migrate/20120112094631_add_announcement_of_a_new_member_to_conference.rb create mode 100644 db/migrate/20120118195740_create_softkeys.rb create mode 100644 db/migrate/20120119103852_add_sip_account_to_softkeys.rb create mode 100644 db/migrate/20120119111944_add_call_waiting_to_sip_accounts.rb create mode 100644 db/migrate/20120119114329_add_clir_and_clip_phone_number_to_sip_accounts.rb create mode 100644 db/migrate/20120119154422_fax_defaults.rb create mode 100644 db/migrate/20120119154633_language_defaults.rb create mode 100644 db/migrate/20120119154759_country_defaults.rb create mode 100644 db/migrate/20120119154952_area_codes_germany.rb create mode 100644 db/migrate/20120119155619_area_codes_poland.rb create mode 100644 db/migrate/20120119161017_call_forward_cases.rb create mode 100644 db/migrate/20120119161152_snom_phones.rb create mode 100644 db/migrate/20120124131057_add_clip_number_to_sip_account.rb create mode 100644 db/migrate/20120124133950_add_clip_no_screening_to_sip_account.rb create mode 100644 db/migrate/20120124135953_add_clip_to_sip_account.rb create mode 100644 db/migrate/20120124142001_remove_name_from_softkey.rb create mode 100644 db/migrate/20120126090831_create_callthroughs.rb create mode 100644 db/migrate/20120127101726_create_system_messages.rb create mode 100644 db/migrate/20120128143538_openstage_phones.rb create mode 100644 db/migrate/20120128191113_create_access_authorizations.rb create mode 100644 db/migrate/20120129094444_create_whitelists.rb create mode 100644 db/migrate/20120130155801_add_sip_account_id_to_access_authorization.rb create mode 100644 db/migrate/20120203093048_create_hunt_groups.rb create mode 100644 db/migrate/20120203120739_create_hunt_group_members.rb create mode 100644 db/migrate/20120210121455_add_language_id_to_users.rb create mode 100644 db/migrate/20120215160448_create_softkey_functions.rb create mode 100644 db/migrate/20120215160449_add_position_to_softkey_function.rb create mode 100644 db/migrate/20120215161054_add_softkey_function_id_to_softkey.rb create mode 100644 db/migrate/20120218182205_create_api_rows.rb create mode 100644 db/migrate/20120219210950_remove_state_from_user.rb create mode 100644 db/migrate/20120228154913_create_cdrs.rb create mode 100644 db/migrate/20120301094049_add_voicemail_boolean_to_call_forward.rb create mode 100644 db/migrate/20120312175918_add_hunt_group_id_to_call_forward.rb create mode 100644 db/migrate/20120313121920_add_polymorphic_to_call_forward.rb create mode 100644 db/migrate/20120314094720_add_send_voicemail_as_email_attachment_to_user.rb create mode 100644 db/migrate/20120329133930_add_bleg_read_time_to_cdrs.rb create mode 100644 db/migrate/20120409092724_add_importer_checksum_to_user.rb create mode 100644 db/migrate/20120409160614_add_description_to_sip_account.rb create mode 100644 db/migrate/20120416074152_callforward_rules_act_per_sip_account_to_sip_account.rb create mode 100644 db/migrate/20120418194029_add_call_forward_id_to_softkeys.rb create mode 100644 db/migrate/20120421073538_add_position_to_call_forward.rb create mode 100644 db/migrate/20120421075735_populate_softkey_functions.rb create mode 100644 db/migrate/20120422072551_populate_softkey_function.rb create mode 100644 db/migrate/20120424062951_add_hotdeskable_to_sip_account.rb create mode 100644 db/migrate/20120425112414_add_nightly_reboot_to_phone.rb create mode 100644 db/migrate/20120509071426_add_from_field_to_tenant.rb create mode 100644 db/migrate/20120510110311_add_forwarding_read_time_to_cdrs.rb create mode 100644 db/migrate/20120513154359_create_gui_functions.rb create mode 100644 db/migrate/20120513155342_create_gui_function_memberships.rb create mode 100644 db/migrate/20120513185233_add_gui_functions.rb create mode 100644 db/migrate/20120515104749_add_hunt_group_function_key.rb create mode 100644 db/migrate/20120515124103_add_hold_softkey_function.rb create mode 100644 db/migrate/20120611093946_create_gs_nodes.rb create mode 100644 db/migrate/20120611150245_add_gs_node_id_to_phone_number.rb create mode 100644 db/migrate/20120614113123_add_gs_node_information_to_user.rb create mode 100644 db/migrate/20120614113931_add_gs_node_information_to_sip_account.rb create mode 100644 db/migrate/20120614115938_add_gs_node_information_to_hunt_group.rb create mode 100644 db/migrate/20120617065247_create_gs_cluster_sync_log_entries.rb create mode 100644 db/migrate/20120617193636_add_site_to_gs_node.rb create mode 100644 db/migrate/20120626094238_add_uuid_to_phone_number.rb create mode 100644 db/migrate/20120626095730_add_uuid_to_users.rb create mode 100644 db/migrate/20120715175419_add_homebase_ip_address_to_gs_cluster_sync_log_entry.rb create mode 100644 db/migrate/20120720070000_add_waiting_to_be_syned_to_gs_cluster_sync_log_entry.rb create mode 100644 db/migrate/20120722072517_add_association_to_gs_cluster_sync_log_entry.rb create mode 100644 db/migrate/20120723065038_add_uuid_to_tenants.rb create mode 100644 db/migrate/20120724131815_add_uuid_to_conferences.rb create mode 100644 db/migrate/20120724131905_add_uuid_to_callthroughs.rb create mode 100644 db/migrate/20120724131956_add_uuid_to_fax_accounts.rb create mode 100644 db/migrate/20120727102518_add_uuid_to_phone_book_entry.rb create mode 100644 db/migrate/20120727105750_add_uuid_to_access_authorization.rb create mode 100644 db/migrate/20120727110501_add_access_authorization_user_id_to_phone_number.rb create mode 100644 db/migrate/20120728073802_add_is_native_to_user.rb create mode 100644 db/migrate/20120728073904_add_is_native_to_phone_number.rb create mode 100644 db/migrate/20120728091842_add_is_native_to_sip_account.rb create mode 100644 db/migrate/20120728113705_add_uuid_to_hunt_group_member.rb create mode 100644 db/migrate/20120728133144_add_uuid_to_phone_number_range.rb create mode 100644 db/migrate/20120728135133_add_uuid_to_fax_documents.rb create mode 100644 db/migrate/20120802132854_add_notification_to_voicemail_msgs.rb create mode 100644 db/migrate/20120813085708_add_uuid_to_conference_invitee.rb create mode 100644 db/migrate/20120821105942_create_automatic_call_distributors.rb create mode 100644 db/migrate/20120822094609_create_acd_callers.rb create mode 100644 db/migrate/20120822124716_create_acd_agents.rb create mode 100644 db/migrate/20120927101336_add_announce_position_to_automatic_call_distributors.rb create mode 100644 db/migrate/20120927101507_add_announce_call_agents_to_automatic_call_distributors.rb create mode 100644 db/migrate/20120927101636_add_greeting_to_automatic_call_distributors.rb create mode 100644 db/migrate/20120927101800_add_goodbye_to_automatic_call_distributors.rb create mode 100644 db/migrate/20120927101908_add_music_to_automatic_call_distributors.rb create mode 100644 db/migrate/20120927110240_change_data_type_for_announce_call_agents.rb create mode 100644 db/migrate/20121009135700_add_automatic_call_distributor_function_key.rb create mode 100644 db/migrate/20121012071908_create_call_histories.rb create mode 100644 db/migrate/20121105123841_add_uuid_to_phone_books.rb create mode 100644 db/migrate/20121105123943_add_uuid_to_addresses.rb create mode 100644 db/migrate/20121105124208_add_uuid_to_call_forwards.rb create mode 100644 db/migrate/20121105124343_add_uuid_to_phone_models.rb create mode 100644 db/migrate/20121105124904_add_uuid_to_softkeys.rb create mode 100644 db/migrate/20121105125043_add_uuid_to_whitelists.rb create mode 100644 db/migrate/20121105125232_populate_uuid_field.rb create mode 100644 db/migrate/20121105144944_add_last_sync_to_gs_nodes.rb create mode 100644 db/migrate/20121107072526_add_bridge_stamp_to_cdrs.rb create mode 100644 db/migrate/20121121080400_add_notify_to_voicemail_prefs.rb create mode 100644 db/migrate/20121121080548_add_attachment_to_voicemail_prefs.rb create mode 100644 db/migrate/20121121080649_add_mark_read_to_voicemail_prefs.rb create mode 100644 db/migrate/20121121081552_add_purge_to_voicemail_prefs.rb create mode 100644 db/migrate/20121125084332_add_provisioning_key_to_phones.rb create mode 100644 db/migrate/20121125084447_add_provisioning_key_active_to_phones.rb create mode 100644 db/schema.rb create mode 100644 db/seeds.rb create mode 100644 db/to-dos/20120119160732_emergency_numbers_germany.rb create mode 100644 db/to-dos/20120223142004_add_more_german_area_codes.rb create mode 100755 install.sh create mode 100644 lib/activerecord_extensions.rb create mode 100644 lib/agi_server.rb create mode 100644 lib/assets/.gitkeep create mode 100644 lib/freeswitch_event.rb create mode 100644 lib/generators/nifty.rb create mode 100644 lib/generators/nifty/authentication/USAGE create mode 100644 lib/generators/nifty/authentication/authentication_generator.rb create mode 100644 lib/generators/nifty/authentication/templates/authlogic_session.rb create mode 100644 lib/generators/nifty/authentication/templates/controller_authentication.rb create mode 100644 lib/generators/nifty/authentication/templates/fixtures.yml create mode 100644 lib/generators/nifty/authentication/templates/migration.rb create mode 100644 lib/generators/nifty/authentication/templates/sessions_controller.rb create mode 100644 lib/generators/nifty/authentication/templates/sessions_helper.rb create mode 100644 lib/generators/nifty/authentication/templates/tests/rspec/sessions_controller.rb create mode 100644 lib/generators/nifty/authentication/templates/tests/rspec/user.rb create mode 100644 lib/generators/nifty/authentication/templates/tests/rspec/users_controller.rb create mode 100644 lib/generators/nifty/authentication/templates/tests/shoulda/sessions_controller.rb create mode 100644 lib/generators/nifty/authentication/templates/tests/shoulda/user.rb create mode 100644 lib/generators/nifty/authentication/templates/tests/shoulda/users_controller.rb create mode 100644 lib/generators/nifty/authentication/templates/tests/testunit/sessions_controller.rb create mode 100644 lib/generators/nifty/authentication/templates/tests/testunit/user.rb create mode 100644 lib/generators/nifty/authentication/templates/tests/testunit/users_controller.rb create mode 100644 lib/generators/nifty/authentication/templates/user.rb create mode 100644 lib/generators/nifty/authentication/templates/users_controller.rb create mode 100644 lib/generators/nifty/authentication/templates/users_helper.rb create mode 100644 lib/generators/nifty/authentication/templates/views/erb/_form.html.erb create mode 100644 lib/generators/nifty/authentication/templates/views/erb/edit.html.erb create mode 100644 lib/generators/nifty/authentication/templates/views/erb/login.html.erb create mode 100644 lib/generators/nifty/authentication/templates/views/erb/signup.html.erb create mode 100644 lib/generators/nifty/authentication/templates/views/haml/_form.html.haml create mode 100644 lib/generators/nifty/authentication/templates/views/haml/edit.html.haml create mode 100644 lib/generators/nifty/authentication/templates/views/haml/login.html.haml create mode 100644 lib/generators/nifty/authentication/templates/views/haml/signup.html.haml create mode 100644 lib/generators/nifty/config/USAGE create mode 100644 lib/generators/nifty/config/config_generator.rb create mode 100644 lib/generators/nifty/config/templates/config.yml create mode 100644 lib/generators/nifty/config/templates/load_config.rb create mode 100644 lib/generators/nifty/layout/USAGE create mode 100644 lib/generators/nifty/layout/layout_generator.rb create mode 100644 lib/generators/nifty/layout/templates/error_messages_helper.rb create mode 100644 lib/generators/nifty/layout/templates/layout.html.haml create mode 100644 lib/generators/nifty/layout/templates/layout_helper.rb create mode 100644 lib/generators/nifty/layout/templates/stylesheet.css create mode 100644 lib/generators/nifty/layout/templates/stylesheet.sass create mode 100644 lib/generators/nifty/scaffold/USAGE create mode 100644 lib/generators/nifty/scaffold/scaffold_generator.rb create mode 100644 lib/generators/nifty/scaffold/templates/actions/create.rb create mode 100644 lib/generators/nifty/scaffold/templates/actions/destroy.rb create mode 100644 lib/generators/nifty/scaffold/templates/actions/edit.rb create mode 100644 lib/generators/nifty/scaffold/templates/actions/index.rb create mode 100644 lib/generators/nifty/scaffold/templates/actions/new.rb create mode 100644 lib/generators/nifty/scaffold/templates/actions/show.rb create mode 100644 lib/generators/nifty/scaffold/templates/actions/update.rb create mode 100644 lib/generators/nifty/scaffold/templates/controller.rb create mode 100644 lib/generators/nifty/scaffold/templates/fixtures.yml create mode 100644 lib/generators/nifty/scaffold/templates/helper.rb create mode 100644 lib/generators/nifty/scaffold/templates/locale.yml create mode 100644 lib/generators/nifty/scaffold/templates/locale_de.yml create mode 100644 lib/generators/nifty/scaffold/templates/migration.rb create mode 100644 lib/generators/nifty/scaffold/templates/model.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/rspec/actions/create.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/rspec/actions/destroy.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/rspec/actions/edit.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/rspec/actions/index.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/rspec/actions/new.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/rspec/actions/show.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/rspec/actions/update.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/rspec/controller.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/rspec/model.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/shoulda/actions/create.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/shoulda/actions/destroy.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/shoulda/actions/edit.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/shoulda/actions/index.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/shoulda/actions/new.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/shoulda/actions/show.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/shoulda/actions/update.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/shoulda/controller.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/shoulda/model.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/testunit/actions/create.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/testunit/actions/destroy.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/testunit/actions/edit.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/testunit/actions/index.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/testunit/actions/new.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/testunit/actions/show.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/testunit/actions/update.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/testunit/controller.rb create mode 100644 lib/generators/nifty/scaffold/templates/tests/testunit/model.rb create mode 100644 lib/generators/nifty/scaffold/templates/views/haml/_form.html.haml create mode 100644 lib/generators/nifty/scaffold/templates/views/haml/_form_core.html.haml create mode 100644 lib/generators/nifty/scaffold/templates/views/haml/_index_core.html.haml create mode 100644 lib/generators/nifty/scaffold/templates/views/haml/edit.html.haml create mode 100644 lib/generators/nifty/scaffold/templates/views/haml/index.html.haml create mode 100644 lib/generators/nifty/scaffold/templates/views/haml/new.html.haml create mode 100644 lib/generators/nifty/scaffold/templates/views/haml/show.html.haml create mode 100644 lib/phone_controllers/snom_phone.rb create mode 100644 lib/tasks/.gitkeep create mode 100644 lib/tasks/cvs_user_import.rake create mode 100644 lib/tasks/fax.rake create mode 100644 lib/tasks/gs_cluster.rake create mode 100644 lib/tasks/originate.rake create mode 100644 lib/tasks/populate_area_codes_de.rake create mode 100644 lib/tasks/populate_area_codes_pl.rake create mode 100644 lib/tasks/populate_country_codes.rake create mode 100644 lib/tasks/send_fax_notifications.rake create mode 100644 lib/tasks/send_voicemail_notifications.rake create mode 100644 lib/templates/erb/scaffold/_form.html.erb create mode 100644 lib/uacsta.rb create mode 100644 log/.gitkeep create mode 100644 misc/TODO-Liste.txt create mode 100644 misc/etc/cron.d/logout_phones create mode 100644 misc/etc/ssl/amooma/server.pem create mode 100644 misc/etc/ssl/amooma/server_cert.pem create mode 100644 misc/etc/ssl/amooma/server_key.pem create mode 100644 misc/example/apache-gs5.conf create mode 100644 misc/example/nginx create mode 100644 misc/example/xml-interface.txt create mode 100644 misc/freeswitch/conf/freeswitch.xml create mode 100644 misc/freeswitch/scripts/acd_wait.lua create mode 100644 misc/freeswitch/scripts/common/call_forwarding.lua create mode 100644 misc/freeswitch/scripts/common/call_history.lua create mode 100644 misc/freeswitch/scripts/common/conference.lua create mode 100644 misc/freeswitch/scripts/common/configuration_file.lua create mode 100644 misc/freeswitch/scripts/common/database.lua create mode 100644 misc/freeswitch/scripts/common/fapi.lua create mode 100644 misc/freeswitch/scripts/common/ipcalc.lua create mode 100644 misc/freeswitch/scripts/common/log.lua create mode 100644 misc/freeswitch/scripts/common/node.lua create mode 100644 misc/freeswitch/scripts/common/phone_number.lua create mode 100644 misc/freeswitch/scripts/common/routing_tables.lua create mode 100644 misc/freeswitch/scripts/common/sip_account.lua create mode 100644 misc/freeswitch/scripts/common/str.lua create mode 100644 misc/freeswitch/scripts/common/sync_log.lua create mode 100644 misc/freeswitch/scripts/configuration.lua create mode 100644 misc/freeswitch/scripts/configuration/freeswitch_xml.lua create mode 100644 misc/freeswitch/scripts/configuration/sip.lua create mode 100644 misc/freeswitch/scripts/dialplan/access_authorizations.lua create mode 100644 misc/freeswitch/scripts/dialplan/acd.lua create mode 100644 misc/freeswitch/scripts/dialplan/callthrough.lua create mode 100644 misc/freeswitch/scripts/dialplan/cdr.lua create mode 100644 misc/freeswitch/scripts/dialplan/dialplan.lua create mode 100644 misc/freeswitch/scripts/dialplan/fax.lua create mode 100644 misc/freeswitch/scripts/dialplan/functions.lua create mode 100644 misc/freeswitch/scripts/dialplan/geo_number.lua create mode 100644 misc/freeswitch/scripts/dialplan/hunt_group.lua create mode 100644 misc/freeswitch/scripts/dialplan/phone_book.lua create mode 100644 misc/freeswitch/scripts/dialplan/presence.lua create mode 100644 misc/freeswitch/scripts/dialplan/route.lua create mode 100644 misc/freeswitch/scripts/dialplan/session.lua create mode 100644 misc/freeswitch/scripts/dialplan/sip_call.lua create mode 100644 misc/freeswitch/scripts/dialplan/tenant.lua create mode 100644 misc/freeswitch/scripts/dialplan/user.lua create mode 100644 misc/freeswitch/scripts/dialplan/voicemail.lua create mode 100644 misc/freeswitch/scripts/dialplan_default.lua create mode 100644 misc/freeswitch/scripts/event/call_history_save.lua create mode 100644 misc/freeswitch/scripts/event/cdr_save.lua create mode 100644 misc/freeswitch/scripts/event/event.lua create mode 100644 misc/freeswitch/scripts/event/perimeter.lua create mode 100644 misc/freeswitch/scripts/event/presence_update.lua create mode 100644 misc/freeswitch/scripts/event_manager.lua create mode 100644 misc/freeswitch/scripts/fax_daemon.lua create mode 100644 misc/freeswitch/scripts/ini/conferences.ini create mode 100644 misc/freeswitch/scripts/ini/database.ini create mode 100644 misc/freeswitch/scripts/ini/dialplan.ini create mode 100644 misc/freeswitch/scripts/ini/events.ini create mode 100644 misc/freeswitch/scripts/ini/gateways.ini.example create mode 100644 misc/freeswitch/scripts/ini/perimeter.ini create mode 100644 misc/freeswitch/scripts/ini/routes.ini create mode 100644 misc/freeswitch/scripts/ini/sip_accounts.ini create mode 100644 misc/freeswitch/scripts/ini/sofia.ini create mode 100644 misc/freeswitch/scripts/phones/phone.lua create mode 100644 misc/freeswitch/scripts/phones/siemens.lua create mode 100644 misc/freeswitch/scripts/phones/snom.lua create mode 100644 misc/freeswitch/scripts/phones/uacsta.lua create mode 100644 misc/freeswitch/scripts/send_fax.lua create mode 100644 misc/mon_ami/asterisk.py create mode 100644 misc/mon_ami/freeswitch.py create mode 100644 misc/mon_ami/helper.py create mode 100644 misc/mon_ami/log.py create mode 100755 misc/mon_ami/mon-ami create mode 100755 misc/mon_ami/mon_ami create mode 100644 misc/mon_ami/mon_ami_handler.py create mode 100644 misc/mon_ami/mon_ami_main.py create mode 100644 misc/mon_ami/mon_ami_server.py create mode 100644 misc/mon_ami/sqliter.py create mode 100644 misc/mon_ami/tcp_server.py create mode 100644 misc/nginx/nginx.conf create mode 100644 private_pub.ru create mode 100644 public/404.html create mode 100644 public/422.html create mode 100644 public/500.html create mode 100644 public/favicon.ico create mode 100644 public/images/fallback/mini_default.jpg create mode 100644 public/images/fallback/mini_default_female.png create mode 100644 public/images/fallback/mini_default_male.png create mode 100644 public/images/fallback/profile_default.jpg create mode 100644 public/images/fallback/profile_default.psd create mode 100644 public/images/fallback/profile_default_female.png create mode 100644 public/images/fallback/profile_default_male.png create mode 100644 public/images/fallback/small_default.jpg create mode 100644 public/images/fallback/small_default_female.png create mode 100644 public/images/fallback/small_default_male.png create mode 100644 public/images/fallback/snom_caller_picture_default.jpg create mode 100644 public/images/fallback/snom_caller_picture_default_female.png create mode 100644 public/images/fallback/snom_caller_picture_default_male.png create mode 100644 public/images/snom/snom_300.jpg create mode 100644 public/images/snom/snom_320.jpg create mode 100644 public/images/snom/snom_360.jpg create mode 100644 public/images/snom/snom_370.jpg create mode 100644 public/images/snom/snom_820.jpg create mode 100644 public/images/snom/snom_821.jpg create mode 100644 public/images/snom/snom_870.jpg create mode 100644 public/robots.txt create mode 100755 script/agi_server create mode 100755 script/delayed_job create mode 100755 script/erd create mode 100755 script/fax_new create mode 100755 script/fax_new.sh create mode 100755 script/logout_phones create mode 100755 script/logout_phones.sh create mode 100755 script/notes create mode 100755 script/rails create mode 100755 script/voicemail_new create mode 100755 script/voicemail_new.sh create mode 100644 test/factories/api_rows.rb create mode 100644 test/factories/area_codes.rb create mode 100644 test/factories/call_forwards.rb create mode 100644 test/factories/conference_invitees.rb create mode 100644 test/factories/conferences.rb create mode 100644 test/factories/countries.rb create mode 100644 test/factories/gemeinschaft_setups.rb create mode 100644 test/factories/gui_function_memberships.rb create mode 100644 test/factories/languages.rb create mode 100644 test/factories/manufacturers.rb create mode 100644 test/factories/ouis.rb create mode 100644 test/factories/phone_book_entries.rb create mode 100644 test/factories/phone_books.rb create mode 100644 test/factories/phone_models.rb create mode 100644 test/factories/phone_number_ranges.rb create mode 100644 test/factories/phone_numbers.rb create mode 100644 test/factories/phones.rb create mode 100644 test/factories/sip_accounts.rb create mode 100644 test/factories/sip_domains.rb create mode 100644 test/factories/softkey_functions.rb create mode 100644 test/factories/tenant_memberships.rb create mode 100644 test/factories/tenants.rb create mode 100644 test/factories/user_group_memberships.rb create mode 100644 test/factories/user_groups.rb create mode 100644 test/factories/users.rb create mode 100644 test/fixtures/.gitkeep create mode 100644 test/functional/.gitkeep create mode 100644 test/functional/access_authorizations_controller_test.rb create mode 100644 test/functional/acd_agents_controller_test.rb create mode 100644 test/functional/acd_callers_controller_test.rb create mode 100644 test/functional/addresses_controller_test.rb create mode 100644 test/functional/api/rows_controller_test.rb create mode 100644 test/functional/automatic_call_distributors_controller_test.rb create mode 100644 test/functional/call_forwards_controller_test.rb create mode 100644 test/functional/callthroughs_controller_test.rb create mode 100644 test/functional/conference_invitees_controller_test.rb create mode 100644 test/functional/conferences_controller_test.rb create mode 100644 test/functional/config_siemens_controller_test.rb create mode 100644 test/functional/fax_accounts_controller_test.rb create mode 100644 test/functional/fax_documents_controller_test.rb create mode 100644 test/functional/gemeinschaft_setups_controller_test.rb create mode 100644 test/functional/gs_cluster_sync_log_entries_controller_test.rb create mode 100644 test/functional/gs_nodes_controller_test.rb create mode 100644 test/functional/gui_functions_controller_test.rb create mode 100644 test/functional/hunt_group_members_controller_test.rb create mode 100644 test/functional/hunt_groups_controller_test.rb create mode 100644 test/functional/manufacturers_controller_test.rb create mode 100644 test/functional/notifications_test.rb create mode 100644 test/functional/page_controller_test.rb create mode 100644 test/functional/phone_book_entries_controller_test.rb create mode 100644 test/functional/phone_books_controller_test.rb create mode 100644 test/functional/phone_models_controller_test.rb create mode 100644 test/functional/phone_number_ranges_controller_test.rb create mode 100644 test/functional/phone_numbers_controller_test.rb create mode 100644 test/functional/phone_sip_accounts_controller_test.rb create mode 100644 test/functional/phones_controller_test.rb create mode 100644 test/functional/phones_sip_accounts_controller_test.rb create mode 100644 test/functional/ringtones_controller_test.rb create mode 100644 test/functional/sessions_controller_test.rb create mode 100644 test/functional/sip_accounts_controller_test.rb create mode 100644 test/functional/sip_domains_controller_test.rb create mode 100644 test/functional/softkeys_controller_test.rb create mode 100644 test/functional/system_messages_controller_test.rb create mode 100644 test/functional/tenants_controller_test.rb create mode 100644 test/functional/user_groups_controller_test.rb create mode 100644 test/functional/users_controller_test.rb create mode 100644 test/functional/whitelists_controller_test.rb create mode 100644 test/integration/.gitkeep create mode 100644 test/performance/browsing_test.rb create mode 100644 test/test_helper.rb create mode 100644 test/unit/.gitkeep create mode 100644 test/unit/access_authorization_test.rb create mode 100644 test/unit/acd_agent_test.rb create mode 100644 test/unit/acd_caller_test.rb create mode 100644 test/unit/address_test.rb create mode 100644 test/unit/api/row_test.rb create mode 100644 test/unit/area_code_test.rb create mode 100644 test/unit/automatic_call_distributor_test.rb create mode 100644 test/unit/call_forward_case_test.rb create mode 100644 test/unit/call_forward_test.rb create mode 100644 test/unit/callthrough_test.rb create mode 100644 test/unit/conference_invitee_test.rb create mode 100644 test/unit/conference_test.rb create mode 100644 test/unit/country_test.rb create mode 100644 test/unit/dial_in_number_store_test.rb create mode 100644 test/unit/fax_account_test.rb create mode 100644 test/unit/fax_document_test.rb create mode 100644 test/unit/fax_page_test.rb create mode 100644 test/unit/fax_resolution_test.rb create mode 100644 test/unit/fax_thumbnail_test.rb create mode 100644 test/unit/gemeinschaft_setup_test.rb create mode 100644 test/unit/gs_cluster_sync_log_entry_test.rb create mode 100644 test/unit/gs_node_test.rb create mode 100644 test/unit/gui_function_membership_test.rb create mode 100644 test/unit/gui_function_test.rb create mode 100644 test/unit/helpers/api/rows_helper_test.rb create mode 100644 test/unit/helpers/config_siemens_helper_test.rb create mode 100644 test/unit/helpers/page_helper_test.rb create mode 100644 test/unit/helpers/sessions_helper_test.rb create mode 100644 test/unit/hunt_group_member_test.rb create mode 100644 test/unit/hunt_group_test.rb create mode 100644 test/unit/language_test.rb create mode 100644 test/unit/manufacturer_test.rb create mode 100644 test/unit/oui_test.rb create mode 100644 test/unit/phone_book_entry_test.rb create mode 100644 test/unit/phone_book_test.rb create mode 100644 test/unit/phone_model_test.rb create mode 100644 test/unit/phone_number_range_test.rb create mode 100644 test/unit/phone_number_test.rb create mode 100644 test/unit/phone_sip_account_test.rb create mode 100644 test/unit/phone_test.rb create mode 100644 test/unit/ringtone_test.rb create mode 100644 test/unit/sip_account_test.rb create mode 100644 test/unit/sip_domain_test.rb create mode 100644 test/unit/softkey_function_test.rb create mode 100644 test/unit/softkey_test.rb create mode 100644 test/unit/system_message_test.rb create mode 100644 test/unit/tenant_membership_test.rb create mode 100644 test/unit/tenant_test.rb create mode 100644 test/unit/user_group_membership_test.rb create mode 100644 test/unit/user_group_test.rb create mode 100644 test/unit/user_test.rb create mode 100644 test/unit/whitelist_test.rb create mode 100644 vendor/assets/stylesheets/.gitkeep create mode 100644 vendor/plugins/.gitkeep diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bf1d09a --- /dev/null +++ b/.gitignore @@ -0,0 +1,88 @@ +# ignore vim swap files: +*.swp + +.DS_Store +.bundle + +/db/*.sqlite3-journal +/db/*.sqlite3 +tmp/ +.DS_Store +/ERD.pdf +/ERD.png +/bin + +# Numerous always-ignore extensions +*.diff +*.err +*.orig +*.log +*.rej +*.swo +*.swp +*.vi +*~ + +# OS or Editor folders +.DS_Store +.cache +.project +.settings +nbproject +Thumbs.db + + +# Extra +.sass-cache +.livereload + +# Dreamweaver added files +_notes +dwsync.xml + +# Komodo +*.komodoproject +.komodotools + +# Folders to ignore +.hg +.svn +/db/*.db +/db/*.db-journal + +log/*.log +tmp/**/* +/.project +*.komodoproject +/.komodotools +.tmp*~ + +# Ignore fixtures. We use factory_girl. +/test/fixtures/*.yml + +ERD.pdf +ERD.png + +/vendor/cache +/vendor/bundle +.settings/* +/.idea + +# ignore Sass cache: +/.sass-cache +tmp/sass-cache +tmp/cache + +# directory created by "bundle install --path ." (not needed anyway): +/ruby + +# ignore wrappers generated by "bundle install --binstubs": +/bin + +/tmp + +# Images +public/uploads +# Freeswitch +misc/freeswitch/conf/freeswitch.serial +misc/freeswitch/scripts/ini/gateway_gateway1.ini diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..163c360 --- /dev/null +++ b/Gemfile @@ -0,0 +1,78 @@ +source 'http://rubygems.org' + +gem 'rails', '3.2.2' + +gem 'bcrypt-ruby' + +gem 'sqlite3' + +gem 'mysql2' + +gem 'cancan' + +gem 'state_machine' + +gem 'acts_as_list' + +# Nicer console output: +gem "hirb" + +gem "nokogiri" + +# Gems used only for assets and not required +# in production environments by default. +group :assets do + gem 'sass-rails', '~> 3.2.3' + gem 'coffee-rails', '~> 3.2.1' + gem 'compass-rails' + + # See https://github.com/sstephenson/execjs#readme for more supported runtimes + gem 'therubyracer' + + gem 'uglifier', '>= 1.0.3' + +end + +gem 'json' + +gem 'jquery-rails' + +group :development do + gem 'factory_girl_rails' + gem 'factory_girl' + gem "rails-erd", "~> 0.4.5" +end + +group :test do + gem 'factory_girl_rails' +end + +gem "haml" +gem "simple_form", '2.0.1' + +# Image Upload +gem 'carrierwave' +gem "mini_magick" + +# Pagination https://github.com/mislav/will_paginate/wiki/Installation +gem 'will_paginate' + +# DelayedJob +gem 'delayed_job' +gem 'delayed_job_active_record' + +# Private Pub http://railscasts.com/episodes/316-private-pub +gem 'private_pub' + +# https://github.com/iain/http_accept_language +gem 'http_accept_language' + +# https://github.com/weppos/breadcrumbs_on_rails +gem 'breadcrumbs_on_rails' + +# UUID Generator https://github.com/assaf/uuid +gem 'uuid' + +# Local Variables: +# mode: ruby +# End: diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..e07b89e --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,209 @@ +GEM + remote: http://rubygems.org/ + specs: + actionmailer (3.2.2) + actionpack (= 3.2.2) + mail (~> 2.4.0) + actionpack (3.2.2) + activemodel (= 3.2.2) + activesupport (= 3.2.2) + builder (~> 3.0.0) + erubis (~> 2.7.0) + journey (~> 1.0.1) + rack (~> 1.4.0) + rack-cache (~> 1.1) + rack-test (~> 0.6.1) + sprockets (~> 2.1.2) + activemodel (3.2.2) + activesupport (= 3.2.2) + builder (~> 3.0.0) + activerecord (3.2.2) + activemodel (= 3.2.2) + activesupport (= 3.2.2) + arel (~> 3.0.2) + tzinfo (~> 0.3.29) + activeresource (3.2.2) + activemodel (= 3.2.2) + activesupport (= 3.2.2) + activesupport (3.2.2) + i18n (~> 0.6) + multi_json (~> 1.0) + acts_as_list (0.1.5) + addressable (2.2.7) + arel (3.0.2) + bcrypt-ruby (3.0.1) + breadcrumbs_on_rails (2.2.0) + builder (3.0.0) + cancan (1.6.7) + carrierwave (0.5.8) + activesupport (~> 3.0) + chunky_png (1.2.5) + coffee-rails (3.2.2) + coffee-script (>= 2.2.0) + railties (~> 3.2.0) + coffee-script (2.2.0) + coffee-script-source + execjs + coffee-script-source (1.2.0) + compass (0.12.rc.1) + chunky_png (~> 1.2) + fssm (>= 0.2.7) + sass (~> 3.1) + compass-rails (1.0.0.rc.3) + compass (~> 0.12.rc.0) + cookiejar (0.3.0) + delayed_job (3.0.1) + activesupport (~> 3.0) + delayed_job_active_record (0.3.2) + activerecord (> 2.1.0) + delayed_job (~> 3.0.0) + em-http-request (1.0.1) + addressable (>= 2.2.3) + cookiejar + em-socksify + eventmachine (>= 1.0.0.beta.4) + http_parser.rb (>= 0.5.3) + em-socksify (0.1.0) + eventmachine + erubis (2.7.0) + eventmachine (1.0.0.beta.4) + execjs (1.3.0) + multi_json (~> 1.0) + factory_girl (2.6.1) + activesupport (>= 2.3.9) + factory_girl_rails (1.7.0) + factory_girl (~> 2.6.0) + railties (>= 3.0.0) + faye (0.8.0) + cookiejar (>= 0.3.0) + em-http-request (>= 0.3.0) + eventmachine (>= 0.12.0) + faye-websocket (>= 0.4.0) + rack (>= 1.0.0) + yajl-ruby (>= 1.0.0) + faye-websocket (0.4.1) + eventmachine (>= 0.12.0) + fssm (0.2.8.1) + haml (3.1.4) + hike (1.2.1) + hirb (0.6.1) + http_accept_language (1.0.2) + http_parser.rb (0.5.3) + i18n (0.6.0) + journey (1.0.3) + jquery-rails (2.0.1) + railties (>= 3.2.0, < 5.0) + thor (~> 0.14) + json (1.6.5) + libv8 (3.3.10.4) + macaddr (1.6.1) + systemu (~> 2.5.0) + mail (2.4.3) + i18n (>= 0.4.0) + mime-types (~> 1.16) + treetop (~> 1.4.8) + mime-types (1.17.2) + mini_magick (3.4) + subexec (~> 0.2.1) + multi_json (1.1.0) + mysql2 (0.3.11) + nokogiri (1.5.5) + polyglot (0.3.3) + private_pub (1.0.1) + faye + rack (1.4.1) + rack-cache (1.2) + rack (>= 0.4) + rack-ssl (1.3.2) + rack + rack-test (0.6.1) + rack (>= 1.0) + rails (3.2.2) + actionmailer (= 3.2.2) + actionpack (= 3.2.2) + activerecord (= 3.2.2) + activeresource (= 3.2.2) + activesupport (= 3.2.2) + bundler (~> 1.0) + railties (= 3.2.2) + rails-erd (0.4.5) + activerecord (~> 3.0) + activesupport (~> 3.0) + ruby-graphviz (~> 0.9.18) + railties (3.2.2) + actionpack (= 3.2.2) + activesupport (= 3.2.2) + rack-ssl (~> 1.3.2) + rake (>= 0.8.7) + rdoc (~> 3.4) + thor (~> 0.14.6) + rake (0.9.2.2) + rdoc (3.12) + json (~> 1.4) + ruby-graphviz (0.9.21) + sass (3.1.15) + sass-rails (3.2.4) + railties (~> 3.2.0) + sass (>= 3.1.10) + tilt (~> 1.3) + simple_form (2.0.1) + actionpack (~> 3.0) + activemodel (~> 3.0) + sprockets (2.1.2) + hike (~> 1.2) + rack (~> 1.0) + tilt (~> 1.1, != 1.3.0) + sqlite3 (1.3.5) + state_machine (1.1.2) + subexec (0.2.1) + systemu (2.5.1) + therubyracer (0.9.10) + libv8 (~> 3.3.10) + thor (0.14.6) + tilt (1.3.3) + treetop (1.4.10) + polyglot + polyglot (>= 0.3.1) + tzinfo (0.3.32) + uglifier (1.2.3) + execjs (>= 0.3.0) + multi_json (>= 1.0.2) + uuid (2.3.5) + macaddr (~> 1.0) + will_paginate (3.0.3) + yajl-ruby (1.1.0) + +PLATFORMS + ruby + +DEPENDENCIES + acts_as_list + bcrypt-ruby + breadcrumbs_on_rails + cancan + carrierwave + coffee-rails (~> 3.2.1) + compass-rails + delayed_job + delayed_job_active_record + factory_girl + factory_girl_rails + haml + hirb + http_accept_language + jquery-rails + json + mini_magick + mysql2 + nokogiri + private_pub + rails (= 3.2.2) + rails-erd (~> 0.4.5) + sass-rails (~> 3.2.3) + simple_form (= 2.0.1) + sqlite3 + state_machine + therubyracer + uglifier (>= 1.0.3) + uuid + will_paginate diff --git a/Guardfile b/Guardfile new file mode 100644 index 0000000..4b273b3 --- /dev/null +++ b/Guardfile @@ -0,0 +1,13 @@ +# A sample Guardfile +# More info at https://github.com/guard/guard#readme + +guard 'livereload' do + watch(%r{app/.+\.(erb|haml)}) + watch(%r{app/helpers/.+\.rb}) + watch(%r{(public/|app/assets).+\.(css|js|html)}) + watch(%r{(public/|app/assets).+\.(css|js|html)}) + watch(%r{(public/|app/assets).*}) + watch(%r{(app/assets/.+\.css)\.s[ac]ss}) { |m| m[1] } + watch(%r{(app/assets/.+\.js)\.coffee}) { |m| m[1] } + watch(%r{config/locales/.+\.yml}) +end diff --git a/README.md b/README.md index e2bc474..a97ad3b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,16 @@ GS5 === -Gemeinschaft 5. A FreeSWITCH and Ruby on Rails based PBX. \ No newline at end of file +Gemeinschaft 5 by the [AMOOMA GmbH](http://amooma.de) in Germany. It is a FreeSWITCH and Ruby on Rails based PBX. + +License +======= +We use this repository to develop and we'd like to invite everybody to add new features or find bugs. There for the repository is not a private one. But the code in this repository is not GPL! Please go to [http://amooma.de/gemeinschaft/gs5](http://amooma.de/gemeinschaft/gs5) for a copy of this software with an other license. + +DO NOT USE CODE FROM THIS REPO FOR A PRODUCTION SYSTEM! + +Development How-to +================== +There is a master and a develop branch in this repository. If you are familiar with [http://nvie.com/posts/a-successful-git-branching-model/](http://nvie.com/posts/a-successful-git-branching-model/) you are good to go. Please send a pull request and an e-mail to stefan.wintermeyer@amooma.de with some info about your code. Regular developer get access to the repository and a closed developer mailinglist. + +We only accept code which was written 100% by you and were you grant us the rights for this code. \ No newline at end of file diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..cd4227d --- /dev/null +++ b/Rakefile @@ -0,0 +1,7 @@ +#!/usr/bin/env rake +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require File.expand_path('../config/application', __FILE__) + +Gemeinschaft42c::Application.load_tasks diff --git a/app/assets/images/amooma-logo.png b/app/assets/images/amooma-logo.png new file mode 100644 index 0000000..11096ff Binary files /dev/null and b/app/assets/images/amooma-logo.png differ diff --git a/app/assets/images/bg-body.png b/app/assets/images/bg-body.png new file mode 100644 index 0000000..777eff6 Binary files /dev/null and b/app/assets/images/bg-body.png differ diff --git a/app/assets/images/gradients/light-to-dark-blue-x63.png b/app/assets/images/gradients/light-to-dark-blue-x63.png new file mode 100644 index 0000000..7eb020f Binary files /dev/null and b/app/assets/images/gradients/light-to-dark-blue-x63.png differ diff --git a/app/assets/images/gradients/white-gray-x29-reverse.png b/app/assets/images/gradients/white-gray-x29-reverse.png new file mode 100644 index 0000000..7b7e879 Binary files /dev/null and b/app/assets/images/gradients/white-gray-x29-reverse.png differ diff --git a/app/assets/images/gradients/white-gray-x29.png b/app/assets/images/gradients/white-gray-x29.png new file mode 100644 index 0000000..a1671d0 Binary files /dev/null and b/app/assets/images/gradients/white-gray-x29.png differ diff --git a/app/assets/images/gradients/white-texture-x63.png b/app/assets/images/gradients/white-texture-x63.png new file mode 100644 index 0000000..1576e8f Binary files /dev/null and b/app/assets/images/gradients/white-texture-x63.png differ diff --git a/app/assets/images/icons/cellphone-32x.png b/app/assets/images/icons/cellphone-32x.png new file mode 100644 index 0000000..cfc41f5 Binary files /dev/null and b/app/assets/images/icons/cellphone-32x.png differ diff --git a/app/assets/images/icons/clock-32x.png b/app/assets/images/icons/clock-32x.png new file mode 100644 index 0000000..c076042 Binary files /dev/null and b/app/assets/images/icons/clock-32x.png differ diff --git a/app/assets/images/icons/cross-16x.png b/app/assets/images/icons/cross-16x.png new file mode 100644 index 0000000..e22ed6f Binary files /dev/null and b/app/assets/images/icons/cross-16x.png differ diff --git a/app/assets/images/icons/facebook-32x.png b/app/assets/images/icons/facebook-32x.png new file mode 100644 index 0000000..08fa0f7 Binary files /dev/null and b/app/assets/images/icons/facebook-32x.png differ diff --git a/app/assets/images/icons/fax-32x.png b/app/assets/images/icons/fax-32x.png new file mode 100644 index 0000000..b05ee59 Binary files /dev/null and b/app/assets/images/icons/fax-32x.png differ diff --git a/app/assets/images/icons/headphones-16x.png b/app/assets/images/icons/headphones-16x.png new file mode 100644 index 0000000..dee8346 Binary files /dev/null and b/app/assets/images/icons/headphones-16x.png differ diff --git a/app/assets/images/icons/headphones-32x.png b/app/assets/images/icons/headphones-32x.png new file mode 100644 index 0000000..89a5df7 Binary files /dev/null and b/app/assets/images/icons/headphones-32x.png differ diff --git a/app/assets/images/icons/house-32x.png b/app/assets/images/icons/house-32x.png new file mode 100644 index 0000000..b112915 Binary files /dev/null and b/app/assets/images/icons/house-32x.png differ diff --git a/app/assets/images/icons/mic-32x.png b/app/assets/images/icons/mic-32x.png new file mode 100644 index 0000000..30c4531 Binary files /dev/null and b/app/assets/images/icons/mic-32x.png differ diff --git a/app/assets/images/icons/microphone-16x.png b/app/assets/images/icons/microphone-16x.png new file mode 100644 index 0000000..b62422d Binary files /dev/null and b/app/assets/images/icons/microphone-16x.png differ diff --git a/app/assets/images/icons/microphone-32x.png b/app/assets/images/icons/microphone-32x.png new file mode 100644 index 0000000..30c4531 Binary files /dev/null and b/app/assets/images/icons/microphone-32x.png differ diff --git a/app/assets/images/icons/mute-16x.png b/app/assets/images/icons/mute-16x.png new file mode 100644 index 0000000..0656f3f Binary files /dev/null and b/app/assets/images/icons/mute-16x.png differ diff --git a/app/assets/images/icons/phone-down-32x.png b/app/assets/images/icons/phone-down-32x.png new file mode 100644 index 0000000..38c3560 Binary files /dev/null and b/app/assets/images/icons/phone-down-32x.png differ diff --git a/app/assets/images/icons/phone-mobile-32x.png b/app/assets/images/icons/phone-mobile-32x.png new file mode 100644 index 0000000..b373e1a Binary files /dev/null and b/app/assets/images/icons/phone-mobile-32x.png differ diff --git a/app/assets/images/icons/phone-up-32x.png b/app/assets/images/icons/phone-up-32x.png new file mode 100644 index 0000000..9b765c7 Binary files /dev/null and b/app/assets/images/icons/phone-up-32x.png differ diff --git a/app/assets/images/icons/search-13x16.png b/app/assets/images/icons/search-13x16.png new file mode 100644 index 0000000..16aa3c6 Binary files /dev/null and b/app/assets/images/icons/search-13x16.png differ diff --git a/app/assets/images/icons/skype-32x.png b/app/assets/images/icons/skype-32x.png new file mode 100644 index 0000000..c3b0978 Binary files /dev/null and b/app/assets/images/icons/skype-32x.png differ diff --git a/app/assets/images/icons/star-16x.png b/app/assets/images/icons/star-16x.png new file mode 100644 index 0000000..6b16932 Binary files /dev/null and b/app/assets/images/icons/star-16x.png differ diff --git a/app/assets/images/icons/suitcase-32x.png b/app/assets/images/icons/suitcase-32x.png new file mode 100644 index 0000000..f53daa9 Binary files /dev/null and b/app/assets/images/icons/suitcase-32x.png differ diff --git a/app/assets/images/icons/tag-16x.png b/app/assets/images/icons/tag-16x.png new file mode 100644 index 0000000..b4522d7 Binary files /dev/null and b/app/assets/images/icons/tag-16x.png differ diff --git a/app/assets/images/icons/twitter-32x.png b/app/assets/images/icons/twitter-32x.png new file mode 100644 index 0000000..51351a7 Binary files /dev/null and b/app/assets/images/icons/twitter-32x.png differ diff --git a/app/assets/images/icons/unmute-16x.png b/app/assets/images/icons/unmute-16x.png new file mode 100644 index 0000000..e9dfde0 Binary files /dev/null and b/app/assets/images/icons/unmute-16x.png differ diff --git a/app/assets/images/icons/user-16x.png b/app/assets/images/icons/user-16x.png new file mode 100644 index 0000000..909403a Binary files /dev/null and b/app/assets/images/icons/user-16x.png differ diff --git a/app/assets/images/icons/user-female-16x.png b/app/assets/images/icons/user-female-16x.png new file mode 100644 index 0000000..38dde34 Binary files /dev/null and b/app/assets/images/icons/user-female-16x.png differ diff --git a/app/assets/images/icons/user-male-16x.png b/app/assets/images/icons/user-male-16x.png new file mode 100644 index 0000000..e03fd0f Binary files /dev/null and b/app/assets/images/icons/user-male-16x.png differ diff --git a/app/assets/images/logo.png b/app/assets/images/logo.png new file mode 100644 index 0000000..e4432b8 Binary files /dev/null and b/app/assets/images/logo.png differ diff --git a/app/assets/images/rails.png b/app/assets/images/rails.png new file mode 100644 index 0000000..d5edc04 Binary files /dev/null and b/app/assets/images/rails.png differ diff --git a/app/assets/images/stubs/user-36x.jpg b/app/assets/images/stubs/user-36x.jpg new file mode 100644 index 0000000..8a391a0 Binary files /dev/null and b/app/assets/images/stubs/user-36x.jpg differ diff --git a/app/assets/images/user.png b/app/assets/images/user.png new file mode 100644 index 0000000..c0e33c7 Binary files /dev/null and b/app/assets/images/user.png differ diff --git a/app/assets/javascripts/api/rows.js.coffee b/app/assets/javascripts/api/rows.js.coffee new file mode 100644 index 0000000..7615679 --- /dev/null +++ b/app/assets/javascripts/api/rows.js.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js new file mode 100644 index 0000000..2e0b0d8 --- /dev/null +++ b/app/assets/javascripts/application.js @@ -0,0 +1,13 @@ +// This is a manifest file that'll be compiled into including all the files listed below. +// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically +// be included in the compiled file accessible from http://example.com/assets/application.js +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// the compiled file. +// +//= require jquery +//= require jquery_ujs +//= require core +//= require vendor/modernizr-2.0.6.min.js +//= require vendor/jquery.condom.js +//= require vendor/jquery.survival-kit +//= require softkeys diff --git a/app/assets/javascripts/config_siemens.js.coffee b/app/assets/javascripts/config_siemens.js.coffee new file mode 100644 index 0000000..7615679 --- /dev/null +++ b/app/assets/javascripts/config_siemens.js.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/app/assets/javascripts/core.coffee b/app/assets/javascripts/core.coffee new file mode 100644 index 0000000..af12aa7 --- /dev/null +++ b/app/assets/javascripts/core.coffee @@ -0,0 +1,5 @@ +$(document).ready -> + $sk = $.ns('sk') + $sk('.search-box').searchBox() + $sk('.simple_form').simpleForms() + \ No newline at end of file diff --git a/app/assets/javascripts/page.js.coffee b/app/assets/javascripts/page.js.coffee new file mode 100644 index 0000000..7615679 --- /dev/null +++ b/app/assets/javascripts/page.js.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/app/assets/javascripts/softkeys.js.coffee b/app/assets/javascripts/softkeys.js.coffee new file mode 100644 index 0000000..23d5233 --- /dev/null +++ b/app/assets/javascripts/softkeys.js.coffee @@ -0,0 +1,25 @@ +jQuery -> + function_name = $('#softkey_softkey_function_id :selected').text() + + if function_name == call_forwarding_function_name + $('#softkey_call_forward_id').parent().show() + $('#softkey_number').parent().hide() + else + $('#softkey_call_forward_id').parent().hide() + if (function_name == hold_function_name || function_name == deactivated_function_name) + $('#softkey_number').parent().hide() + else + $('#softkey_number').parent().show() + + $('#softkey_softkey_function_id').change -> + $('#softkey_label').parent().show() + function_name = $('#softkey_softkey_function_id :selected').text() + if function_name == call_forwarding_function_name + $('#softkey_call_forward_id').parent().show("slow") + $('#softkey_number').parent().hide("slow") + else + $('#softkey_call_forward_id').parent().hide("slow") + if (function_name == hold_function_name || function_name == deactivated_function_name) + $('#softkey_number').parent().hide("slow") + else + $('#softkey_number').parent().show("slow") diff --git a/app/assets/javascripts/vendor/autoresize.jquery.js b/app/assets/javascripts/vendor/autoresize.jquery.js new file mode 100644 index 0000000..28cec5d --- /dev/null +++ b/app/assets/javascripts/vendor/autoresize.jquery.js @@ -0,0 +1,94 @@ +/* + * jQuery autoResize (textarea auto-resizer) + * @copyright James Padolsey http://james.padolsey.com + * @version 1.04 + */ + +(function($){ + $.fn.autoResize = function(options) { + // Just some abstracted details, + // to make plugin users happy: + var settings = $.extend({ + onResize : function(){}, + animate : true, + animateDuration : 150, + animateCallback : function(){}, + extraSpace : 20, + limit: 1000 + }, options); + + // Only textarea's auto-resize: + this.filter('textarea').each(function(){ + + // Get rid of scrollbars and disable WebKit resizing: + var textarea = $(this).css({resize:'none','overflow-y':'hidden'}), + + // Cache original height, for use later: + origHeight = textarea.height(), + + // Need clone of textarea, hidden off screen: + clone = (function(){ + + // Properties which may effect space taken up by chracters: + var props = ['height','width','lineHeight','textDecoration','letterSpacing'], + propOb = {}; + + // Create object of styles to apply: + $.each(props, function(i, prop){ + propOb[prop] = textarea.css(prop); + }); + + // Clone the actual textarea removing unique properties + // and insert before original textarea: + return textarea.clone().removeAttr('id').removeAttr('name').css({ + position: 'absolute', + top: 0, + left: -9999 + }).css(propOb).attr('tabIndex','-1').insertBefore(textarea); + + })(), + lastScrollTop = null, + updateSize = function() { + + // Prepare the clone: + clone.height(0).val($(this).val()).scrollTop(10000); + + // Find the height of text: + var scrollTop = Math.max(clone.scrollTop(), origHeight) + settings.extraSpace, + toChange = $(this).add(clone); + + // Don't do anything if scrollTip hasen't changed: + if (lastScrollTop === scrollTop) { return; } + lastScrollTop = scrollTop; + + // Check for limit: + if ( scrollTop >= settings.limit ) { + $(this).css('overflow-y',''); + return; + } + // Fire off callback: + settings.onResize.call(this); + + // Either animate or directly apply height: + settings.animate && textarea.css('display') === 'block' ? + toChange.stop().animate({height:scrollTop}, settings.animateDuration, settings.animateCallback) + : toChange.height(scrollTop); + }; + + // Bind namespaced handlers to appropriate events: + textarea + .unbind('.dynSiz') + .bind('keyup.dynSiz', updateSize) + .bind('keydown.dynSiz', updateSize) + .bind('change.dynSiz', updateSize); + + }); + + // Chain: + return this; + + }; + + + +})(jQuery); diff --git a/app/assets/javascripts/vendor/fancybox/jquery.easing-1.3.pack.js b/app/assets/javascripts/vendor/fancybox/jquery.easing-1.3.pack.js new file mode 100755 index 0000000..ef74321 --- /dev/null +++ b/app/assets/javascripts/vendor/fancybox/jquery.easing-1.3.pack.js @@ -0,0 +1,205 @@ +/* + * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ + * + * Uses the built in easing capabilities added In jQuery 1.1 + * to offer multiple easing options + * + * TERMS OF USE - jQuery Easing + * + * Open source under the BSD License. + * + * Copyright © 2008 George McGinley Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the author nor the names of contributors may be used to endorse + * or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * +*/ + +// t: current time, b: begInnIng value, c: change In value, d: duration +jQuery.easing['jswing'] = jQuery.easing['swing']; + +jQuery.extend( jQuery.easing, +{ + def: 'easeOutQuad', + swing: function (x, t, b, c, d) { + //alert(jQuery.easing.default); + return jQuery.easing[jQuery.easing.def](x, t, b, c, d); + }, + easeInQuad: function (x, t, b, c, d) { + return c*(t/=d)*t + b; + }, + easeOutQuad: function (x, t, b, c, d) { + return -c *(t/=d)*(t-2) + b; + }, + easeInOutQuad: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; + }, + easeInCubic: function (x, t, b, c, d) { + return c*(t/=d)*t*t + b; + }, + easeOutCubic: function (x, t, b, c, d) { + return c*((t=t/d-1)*t*t + 1) + b; + }, + easeInOutCubic: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t + b; + return c/2*((t-=2)*t*t + 2) + b; + }, + easeInQuart: function (x, t, b, c, d) { + return c*(t/=d)*t*t*t + b; + }, + easeOutQuart: function (x, t, b, c, d) { + return -c * ((t=t/d-1)*t*t*t - 1) + b; + }, + easeInOutQuart: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t + b; + return -c/2 * ((t-=2)*t*t*t - 2) + b; + }, + easeInQuint: function (x, t, b, c, d) { + return c*(t/=d)*t*t*t*t + b; + }, + easeOutQuint: function (x, t, b, c, d) { + return c*((t=t/d-1)*t*t*t*t + 1) + b; + }, + easeInOutQuint: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; + return c/2*((t-=2)*t*t*t*t + 2) + b; + }, + easeInSine: function (x, t, b, c, d) { + return -c * Math.cos(t/d * (Math.PI/2)) + c + b; + }, + easeOutSine: function (x, t, b, c, d) { + return c * Math.sin(t/d * (Math.PI/2)) + b; + }, + easeInOutSine: function (x, t, b, c, d) { + return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; + }, + easeInExpo: function (x, t, b, c, d) { + return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; + }, + easeOutExpo: function (x, t, b, c, d) { + return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; + }, + easeInOutExpo: function (x, t, b, c, d) { + if (t==0) return b; + if (t==d) return b+c; + if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; + return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; + }, + easeInCirc: function (x, t, b, c, d) { + return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; + }, + easeOutCirc: function (x, t, b, c, d) { + return c * Math.sqrt(1 - (t=t/d-1)*t) + b; + }, + easeInOutCirc: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; + return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; + }, + easeInElastic: function (x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + }, + easeOutElastic: function (x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; + }, + easeInOutElastic: function (x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; + }, + easeInBack: function (x, t, b, c, d, s) { + if (s == undefined) s = 1.70158; + return c*(t/=d)*t*((s+1)*t - s) + b; + }, + easeOutBack: function (x, t, b, c, d, s) { + if (s == undefined) s = 1.70158; + return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; + }, + easeInOutBack: function (x, t, b, c, d, s) { + if (s == undefined) s = 1.70158; + if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; + return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; + }, + easeInBounce: function (x, t, b, c, d) { + return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b; + }, + easeOutBounce: function (x, t, b, c, d) { + if ((t/=d) < (1/2.75)) { + return c*(7.5625*t*t) + b; + } else if (t < (2/2.75)) { + return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; + } else if (t < (2.5/2.75)) { + return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; + } else { + return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; + } + }, + easeInOutBounce: function (x, t, b, c, d) { + if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b; + return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b; + } +}); + +/* + * + * TERMS OF USE - EASING EQUATIONS + * + * Open source under the BSD License. + * + * Copyright © 2001 Robert Penner + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the author nor the names of contributors may be used to endorse + * or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ \ No newline at end of file diff --git a/app/assets/javascripts/vendor/fancybox/jquery.fancybox-1.3.4.pack.js b/app/assets/javascripts/vendor/fancybox/jquery.fancybox-1.3.4.pack.js new file mode 100755 index 0000000..1373ed0 --- /dev/null +++ b/app/assets/javascripts/vendor/fancybox/jquery.fancybox-1.3.4.pack.js @@ -0,0 +1,46 @@ +/* + * FancyBox - jQuery Plugin + * Simple and fancy lightbox alternative + * + * Examples and documentation at: http://fancybox.net + * + * Copyright (c) 2008 - 2010 Janis Skarnelis + * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated. + * + * Version: 1.3.4 (11/11/2010) + * Requires: jQuery v1.3+ + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + */ + +;(function(b){var m,t,u,f,D,j,E,n,z,A,q=0,e={},o=[],p=0,d={},l=[],G=null,v=new Image,J=/\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,W=/[^\.]\.(swf)\s*$/i,K,L=1,y=0,s="",r,i,h=false,B=b.extend(b("
")[0],{prop:0}),M=b.browser.msie&&b.browser.version<7&&!window.XMLHttpRequest,N=function(){t.hide();v.onerror=v.onload=null;G&&G.abort();m.empty()},O=function(){if(false===e.onError(o,q,e)){t.hide();h=false}else{e.titleShow=false;e.width="auto";e.height="auto";m.html('

The requested content cannot be loaded.
Please try again later.

'); +F()}},I=function(){var a=o[q],c,g,k,C,P,w;N();e=b.extend({},b.fn.fancybox.defaults,typeof b(a).data("fancybox")=="undefined"?e:b(a).data("fancybox"));w=e.onStart(o,q,e);if(w===false)h=false;else{if(typeof w=="object")e=b.extend(e,w);k=e.title||(a.nodeName?b(a).attr("title"):a.title)||"";if(a.nodeName&&!e.orig)e.orig=b(a).children("img:first").length?b(a).children("img:first"):b(a);if(k===""&&e.orig&&e.titleFromAlt)k=e.orig.attr("alt");c=e.href||(a.nodeName?b(a).attr("href"):a.href)||null;if(/^(?:javascript)/i.test(c)|| +c=="#")c=null;if(e.type){g=e.type;if(!c)c=e.content}else if(e.content)g="html";else if(c)g=c.match(J)?"image":c.match(W)?"swf":b(a).hasClass("iframe")?"iframe":c.indexOf("#")===0?"inline":"ajax";if(g){if(g=="inline"){a=c.substr(c.indexOf("#"));g=b(a).length>0?"inline":"ajax"}e.type=g;e.href=c;e.title=k;if(e.autoDimensions)if(e.type=="html"||e.type=="inline"||e.type=="ajax"){e.width="auto";e.height="auto"}else e.autoDimensions=false;if(e.modal){e.overlayShow=true;e.hideOnOverlayClick=false;e.hideOnContentClick= +false;e.enableEscapeButton=false;e.showCloseButton=false}e.padding=parseInt(e.padding,10);e.margin=parseInt(e.margin,10);m.css("padding",e.padding+e.margin);b(".fancybox-inline-tmp").unbind("fancybox-cancel").bind("fancybox-change",function(){b(this).replaceWith(j.children())});switch(g){case "html":m.html(e.content);F();break;case "inline":if(b(a).parent().is("#fancybox-content")===true){h=false;break}b('
').hide().insertBefore(b(a)).bind("fancybox-cleanup",function(){b(this).replaceWith(j.children())}).bind("fancybox-cancel", +function(){b(this).replaceWith(m.children())});b(a).appendTo(m);F();break;case "image":h=false;b.fancybox.showActivity();v=new Image;v.onerror=function(){O()};v.onload=function(){h=true;v.onerror=v.onload=null;e.width=v.width;e.height=v.height;b("").attr({id:"fancybox-img",src:v.src,alt:e.title}).appendTo(m);Q()};v.src=c;break;case "swf":e.scrolling="no";C='';P="";b.each(e.swf,function(x,H){C+='';P+=" "+x+'="'+H+'"'});C+='";m.html(C);F();break;case "ajax":h=false;b.fancybox.showActivity();e.ajax.win=e.ajax.success;G=b.ajax(b.extend({},e.ajax,{url:c,data:e.ajax.data||{},error:function(x){x.status>0&&O()},success:function(x,H,R){if((typeof R=="object"?R:G).status==200){if(typeof e.ajax.win== +"function"){w=e.ajax.win(c,x,H,R);if(w===false){t.hide();return}else if(typeof w=="string"||typeof w=="object")x=w}m.html(x);F()}}}));break;case "iframe":Q()}}else O()}},F=function(){var a=e.width,c=e.height;a=a.toString().indexOf("%")>-1?parseInt((b(window).width()-e.margin*2)*parseFloat(a)/100,10)+"px":a=="auto"?"auto":a+"px";c=c.toString().indexOf("%")>-1?parseInt((b(window).height()-e.margin*2)*parseFloat(c)/100,10)+"px":c=="auto"?"auto":c+"px";m.wrapInner('
');e.width=m.width();e.height=m.height();Q()},Q=function(){var a,c;t.hide();if(f.is(":visible")&&false===d.onCleanup(l,p,d)){b.event.trigger("fancybox-cancel");h=false}else{h=true;b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");f.is(":visible")&&d.titlePosition!=="outside"&&f.css("height",f.height());l=o;p=q;d=e;if(d.overlayShow){u.css({"background-color":d.overlayColor, +opacity:d.overlayOpacity,cursor:d.hideOnOverlayClick?"pointer":"auto",height:b(document).height()});if(!u.is(":visible")){M&&b("select:not(#fancybox-tmp select)").filter(function(){return this.style.visibility!=="hidden"}).css({visibility:"hidden"}).one("fancybox-cleanup",function(){this.style.visibility="inherit"});u.show()}}else u.hide();i=X();s=d.title||"";y=0;n.empty().removeAttr("style").removeClass();if(d.titleShow!==false){if(b.isFunction(d.titleFormat))a=d.titleFormat(s,l,p,d);else a=s&&s.length? +d.titlePosition=="float"?'
'+s+'
':'
'+s+"
":false;s=a;if(!(!s||s==="")){n.addClass("fancybox-title-"+d.titlePosition).html(s).appendTo("body").show();switch(d.titlePosition){case "inside":n.css({width:i.width-d.padding*2,marginLeft:d.padding,marginRight:d.padding}); +y=n.outerHeight(true);n.appendTo(D);i.height+=y;break;case "over":n.css({marginLeft:d.padding,width:i.width-d.padding*2,bottom:d.padding}).appendTo(D);break;case "float":n.css("left",parseInt((n.width()-i.width-40)/2,10)*-1).appendTo(f);break;default:n.css({width:i.width-d.padding*2,paddingLeft:d.padding,paddingRight:d.padding}).appendTo(f)}}}n.hide();if(f.is(":visible")){b(E.add(z).add(A)).hide();a=f.position();r={top:a.top,left:a.left,width:f.width(),height:f.height()};c=r.width==i.width&&r.height== +i.height;j.fadeTo(d.changeFade,0.3,function(){var g=function(){j.html(m.contents()).fadeTo(d.changeFade,1,S)};b.event.trigger("fancybox-change");j.empty().removeAttr("filter").css({"border-width":d.padding,width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2});if(c)g();else{B.prop=0;b(B).animate({prop:1},{duration:d.changeSpeed,easing:d.easingChange,step:T,complete:g})}})}else{f.removeAttr("style");j.css("border-width",d.padding);if(d.transitionIn=="elastic"){r=V();j.html(m.contents()); +f.show();if(d.opacity)i.opacity=0;B.prop=0;b(B).animate({prop:1},{duration:d.speedIn,easing:d.easingIn,step:T,complete:S})}else{d.titlePosition=="inside"&&y>0&&n.show();j.css({width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2}).html(m.contents());f.css(i).fadeIn(d.transitionIn=="none"?0:d.speedIn,S)}}}},Y=function(){if(d.enableEscapeButton||d.enableKeyboardNav)b(document).bind("keydown.fb",function(a){if(a.keyCode==27&&d.enableEscapeButton){a.preventDefault();b.fancybox.close()}else if((a.keyCode== +37||a.keyCode==39)&&d.enableKeyboardNav&&a.target.tagName!=="INPUT"&&a.target.tagName!=="TEXTAREA"&&a.target.tagName!=="SELECT"){a.preventDefault();b.fancybox[a.keyCode==37?"prev":"next"]()}});if(d.showNavArrows){if(d.cyclic&&l.length>1||p!==0)z.show();if(d.cyclic&&l.length>1||p!=l.length-1)A.show()}else{z.hide();A.hide()}},S=function(){if(!b.support.opacity){j.get(0).style.removeAttribute("filter");f.get(0).style.removeAttribute("filter")}e.autoDimensions&&j.css("height","auto");f.css("height","auto"); +s&&s.length&&n.show();d.showCloseButton&&E.show();Y();d.hideOnContentClick&&j.bind("click",b.fancybox.close);d.hideOnOverlayClick&&u.bind("click",b.fancybox.close);b(window).bind("resize.fb",b.fancybox.resize);d.centerOnScroll&&b(window).bind("scroll.fb",b.fancybox.center);if(d.type=="iframe")b('').appendTo(j); +f.show();h=false;b.fancybox.center();d.onComplete(l,p,d);var a,c;if(l.length-1>p){a=l[p+1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}if(p>0){a=l[p-1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}},T=function(a){var c={width:parseInt(r.width+(i.width-r.width)*a,10),height:parseInt(r.height+(i.height-r.height)*a,10),top:parseInt(r.top+(i.top-r.top)*a,10),left:parseInt(r.left+(i.left-r.left)*a,10)};if(typeof i.opacity!=="undefined")c.opacity=a<0.5?0.5:a;f.css(c); +j.css({width:c.width-d.padding*2,height:c.height-y*a-d.padding*2})},U=function(){return[b(window).width()-d.margin*2,b(window).height()-d.margin*2,b(document).scrollLeft()+d.margin,b(document).scrollTop()+d.margin]},X=function(){var a=U(),c={},g=d.autoScale,k=d.padding*2;c.width=d.width.toString().indexOf("%")>-1?parseInt(a[0]*parseFloat(d.width)/100,10):d.width+k;c.height=d.height.toString().indexOf("%")>-1?parseInt(a[1]*parseFloat(d.height)/100,10):d.height+k;if(g&&(c.width>a[0]||c.height>a[1]))if(e.type== +"image"||e.type=="swf"){g=d.width/d.height;if(c.width>a[0]){c.width=a[0];c.height=parseInt((c.width-k)/g+k,10)}if(c.height>a[1]){c.height=a[1];c.width=parseInt((c.height-k)*g+k,10)}}else{c.width=Math.min(c.width,a[0]);c.height=Math.min(c.height,a[1])}c.top=parseInt(Math.max(a[3]-20,a[3]+(a[1]-c.height-40)*0.5),10);c.left=parseInt(Math.max(a[2]-20,a[2]+(a[0]-c.width-40)*0.5),10);return c},V=function(){var a=e.orig?b(e.orig):false,c={};if(a&&a.length){c=a.offset();c.top+=parseInt(a.css("paddingTop"), +10)||0;c.left+=parseInt(a.css("paddingLeft"),10)||0;c.top+=parseInt(a.css("border-top-width"),10)||0;c.left+=parseInt(a.css("border-left-width"),10)||0;c.width=a.width();c.height=a.height();c={width:c.width+d.padding*2,height:c.height+d.padding*2,top:c.top-d.padding-20,left:c.left-d.padding-20}}else{a=U();c={width:d.padding*2,height:d.padding*2,top:parseInt(a[3]+a[1]*0.5,10),left:parseInt(a[2]+a[0]*0.5,10)}}return c},Z=function(){if(t.is(":visible")){b("div",t).css("top",L*-40+"px");L=(L+1)%12}else clearInterval(K)}; +b.fn.fancybox=function(a){if(!b(this).length)return this;b(this).data("fancybox",b.extend({},a,b.metadata?b(this).metadata():{})).unbind("click.fb").bind("click.fb",function(c){c.preventDefault();if(!h){h=true;b(this).blur();o=[];q=0;c=b(this).attr("rel")||"";if(!c||c==""||c==="nofollow")o.push(this);else{o=b("a[rel="+c+"], area[rel="+c+"]");q=o.index(this)}I()}});return this};b.fancybox=function(a,c){var g;if(!h){h=true;g=typeof c!=="undefined"?c:{};o=[];q=parseInt(g.index,10)||0;if(b.isArray(a)){for(var k= +0,C=a.length;ko.length||q<0)q=0;I()}};b.fancybox.showActivity=function(){clearInterval(K);t.show();K=setInterval(Z,66)};b.fancybox.hideActivity=function(){t.hide()};b.fancybox.next=function(){return b.fancybox.pos(p+ +1)};b.fancybox.prev=function(){return b.fancybox.pos(p-1)};b.fancybox.pos=function(a){if(!h){a=parseInt(a);o=l;if(a>-1&&a1){q=a>=l.length?0:l.length-1;I()}}};b.fancybox.cancel=function(){if(!h){h=true;b.event.trigger("fancybox-cancel");N();e.onCancel(o,q,e);h=false}};b.fancybox.close=function(){function a(){u.fadeOut("fast");n.empty().hide();f.hide();b.event.trigger("fancybox-cleanup");j.empty();d.onClosed(l,p,d);l=e=[];p=q=0;d=e={};h=false}if(!(h||f.is(":hidden"))){h= +true;if(d&&false===d.onCleanup(l,p,d))h=false;else{N();b(E.add(z).add(A)).hide();b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");j.find("iframe").attr("src",M&&/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank");d.titlePosition!=="inside"&&n.empty();f.stop();if(d.transitionOut=="elastic"){r=V();var c=f.position();i={top:c.top,left:c.left,width:f.width(),height:f.height()};if(d.opacity)i.opacity=1;n.empty().hide();B.prop=1; +b(B).animate({prop:0},{duration:d.speedOut,easing:d.easingOut,step:T,complete:a})}else f.fadeOut(d.transitionOut=="none"?0:d.speedOut,a)}}};b.fancybox.resize=function(){u.is(":visible")&&u.css("height",b(document).height());b.fancybox.center(true)};b.fancybox.center=function(a){var c,g;if(!h){g=a===true?1:0;c=U();!g&&(f.width()>c[0]||f.height()>c[1])||f.stop().animate({top:parseInt(Math.max(c[3]-20,c[3]+(c[1]-j.height()-40)*0.5-d.padding)),left:parseInt(Math.max(c[2]-20,c[2]+(c[0]-j.width()-40)*0.5- +d.padding))},typeof a=="number"?a:200)}};b.fancybox.init=function(){if(!b("#fancybox-wrap").length){b("body").append(m=b('
'),t=b('
'),u=b('
'),f=b('
'));D=b('
').append('
').appendTo(f); +D.append(j=b('
'),E=b(''),n=b('
'),z=b(''),A=b(''));E.click(b.fancybox.close);t.click(b.fancybox.cancel);z.click(function(a){a.preventDefault();b.fancybox.prev()});A.click(function(a){a.preventDefault();b.fancybox.next()}); +b.fn.mousewheel&&f.bind("mousewheel.fb",function(a,c){if(h)a.preventDefault();else if(b(a.target).get(0).clientHeight==0||b(a.target).get(0).scrollHeight===b(a.target).get(0).clientHeight){a.preventDefault();b.fancybox[c>0?"prev":"next"]()}});b.support.opacity||f.addClass("fancybox-ie");if(M){t.addClass("fancybox-ie6");f.addClass("fancybox-ie6");b('').prependTo(D)}}}; +b.fn.fancybox.defaults={padding:10,margin:40,opacity:false,modal:false,cyclic:false,scrolling:"auto",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:"transparent"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.7,overlayColor:"#777",titleShow:true,titlePosition:"float",titleFormat:null,titleFromAlt:false,transitionIn:"fade",transitionOut:"fade",speedIn:300,speedOut:300,changeSpeed:300,changeFade:"fast",easingIn:"swing", +easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,enableKeyboardNav:true,onStart:function(){},onCancel:function(){},onComplete:function(){},onCleanup:function(){},onClosed:function(){},onError:function(){}};b(document).ready(function(){b.fancybox.init()})})(jQuery); \ No newline at end of file diff --git a/app/assets/javascripts/vendor/fancybox/jquery.mousewheel-3.0.4.pack.js b/app/assets/javascripts/vendor/fancybox/jquery.mousewheel-3.0.4.pack.js new file mode 100755 index 0000000..cb66588 --- /dev/null +++ b/app/assets/javascripts/vendor/fancybox/jquery.mousewheel-3.0.4.pack.js @@ -0,0 +1,14 @@ +/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net) +* Licensed under the MIT License (LICENSE.txt). +* +* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. +* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. +* Thanks to: Seamus Leahy for adding deltaX and deltaY +* +* Version: 3.0.4 +* +* Requires: 1.2.2+ +*/ + +(function(d){function g(a){var b=a||window.event,i=[].slice.call(arguments,1),c=0,h=0,e=0;a=d.event.fix(b);a.type="mousewheel";if(a.wheelDelta)c=a.wheelDelta/120;if(a.detail)c=-a.detail/3;e=c;if(b.axis!==undefined&&b.axis===b.HORIZONTAL_AXIS){e=0;h=-1*c}if(b.wheelDeltaY!==undefined)e=b.wheelDeltaY/120;if(b.wheelDeltaX!==undefined)h=-1*b.wheelDeltaX/120;i.unshift(a,c,h,e);return d.event.handle.apply(this,i)}var f=["DOMMouseScroll","mousewheel"];d.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a= +f.length;a;)this.addEventListener(f[--a],g,false);else this.onmousewheel=g},teardown:function(){if(this.removeEventListener)for(var a=f.length;a;)this.removeEventListener(f[--a],g,false);else this.onmousewheel=null}};d.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})})(jQuery); \ No newline at end of file diff --git a/app/assets/javascripts/vendor/html5boilerplate.js b/app/assets/javascripts/vendor/html5boilerplate.js new file mode 100644 index 0000000..7cb21b1 --- /dev/null +++ b/app/assets/javascripts/vendor/html5boilerplate.js @@ -0,0 +1,20 @@ + +// usage: log('inside coolFunc', this, arguments); +// paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/ +window.log = function(){ + log.history = log.history || []; // store logs to an array for reference + log.history.push(arguments); + if(this.console) { + arguments.callee = arguments.callee.caller; + var newarr = [].slice.call(arguments); + (typeof console.log === 'object' ? log.apply.call(console.log, console, newarr) : console.log.apply(console, newarr)); + } +}; + +// make it safe to use console.log always +(function(b){function c(){}for(var d="assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,timeStamp,profile,profileEnd,time,timeEnd,trace,warn".split(","),a;a=d.pop();){b[a]=b[a]||c}})((function(){try +{console.log();return window.console;}catch(err){return window.console={};}})()); + + +// place any jQuery/helper plugins in here, instead of separate, slower script files. + diff --git a/app/assets/javascripts/vendor/jquery-1.6.2.min.js b/app/assets/javascripts/vendor/jquery-1.6.2.min.js new file mode 100755 index 0000000..48590ec --- /dev/null +++ b/app/assets/javascripts/vendor/jquery-1.6.2.min.js @@ -0,0 +1,18 @@ +/*! + * jQuery JavaScript Library v1.6.2 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Thu Jun 30 14:16:56 2011 -0400 + */ +(function(a,b){function cv(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cs(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"":"")+""),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cr(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cq(){cn=b}function cp(){setTimeout(cq,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bx(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bm(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(be,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bl(a){f.nodeName(a,"input")?bk(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bk)}function bk(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bj(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bi(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bh(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i=0===c})}function V(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function N(a,b){return(a&&a!=="*"?a+".":"")+b.replace(z,"`").replace(A,"&")}function M(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function K(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function E(){return!0}function D(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z])/ig,x=function(a,b){return b.toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!A){A=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a);return c===b||D.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(b,c,d){a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),d=c.documentElement,(!d||!d.nodeName||d.nodeName==="parsererror")&&e.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0},m&&f.extend(p,{position:"absolute",left:-1e3,top:-1e3});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
t
",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g=f.expando,h=typeof c=="string",i,j=a.nodeType,k=j?f.cache:a,l=j?a[f.expando]:a[f.expando]&&f.expando;if((!l||e&&l&&!k[l][g])&&h&&d===b)return;l||(j?a[f.expando]=l=++f.uuid:l=f.expando),k[l]||(k[l]={},j||(k[l].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?k[l][g]=f.extend(k[l][g],c):k[l]=f.extend(k[l],c);i=k[l],e&&(i[g]||(i[g]={}),i=i[g]),d!==b&&(i[f.camelCase(c)]=d);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[f.camelCase(c)]||i[c]:i}},removeData:function(b,c,d){if(!!f.acceptData(b)){var e=f.expando,g=b.nodeType,h=g?f.cache:b,i=g?b[f.expando]:f.expando;if(!h[i])return;if(c){var j=d?h[i][e]:h[i];if(j){delete j[c];if(!l(j))return}}if(d){delete h[i][e];if(!l(h[i]))return}var k=h[i][e];f.support.deleteExpando||h!=a?delete h[i]:h[i]=null,k?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=k):g&&(f.support.deleteExpando?delete b[f.expando]:b.removeAttribute?b.removeAttribute(f.expando):b[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=w:v&&c!=="className"&&(f.nodeName(a,"form")||u.test(c))&&(i=v)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.support.getSetAttribute?a.removeAttribute(b):(f.attr(a,b,""),a.removeAttributeNode(a.getAttributeNode(b))),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},tabIndex:{get:function(a){var c=a.getAttributeNode("tabIndex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}},value:{get:function(a,b){if(v&&f.nodeName(a,"button"))return v.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(v&&f.nodeName(a,"button"))return v.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==b?g:a[c]},propHooks:{}}),w={get:function(a,c){return f.prop(a,c)?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(f.attrFix=f.propFix,v=f.attrHooks.name=f.attrHooks.title=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,c){var d=a.getAttributeNode(c);if(d){d.nodeValue=b;return b}}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var x=/\.(.*)$/,y=/^(?:textarea|input|select)$/i,z=/\./g,A=/ /g,B=/[^\w\s.|`]/g,C=function(a){return a.replace(B,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=D;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=D);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),C).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i. +shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},J=function(c){var d=c.target,e,g;if(!!y.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=I(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:J,beforedeactivate:J,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&J.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&J.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",I(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in H)f.event.add(this,c+".specialChange",H[c]);return y.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return y.test(this.nodeName)}},H=f.event.special.change.filters,H.focus=H.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=T.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a=="string")return f.inArray(this[0],a?f(a):this.parent().children());return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(V(c[0])||V(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=S.call(arguments);O.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!U[a]?f.unique(e):e,(this.length>1||Q.test(d))&&P.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var X=/ jQuery\d+="(?:\d+|null)"/g,Y=/^\s+/,Z=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,$=/<([\w:]+)/,_=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};bf.optgroup=bf.option,bf.tbody=bf.tfoot=bf.colgroup=bf.caption=bf.thead,bf.th=bf.td,f.support.htmlSerialize||(bf._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(X,""):null;if(typeof a=="string"&&!bb.test(a)&&(f.support.leadingWhitespace||!Y.test(a))&&!bf[($.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Z,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j +)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bi(a,d),e=bj(a),g=bj(d);for(h=0;e[h];++h)bi(e[h],g[h])}if(b){bh(a,d);if(c){e=bj(a),g=bj(d);for(h=0;e[h];++h)bh(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!ba.test(k))k=b.createTextNode(k);else{k=k.replace(Z,"<$1>");var l=($.exec(k)||["",""])[1].toLowerCase(),m=bf[l]||bf._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=_.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&Y.test(k)&&o.insertBefore(b.createTextNode(Y.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bo.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle;c.zoom=1;var e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.filter=bn.test(g)?g.replace(bn,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bx(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(by=function(a,c){var d,e,g;c=c.replace(bp,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bz=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bq.test(d)&&br.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bx=by||bz,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bB=/%20/g,bC=/\[\]$/,bD=/\r?\n/g,bE=/#.*$/,bF=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bG=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bH=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,bI=/^(?:GET|HEAD)$/,bJ=/^\/\//,bK=/\?/,bL=/)<[^<]*)*<\/script>/gi,bM=/^(?:select|textarea)/i,bN=/\s+/,bO=/([?&])_=[^&]*/,bP=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bQ=f.fn.load,bR={},bS={},bT,bU;try{bT=e.href}catch(bV){bT=c.createElement("a"),bT.href="",bT=bT.href}bU=bP.exec(bT.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bQ)return bQ.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bL,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bM.test(this.nodeName)||bG.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bD,"\r\n")}}):{name:b.name,value:c.replace(bD,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?f.extend(!0,a,f.ajaxSettings,b):(b=a,a=f.extend(!0,f.ajaxSettings,b));for(var c in{context:1,url:1})c in b?a[c]=b[c]:c in f.ajaxSettings&&(a[c]=f.ajaxSettings[c]);return a},ajaxSettings:{url:bT,isLocal:bH.test(bU[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML}},ajaxPrefilter:bW(bR),ajaxTransport:bW(bS),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a?4:0;var o,r,u,w=l?bZ(d,v,l):b,x,y;if(a>=200&&a<300||a===304){if(d.ifModified){if(x=v.getResponseHeader("Last-Modified"))f.lastModified[k]=x;if(y=v.getResponseHeader("Etag"))f.etag[k]=y}if(a===304)c="notmodified",o=!0;else try{r=b$(d,w),c="success",o=!0}catch(z){c="parsererror",u=z}}else{u=c;if(!c||a)c="error",a<0&&(a=0)}v.status=a,v.statusText=c,o?h.resolveWith(e,[r,c,v]):h.rejectWith(e,[v,c,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,c]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bF.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bE,"").replace(bJ,bU[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bN),d.crossDomain==null&&(r=bP.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bU[1]&&r[2]==bU[2]&&(r[3]||(r[1]==="http:"?80:443))==(bU[3]||(bU[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bX(bR,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bI.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bK.test(d.url)?"&":"?")+d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bO,"$1_="+x);d.url=y+(y===d.url?(bK.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", */*; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bX(bS,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){status<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bB,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn,co=a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cr("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cu.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cu.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cv(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cv(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c];return e.document.compatMode==="CSS1Compat"&&g||e.document.body["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var h=f.css(e,d),i=parseFloat(h);return f.isNaN(i)?h:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file diff --git a/app/assets/javascripts/vendor/jquery.condom.js b/app/assets/javascripts/vendor/jquery.condom.js new file mode 100644 index 0000000..5d24a7e --- /dev/null +++ b/app/assets/javascripts/vendor/jquery.condom.js @@ -0,0 +1,52 @@ +/* + * jQuery Condom (Use namespaces to protect your global integrity.) + * Version 0.0.3 + * + * Copyright (c) 2011 Mario "Kuroir" Ricalde (http://kuroir.com) + * & Micha Niskin (micha@thinkminimo.com) + * Licensed jointly under the GPL and MIT licenses, + * choose which one suits your project best! + */ +(function($) { + var methods = {}; + $.ns = function(ns) { + // Define namespace if it doesn't exist. + methods[ns] = methods[ns] || {}; + + // Get reference to a namespaced jQ object + function nsfun(selector, context) { + return $(selector, context).ns(ns); + } + + // Allows you to add methods ala jQuery.fn (useful to namespace premade plugins) + nsfun.fn = methods[ns]; + + // Add a method. + nsfun.add = function(fname, fn) { + var new_funcs = typeof fname == "object" ? fname : {}; + // One method. + if (new_funcs !== fname) + new_funcs[fname] = fn; + // Group of methods. + $.each(new_funcs, function(fname, fn) { + methods[ns][fname] = function() { + fn.apply(this, arguments); + return this; + }; + }); + return this; + }; + + // Get methods. + nsfun.methods = function() { + return $.extend({}, methods[ns]); + }; + + return nsfun; + }; + // The only function that touches $.fn + $.fn.ns = function(ns) { + if (methods[ns]) $.extend(this, methods[ns]); + return this; + }; +})(jQuery); diff --git a/app/assets/javascripts/vendor/jquery.easy-slider-1.7.js b/app/assets/javascripts/vendor/jquery.easy-slider-1.7.js new file mode 100644 index 0000000..ff5518f --- /dev/null +++ b/app/assets/javascripts/vendor/jquery.easy-slider-1.7.js @@ -0,0 +1,225 @@ +/* + * Easy Slider 1.7 - jQuery plugin + * written by Alen Grakalic + * http://cssglobe.com/post/4004/easy-slider-15-the-easiest-jquery-plugin-for-sliding + * + * Copyright (c) 2009 Alen Grakalic (http://cssglobe.com) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * Built for jQuery library + * http://jquery.com + * + */ + +/* + * markup example for $("#slider").easySlider(); + * + *
+ *
    + *
  • + *
  • + *
  • + *
  • + *
  • + *
+ *
+ * + */ + +(function($) { + + $.fn.easySlider = function(options){ + + // default configuration properties + var defaults = { + prevId: 'prevBtn', + prevText: 'Previous', + nextId: 'nextBtn', + nextText: 'Next', + controlsShow: true, + controlsBefore: '', + controlsAfter: '', + controlsFade: true, + firstId: 'firstBtn', + firstText: 'First', + firstShow: false, + lastId: 'lastBtn', + lastText: 'Last', + lastShow: false, + vertical: false, + speed: 800, + auto: false, + pause: 2000, + continuous: false, + numeric: false, + numericId: 'controls' + }; + + var options = $.extend(defaults, options); + + this.each(function() { + var obj = $(this); + var s = $("li", obj).length; + var w = $("li", obj).width(); + var h = $("li", obj).height(); + var clickable = true; + obj.width(w); + obj.height(h); + obj.css("overflow","hidden"); + var ts = s-1; + var t = 0; + $("ul", obj).css('width',s*w); + + if(options.continuous){ + $("ul", obj).prepend($("ul li:last-child", obj).clone().css("margin-left","-"+ w +"px")); + $("ul", obj).append($("ul li:nth-child(2)", obj).clone()); + $("ul", obj).css('width',(s+1)*w); + }; + + if(!options.vertical) $("li", obj).css('float','left'); + + if(options.controlsShow){ + var html = options.controlsBefore; + if(options.numeric){ + html += '
    '; + } else { + if(options.firstShow) html += ''+ options.firstText +''; + html += ' '+ options.prevText +''; + html += ' '+ options.nextText +''; + if(options.lastShow) html += ' '+ options.lastText +''; + }; + + html += options.controlsAfter; + $(obj).after(html); + }; + + if(options.numeric){ + for(var i=0;i'+ (i+1) +'') + .appendTo($("#"+ options.numericId)) + .click(function(){ + animate($("a",$(this)).attr('rel'),true); + }); + }; + } else { + $("a","#"+options.nextId).click(function(){ + animate("next",true); + }); + $("a","#"+options.prevId).click(function(){ + animate("prev",true); + }); + $("a","#"+options.firstId).click(function(){ + animate("first",true); + }); + $("a","#"+options.lastId).click(function(){ + animate("last",true); + }); + }; + + function setCurrent(i){ + i = parseInt(i)+1; + $("li", "#" + options.numericId).removeClass("current"); + $("li#" + options.numericId + i).addClass("current"); + }; + + function adjust(){ + if(t>ts) t=0; + if(t<0) t=ts; + if(!options.vertical) { + $("ul",obj).css("margin-left",(t*w*-1)); + } else { + $("ul",obj).css("margin-left",(t*h*-1)); + } + clickable = true; + if(options.numeric) setCurrent(t); + }; + + function animate(dir,clicked){ + if (clickable){ + clickable = false; + var ot = t; + switch(dir){ + case "next": + t = (ot>=ts) ? (options.continuous ? t+1 : ts) : t+1; + break; + case "prev": + t = (t<=0) ? (options.continuous ? t-1 : 0) : t-1; + break; + case "first": + t = 0; + break; + case "last": + t = ts; + break; + default: + t = dir; + break; + }; + var diff = Math.abs(ot-t); + var speed = diff*options.speed; + if(!options.vertical) { + p = (t*w*-1); + $("ul",obj).animate( + { marginLeft: p }, + { queue:false, duration:speed, complete:adjust } + ); + } else { + p = (t*h*-1); + $("ul",obj).animate( + { marginTop: p }, + { queue:false, duration:speed, complete:adjust } + ); + }; + + if(!options.continuous && options.controlsFade){ + if(t==ts){ + $("a","#"+options.nextId).hide(); + $("a","#"+options.lastId).hide(); + } else { + $("a","#"+options.nextId).show(); + $("a","#"+options.lastId).show(); + }; + if(t==0){ + $("a","#"+options.prevId).hide(); + $("a","#"+options.firstId).hide(); + } else { + $("a","#"+options.prevId).show(); + $("a","#"+options.firstId).show(); + }; + }; + + if(clicked) clearTimeout(timeout); + if(options.auto && dir=="next" && !clicked){; + timeout = setTimeout(function(){ + animate("next",false); + },diff*options.speed+options.pause); + }; + + }; + + }; + // init + var timeout; + if(options.auto){; + timeout = setTimeout(function(){ + animate("next",false); + },options.pause); + }; + + if(options.numeric) setCurrent(0); + + if(!options.continuous && options.controlsFade){ + $("a","#"+options.prevId).hide(); + $("a","#"+options.firstId).hide(); + }; + + }); + + }; + +})(jQuery); + + diff --git a/app/assets/javascripts/vendor/jquery.survival-kit.coffee b/app/assets/javascripts/vendor/jquery.survival-kit.coffee new file mode 100644 index 0000000..654e167 --- /dev/null +++ b/app/assets/javascripts/vendor/jquery.survival-kit.coffee @@ -0,0 +1,36 @@ +Array.prototype.empty = -> + if this.length <= 0 + return true + else + return false + +$.ns('sk').add { + # Search Box Helper + searchBox: -> + input = $('input.text', this) + default_mes = input.val() + input.focus(-> + if input.val() == default_mes + input.val '' + ).blur(-> + if input.val() == '' + input.val default_mes + ) + + # Simple Form Style Helper. + simpleForms: -> + max = 0 + labels = $("div:not(.boolean) > label", this) + hints = $("div:not(.boolean) > .hint", this) + labels.each -> + if $(this).width() > max + max = $(this).width() + $('> .hint.padded', this).css 'padding-left' : max + + # Get the horizontal-spacing (set on the css.) + horizontal_spacing = parseInt(labels.first().css('margin-right')) + + hints.css 'padding-left' : (max + horizontal_spacing) + $('.actions', this).css 'padding-left' : (max + horizontal_spacing) + labels.width(max) +} diff --git a/app/assets/javascripts/vendor/jquery.tmpl.js b/app/assets/javascripts/vendor/jquery.tmpl.js new file mode 100644 index 0000000..a819d61 --- /dev/null +++ b/app/assets/javascripts/vendor/jquery.tmpl.js @@ -0,0 +1,486 @@ +/* + * jQuery Templating Plugin + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + */ +(function( jQuery, undefined ){ + var oldManip = jQuery.fn.domManip, tmplItmAtt = "_tmplitem", htmlExpr = /^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /, + newTmplItems = {}, wrappedItems = {}, appendToTmplItems, topTmplItem = { key: 0, data: {} }, itemKey = 0, cloneIndex = 0, stack = []; + + function newTmplItem( options, parentItem, fn, data ) { + // Returns a template item data structure for a new rendered instance of a template (a 'template item'). + // The content field is a hierarchical array of strings and nested items (to be + // removed and replaced by nodes field of dom elements, once inserted in DOM). + var newItem = { + data: data || (parentItem ? parentItem.data : {}), + _wrap: parentItem ? parentItem._wrap : null, + tmpl: null, + parent: parentItem || null, + nodes: [], + calls: tiCalls, + nest: tiNest, + wrap: tiWrap, + html: tiHtml, + update: tiUpdate + }; + if ( options ) { + jQuery.extend( newItem, options, { nodes: [], parent: parentItem } ); + } + if ( fn ) { + // Build the hierarchical content to be used during insertion into DOM + newItem.tmpl = fn; + newItem._ctnt = newItem._ctnt || newItem.tmpl( jQuery, newItem ); + newItem.key = ++itemKey; + // Keep track of new template item, until it is stored as jQuery Data on DOM element + (stack.length ? wrappedItems : newTmplItems)[itemKey] = newItem; + } + return newItem; + } + + // Override appendTo etc., in order to provide support for targeting multiple elements. (This code would disappear if integrated in jquery core). + jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" + }, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var ret = [], insert = jQuery( selector ), elems, i, l, tmplItems, + parent = this.length === 1 && this[0].parentNode; + + appendToTmplItems = newTmplItems || {}; + if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) { + insert[ original ]( this[0] ); + ret = this; + } else { + for ( i = 0, l = insert.length; i < l; i++ ) { + cloneIndex = i; + elems = (i > 0 ? this.clone(true) : this).get(); + jQuery.fn[ original ].apply( jQuery(insert[i]), elems ); + ret = ret.concat( elems ); + } + cloneIndex = 0; + ret = this.pushStack( ret, name, insert.selector ); + } + tmplItems = appendToTmplItems; + appendToTmplItems = null; + jQuery.tmpl.complete( tmplItems ); + return ret; + }; + }); + + jQuery.fn.extend({ + // Use first wrapped element as template markup. + // Return wrapped set of template items, obtained by rendering template against data. + tmpl: function( data, options, parentItem ) { + return jQuery.tmpl( this[0], data, options, parentItem ); + }, + + // Find which rendered template item the first wrapped DOM element belongs to + tmplItem: function() { + return jQuery.tmplItem( this[0] ); + }, + + // Consider the first wrapped element as a template declaration, and get the compiled template or store it as a named template. + template: function( name ) { + return jQuery.template( name, this[0] ); + }, + + domManip: function( args, table, callback, options ) { + // This appears to be a bug in the appendTo, etc. implementation + // it should be doing .call() instead of .apply(). See #6227 + if ( args[0] && args[0].nodeType ) { + var dmArgs = jQuery.makeArray( arguments ), argsLength = args.length, i = 0, tmplItem; + while ( i < argsLength && !(tmplItem = jQuery.data( args[i++], "tmplItem" ))) {} + if ( argsLength > 1 ) { + dmArgs[0] = [jQuery.makeArray( args )]; + } + if ( tmplItem && cloneIndex ) { + dmArgs[2] = function( fragClone ) { + // Handler called by oldManip when rendered template has been inserted into DOM. + jQuery.tmpl.afterManip( this, fragClone, callback ); + }; + } + oldManip.apply( this, dmArgs ); + } else { + oldManip.apply( this, arguments ); + } + cloneIndex = 0; + if ( !appendToTmplItems ) { + jQuery.tmpl.complete( newTmplItems ); + } + return this; + } + }); + + jQuery.extend({ + // Return wrapped set of template items, obtained by rendering template against data. + tmpl: function( tmpl, data, options, parentItem ) { + var ret, topLevel = !parentItem; + if ( topLevel ) { + // This is a top-level tmpl call (not from a nested template using {{tmpl}}) + parentItem = topTmplItem; + tmpl = jQuery.template[tmpl] || jQuery.template( null, tmpl ); + wrappedItems = {}; // Any wrapped items will be rebuilt, since this is top level + } else if ( !tmpl ) { + // The template item is already associated with DOM - this is a refresh. + // Re-evaluate rendered template for the parentItem + tmpl = parentItem.tmpl; + newTmplItems[parentItem.key] = parentItem; + parentItem.nodes = []; + if ( parentItem.wrapped ) { + updateWrapped( parentItem, parentItem.wrapped ); + } + // Rebuild, without creating a new template item + return jQuery( build( parentItem, null, parentItem.tmpl( jQuery, parentItem ) )); + } + if ( !tmpl ) { + return []; // Could throw... + } + if ( typeof data === "function" ) { + data = data.call( parentItem || {} ); + } + if ( options && options.wrapped ) { + updateWrapped( options, options.wrapped ); + } + ret = jQuery.isArray( data ) ? + jQuery.map( data, function( dataItem ) { + return dataItem ? newTmplItem( options, parentItem, tmpl, dataItem ) : null; + }) : + [ newTmplItem( options, parentItem, tmpl, data ) ]; + return topLevel ? jQuery( build( parentItem, null, ret ) ) : ret; + }, + + // Return rendered template item for an element. + tmplItem: function( elem ) { + var tmplItem; + if ( elem instanceof jQuery ) { + elem = elem[0]; + } + while ( elem && elem.nodeType === 1 && !(tmplItem = jQuery.data( elem, "tmplItem" )) && (elem = elem.parentNode) ) {} + return tmplItem || topTmplItem; + }, + + // Set: + // Use $.template( name, tmpl ) to cache a named template, + // where tmpl is a template string, a script element or a jQuery instance wrapping a script element, etc. + // Use $( "selector" ).template( name ) to provide access by name to a script block template declaration. + + // Get: + // Use $.template( name ) to access a cached template. + // Also $( selectorToScriptBlock ).template(), or $.template( null, templateString ) + // will return the compiled template, without adding a name reference. + // If templateString includes at least one HTML tag, $.template( templateString ) is equivalent + // to $.template( null, templateString ) + template: function( name, tmpl ) { + if (tmpl) { + // Compile template and associate with name + if ( typeof tmpl === "string" ) { + // This is an HTML string being passed directly in. + tmpl = buildTmplFn( tmpl ) + } else if ( tmpl instanceof jQuery ) { + tmpl = tmpl[0] || {}; + } + if ( tmpl.nodeType ) { + // If this is a template block, use cached copy, or generate tmpl function and cache. + tmpl = jQuery.data( tmpl, "tmpl" ) || jQuery.data( tmpl, "tmpl", buildTmplFn( tmpl.innerHTML )); + } + return typeof name === "string" ? (jQuery.template[name] = tmpl) : tmpl; + } + // Return named compiled template + return name ? (typeof name !== "string" ? jQuery.template( null, name ): + (jQuery.template[name] || + // If not in map, treat as a selector. (If integrated with core, use quickExpr.exec) + jQuery.template( null, htmlExpr.test( name ) ? name : jQuery( name )))) : null; + }, + + encode: function( text ) { + // Do HTML encoding replacing < > & and ' and " by corresponding entities. + return ("" + text).split("<").join("<").split(">").join(">").split('"').join(""").split("'").join("'"); + } + }); + + jQuery.extend( jQuery.tmpl, { + tag: { + "tmpl": { + _default: { $2: "null" }, + open: "if($notnull_1){_=_.concat($item.nest($1,$2));}" + // tmpl target parameter can be of type function, so use $1, not $1a (so not auto detection of functions) + // This means that {{tmpl foo}} treats foo as a template (which IS a function). + // Explicit parens can be used if foo is a function that returns a template: {{tmpl foo()}}. + }, + "wrap": { + _default: { $2: "null" }, + open: "$item.calls(_,$1,$2);_=[];", + close: "call=$item.calls();_=call._.concat($item.wrap(call,_));" + }, + "each": { + _default: { $2: "$index, $value" }, + open: "if($notnull_1){$.each($1a,function($2){with(this){", + close: "}});}" + }, + "if": { + open: "if(($notnull_1) && $1a){", + close: "}" + }, + "else": { + _default: { $1: "true" }, + open: "}else if(($notnull_1) && $1a){" + }, + "html": { + // Unecoded expression evaluation. + open: "if($notnull_1){_.push($1a);}" + }, + "=": { + // Encoded expression evaluation. Abbreviated form is ${}. + _default: { $1: "$data" }, + open: "if($notnull_1){_.push($.encode($1a));}" + }, + "!": { + // Comment tag. Skipped by parser + open: "" + } + }, + + // This stub can be overridden, e.g. in jquery.tmplPlus for providing rendered events + complete: function( items ) { + newTmplItems = {}; + }, + + // Call this from code which overrides domManip, or equivalent + // Manage cloning/storing template items etc. + afterManip: function afterManip( elem, fragClone, callback ) { + // Provides cloned fragment ready for fixup prior to and after insertion into DOM + var content = fragClone.nodeType === 11 ? + jQuery.makeArray(fragClone.childNodes) : + fragClone.nodeType === 1 ? [fragClone] : []; + + // Return fragment to original caller (e.g. append) for DOM insertion + callback.call( elem, fragClone ); + + // Fragment has been inserted:- Add inserted nodes to tmplItem data structure. Replace inserted element annotations by jQuery.data. + storeTmplItems( content ); + cloneIndex++; + } + }); + + //========================== Private helper functions, used by code above ========================== + + function build( tmplItem, nested, content ) { + // Convert hierarchical content into flat string array + // and finally return array of fragments ready for DOM insertion + var frag, ret = content ? jQuery.map( content, function( item ) { + return (typeof item === "string") ? + // Insert template item annotations, to be converted to jQuery.data( "tmplItem" ) when elems are inserted into DOM. + (tmplItem.key ? item.replace( /(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g, "$1 " + tmplItmAtt + "=\"" + tmplItem.key + "\" $2" ) : item) : + // This is a child template item. Build nested template. + build( item, tmplItem, item._ctnt ); + }) : + // If content is not defined, insert tmplItem directly. Not a template item. May be a string, or a string array, e.g. from {{html $item.html()}}. + tmplItem; + if ( nested ) { + return ret; + } + + // top-level template + ret = ret.join(""); + + // Support templates which have initial or final text nodes, or consist only of text + // Also support HTML entities within the HTML markup. + ret.replace( /^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/, function( all, before, middle, after) { + frag = jQuery( middle ).get(); + + storeTmplItems( frag ); + if ( before ) { + frag = unencode( before ).concat(frag); + } + if ( after ) { + frag = frag.concat(unencode( after )); + } + }); + return frag ? frag : unencode( ret ); + } + + function unencode( text ) { + // Use createElement, since createTextNode will not render HTML entities correctly + var el = document.createElement( "div" ); + el.innerHTML = text; + return jQuery.makeArray(el.childNodes); + } + + // Generate a reusable function that will serve to render a template against data + function buildTmplFn( markup ) { + return new Function("jQuery","$item", + "var $=jQuery,call,_=[],$data=$item.data;" + + + // Introduce the data as local variables using with(){} + "with($data){_.push('" + + + // Convert the template into pure JavaScript + jQuery.trim(markup) + .replace( /([\\'])/g, "\\$1" ) + .replace( /[\r\t\n]/g, " " ) + .replace( /\$\{([^\}]*)\}/g, "{{= $1}}" ) + .replace( /\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g, + function( all, slash, type, fnargs, target, parens, args ) { + var tag = jQuery.tmpl.tag[ type ], def, expr, exprAutoFnDetect; + if ( !tag ) { + throw "Template command not found: " + type; + } + def = tag._default || []; + if ( parens && !/\w$/.test(target)) { + target += parens; + parens = ""; + } + if ( target ) { + target = unescape( target ); + args = args ? ("," + unescape( args ) + ")") : (parens ? ")" : ""); + // Support for target being things like a.toLowerCase(); + // In that case don't call with template item as 'this' pointer. Just evaluate... + expr = parens ? (target.indexOf(".") > -1 ? target + parens : ("(" + target + ").call($item" + args)) : target; + exprAutoFnDetect = parens ? expr : "(typeof(" + target + ")==='function'?(" + target + ").call($item):(" + target + "))"; + } else { + exprAutoFnDetect = expr = def.$1 || "null"; + } + fnargs = unescape( fnargs ); + return "');" + + tag[ slash ? "close" : "open" ] + .split( "$notnull_1" ).join( target ? "typeof(" + target + ")!=='undefined' && (" + target + ")!=null" : "true" ) + .split( "$1a" ).join( exprAutoFnDetect ) + .split( "$1" ).join( expr ) + .split( "$2" ).join( fnargs ? + fnargs.replace( /\s*([^\(]+)\s*(\((.*?)\))?/g, function( all, name, parens, params ) { + params = params ? ("," + params + ")") : (parens ? ")" : ""); + return params ? ("(" + name + ").call($item" + params) : all; + }) + : (def.$2||"") + ) + + "_.push('"; + }) + + "');}return _;" + ); + } + function updateWrapped( options, wrapped ) { + // Build the wrapped content. + options._wrap = build( options, true, + // Suport imperative scenario in which options.wrapped can be set to a selector or an HTML string. + jQuery.isArray( wrapped ) ? wrapped : [htmlExpr.test( wrapped ) ? wrapped : jQuery( wrapped ).html()] + ).join(""); + } + + function unescape( args ) { + return args ? args.replace( /\\'/g, "'").replace(/\\\\/g, "\\" ) : null; + } + function outerHtml( elem ) { + var div = document.createElement("div"); + div.appendChild( elem.cloneNode(true) ); + return div.innerHTML; + } + + // Store template items in jQuery.data(), ensuring a unique tmplItem data data structure for each rendered template instance. + function storeTmplItems( content ) { + var keySuffix = "_" + cloneIndex, elem, elems, newClonedItems = {}, i, l, m; + for ( i = 0, l = content.length; i < l; i++ ) { + if ( (elem = content[i]).nodeType !== 1 ) { + continue; + } + elems = elem.getElementsByTagName("*"); + for ( m = elems.length - 1; m >= 0; m-- ) { + processItemKey( elems[m] ); + } + processItemKey( elem ); + } + function processItemKey( el ) { + var pntKey, pntNode = el, pntItem, tmplItem, key; + // Ensure that each rendered template inserted into the DOM has its own template item, + if ( (key = el.getAttribute( tmplItmAtt ))) { + while ( pntNode.parentNode && (pntNode = pntNode.parentNode).nodeType === 1 && !(pntKey = pntNode.getAttribute( tmplItmAtt ))) { } + if ( pntKey !== key ) { + // The next ancestor with a _tmplitem expando is on a different key than this one. + // So this is a top-level element within this template item + // Set pntNode to the key of the parentNode, or to 0 if pntNode.parentNode is null, or pntNode is a fragment. + pntNode = pntNode.parentNode ? (pntNode.nodeType === 11 ? 0 : (pntNode.getAttribute( tmplItmAtt ) || 0)) : 0; + if ( !(tmplItem = newTmplItems[key]) ) { + // The item is for wrapped content, and was copied from the temporary parent wrappedItem. + tmplItem = wrappedItems[key]; + tmplItem = newTmplItem( tmplItem, newTmplItems[pntNode]||wrappedItems[pntNode], null, true ); + tmplItem.key = ++itemKey; + newTmplItems[itemKey] = tmplItem; + } + if ( cloneIndex ) { + cloneTmplItem( key ); + } + } + el.removeAttribute( tmplItmAtt ); + } else if ( cloneIndex && (tmplItem = jQuery.data( el, "tmplItem" )) ) { + // This was a rendered element, cloned during append or appendTo etc. + // TmplItem stored in jQuery data has already been cloned in cloneCopyEvent. We must replace it with a fresh cloned tmplItem. + cloneTmplItem( tmplItem.key ); + newTmplItems[tmplItem.key] = tmplItem; + pntNode = jQuery.data( el.parentNode, "tmplItem" ); + pntNode = pntNode ? pntNode.key : 0; + } + if ( tmplItem ) { + pntItem = tmplItem; + // Find the template item of the parent element. + // (Using !=, not !==, since pntItem.key is number, and pntNode may be a string) + while ( pntItem && pntItem.key != pntNode ) { + // Add this element as a top-level node for this rendered template item, as well as for any + // ancestor items between this item and the item of its parent element + pntItem.nodes.push( el ); + pntItem = pntItem.parent; + } + // Delete content built during rendering - reduce API surface area and memory use, and avoid exposing of stale data after rendering... + delete tmplItem._ctnt; + delete tmplItem._wrap; + // Store template item as jQuery data on the element + jQuery.data( el, "tmplItem", tmplItem ); + } + function cloneTmplItem( key ) { + key = key + keySuffix; + tmplItem = newClonedItems[key] = + (newClonedItems[key] || newTmplItem( tmplItem, newTmplItems[tmplItem.parent.key + keySuffix] || tmplItem.parent, null, true )); + } + } + } + + //---- Helper functions for template item ---- + + function tiCalls( content, tmpl, data, options ) { + if ( !content ) { + return stack.pop(); + } + stack.push({ _: content, tmpl: tmpl, item:this, data: data, options: options }); + } + + function tiNest( tmpl, data, options ) { + // nested template, using {{tmpl}} tag + return jQuery.tmpl( jQuery.template( tmpl ), data, options, this ); + } + + function tiWrap( call, wrapped ) { + // nested template, using {{wrap}} tag + var options = call.options || {}; + options.wrapped = wrapped; + // Apply the template, which may incorporate wrapped content, + return jQuery.tmpl( jQuery.template( call.tmpl ), call.data, options, call.item ); + } + + function tiHtml( filter, textOnly ) { + var wrapped = this._wrap; + return jQuery.map( + jQuery( jQuery.isArray( wrapped ) ? wrapped.join("") : wrapped ).filter( filter || "*" ), + function(e) { + return textOnly ? + e.innerText || e.textContent : + e.outerHTML || outerHtml(e); + }); + } + + function tiUpdate() { + var coll = this.nodes; + jQuery.tmpl( null, null, null, this).insertBefore( coll[0] ); + jQuery( coll ).remove(); + } +})( jQuery ); \ No newline at end of file diff --git a/app/assets/javascripts/vendor/modernizr-2.0.6.min.js b/app/assets/javascripts/vendor/modernizr-2.0.6.min.js new file mode 100755 index 0000000..52cd7e1 --- /dev/null +++ b/app/assets/javascripts/vendor/modernizr-2.0.6.min.js @@ -0,0 +1,1116 @@ +/*! + * Modernizr v2.0.6 + * http://www.modernizr.com + * + * Copyright (c) 2009-2011 Faruk Ates, Paul Irish, Alex Sexton + * Dual-licensed under the BSD or MIT licenses: www.modernizr.com/license/ + */ + +/* + * Modernizr tests which native CSS3 and HTML5 features are available in + * the current UA and makes the results available to you in two ways: + * as properties on a global Modernizr object, and as classes on the + * element. This information allows you to progressively enhance + * your pages with a granular level of control over the experience. + * + * Modernizr has an optional (not included) conditional resource loader + * called Modernizr.load(), based on Yepnope.js (yepnopejs.com). + * To get a build that includes Modernizr.load(), as well as choosing + * which tests to include, go to www.modernizr.com/download/ + * + * Authors Faruk Ates, Paul Irish, Alex Sexton, + * Contributors Ryan Seddon, Ben Alman + */ + +window.Modernizr = (function( window, document, undefined ) { + + var version = '2.0.6', + + Modernizr = {}, + + // option for enabling the HTML classes to be added + enableClasses = true, + + docElement = document.documentElement, + docHead = document.head || document.getElementsByTagName('head')[0], + + /** + * Create our "modernizr" element that we do most feature tests on. + */ + mod = 'modernizr', + modElem = document.createElement(mod), + mStyle = modElem.style, + + /** + * Create the input element for various Web Forms feature tests. + */ + inputElem = document.createElement('input'), + + smile = ':)', + + toString = Object.prototype.toString, + + // List of property values to set for css tests. See ticket #21 + prefixes = ' -webkit- -moz- -o- -ms- -khtml- '.split(' '), + + // Following spec is to expose vendor-specific style properties as: + // elem.style.WebkitBorderRadius + // and the following would be incorrect: + // elem.style.webkitBorderRadius + + // Webkit ghosts their properties in lowercase but Opera & Moz do not. + // Microsoft foregoes prefixes entirely <= IE8, but appears to + // use a lowercase `ms` instead of the correct `Ms` in IE9 + + // More here: http://github.com/Modernizr/Modernizr/issues/issue/21 + domPrefixes = 'Webkit Moz O ms Khtml'.split(' '), + + ns = {'svg': 'http://www.w3.org/2000/svg'}, + + tests = {}, + inputs = {}, + attrs = {}, + + classes = [], + + featureName, // used in testing loop + + + // Inject element with style element and some CSS rules + injectElementWithStyles = function( rule, callback, nodes, testnames ) { + + var style, ret, node, + div = document.createElement('div'); + + if ( parseInt(nodes, 10) ) { + // In order not to give false positives we create a node for each test + // This also allows the method to scale for unspecified uses + while ( nodes-- ) { + node = document.createElement('div'); + node.id = testnames ? testnames[nodes] : mod + (nodes + 1); + div.appendChild(node); + } + } + + // '].join(''); + div.id = mod; + div.innerHTML += style; + docElement.appendChild(div); + + ret = callback(div, rule); + div.parentNode.removeChild(div); + + return !!ret; + + }, + + + // adapted from matchMedia polyfill + // by Scott Jehl and Paul Irish + // gist.github.com/786768 + testMediaQuery = function( mq ) { + + if ( window.matchMedia ) { + return matchMedia(mq).matches; + } + + var bool; + + injectElementWithStyles('@media ' + mq + ' { #' + mod + ' { position: absolute; } }', function( node ) { + bool = (window.getComputedStyle ? + getComputedStyle(node, null) : + node.currentStyle)['position'] == 'absolute'; + }); + + return bool; + + }, + + + /** + * isEventSupported determines if a given element supports the given event + * function from http://yura.thinkweb2.com/isEventSupported/ + */ + isEventSupported = (function() { + + var TAGNAMES = { + 'select': 'input', 'change': 'input', + 'submit': 'form', 'reset': 'form', + 'error': 'img', 'load': 'img', 'abort': 'img' + }; + + function isEventSupported( eventName, element ) { + + element = element || document.createElement(TAGNAMES[eventName] || 'div'); + eventName = 'on' + eventName; + + // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize", whereas `in` "catches" those + var isSupported = eventName in element; + + if ( !isSupported ) { + // If it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element + if ( !element.setAttribute ) { + element = document.createElement('div'); + } + if ( element.setAttribute && element.removeAttribute ) { + element.setAttribute(eventName, ''); + isSupported = is(element[eventName], 'function'); + + // If property was created, "remove it" (by setting value to `undefined`) + if ( !is(element[eventName], undefined) ) { + element[eventName] = undefined; + } + element.removeAttribute(eventName); + } + } + + element = null; + return isSupported; + } + return isEventSupported; + })(); + + // hasOwnProperty shim by kangax needed for Safari 2.0 support + var _hasOwnProperty = ({}).hasOwnProperty, hasOwnProperty; + if ( !is(_hasOwnProperty, undefined) && !is(_hasOwnProperty.call, undefined) ) { + hasOwnProperty = function (object, property) { + return _hasOwnProperty.call(object, property); + }; + } + else { + hasOwnProperty = function (object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */ + return ((property in object) && is(object.constructor.prototype[property], undefined)); + }; + } + + /** + * setCss applies given styles to the Modernizr DOM node. + */ + function setCss( str ) { + mStyle.cssText = str; + } + + /** + * setCssAll extrapolates all vendor-specific css strings. + */ + function setCssAll( str1, str2 ) { + return setCss(prefixes.join(str1 + ';') + ( str2 || '' )); + } + + /** + * is returns a boolean for if typeof obj is exactly type. + */ + function is( obj, type ) { + return typeof obj === type; + } + + /** + * contains returns a boolean for if substr is found within str. + */ + function contains( str, substr ) { + return !!~('' + str).indexOf(substr); + } + + /** + * testProps is a generic CSS / DOM property test; if a browser supports + * a certain property, it won't return undefined for it. + * A supported CSS property returns empty string when its not yet set. + */ + function testProps( props, prefixed ) { + for ( var i in props ) { + if ( mStyle[ props[i] ] !== undefined ) { + return prefixed == 'pfx' ? props[i] : true; + } + } + return false; + } + + /** + * testPropsAll tests a list of DOM properties we want to check against. + * We specify literally ALL possible (known and/or likely) properties on + * the element including the non-vendor prefixed one, for forward- + * compatibility. + */ + function testPropsAll( prop, prefixed ) { + + var ucProp = prop.charAt(0).toUpperCase() + prop.substr(1), + props = (prop + ' ' + domPrefixes.join(ucProp + ' ') + ucProp).split(' '); + + return testProps(props, prefixed); + } + + /** + * testBundle tests a list of CSS features that require element and style injection. + * By bundling them together we can reduce the need to touch the DOM multiple times. + */ + /*>>testBundle*/ + var testBundle = (function( styles, tests ) { + var style = styles.join(''), + len = tests.length; + + injectElementWithStyles(style, function( node, rule ) { + var style = document.styleSheets[document.styleSheets.length - 1], + // IE8 will bork if you create a custom build that excludes both fontface and generatedcontent tests. + // So we check for cssRules and that there is a rule available + // More here: https://github.com/Modernizr/Modernizr/issues/288 & https://github.com/Modernizr/Modernizr/issues/293 + cssText = style.cssRules && style.cssRules[0] ? style.cssRules[0].cssText : style.cssText || "", + children = node.childNodes, hash = {}; + + while ( len-- ) { + hash[children[len].id] = children[len]; + } + + /*>>touch*/ Modernizr['touch'] = ('ontouchstart' in window) || hash['touch'].offsetTop === 9; /*>>touch*/ + /*>>csstransforms3d*/ Modernizr['csstransforms3d'] = hash['csstransforms3d'].offsetLeft === 9; /*>>csstransforms3d*/ + /*>>generatedcontent*/Modernizr['generatedcontent'] = hash['generatedcontent'].offsetHeight >= 1; /*>>generatedcontent*/ + /*>>fontface*/ Modernizr['fontface'] = /src/i.test(cssText) && + cssText.indexOf(rule.split(' ')[0]) === 0; /*>>fontface*/ + }, len, tests); + + })([ + // Pass in styles to be injected into document + /*>>fontface*/ '@font-face {font-family:"font";src:url("https://")}' /*>>fontface*/ + + /*>>touch*/ ,['@media (',prefixes.join('touch-enabled),('),mod,')', + '{#touch{top:9px;position:absolute}}'].join('') /*>>touch*/ + + /*>>csstransforms3d*/ ,['@media (',prefixes.join('transform-3d),('),mod,')', + '{#csstransforms3d{left:9px;position:absolute}}'].join('')/*>>csstransforms3d*/ + + /*>>generatedcontent*/,['#generatedcontent:after{content:"',smile,'";visibility:hidden}'].join('') /*>>generatedcontent*/ + ], + [ + /*>>fontface*/ 'fontface' /*>>fontface*/ + /*>>touch*/ ,'touch' /*>>touch*/ + /*>>csstransforms3d*/ ,'csstransforms3d' /*>>csstransforms3d*/ + /*>>generatedcontent*/,'generatedcontent' /*>>generatedcontent*/ + + ]);/*>>testBundle*/ + + + /** + * Tests + * ----- + */ + + tests['flexbox'] = function() { + /** + * setPrefixedValueCSS sets the property of a specified element + * adding vendor prefixes to the VALUE of the property. + * @param {Element} element + * @param {string} property The property name. This will not be prefixed. + * @param {string} value The value of the property. This WILL be prefixed. + * @param {string=} extra Additional CSS to append unmodified to the end of + * the CSS string. + */ + function setPrefixedValueCSS( element, property, value, extra ) { + property += ':'; + element.style.cssText = (property + prefixes.join(value + ';' + property)).slice(0, -property.length) + (extra || ''); + } + + /** + * setPrefixedPropertyCSS sets the property of a specified element + * adding vendor prefixes to the NAME of the property. + * @param {Element} element + * @param {string} property The property name. This WILL be prefixed. + * @param {string} value The value of the property. This will not be prefixed. + * @param {string=} extra Additional CSS to append unmodified to the end of + * the CSS string. + */ + function setPrefixedPropertyCSS( element, property, value, extra ) { + element.style.cssText = prefixes.join(property + ':' + value + ';') + (extra || ''); + } + + var c = document.createElement('div'), + elem = document.createElement('div'); + + setPrefixedValueCSS(c, 'display', 'box', 'width:42px;padding:0;'); + setPrefixedPropertyCSS(elem, 'box-flex', '1', 'width:10px;'); + + c.appendChild(elem); + docElement.appendChild(c); + + var ret = elem.offsetWidth === 42; + + c.removeChild(elem); + docElement.removeChild(c); + + return ret; + }; + + // On the S60 and BB Storm, getContext exists, but always returns undefined + // http://github.com/Modernizr/Modernizr/issues/issue/97/ + + tests['canvas'] = function() { + var elem = document.createElement('canvas'); + return !!(elem.getContext && elem.getContext('2d')); + }; + + tests['canvastext'] = function() { + return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function')); + }; + + // This WebGL test may false positive. + // But really it's quite impossible to know whether webgl will succeed until after you create the context. + // You might have hardware that can support a 100x100 webgl canvas, but will not support a 1000x1000 webgl + // canvas. So this feature inference is weak, but intentionally so. + + // It is known to false positive in FF4 with certain hardware and the iPad 2. + + tests['webgl'] = function() { + return !!window.WebGLRenderingContext; + }; + + /* + * The Modernizr.touch test only indicates if the browser supports + * touch events, which does not necessarily reflect a touchscreen + * device, as evidenced by tablets running Windows 7 or, alas, + * the Palm Pre / WebOS (touch) phones. + * + * Additionally, Chrome (desktop) used to lie about its support on this, + * but that has since been rectified: http://crbug.com/36415 + * + * We also test for Firefox 4 Multitouch Support. + * + * For more info, see: http://modernizr.github.com/Modernizr/touch.html + */ + + tests['touch'] = function() { + return Modernizr['touch']; + }; + + /** + * geolocation tests for the new Geolocation API specification. + * This test is a standards compliant-only test; for more complete + * testing, including a Google Gears fallback, please see: + * http://code.google.com/p/geo-location-javascript/ + * or view a fallback solution using google's geo API: + * http://gist.github.com/366184 + */ + tests['geolocation'] = function() { + return !!navigator.geolocation; + }; + + // Per 1.6: + // This used to be Modernizr.crosswindowmessaging but the longer + // name has been deprecated in favor of a shorter and property-matching one. + // The old API is still available in 1.6, but as of 2.0 will throw a warning, + // and in the first release thereafter disappear entirely. + tests['postmessage'] = function() { + return !!window.postMessage; + }; + + // Web SQL database detection is tricky: + + // In chrome incognito mode, openDatabase is truthy, but using it will + // throw an exception: http://crbug.com/42380 + // We can create a dummy database, but there is no way to delete it afterwards. + + // Meanwhile, Safari users can get prompted on any database creation. + // If they do, any page with Modernizr will give them a prompt: + // http://github.com/Modernizr/Modernizr/issues/closed#issue/113 + + // We have chosen to allow the Chrome incognito false positive, so that Modernizr + // doesn't litter the web with these test databases. As a developer, you'll have + // to account for this gotcha yourself. + tests['websqldatabase'] = function() { + var result = !!window.openDatabase; + /* if (result){ + try { + result = !!openDatabase( mod + "testdb", "1.0", mod + "testdb", 2e4); + } catch(e) { + } + } */ + return result; + }; + + // Vendors had inconsistent prefixing with the experimental Indexed DB: + // - Webkit's implementation is accessible through webkitIndexedDB + // - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB + // For speed, we don't test the legacy (and beta-only) indexedDB + tests['indexedDB'] = function() { + for ( var i = -1, len = domPrefixes.length; ++i < len; ){ + if ( window[domPrefixes[i].toLowerCase() + 'IndexedDB'] ){ + return true; + } + } + return !!window.indexedDB; + }; + + // documentMode logic from YUI to filter out IE8 Compat Mode + // which false positives. + tests['hashchange'] = function() { + return isEventSupported('hashchange', window) && (document.documentMode === undefined || document.documentMode > 7); + }; + + // Per 1.6: + // This used to be Modernizr.historymanagement but the longer + // name has been deprecated in favor of a shorter and property-matching one. + // The old API is still available in 1.6, but as of 2.0 will throw a warning, + // and in the first release thereafter disappear entirely. + tests['history'] = function() { + return !!(window.history && history.pushState); + }; + + tests['draganddrop'] = function() { + return isEventSupported('dragstart') && isEventSupported('drop'); + }; + + // Mozilla is targeting to land MozWebSocket for FF6 + // bugzil.la/659324 + tests['websockets'] = function() { + for ( var i = -1, len = domPrefixes.length; ++i < len; ){ + if ( window[domPrefixes[i] + 'WebSocket'] ){ + return true; + } + } + return 'WebSocket' in window; + }; + + + // http://css-tricks.com/rgba-browser-support/ + tests['rgba'] = function() { + // Set an rgba() color and check the returned value + + setCss('background-color:rgba(150,255,150,.5)'); + + return contains(mStyle.backgroundColor, 'rgba'); + }; + + tests['hsla'] = function() { + // Same as rgba(), in fact, browsers re-map hsla() to rgba() internally, + // except IE9 who retains it as hsla + + setCss('background-color:hsla(120,40%,100%,.5)'); + + return contains(mStyle.backgroundColor, 'rgba') || contains(mStyle.backgroundColor, 'hsla'); + }; + + tests['multiplebgs'] = function() { + // Setting multiple images AND a color on the background shorthand property + // and then querying the style.background property value for the number of + // occurrences of "url(" is a reliable method for detecting ACTUAL support for this! + + setCss('background:url(https://),url(https://),red url(https://)'); + + // If the UA supports multiple backgrounds, there should be three occurrences + // of the string "url(" in the return value for elemStyle.background + + return /(url\s*\(.*?){3}/.test(mStyle.background); + }; + + + // In testing support for a given CSS property, it's legit to test: + // `elem.style[styleName] !== undefined` + // If the property is supported it will return an empty string, + // if unsupported it will return undefined. + + // We'll take advantage of this quick test and skip setting a style + // on our modernizr element, but instead just testing undefined vs + // empty string. + + + tests['backgroundsize'] = function() { + return testPropsAll('backgroundSize'); + }; + + tests['borderimage'] = function() { + return testPropsAll('borderImage'); + }; + + + // Super comprehensive table about all the unique implementations of + // border-radius: http://muddledramblings.com/table-of-css3-border-radius-compliance + + tests['borderradius'] = function() { + return testPropsAll('borderRadius'); + }; + + // WebOS unfortunately false positives on this test. + tests['boxshadow'] = function() { + return testPropsAll('boxShadow'); + }; + + // FF3.0 will false positive on this test + tests['textshadow'] = function() { + return document.createElement('div').style.textShadow === ''; + }; + + + tests['opacity'] = function() { + // Browsers that actually have CSS Opacity implemented have done so + // according to spec, which means their return values are within the + // range of [0.0,1.0] - including the leading zero. + + setCssAll('opacity:.55'); + + // The non-literal . in this regex is intentional: + // German Chrome returns this value as 0,55 + // https://github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632 + return /^0.55$/.test(mStyle.opacity); + }; + + + tests['cssanimations'] = function() { + return testPropsAll('animationName'); + }; + + + tests['csscolumns'] = function() { + return testPropsAll('columnCount'); + }; + + + tests['cssgradients'] = function() { + /** + * For CSS Gradients syntax, please see: + * http://webkit.org/blog/175/introducing-css-gradients/ + * https://developer.mozilla.org/en/CSS/-moz-linear-gradient + * https://developer.mozilla.org/en/CSS/-moz-radial-gradient + * http://dev.w3.org/csswg/css3-images/#gradients- + */ + + var str1 = 'background-image:', + str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));', + str3 = 'linear-gradient(left top,#9f9, white);'; + + setCss( + (str1 + prefixes.join(str2 + str1) + prefixes.join(str3 + str1)).slice(0, -str1.length) + ); + + return contains(mStyle.backgroundImage, 'gradient'); + }; + + + tests['cssreflections'] = function() { + return testPropsAll('boxReflect'); + }; + + + tests['csstransforms'] = function() { + return !!testProps(['transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform']); + }; + + + tests['csstransforms3d'] = function() { + + var ret = !!testProps(['perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective']); + + // Webkit’s 3D transforms are passed off to the browser's own graphics renderer. + // It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in + // some conditions. As a result, Webkit typically recognizes the syntax but + // will sometimes throw a false positive, thus we must do a more thorough check: + if ( ret && 'webkitPerspective' in docElement.style ) { + + // Webkit allows this media query to succeed only if the feature is enabled. + // `@media (transform-3d),(-o-transform-3d),(-moz-transform-3d),(-ms-transform-3d),(-webkit-transform-3d),(modernizr){ ... }` + ret = Modernizr['csstransforms3d']; + } + return ret; + }; + + + tests['csstransitions'] = function() { + return testPropsAll('transitionProperty'); + }; + + + /*>>fontface*/ + // @font-face detection routine by Diego Perini + // http://javascript.nwbox.com/CSSSupport/ + tests['fontface'] = function() { + return Modernizr['fontface']; + }; + /*>>fontface*/ + + // CSS generated content detection + tests['generatedcontent'] = function() { + return Modernizr['generatedcontent']; + }; + + + + // These tests evaluate support of the video/audio elements, as well as + // testing what types of content they support. + // + // We're using the Boolean constructor here, so that we can extend the value + // e.g. Modernizr.video // true + // Modernizr.video.ogg // 'probably' + // + // Codec values from : http://github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845 + // thx to NielsLeenheer and zcorpan + + // Note: in FF 3.5.1 and 3.5.0, "no" was a return value instead of empty string. + // Modernizr does not normalize for that. + + tests['video'] = function() { + var elem = document.createElement('video'), + bool = false; + + // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224 + try { + if ( bool = !!elem.canPlayType ) { + bool = new Boolean(bool); + bool.ogg = elem.canPlayType('video/ogg; codecs="theora"'); + + // Workaround required for IE9, which doesn't report video support without audio codec specified. + // bug 599718 @ msft connect + var h264 = 'video/mp4; codecs="avc1.42E01E'; + bool.h264 = elem.canPlayType(h264 + '"') || elem.canPlayType(h264 + ', mp4a.40.2"'); + + bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"'); + } + + } catch(e) { } + + return bool; + }; + + tests['audio'] = function() { + var elem = document.createElement('audio'), + bool = false; + + try { + if ( bool = !!elem.canPlayType ) { + bool = new Boolean(bool); + bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"'); + bool.mp3 = elem.canPlayType('audio/mpeg;'); + + // Mimetypes accepted: + // https://developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements + // http://bit.ly/iphoneoscodecs + bool.wav = elem.canPlayType('audio/wav; codecs="1"'); + bool.m4a = elem.canPlayType('audio/x-m4a;') || elem.canPlayType('audio/aac;'); + } + } catch(e) { } + + return bool; + }; + + + // Firefox has made these tests rather unfun. + + // In FF4, if disabled, window.localStorage should === null. + + // Normally, we could not test that directly and need to do a + // `('localStorage' in window) && ` test first because otherwise Firefox will + // throw http://bugzil.la/365772 if cookies are disabled + + // However, in Firefox 4 betas, if dom.storage.enabled == false, just mentioning + // the property will throw an exception. http://bugzil.la/599479 + // This looks to be fixed for FF4 Final. + + // Because we are forced to try/catch this, we'll go aggressive. + + // FWIW: IE8 Compat mode supports these features completely: + // http://www.quirksmode.org/dom/html5.html + // But IE8 doesn't support either with local files + + tests['localstorage'] = function() { + try { + return !!localStorage.getItem; + } catch(e) { + return false; + } + }; + + tests['sessionstorage'] = function() { + try { + return !!sessionStorage.getItem; + } catch(e){ + return false; + } + }; + + + tests['webworkers'] = function() { + return !!window.Worker; + }; + + + tests['applicationcache'] = function() { + return !!window.applicationCache; + }; + + + // Thanks to Erik Dahlstrom + tests['svg'] = function() { + return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect; + }; + + // specifically for SVG inline in HTML, not within XHTML + // test page: paulirish.com/demo/inline-svg + tests['inlinesvg'] = function() { + var div = document.createElement('div'); + div.innerHTML = ''; + return (div.firstChild && div.firstChild.namespaceURI) == ns.svg; + }; + + // Thanks to F1lt3r and lucideer, ticket #35 + tests['smil'] = function() { + return !!document.createElementNS && /SVG/.test(toString.call(document.createElementNS(ns.svg, 'animate'))); + }; + + tests['svgclippaths'] = function() { + // Possibly returns a false positive in Safari 3.2? + return !!document.createElementNS && /SVG/.test(toString.call(document.createElementNS(ns.svg, 'clipPath'))); + }; + + // input features and input types go directly onto the ret object, bypassing the tests loop. + // Hold this guy to execute in a moment. + function webforms() { + // Run through HTML5's new input attributes to see if the UA understands any. + // We're using f which is the element created early on + // Mike Taylr has created a comprehensive resource for testing these attributes + // when applied to all input types: + // http://miketaylr.com/code/input-type-attr.html + // spec: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary + + // Only input placeholder is tested while textarea's placeholder is not. + // Currently Safari 4 and Opera 11 have support only for the input placeholder + // Both tests are available in feature-detects/forms-placeholder.js + Modernizr['input'] = (function( props ) { + for ( var i = 0, len = props.length; i < len; i++ ) { + attrs[ props[i] ] = !!(props[i] in inputElem); + } + return attrs; + })('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' ')); + + // Run through HTML5's new input types to see if the UA understands any. + // This is put behind the tests runloop because it doesn't return a + // true/false like all the other tests; instead, it returns an object + // containing each input type with its corresponding true/false value + + // Big thanks to @miketaylr for the html5 forms expertise. http://miketaylr.com/ + Modernizr['inputtypes'] = (function(props) { + + for ( var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++ ) { + + inputElem.setAttribute('type', inputElemType = props[i]); + bool = inputElem.type !== 'text'; + + // We first check to see if the type we give it sticks.. + // If the type does, we feed it a textual value, which shouldn't be valid. + // If the value doesn't stick, we know there's input sanitization which infers a custom UI + if ( bool ) { + + inputElem.value = smile; + inputElem.style.cssText = 'position:absolute;visibility:hidden;'; + + if ( /^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined ) { + + docElement.appendChild(inputElem); + defaultView = document.defaultView; + + // Safari 2-4 allows the smiley as a value, despite making a slider + bool = defaultView.getComputedStyle && + defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' && + // Mobile android web browser has false positive, so must + // check the height to see if the widget is actually there. + (inputElem.offsetHeight !== 0); + + docElement.removeChild(inputElem); + + } else if ( /^(search|tel)$/.test(inputElemType) ){ + // Spec doesnt define any special parsing or detectable UI + // behaviors so we pass these through as true + + // Interestingly, opera fails the earlier test, so it doesn't + // even make it here. + + } else if ( /^(url|email)$/.test(inputElemType) ) { + // Real url and email support comes with prebaked validation. + bool = inputElem.checkValidity && inputElem.checkValidity() === false; + + } else if ( /^color$/.test(inputElemType) ) { + // chuck into DOM and force reflow for Opera bug in 11.00 + // github.com/Modernizr/Modernizr/issues#issue/159 + docElement.appendChild(inputElem); + docElement.offsetWidth; + bool = inputElem.value != smile; + docElement.removeChild(inputElem); + + } else { + // If the upgraded input compontent rejects the :) text, we got a winner + bool = inputElem.value != smile; + } + } + + inputs[ props[i] ] = !!bool; + } + return inputs; + })('search tel url email datetime date month week time datetime-local number range color'.split(' ')); + } + + + // End of test definitions + // ----------------------- + + + + // Run through all tests and detect their support in the current UA. + // todo: hypothetically we could be doing an array of tests and use a basic loop here. + for ( var feature in tests ) { + if ( hasOwnProperty(tests, feature) ) { + // run the test, throw the return value into the Modernizr, + // then based on that boolean, define an appropriate className + // and push it into an array of classes we'll join later. + featureName = feature.toLowerCase(); + Modernizr[featureName] = tests[feature](); + + classes.push((Modernizr[featureName] ? '' : 'no-') + featureName); + } + } + + // input tests need to run. + Modernizr.input || webforms(); + + + /** + * addTest allows the user to define their own feature tests + * the result will be added onto the Modernizr object, + * as well as an appropriate className set on the html element + * + * @param feature - String naming the feature + * @param test - Function returning true if feature is supported, false if not + */ + Modernizr.addTest = function ( feature, test ) { + if ( typeof feature == "object" ) { + for ( var key in feature ) { + if ( hasOwnProperty( feature, key ) ) { + Modernizr.addTest( key, feature[ key ] ); + } + } + } else { + + feature = feature.toLowerCase(); + + if ( Modernizr[feature] !== undefined ) { + // we're going to quit if you're trying to overwrite an existing test + // if we were to allow it, we'd do this: + // var re = new RegExp("\\b(no-)?" + feature + "\\b"); + // docElement.className = docElement.className.replace( re, '' ); + // but, no rly, stuff 'em. + return; + } + + test = typeof test == "boolean" ? test : !!test(); + + docElement.className += ' ' + (test ? '' : 'no-') + feature; + Modernizr[feature] = test; + + } + + return Modernizr; // allow chaining. + }; + + + // Reset modElem.cssText to nothing to reduce memory footprint. + setCss(''); + modElem = inputElem = null; + + //>>BEGIN IEPP + // Enable HTML 5 elements for styling (and printing) in IE. + if ( window.attachEvent && (function(){ var elem = document.createElement('div'); + elem.innerHTML = ''; + return elem.childNodes.length !== 1; })() ) { + + // iepp v2 by @jon_neal & afarkas : github.com/aFarkas/iepp/ + (function(win, doc) { + win.iepp = win.iepp || {}; + var iepp = win.iepp, + elems = iepp.html5elements || 'abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video', + elemsArr = elems.split('|'), + elemsArrLen = elemsArr.length, + elemRegExp = new RegExp('(^|\\s)('+elems+')', 'gi'), + tagRegExp = new RegExp('<(\/*)('+elems+')', 'gi'), + filterReg = /^\s*[\{\}]\s*$/, + ruleRegExp = new RegExp('(^|[^\\n]*?\\s)('+elems+')([^\\n]*)({[\\n\\w\\W]*?})', 'gi'), + docFrag = doc.createDocumentFragment(), + html = doc.documentElement, + head = html.firstChild, + bodyElem = doc.createElement('body'), + styleElem = doc.createElement('style'), + printMedias = /print|all/, + body; + function shim(doc) { + var a = -1; + while (++a < elemsArrLen) + // Use createElement so IE allows HTML5-named elements in a document + doc.createElement(elemsArr[a]); + } + + iepp.getCSS = function(styleSheetList, mediaType) { + if(styleSheetList+'' === undefined){return '';} + var a = -1, + len = styleSheetList.length, + styleSheet, + cssTextArr = []; + while (++a < len) { + styleSheet = styleSheetList[a]; + //currently no test for disabled/alternate stylesheets + if(styleSheet.disabled){continue;} + mediaType = styleSheet.media || mediaType; + // Get css from all non-screen stylesheets and their imports + if (printMedias.test(mediaType)) cssTextArr.push(iepp.getCSS(styleSheet.imports, mediaType), styleSheet.cssText); + //reset mediaType to all with every new *not imported* stylesheet + mediaType = 'all'; + } + return cssTextArr.join(''); + }; + + iepp.parseCSS = function(cssText) { + var cssTextArr = [], + rule; + while ((rule = ruleRegExp.exec(cssText)) != null){ + // Replace all html5 element references with iepp substitute classnames + cssTextArr.push(( (filterReg.exec(rule[1]) ? '\n' : rule[1]) +rule[2]+rule[3]).replace(elemRegExp, '$1.iepp_$2')+rule[4]); + } + return cssTextArr.join('\n'); + }; + + iepp.writeHTML = function() { + var a = -1; + body = body || doc.body; + while (++a < elemsArrLen) { + var nodeList = doc.getElementsByTagName(elemsArr[a]), + nodeListLen = nodeList.length, + b = -1; + while (++b < nodeListLen) + if (nodeList[b].className.indexOf('iepp_') < 0) + // Append iepp substitute classnames to all html5 elements + nodeList[b].className += ' iepp_'+elemsArr[a]; + } + docFrag.appendChild(body); + html.appendChild(bodyElem); + // Write iepp substitute print-safe document + bodyElem.className = body.className; + bodyElem.id = body.id; + // Replace HTML5 elements with which is print-safe and shouldn't conflict since it isn't part of html5 + bodyElem.innerHTML = body.innerHTML.replace(tagRegExp, '<$1font'); + }; + + + iepp._beforePrint = function() { + // Write iepp custom print CSS + styleElem.styleSheet.cssText = iepp.parseCSS(iepp.getCSS(doc.styleSheets, 'all')); + iepp.writeHTML(); + }; + + iepp.restoreHTML = function(){ + // Undo everything done in onbeforeprint + bodyElem.innerHTML = ''; + html.removeChild(bodyElem); + html.appendChild(body); + }; + + iepp._afterPrint = function(){ + // Undo everything done in onbeforeprint + iepp.restoreHTML(); + styleElem.styleSheet.cssText = ''; + }; + + + + // Shim the document and iepp fragment + shim(doc); + shim(docFrag); + + // + if(iepp.disablePP){return;} + + // Add iepp custom print style element + head.insertBefore(styleElem, head.firstChild); + styleElem.media = 'print'; + styleElem.className = 'iepp-printshim'; + win.attachEvent( + 'onbeforeprint', + iepp._beforePrint + ); + win.attachEvent( + 'onafterprint', + iepp._afterPrint + ); + })(window, document); + } + //>>END IEPP + + // Assign private properties to the return object with prefix + Modernizr._version = version; + + // expose these for the plugin API. Look in the source for how to join() them against your input + Modernizr._prefixes = prefixes; + Modernizr._domPrefixes = domPrefixes; + + // Modernizr.mq tests a given media query, live against the current state of the window + // A few important notes: + // * If a browser does not support media queries at all (eg. oldIE) the mq() will always return false + // * A max-width or orientation query will be evaluated against the current state, which may change later. + // * You must specify values. Eg. If you are testing support for the min-width media query use: + // Modernizr.mq('(min-width:0)') + // usage: + // Modernizr.mq('only screen and (max-width:768)') + Modernizr.mq = testMediaQuery; + + // Modernizr.hasEvent() detects support for a given event, with an optional element to test on + // Modernizr.hasEvent('gesturestart', elem) + Modernizr.hasEvent = isEventSupported; + + // Modernizr.testProp() investigates whether a given style property is recognized + // Note that the property names must be provided in the camelCase variant. + // Modernizr.testProp('pointerEvents') + Modernizr.testProp = function(prop){ + return testProps([prop]); + }; + + // Modernizr.testAllProps() investigates whether a given style property, + // or any of its vendor-prefixed variants, is recognized + // Note that the property names must be provided in the camelCase variant. + // Modernizr.testAllProps('boxSizing') + Modernizr.testAllProps = testPropsAll; + + + + // Modernizr.testStyles() allows you to add custom styles to the document and test an element afterwards + // Modernizr.testStyles('#modernizr { position:absolute }', function(elem, rule){ ... }) + Modernizr.testStyles = injectElementWithStyles; + + + // Modernizr.prefixed() returns the prefixed or nonprefixed property name variant of your input + // Modernizr.prefixed('boxSizing') // 'MozBoxSizing' + + // Properties must be passed as dom-style camelcase, rather than `box-sizing` hypentated style. + // Return values will also be the camelCase variant, if you need to translate that to hypenated style use: + // + // str.replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-'); + + // If you're trying to ascertain which transition end event to bind to, you might do something like... + // + // var transEndEventNames = { + // 'WebkitTransition' : 'webkitTransitionEnd', + // 'MozTransition' : 'transitionend', + // 'OTransition' : 'oTransitionEnd', + // 'msTransition' : 'msTransitionEnd', // maybe? + // 'transition' : 'transitionEnd' + // }, + // transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ]; + + Modernizr.prefixed = function(prop){ + return testPropsAll(prop, 'pfx'); + }; + + + + // Remove "no-js" class from element, if it exists: + docElement.className = docElement.className.replace(/\bno-js\b/, '') + + // Add the new classes to the element. + + (enableClasses ? ' js ' + classes.join(' ') : ''); + + return Modernizr; + +})(this, this.document); \ No newline at end of file diff --git a/app/assets/stylesheets/api/rows.css.scss b/app/assets/stylesheets/api/rows.css.scss new file mode 100644 index 0000000..4fad3d5 --- /dev/null +++ b/app/assets/stylesheets/api/rows.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the api/rows controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/app/layouts/_app.scss b/app/assets/stylesheets/app/layouts/_app.scss new file mode 100644 index 0000000..abbe8b1 --- /dev/null +++ b/app/assets/stylesheets/app/layouts/_app.scss @@ -0,0 +1,24 @@ +// Application Layout +// ---------------------------------------- +// TODO: This generates huge selectors.. +.app { + + #main { + @include center-container(1000px, 0, 0 8px); + @include clearfix; + @include debug(gray); + } + + $sidebar: 215px; + $content: 758px; + + .container { + & > aside { + @include float(left, $sidebar, green); + } + + & > .content { + @include float(right, $content, blue); + } + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/app/layouts/_conference.scss b/app/assets/stylesheets/app/layouts/_conference.scss new file mode 100644 index 0000000..18fb232 --- /dev/null +++ b/app/assets/stylesheets/app/layouts/_conference.scss @@ -0,0 +1,136 @@ +// Conference +// ---------------------------------------- + +// The Usual Box with Mute, Cross +.actor { + @include clearfix; + @include gradient(#FDFDFD, #EFEFEF); + @include size(auto, 50px,6px, 1px 0 1px 0); + border-bottom:1px solid #E3E3E8; + border-top:1px solid #FFF; + img { + @extend .ext-bradius-inner; + float:left; + margin-right:6px; + } + .info { + .name { + display:block; + font-size:size(15px); + width:188px; + } + .status { + color:#818181; + } + float:left; + } + .voice-actions { + float:right; + } +} + +// Audio Controls. +.voice-actions { + padding:10px 0; + text-align:right; + width:100px; + .make.speaker { + @include image-replace('icons/microphone-16x.png'); + display:inline-block; + } + .make.listener { + @include image-replace('icons/headphones-16x.png'); + display:inline-block; + } + + .voice { + &.muted { + @include image-replace('icons/mute-16x.png'); + display:inline-block; + } + &.unmuted { + @include image-replace('icons/unmute-16x.png'); + display:inline-block; + } + } + .remove { + @include image-replace('icons/cross-16x.png'); + display:inline-block; + } + a { + margin:0 5px; + opacity:0.6; + &:hover { opacity:1.0;} + } +} + + +.conference { + @include pie-clearfix(); + .panel { + @include box-shadow(1px 1px 0px #FFF inset, 1px 1px 1px #EDEDED); + background:#F7F7F7; + border:1px solid #E3E3E8; + float:left; + margin: 0 10px; + width: 303px; + &.speakers { + header { @include gradient(#FFF, #F3F3DE); } + h3 { background:transparent image-url('icons/microphone-32x.png') left top no-repeat; } + } + &.listeners { + header { @include gradient(#FFF, #DCEAF2); } + h3 { background:transparent image-url('icons/headphones-32x.png') left top no-repeat; } + } + &.log { + header { @include gradient(#FFF, #E7E7E7); } + h3 { background:transparent image-url('icons/clock-32x.png') left top no-repeat; } + } + } + .first { margin-left:0;} + .last { margin-right:0;} + header { + @include box-shadow(1px 1px 0px #FFF inset, 0px 1px 0px #FFF); + border-bottom:1px solid #E3E3E8; + padding:10px; + } + h3 { + font-size:size(24px); + font-weight:normal; + margin:0; + opacity:0.8; + padding:2px 2px 2px 43px; + } + .message { + @include gradient( #EEEEEE, #fff); + border-bottom:1px solid #E3E3E8; + padding:10px; + input { + @include input-effects; + @include size(283px, auto, 5px, 1px solid #E3E3E8 ); + color:#696969; + } + } + .actors, .messages { + height:290px; // This should be X times the amount of items + overflow:auto; + } +} + +.log { + .messages { + color:#484848; + div { + background:#FFF; + border-bottom:1px solid #E3E3E8; + border-top:1px solid #FFF; + padding:5px 10px; + } + .status { + background:#F5F5F5; + } + .name { + font-weight:bold; + } + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/app/layouts/_phone-book-entry.scss b/app/assets/stylesheets/app/layouts/_phone-book-entry.scss new file mode 100644 index 0000000..f9e2345 --- /dev/null +++ b/app/assets/stylesheets/app/layouts/_phone-book-entry.scss @@ -0,0 +1,176 @@ +// Phone Book Entry Show +// ---------------------------------------- +// Icons: http://www.iconfinder.com/search/?q=iconset%3Acc_mono_icon_set +//http://www.iconfinder.com/search/?q=iconset%3AHelveticons_Social +section.phone-book-entry { + @include clearfix; + a { + @include link-colors(#49494D, $link-color); + } + .sidebar { + @include size(220px, auto, none, 0 1px 0 0); + border-right:1px solid #E3E3E8; + float:left; + } + .content { + float:right; + width:716px; + + } + + .username { + font-size: 46px; + font-weight:normal; + margin: 0 0 10px 0; + } + .personal { + margin-top:5px; + span { + margin-right:10px; + padding-left:22px; + } + .nickname { + background:transparent image-url('icons/user-16x.png') left 1px no-repeat; + } + .birthday { + background:transparent image-url('icons/star-16x.png') left -1px no-repeat;; + } + } + + .work { + font-size: 18px; + } + + .tags { + background:transparent image-url('icons/tag-16x.png') left 0px no-repeat; + margin-top:10px; + padding-left:22px; + } + + + .activity { + & > h2 { + font-size: 27px; + font-weight: normal; + } + textarea { + border-color: #E3E3E8; + height: 15px; + padding: 12px; + width: 689px; + } + .entry { + @include clearfix; + background-position: 12px 9px; + border-bottom: 1px solid #E3E3E8; + font-size: 16px; + + padding: 12px 0px 15px 55px; + .motive { + + display: block; + float: left; + line-height: 25px; + width: 529px; + + } + .timestamp { + color: #929298; + float: right; + font-size: 12px; + line-height: 26px; + } + } + } + + + // Icons + .home { + background:transparent image-url('icons/house-32x.png') left 2px no-repeat; + } + .office { + background:transparent image-url('icons/suitcase-32x.png') left 2px no-repeat; + } + .cellphone { + background:transparent image-url('icons/phone-mobile-32x.png') left 2px no-repeat; + } + .phone { + background:transparent image-url('icons/phone-up-32x.png') left 2px no-repeat; + } + .phone-down { + background:transparent image-url('icons/phone-down-32x.png') left 2px no-repeat; + } + .fax { + background:transparent image-url('icons/fax-32x.png') left 2px no-repeat; + } + .skype { + background:transparent image-url('icons/skype-32x.png') left 2px no-repeat; + } + .twitter { + background:transparent image-url('icons/twitter-32x.png') left 2px no-repeat; + } + .voice-message { + background:transparent image-url('icons/mic-32x.png') left 2px no-repeat; + } + + + + .comment { + @include clearfix; + border-bottom:1px solid #E3E3E8; + padding: 11px; + .display { + float:left; + overflow:hidden; + } + .info { + margin-bottom:4px; + } + .info,.body { + padding-left:47px; + } + .commenter { + font-size: 17px; + font-weight: bold; + } + .time { + color:#929298; + } + .info { + display:block; + } + } + + + .display { + @include border-radius(10px 0 10px 0); + } + .description { + margin:10px 0; + } + .widget { + border-top:1px solid #E3E3E8; + padding:23px 0; + width:200px; // Width of the image + div { + margin:10px 0; + padding-left:51px; + a { + color:#4B4B4B; + display:block; + font-size:size(17px); + font-weight:bold; + } + span { + color:#E3E3E8; + font-size:size(12px); + } + } + + &.adresses { + strong { + display:block; + } + } + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/app/pages/_phone_book.scss b/app/assets/stylesheets/app/pages/_phone_book.scss new file mode 100644 index 0000000..3670e8e --- /dev/null +++ b/app/assets/stylesheets/app/pages/_phone_book.scss @@ -0,0 +1,25 @@ +header.tabular-nav { @extend .ext-bradius-t; } +footer.tabular-nav { @extend .ext-bradius-b; } + +.tabular-nav { + @include clearfix; + line-height: 41px; + padding: 0 14px; + @include gradient(#69ABFB, #75AAEC); + .pagination { + float:right; + } + nav { + float:left; + margin-top: 1px; + @include size(395px, auto); + ol { + @include inline-list; + a { + font-weight:bold; + color:#fff; + font-size: 14px; + } + } + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/app/shared/_contents.scss b/app/assets/stylesheets/app/shared/_contents.scss new file mode 100644 index 0000000..8f88802 --- /dev/null +++ b/app/assets/stylesheets/app/shared/_contents.scss @@ -0,0 +1,374 @@ +// Contents +// ----------------------------------------´ + +// Wrap Everything +#container { + margin:0 auto; + width:$site-total-width; +} + +// Global Layout. +#content { + @extend .ext-bradius; + @include gradient(#fff, #FAF9FA); + border:1px solid #C0C0CA; + .light { + @extend .ext-bradius; + border:1px solid #ECECEF; + padding:20px; + } +} + + +// Content Header Object +// ---------------------------------------- + +.breadcrumbs { + color:$border-dark-color; + font-size:size(12px); + margin-bottom: 5px; + a { + @include link-colors(#8A8A91, $link-hover-color, #8A8A91, #8A8A91); + } +} + +header.main { + border-bottom:1px solid $border-dark-color; + margin-bottom:20px; + h1,h2 { + color:#49494D; + margin-top:0px; + } +} + + +// Flash Notice Object +// ---------------------------------------- +.flash { + @extend .ext-bradius; + @include box-shadow(0px 1px 2px darken(#F0F0F3, 20%)); + font-weight:bold; + margin-bottom:$vertical-margin; + position:relative; + .sign { + $sign-height: 26px; + @include pos-y-center($sign-height); + font-family:Georgia; + font-size:23px; + height:$sign-height; + } + .light { + @extend .ext-texture; + background-position:left bottom; + padding:15px 21px; + } + .message { + line-height:18px; + padding-left:26px; + } + + &.notice, &.flash { + @include text-shadow(1px 1px 1px #EDF3FA); + background:#CCE4FF; + color:#37547B; + } + + &.warning, &.alert { + $border-bottom: #EE9C00; + $border-light:#EDCC37; + @include text-shadow(1px 1px 1px #FEF6D7); + background:#FFE070; + border:{ + bottom:1px solid $border-bottom; + top:1px solid lighten(saturate($border-light, 5%), 9%); + }; + color:#7A2300; + } +} + + +// Scaffolding Tables +// ---------------------------------------- +table { + th { + color: #6A747B; + font-size: 14px; + font-weight: bold; + padding: 10px 8px; + } + .odd { + background:#F4F6FB; + border-bottom:1px solid #EDEFF8; + } + td { + padding:8px; + } +} + + +// Pagination Object +// ---------------------------------------- +.pagination { @include pagination(); } + + +// Entries Object. +// ---------------------------------------- +header.entries-nav { @extend .ext-bradius-inner-t; } +footer.entries-nav { @extend .ext-bradius-inner-b; } + +.entries-nav { + @include box-shadow( + inset 0px 1px 0px #aad2ff, // Light Top + 0 -1px 0px #A3C9E7, // Shadow Top + inset 0 -1px 2px #518CBC // Shadow Bottom + ); + @include clearfix; + @include gradient(#69ABFB, #75AAEC); + line-height: 41px; + padding: 0 14px; + nav { + color:#5490C3; + float:left; + margin-top: 1px; + width:540px; + } + // ABC + ol { + @include inline-list; + a { + @include link-colors(#fff, #FFFFC2); + @include text-shadow(0 2px 0px #5D96CC); + font-size: 14px; + font-weight:bold; + padding:0 3px; + } + } + .pagination { + float:right; + } +} + + +// Phone Book Entry +// ---------------------------------------- + +// Title Extension +.ext-pbe-big { display:block; font-size:size(18px); font-weight:bold; } + +.phone-book-entries { + table { margin:0;} +} +// Listing Version +tr.phone-book-entry { + @include clearfix; + color:#7F7F7F; + td { + vertical-align:middle; + } + &.odd { + background:#F4F6FB; + border-bottom:1px solid #EDEFF8; + } + img { + opacity:0.8; + } + // All Link colors + a { + @include link-colors(#577DA2, $link-color); + } + .name { + @extend .ext-pbe-big; + } + .company { + font-size:size(16px); + } + .user { + @include size(34%); + } + .phone { + @extend .ext-pbe-big; + } + .contact { + @include size(28%); + } + .extra { + @include size(38%); + } +} + +// Call History Entry +// ---------------------------------------- + +.call-history-entries { + table { margin:0;} +} + +// Listing Version +tr.call-history-entry { + @include clearfix; + color:#7F7F7F; + td { + vertical-align:middle; + } + &.odd { + background:#F4F6FB; + border-bottom:1px solid #EDEFF8; + } + img { + opacity:0.8; + } + // All Link colors + a { + @include link-colors(#577DA2, $link-color); + } + .select_box { + @include size(2%); + } + .thumbnail { + @include size(5%); + } + .time { + @include size(15%); + } + .user { + @include size(45%); + } + .status { + @include size(15%); + } + .actions { + @include size(5%); + } + .name { + @extend .ext-pbe-big; + } + .phone { + @extend .ext-pbe-big; + } + .call-forwarded { + background:transparent image-url('icons/gs_forward_16x.png') no-repeat; + padding-left: 20px; + } + .call-placed { + background:transparent image-url('icons/gs_placed_16x.png') no-repeat; + padding-left: 20px; + } + .call-received { + background:transparent image-url('icons/gs_received_16x.png') no-repeat; + padding-left: 20px; + } + .call-missed { + background:transparent image-url('icons/gs_missed_16x.png') no-repeat; + padding-left: 20px; + } + .voicemail { + background:transparent image-url('icons/gs_envelope_16x.png') no-repeat; + padding-left: 20px; + } + .duration { + @extend .ext-pbe-big; + } +} + +// Voicemail Messages Entry +// ---------------------------------------- + +.voicemail-messages-entries { + table { margin:0;} +} + +// Listing Version +tr.voicemail-messages-entry { + @include clearfix; + color:#7F7F7F; + td { + vertical-align:middle; + } + &.odd { + background:#F4F6FB; + border-bottom:1px solid #EDEFF8; + } + img { + opacity:0.8; + } + // All Link colors + a { + @include link-colors(#577DA2, $link-color); + } + .select_box { + @include size(2%); + } + .time { + @include size(15%); + } + .folder { + @include size(10%); + } + .user { + @include size(40%); + } + .status { + @include size(5%); + } + .actions { + @include size(5%); + } + .name { + @extend .ext-pbe-big; + } + .phone { + @extend .ext-pbe-big; + } + .voicemail-received { + background:transparent image-url('icons/gs_received_16x.png') no-repeat; + padding-left: 20px; + } + .voicemail-read { + background:transparent image-url('icons/gs_envelope_16x.png') no-repeat; + padding-left: 20px; + } + .duration { + @extend .ext-pbe-big; + } +} + + +// users#show +// ---------------------------------------- +#user-show { + @include clearfix; + .display { + float:left; + } + aside { + float:left; + padding-top:5px; + width: 250px; + p { + margin-left:70+26px; + } + } + section { + float:right; + width:650px; + h2:first-child { + margin-top:0; + } + } +} + + +// Simple Form Error Messgaes +// ----------------------------------------´ +p.error_notification { + @include gradient(mix(#EB6565, #994F5D, 60%), #994F5D); + border: 1px solid #7B404A; + border-radius: 4px; + box-shadow: inset 1px 1px 0px darken(#f3a0a0, 10%),inset -1px -1px 0px darken(#eb6565, 3%); + color:#FFF; + font-weight: bold; + margin: 0 0 0 158px; + padding: 10px 15px; + text-shadow: 2px 2px 1px #82434E; + width: 282px; +} \ No newline at end of file diff --git a/app/assets/stylesheets/app/shared/_footers.scss b/app/assets/stylesheets/app/shared/_footers.scss new file mode 100644 index 0000000..be0f54f --- /dev/null +++ b/app/assets/stylesheets/app/shared/_footers.scss @@ -0,0 +1,90 @@ +// Footers +// ---------------------------------------- + +//@include sticky-footer(54px, "#container", "#footer-spacing", "footer"); + +footer#main { + @include clearfix; + position:relative; + margin:$vertical-margin 0; + @include gradient(#fff, #FAF9FA); + border:1px solid #C0C0CA; + @extend .ext-bradius; + .light { + padding:10px 20px; + border:1px solid #ECECEF; + @extend .ext-bradius; + } + + ul { + @include clearfix; + list-style:none; + float:left; + margin:0; + li { + float:left; + margin-bottom: 0px; + } + a { + @include debug; + line-height:43px; + padding: 10px 20px; + border:{ + left:1px solid $border-dark-color; + }; + } + li:first-child a{ + border-left:none; + } +// @include horizontal-navigation( +// /*$height : */ 32px, +// /*$color : */ red, +// /*$hover-color : */ red, +// /*$active-color : */ red, +// /*$text-shadow : */ #530008, +// /*$bg : */ none, +// /*$bg-hover : */ none, +// /*$bg-active : */ none, +// /*$box-shadow : */ none, +// /*$box-shadow-hover : */ none, +// /*$box-shadow-active : */ none, +// /*$border-light : */ #E3E3E8, +// /*$border-shadow : */ lighten(#E3E3E8,5%), +// /*$padding : */ 0 10px, +// /*$margin : */ none, +// /*\border-radius : */ none, +// /*$font-weight : */ none, +// /*$font-size : */ 14px, +// /*$tab-space : */ none +// ); + } + +} + +.amooma-logo { + background:#FAF9FA; + @include debug; + float:right; + padding:7px 7px 7px 16px; + @include border-radius(0 $global-border-radius $global-border-radius 0); + border-left:1px solid $border-dark-color; + @include box-shadow(-1px -1px 1px #FFFFFF); + a { + @include image-replace('amooma-logo.png'); + float:right; + opacity:0.6; + margin: 5px 5px 0 0; + &:hover { + opacity:1; + } + } + span { + @include debug; + font-size:11px; + color:#74748B; + float:left; + line-height:30px; + margin-right:10px; + } + +} \ No newline at end of file diff --git a/app/assets/stylesheets/app/shared/_handheld.scss b/app/assets/stylesheets/app/shared/_handheld.scss new file mode 100644 index 0000000..1efc5e9 --- /dev/null +++ b/app/assets/stylesheets/app/shared/_handheld.scss @@ -0,0 +1,25 @@ +// +// Media queries for responsive design. +// +// These follow after primary styles so they will successfully override. +// + +@media all and (orientation:portrait) { + // Style adjustments for portrait mode goes here + +} + +@media all and (orientation:landscape) { + // Style adjustments for landscape mode goes here + +} + +// Grade-A Mobile Browsers (Opera Mobile, Mobile Safari, Android Chrome) +// consider this: www.cloudfour.com/css-media-query-for-mobile-is-fools-gold/ +@media screen and (max-device-width: 480px) { + + + // Uncomment if you don't want iOS and WinMobile to mobile-optimize the text for you: j.mp/textsizeadjust + // html { -webkit-text-size-adjust:none; -ms-text-size-adjust:none; } +} + diff --git a/app/assets/stylesheets/app/shared/_headers.scss b/app/assets/stylesheets/app/shared/_headers.scss new file mode 100644 index 0000000..6f8f0fe --- /dev/null +++ b/app/assets/stylesheets/app/shared/_headers.scss @@ -0,0 +1,145 @@ +// Headers +// ---------------------------------------- + +// -- File Variables ---------------------- + +$border-light:#74B8EA; +$background: #F0F0F3; +$user-context-width:227px; + + +// ---------------------------------------- + +.ext-texture { + background:transparent image-url('gradients/white-texture-x63.png') left top repeat-x; +} + +.ext-header { + max-width:$site-total-width - 2px; // Minus the borders + height:63px; + @extend .ext-bradius; +} + + +// Header Object +// ---------------------------------------- + +header#main { + @extend .ext-header; + background:$background image-url('gradients/light-to-dark-blue-x63.png') left top repeat-x; + margin:$vertical-margin 0; + border:1px solid $border-light; + border-bottom:1px solid #518CBC; + border-top:1px solid lighten(saturate($border-light, 5%), 9%); + @include box-shadow(0px 1px 2px darken(#F0F0F3, 20%)); + position:relative; + overflow:hidden; + .light { + @extend .ext-header; + @extend .ext-texture; + height:62px; + border-bottom:1px solid $border-light; + + // Used as a spacer for the width + padding:0 $user-context-width 0 0; + } + + // Resizable Navigation Items. + span { + @include debug; + float:left; + margin-left:15px; + font-size:size(17px); + line-height:62px; + display:inline; + float:left; + margin-right:7px; + } + + .message { + margin-left:206px; + } + + a { + @include text-shadow(1px 1px 0px darken(#518CBC, 12%)); + color:#fff; + &:active, &:hover { + color:#FFFF70; + text-decoration:none; + } + } +} + +// User Context Object +// ---------------------------------------- + +.user-context { + @include pos(0 10px); + @include size(200px); + padding-left:12px; + text-align:center; + font-size:size(17px); + line-height:62px; + color:#DDDDDD; + border-left:1px solid $border-light; + @include box-shadow(-1px -1px 0px #3A91DE); + // Logged out version of this little guy. + .display { + @extend .ext-bradius-inner; + @include box-shadow(0 -1px 0px #518CBC, 0 1px 0 #74B8EA); + vertical-align: middle; + margin: -2px 7px 0 0; + } + .logged-out { + @include box-shadow(none); + } + .user { + width: 170px; + display: block; + text-align:left; + } + .logout { + display: block; + position: absolute; + top: 0; + right: 0; + } +} + + +// Logo Object +// ---------------------------------------- + +.gemeinschaft-logo { + @include logo('logo.png'); + @include pos(2px 0 0 10px); + @include debug; +} + + +// Search Box Object +// ---------------------------------------- + +.search-box { + @extend .ext-bradius-inner; + float: left; + margin-left: 200px; + margin-top: 18px; + border-bottom: 1px solid #74B7EB; + position: relative; + input.text { + z-index: 0; + @extend .ext-bradius-inner; + background: #fff image-url('gradients/white-gray-x29-reverse.png') left top repeat-x; + line-height: 25px; + height: 25px; + border: 1px solid #3472B2; + @include size(160px, 25px, 0 23px 0 12px); + } + input[type="submit"] { + @include pos(5px 6px 0 0); + @include image-replace('icons/search-13x16.png'); + border:0; + } +} + diff --git a/app/assets/stylesheets/app/shared/_ie.scss b/app/assets/stylesheets/app/shared/_ie.scss new file mode 100644 index 0000000..afbe7e4 --- /dev/null +++ b/app/assets/stylesheets/app/shared/_ie.scss @@ -0,0 +1,7 @@ +// Internet Explorer Hate File. +// ---------------------------------------- +// Here you'll find all css which it's focused at a specific browser. +@if in-compatibility-mode() { + .ie7 {} + .ie8 {} +} \ No newline at end of file diff --git a/app/assets/stylesheets/app/shared/_media.scss b/app/assets/stylesheets/app/shared/_media.scss new file mode 100644 index 0000000..c528a1f --- /dev/null +++ b/app/assets/stylesheets/app/shared/_media.scss @@ -0,0 +1,16 @@ +// Survival ✚ Kit +// Normalize.css + +//PLACEHOLDER Media Queries for Responsive Design. +//These override the primary ('mobile first') styles +//Modify as content requires. + +@media only screen and (min-width: 480px) { + /* Style adjustments for viewports 480px and over go here */ + +} + +@media only screen and (min-width: 768px) { + /* Style adjustments for viewports 768px and over go here */ + +} \ No newline at end of file diff --git a/app/assets/stylesheets/app/shared/_print.scss b/app/assets/stylesheets/app/shared/_print.scss new file mode 100644 index 0000000..c8594e4 --- /dev/null +++ b/app/assets/stylesheets/app/shared/_print.scss @@ -0,0 +1,17 @@ +// Survival ✚ Kit +// Normalize.css + +@media print { + * { background: transparent !important; color: black !important; text-shadow: none !important; filter:none !important; -ms-filter: none !important; } /* Black prints faster: h5bp.com/s */ + a, a:visited { text-decoration: underline; } + a[href]:after { content: " (" attr(href) ")"; } + abbr[title]:after { content: " (" attr(title) ")"; } + .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } /* Don't show links for images, or javascript/internal links */ + pre, blockquote { border: 1px solid #999; page-break-inside: avoid; } + thead { display: table-header-group; } /* h5bp.com/t */ + tr, img { page-break-inside: avoid; } + img { max-width: 100% !important; } + @page { margin: 0.5cm; } + p, h2, h3 { orphans: 3; widows: 3; } + h2, h3 { page-break-after: avoid; } +} \ No newline at end of file diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss new file mode 100644 index 0000000..32e54f4 --- /dev/null +++ b/app/assets/stylesheets/application.css.scss @@ -0,0 +1,117 @@ +// Survival ✚ Kit [ Bootstrapper File ] + +// Dependencies +// ---------------------------------------- +@import "vendor/survival-kit/secure"; +@import "compass"; +@import "vendor/boilerplate-1.0/reset"; +@import "vendor/survival-kit/loader"; +@import "vendor/fancy-buttons/fancy-buttons"; + + +// Project Variables +// ---------------------------------------- +// Use @include debug; to show a color overlay on the element when this is set to true. +$debug : false; +// Typography +$base-font-family : "Helvetica Neue", Arial, Helvetica, sans-serif; +$base-font-size : 13px; +$base-line-height : 1.231; +$font-color : #222; +$link-color : #00e; +$link-hover-color : #06e; +$link-visited-color : #551a8b; +// ETC +$hr-color : #ccc; +// Selection +$selected-font-color : #fff; +$selected-background-color : #0084AC; +// Lists +$list-margin : 1em 0; +$list-padding : 0 0 0 2em; +// Container Width +$container-width : 1000px; +// Use @if in-compatibility-mode() to add conditional CSS (useful for mixins). +$compatibility-mode : true, ie7 ie8 ie9 ff2 chrome9; + +// -- Project Variables Overrides --------- + +$site-total-width : 1000px; +$vertical-margin : 15px; +$global-border-radius : 8px; +$global-inner-border-radius : 6px; + + +// -- Colors ------------------------------ +$link-color:#388DDA; +$border-dark-color: #E3E3E8; + +// Hooks +// ---------------------------------------- +// Mixins that are called from the Library files to add some extra styling. + +@mixin sk-html() { } + +@mixin sk-body() { + background:#F0F3F3 image-url('bg-body.png') left top repeat; +} + +// h1, h2, h3, h4, h5, h6 +@mixin sk-header-tags() { + font-weight:bold; +} + + +// Global Styling +// ---------------------------------------- +// Calculate all H# Tags. +@include htags-sizes($base-font-size + 20); +@include simple-forms(auto, block-hints no-stars ); +ul { + ul { + margin:0; + } +} + +// Global Classes for extension. +// ---------------------------------------- +// Here you place classes which are used as extensions across all the project. +// Prefix them with .ext- + + +// The default fancy button, used across the SK. +// @TODO: Turn this into a mixin @include sk-button(small/medium/big); +.sk-button, .button { + @include fancy-button(#1E81D5); +} +a.button { margin:10px 0;} + +// Border Radius +// ---------------------------------------- +.ext-bradius { @include border-radius($global-border-radius); } +.ext-bradius-inner-t { @include border-radius($global-inner-border-radius $global-inner-border-radius 0 0); } +.ext-bradius-inner-b { @include border-radius(0 0 $global-inner-border-radius $global-inner-border-radius); } +.ext-bradius-inner { @include border-radius($global-inner-border-radius); } + + +// The Partials +// ---------------------------------------- +// Base styles thanks to html5boilerplate. This one uses the Hooks defined before. +@import "vendor/boilerplate-1.0/styles"; + +// -- Shared Partials + // Headers and related material go here. + @import "app/shared/headers"; + // Footers and related material go here. + @import "app/shared/footers"; + // Content and Related Material go here. + @import "app/shared/contents"; + +// -- Layouts Partials + // The most general one goes first + @import "app/layouts/app"; + @import "app/layouts/phone-book-entry"; + @import "app/layouts/conference"; + + // Compatibility.. oh jeez. + @import "app/shared/ie"; \ No newline at end of file diff --git a/app/assets/stylesheets/scaffolds.css.scss b/app/assets/stylesheets/scaffolds.css.scss new file mode 100644 index 0000000..05188f0 --- /dev/null +++ b/app/assets/stylesheets/scaffolds.css.scss @@ -0,0 +1,56 @@ +body { + background-color: #fff; + color: #333; + font-family: verdana, arial, helvetica, sans-serif; + font-size: 13px; + line-height: 18px; } + +p, ol, ul, td { + font-family: verdana, arial, helvetica, sans-serif; + font-size: 13px; + line-height: 18px; } + +pre { + background-color: #eee; + padding: 10px; + font-size: 11px; } + +a { + color: #000; + &:visited { + color: #666; } + &:hover { + color: #fff; + background-color: #000; } } + +div { + &.field, &.actions { + margin-bottom: 10px; } } + +#notice { + color: green; } + +.field_with_errors { + padding: 2px; + background-color: red; + display: table; } + +#error_explanation { + width: 450px; + border: 2px solid red; + padding: 7px; + padding-bottom: 0; + margin-bottom: 20px; + background-color: #f0f0f0; + h2 { + text-align: left; + font-weight: bold; + padding: 5px 5px 5px 15px; + font-size: 12px; + margin: -7px; + margin-bottom: 0px; + background-color: #c00; + color: #fff; } + ul li { + font-size: 12px; + list-style: square; } } diff --git a/app/assets/stylesheets/vendor/README b/app/assets/stylesheets/vendor/README new file mode 100644 index 0000000..016b5fa --- /dev/null +++ b/app/assets/stylesheets/vendor/README @@ -0,0 +1 @@ +Here you should place the files that are not part of your project, but you use them at some point. \ No newline at end of file diff --git a/app/assets/stylesheets/vendor/boilerplate-1.0/README b/app/assets/stylesheets/vendor/boilerplate-1.0/README new file mode 100644 index 0000000..a5aa5b1 --- /dev/null +++ b/app/assets/stylesheets/vendor/boilerplate-1.0/README @@ -0,0 +1,15 @@ +HTML5 ✰ Boilerplate (ac92ae7a) + +style.css contains a reset, font normalization and some base styles. + +Credit is left where credit is due. +Much inspiration was taken from these projects: +- yui.yahooapis.com/2.8.1/build/base/base.css +- camendesign.com/design/ +- praegnanz.de/weblog/htmlcssjs-kickstart + +Implementation to Compass as part of Survival Kit by Mario "Kuroir" Ricalde. + +Notes: + + Not implementing Non-semantic helper classes. Use Compass builts-in. \ No newline at end of file diff --git a/app/assets/stylesheets/vendor/boilerplate-1.0/_reset.scss b/app/assets/stylesheets/vendor/boilerplate-1.0/_reset.scss new file mode 100644 index 0000000..efd1ac6 --- /dev/null +++ b/app/assets/stylesheets/vendor/boilerplate-1.0/_reset.scss @@ -0,0 +1,37 @@ +// html5doctor.com Reset Stylesheet (Eric Meyer's Reset Reloaded + HTML5 baseline) +// v1.6.1 2010-09-17 | Authors: Eric Meyer & Richard Clark +// html5doctor.com/html-5-reset-stylesheet/ +html, body, div, span, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, +small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, figcaption, figure, +footer, header, hgroup, menu, nav, section, summary, +time, mark, audio, video{ + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} + +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} + +blockquote, q { quotes: none; } + +blockquote:before, blockquote:after, +q:before, q:after { content: ""; content: none; } + +del { text-decoration: line-through; } + +abbr[title], dfn[title] { border-bottom: 1px dotted; cursor: help; } + +table { border-collapse: collapse; border-spacing: 0; } + +input, select { vertical-align: middle; } diff --git a/app/assets/stylesheets/vendor/boilerplate-1.0/_styles.scss b/app/assets/stylesheets/vendor/boilerplate-1.0/_styles.scss new file mode 100644 index 0000000..3852329 --- /dev/null +++ b/app/assets/stylesheets/vendor/boilerplate-1.0/_styles.scss @@ -0,0 +1,171 @@ +// HTML5 ✰ Boilerplate +// +// style.css contains a reset, font normalization and some base styles. +// +// Credit is left where credit is due. +// Much inspiration was taken from these projects: +// - yui.yahooapis.com/2.8.1/build/base/base.css +// - camendesign.com/design/ +// - praegnanz.de/weblog/htmlcssjs-kickstart +// +// Modified to fit Survival ✚ Kit + + html { + @include sk-html; + overflow-y: scroll; + } + + +// Sections (body, section, nav, article, aside, h1..6, header, footer, address) +// ---------------------------------------- + + body, select, input, textarea { color: $font-color; font-family: $base-font-family; } + + body { @include sk-body; font-size: $base-font-size; line-height: $base-line-height; } + + +// Grouping Content (p, hr, pre, blockquote, ol, ul, li, dl, dt, dt, dd, figure, figcaption, div) +// ---------------------------------------- + + p { margin: 0 0 1em 0;} + li { margin-bottom: (1em / 2);} + + hr { border: 0; border-top: 1px solid $hr-color; display: block; height: 1px; margin: 1em 0; padding: 0; } + + blockquote { color: #666; font-style: italic; margin: 1.5em; } + + // normalize monospace sizing + // meyerweb.com/eric/thoughts/2010/02/12/fixed-monospace-sizing/ + // en.wikipedia.org/wiki/MediaWiki_talk:Common.css/Archive_11#Teletype_style_fix_for_Chrome + pre { + // www.pathf.com/blogs/2008/05/formatting-quoted-code-in-blog-posts-css21-white-space-pre-wrap/ + white-space: pre; white-space: pre-wrap; word-wrap: break-word; + padding: 15px; + } + + pre, code, kbd, samp { font-family: monospace, sans-serif; } + + // Lists + ul, ol { margin:$list-margin; padding:$list-padding;} + + ol { list-style-type: decimal; } + + // Remove margin from navigation lists. + nav ul, + nav li { list-style:none; list-style-image: none; margin: 0; } + + // Lists + dl { margin: 0 0 1.5em 0; } + + dl dt { font-weight: bold; } + + dd { margin-left: 1.5em;} + + +// Text Level Semantics (a, em, strong, small, s, cite, q, dfn, abbr, time, code, var, samp, kbd, sub, i, b, u, mark, ruby, rt, rp, bdi, bdo, span, br, wbr) +// ---------------------------------------- + + // Accessible focus treatment: people.opera.com/patrickl/experiments/keyboard/test + a {text-decoration:none;} + + a:hover, a:active { outline: none; text-decoration:underline;} + + a, a:active, a:visited { color: $link-color; } + + a:hover { color: $link-hover-color; } + + // Headers (h1, h2, etc) have no default font-size or margin; define those yourself + h1, h2, h3, h4, h5, h6 { @include sk-header-tags; } + + // j.mp/webkit-tap-highlight-color + a:link { -webkit-tap-highlight-color: #FF5E99; } + + small { font-size: 85%; } + + strong, b, th, dfn { font-weight: bold; } + + em, i { font-style:italic; } + + mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; } + + abbr, + acronym { border-bottom: 1px dotted #666; } + + address { font-style: italic; margin: 0 0 1.5em; } + + // Set sub, sup without affecting line-height: gist.github.com/413930 + sub, sup { font-size: 75%; line-height: 0; position: relative; } + + sup { top: -0.5em; } + + sub { bottom: -0.25em; } + + +// Embedded Content (img) +// ---------------------------------------- + + // Bicubic resizing for non-native sized IMG: + // code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image-resizing/ + .ie7 img { -ms-interpolation-mode: bicubic; } + + +// Tabular Data (table, caption, colgroup, col, tbody, thead, tfoot, tr, td, th) +// ---------------------------------------- + + table { margin-bottom: 1.4em; width:100%; } + + th { font-weight: bold; } + + th,td,caption { padding: 4px 10px 4px 5px; text-align: left; } + + +// Edits (ins, del) +// ---------------------------------------- + + ins { background-color: #ff9; color: #000; text-decoration: none; } + + del { color:#666; } + + +// Forms +// ---------------------------------------- + + select, input, textarea, button { font: 99% $base-font-family; outline:none;} + + td { vertical-align: top; } + + textarea { overflow: auto; } + + // Align checkboxes, radios, text inputs with their label by: Thierry Koblentz tjkdesign.com/ez-css/css/base.css + input[type="radio"] { vertical-align: text-bottom; } + + input[type="checkbox"] { vertical-align: bottom; } + + // Hand cursor on clickable input elements + + label, input[type="button"], input[type="submit"], input[type="image"], button { cursor: pointer; } + + // Webkit browsers add a 2px margin outside the chrome of form elements + button, input, select, textarea { margin: 0; } + + + // required:valid and required:invalid moved to form.scss + + // Make buttons play nice in IE: + // www.viget.com/inspire/styling-the-button-element-in-internet-explorer/ + button { overflow: visible; width: auto; } + + @if in-compatibility-mode() { + .ie7 input[type="checkbox"] { vertical-align: baseline; } + + .ie6 input { vertical-align: text-bottom; } + + .ie6 legend, .ie7 legend { margin-left: -7px; } + } + + +// Etc. +// ---------------------------------------- + + ::-moz-selection{ background: $selected-background-color; color:$selected-font-color; text-shadow: none; } + ::selection { background:$selected-background-color; color:$selected-font-color; text-shadow: none; } diff --git a/app/assets/stylesheets/vendor/boilerplate-2.0/README b/app/assets/stylesheets/vendor/boilerplate-2.0/README new file mode 100644 index 0000000..c9cd066 --- /dev/null +++ b/app/assets/stylesheets/vendor/boilerplate-2.0/README @@ -0,0 +1,16 @@ +HTML5 ✰ Boilerplate 2.0 (7467f9c0417a0c1f9863e2d000aad73f34836ef2) + +style.css contains a reset, font normalization and some base styles. + +Credit is left where credit is due. +Much inspiration was taken from these projects: +- yui.yahooapis.com/2.8.1/build/base/base.css +- camendesign.com/design/ +- praegnanz.de/weblog/htmlcssjs-kickstart + +Implementation to Compass as part of Survival Kit by Mario "Kuroir" Ricalde. + +Notes: + + - Not implementing Non-semantic helper classes. Use Compass builts-in. + - 1.0 and 2.0 are very similar. With 2.0 you save a couple of bytes.. maybe not worth the change? \ No newline at end of file diff --git a/app/assets/stylesheets/vendor/boilerplate-2.0/_styles.scss b/app/assets/stylesheets/vendor/boilerplate-2.0/_styles.scss new file mode 100644 index 0000000..6268a35 --- /dev/null +++ b/app/assets/stylesheets/vendor/boilerplate-2.0/_styles.scss @@ -0,0 +1,209 @@ +// +// HTML5 ✰ Boilerplate +// +// What follows is the result of much research on cross-browser styling. +// Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal, +// Kroc Camen, and the H5BP dev community and team. +// +// Detailed information about this CSS: h5bp.com/css +// +// ==|== normalize ========================================================== +// + + +// ========================================================================== +// HTML5 display definitions +// ========================================================================== + +article, aside, details, figcaption, figure, footer, header, hgroup, nav, section { display: block; } +audio, canvas, video { display: inline-block; *display: inline; *zoom: 1; } +audio:not([controls]) { display: none; } +[hidden] { display: none; } + +// ========================================================================== +// Base +// ========================================================================== + +// +// 1. Correct text resizing oddly in IE6/7 when body font-size is set using em units +// 2. Force vertical scrollbar in non-IE +// 3. Prevent iOS text size adjust on device orientation change, without disabling user zoom: h5bp.com/g +// + +html { font-size: 100%; overflow-y: scroll; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; } + +body { margin: 0; font-size: $base-font-size; line-height: $base-line-height; } + +body, button, input, select, textarea { font-family: $base-font-family; color: $font-color; } + +// +// Remove text-shadow in selection highlight: h5bp.com/i +// These selection declarations have to be separate +// Also: hot pink! (or customize the background color to match your design) +// + +::-moz-selection { background: $selected-background-color; color: $selected-font-color; text-shadow: none; } +::selection { background: $selected-background-color; color: $selected-font-color; text-shadow: none; } + + +// ========================================================================== +// Links +// ========================================================================== + +a { color: $link-color; } +a:visited { color: $link-visited-color; } +a:hover { color: $link-hover-color; } +a:focus { outline: thin dotted; } + +/* Improve readability when focused and hovered in all browsers: h5bp.com/h */ +a:hover, a:active { outline: 0; } + + +// ========================================================================== +// Typography +// ========================================================================== + +abbr[title] { border-bottom: 1px dotted; } + +b, strong { font-weight: bold; } + +i, em { font-style:italic;} + +blockquote { margin: 1em 40px; } + +dfn { font-style: italic; } + +hr { display: block; height: 1px; border: 0; border-top: 1px solid $hr-color; margin: 1em 0; padding: 0; } + +ins { background: #ff9; color: #000; text-decoration: none; } + +mark { background: #ff0; color: #000; font-style: italic; font-weight: bold; } + +// Redeclare monospace font family: h5bp.com/j +pre, code, kbd, samp { font-family: monospace, monospace; _font-family: 'courier new', monospace; font-size: 1em; } + +// Improve readability of pre-formatted text in all browsers +pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; } + +q { quotes: none; } +q:before, q:after { content: ""; content: none; } + +small { font-size: 85%; } + +// Position subscript and superscript content without affecting line-height: h5bp.com/k +sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } +sup { top: -0.5em; } +sub { bottom: -0.25em; } + + +// ========================================================================== +// Lists +// ========================================================================== +dl {margin:$list-margin;} +ul, ol { margin: $list-margin; padding: $list-padding; } +dd { margin: 0 0 0 40px; } +nav ul, nav ol { list-style: none; list-style-image: none; margin: 0; padding: 0; } + + +// ========================================================================== +// Embedded content +// ========================================================================== + +// +// 1. Improve image quality when scaled in IE7: h5bp.com/d +// 2. Remove the gap between images and borders on image containers: h5bp.com/e +// + +img { border: 0; -ms-interpolation-mode: bicubic; vertical-align: middle; } + +// +// Correct overflow not hidden in IE9 +// + +svg:not(:root) { overflow: hidden; } + + +// ========================================================================== +// Figures +// ========================================================================== + +figure { margin: 0; } + + +// ========================================================================== +// Forms +// ========================================================================== + +form { margin: 0; } +fieldset { border: 0; margin: 0; padding: 0; } + +// Indicate that 'label' will shift focus to the associated form element +label { cursor: pointer; } + +// +// 1. Correct color not inheriting in IE6/7/8/9 +// 2. Correct alignment displayed oddly in IE6/7 +// + +legend { border: 0; *margin-left: -7px; padding: 0; } + +// +// 1. Correct font-size not inheriting in all browsers +// 2. Remove margins in FF3/4 S5 Chrome +// 3. Define consistent vertical alignment display in all browsers +// + +button, input, select, textarea { font-size: 100%; margin: 0; vertical-align: baseline; *vertical-align: middle; } + +// +// 1. Define line-height as normal to match FF3/4 (set using !important in the UA stylesheet) +// 2. Correct inner spacing displayed oddly in IE6/7 +// + +button, input { line-height: normal; *overflow: visible; } + +// +// Reintroduce inner spacing in 'table' to avoid overlap and whitespace issues in IE6/7 +// + +table button, table input { *overflow: auto; } + +// +// 1. Display hand cursor for clickable form elements +// 2. Allow styling of clickable form elements in iOS +// + +button, input[type="button"], input[type="reset"], input[type="submit"] { cursor: pointer; -webkit-appearance: button; } + +// +// Consistent box sizing and appearance +// + +input[type="checkbox"], input[type="radio"] { box-sizing: border-box; } +input[type="search"] { -webkit-appearance: textfield; -moz-box-sizing: content-box; -webkit-box-sizing: content-box; box-sizing: content-box; } +input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; } + +// +// Remove inner padding and border in FF3/4: h5bp.com/l +// + +button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; } + +// +// 1. Remove default vertical scrollbar in IE6/7/8/9 +// 2. Allow only vertical resizing +// + +textarea { overflow: auto; vertical-align: top; resize: vertical; } + +// Colors for form validity +input:valid, textarea:valid { } +input:invalid, textarea:invalid { background-color: #f0dddd; } + + +// ========================================================================== +// Tables +// ========================================================================== + +table { border-collapse: collapse; border-spacing: 0; } +td { vertical-align: top; } \ No newline at end of file diff --git a/app/assets/stylesheets/vendor/easy-slider/_numeric.scss b/app/assets/stylesheets/vendor/easy-slider/_numeric.scss new file mode 100644 index 0000000..db61e78 --- /dev/null +++ b/app/assets/stylesheets/vendor/easy-slider/_numeric.scss @@ -0,0 +1,44 @@ +// +// @TODO: Add docs to easy-slider-numeric! +// +@mixin easy-slider-numeric($width, $height, $selector:'#slider') { + #{$selector} { + & ul, & li { + margin:0; + padding:0; + list-style:none; + } + & li { + width:$width; + height:$height; + overflow:hidden; + } + } + @include _numeric-controls(); +} + +// You can override this function to alter the appearance of the numeric controls. +@mixin _numeric-controls() { + #controls{ + margin:10px 0; + line-height:28px; + list-style:none; + text-align:right; + li { + @include inline-block; + margin:0 0 0 10px; + } + .current a { + background:#FFFFFF; + color:#C80111; + @include box-shadow(0px 0px 3px #B2B2B2); + padding:6px 11px; // Simulate "hover" + } + a { + padding:5px 10px; + background:#F5F5F5; + border: 1px solid #AEAEAE; + color: #7F7F7F; + } + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/vendor/facebox/_facebox.scss b/app/assets/stylesheets/vendor/facebox/_facebox.scss new file mode 100644 index 0000000..53e612d --- /dev/null +++ b/app/assets/stylesheets/vendor/facebox/_facebox.scss @@ -0,0 +1,85 @@ +$facebox-overlay: #000 !default; +#facebox { + left: 0; + position: fixed; + text-align: left; + top: 0; + z-index: 100; +} + + +#facebox .popup{ + border:9px solid rgba(0, 157, 214, 0.8); + border-radius:5px; + -moz-border-radius:5px; + -webkit-border-radius:5px; + box-shadow:0 0 18px rgba(0,0,0,0.4); + -moz-box-shadow:0 0 18px rgba(0,0,0,0.4); + -webkit-box-shadow:0 0 18px rgba(0,0,0,0.4); + position:relative; +} + +#facebox .content { + background: #fff; + border-radius:4px; + -moz-border-radius:4px; + -webkit-border-radius:4px; + display:table; + min-width: 370px; + padding: 10px; +} + +#facebox .content > p:first-child{ + margin-top:0; +} +#facebox .content > p:last-child{ + margin-bottom:0; +} + +#facebox .close{ + padding:2px; + position:absolute; + right:5px; + top:5px; + z-index:101; +} +#facebox .close img{ + opacity:0.3; +} +#facebox .close:hover img{ + opacity:1.0; +} + +#facebox .loading { + text-align: center; +} + +#facebox .image { + text-align: center; +} + +#facebox img { + border: 0; + margin: 0; +} + +#facebox_overlay { + height:100%; + left: 0px; + position: fixed; + top: 0px; + width:100%; +} + +.facebox_hide { + z-index:-100; +} + +.facebox_overlayBG { + background-color: $facebox-overlay; + z-index: 99; +} + +#facebox h1{ + margin: 0 0 10px 0; +} diff --git a/app/assets/stylesheets/vendor/fancy-box/README b/app/assets/stylesheets/vendor/fancy-box/README new file mode 100644 index 0000000..70212dd --- /dev/null +++ b/app/assets/stylesheets/vendor/fancy-box/README @@ -0,0 +1,4 @@ +Fancybox 1.3.4 (2010/11/11) +Licensed under both MIT and GPL licenses + +http://fancybox.net/ \ No newline at end of file diff --git a/app/assets/stylesheets/vendor/fancy-box/_fancy-box.scss b/app/assets/stylesheets/vendor/fancy-box/_fancy-box.scss new file mode 100755 index 0000000..7ec2644 --- /dev/null +++ b/app/assets/stylesheets/vendor/fancy-box/_fancy-box.scss @@ -0,0 +1,336 @@ +// +// FancyBox - jQuery Plugin +// Simple and fancy lightbox alternative +// +// Examples and documentation at: http://fancybox.net +// +// Copyright (c) 2008 - 2010 Janis Skarnelis +// That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated. +// +// Version: 1.3.4 (11/11/2010) +// Requires: jQuery v1.3+ +// +// Dual licensed under the MIT and GPL licenses: +// http://www.opensource.org/licenses/mit-license.php +// http://www.gnu.org/licenses/gpl.html +// + +#fancybox-loading { + position: fixed; + top: 50%; + left: 50%; + width: 40px; + height: 40px; + margin-top: -20px; + margin-left: -20px; + cursor: pointer; + overflow: hidden; + z-index: 1104; + display: none; +} + +#fancybox-loading div { + position: absolute; + top: 0; + left: 0; + width: 40px; + height: 480px; + background-image: image-url('vendor/fancy-box/fancybox.png'); +} + +#fancybox-overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + z-index: 1100; + display: none; +} + +#fancybox-tmp { + padding: 0; + margin: 0; + border: 0; + overflow: auto; + display: none; +} + +#fancybox-wrap { + position: absolute; + top: 0; + left: 0; + padding: 20px; + z-index: 1101; + outline: none; + display: none; +} + +#fancybox-outer { + position: relative; + width: 100%; + height: 100%; + background: #fff; +} + +#fancybox-content { + width: 0; + height: 0; + padding: 0; + outline: none; + position: relative; + overflow: hidden; + z-index: 1102; + border: 0px solid #fff; +} + +#fancybox-hide-sel-frame { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: transparent; + z-index: 1101; +} + +#fancybox-close { + position: absolute; + top: -15px; + right: -15px; + width: 30px; + height: 30px; + background: transparent image-url('vendor/fancy-box/fancybox.png') -40px 0px; + cursor: pointer; + z-index: 1103; + display: none; +} + +#fancybox-error { + color: #444; + font: normal 12px/20px Arial; + padding: 14px; + margin: 0; +} + +#fancybox-img { + width: 100%; + height: 100%; + padding: 0; + margin: 0; + border: none; + outline: none; + line-height: 0; + vertical-align: top; +} + +#fancybox-frame { + width: 100%; + height: 100%; + border: none; + display: block; +} + +#fancybox-left, #fancybox-right { + position: absolute; + bottom: 0px; + height: 100%; + width: 35%; + cursor: pointer; + outline: none; + background: transparent image-url('vendor/fancy-box/blank.gif'); + z-index: 1102; + display: none; +} + +#fancybox-left { + left: 0px; +} + +#fancybox-right { + right: 0px; +} + +#fancybox-left-ico, #fancybox-right-ico { + position: absolute; + top: 50%; + left: -9999px; + width: 30px; + height: 30px; + margin-top: -15px; + cursor: pointer; + z-index: 1102; + display: block; +} + +#fancybox-left-ico { + background-image: image-url('vendor/fancy-box/fancybox.png'); + background-position: -40px -30px; +} + +#fancybox-right-ico { + background-image: image-url('vendor/fancy-box/fancybox.png'); + background-position: -40px -60px; +} + +#fancybox-left:hover, #fancybox-right:hover { + visibility: visible; /* IE6 */ +} + +#fancybox-left:hover span { + left: 20px; +} + +#fancybox-right:hover span { + left: auto; + right: 20px; +} + +.fancybox-bg { + position: absolute; + padding: 0; + margin: 0; + border: 0; + width: 20px; + height: 20px; + z-index: 1001; +} + +#fancybox-bg-n { + top: -20px; + left: 0; + width: 100%; + background-image: image-url('vendor/fancy-box/fancybox-x.png'); +} + +#fancybox-bg-ne { + top: -20px; + right: -20px; + background-image: image-url('vendor/fancy-box/fancybox.png'); + background-position: -40px -162px; +} + +#fancybox-bg-e { + top: 0; + right: -20px; + height: 100%; + background-image: image-url('vendor/fancy-box/fancybox-y.png'); + background-position: -20px 0px; +} + +#fancybox-bg-se { + bottom: -20px; + right: -20px; + background-image: image-url('vendor/fancy-box/fancybox.png'); + background-position: -40px -182px; +} + +#fancybox-bg-s { + bottom: -20px; + left: 0; + width: 100%; + background-image: image-url('vendor/fancy-box/fancybox-x.png'); + background-position: 0px -20px; +} + +#fancybox-bg-sw { + bottom: -20px; + left: -20px; + background-image: image-url('vendor/fancy-box/fancybox.png'); + background-position: -40px -142px; +} + +#fancybox-bg-w { + top: 0; + left: -20px; + height: 100%; + background-image: image-url('vendor/fancy-box/fancybox-y.png'); +} + +#fancybox-bg-nw { + top: -20px; + left: -20px; + background-image: image-url('vendor/fancy-box/fancybox.png'); + background-position: -40px -122px; +} + +#fancybox-title { + font-family: Helvetica; + font-size: 12px; + z-index: 1102; +} + +.fancybox-title-inside { + padding-bottom: 10px; + text-align: center; + color: #333; + background: #fff; + position: relative; +} + +.fancybox-title-outside { + padding-top: 10px; + color: #fff; +} + +.fancybox-title-over { + position: absolute; + bottom: 0; + left: 0; + color: #FFF; + text-align: left; +} + +#fancybox-title-over { + padding: 10px; + background-image: image-url('vendor/fancy-box/fancy_title_over.png'); + display: block; +} + +.fancybox-title-float { + position: absolute; + left: 0; + bottom: -20px; + height: 32px; +} + +#fancybox-title-float-wrap { + border: none; + border-collapse: collapse; + width: auto; +} + +#fancybox-title-float-wrap td { + border: none; + white-space: nowrap; +} + +#fancybox-title-float-left { + padding: 0 0 0 15px; + background: image-url('vendor/fancy-box/fancybox.png') -40px -90px no-repeat; +} + +#fancybox-title-float-main { + color: #FFF; + line-height: 29px; + font-weight: bold; + padding: 0 0 3px 0; + background: image-url('vendor/fancy-box/fancybox-x.png') 0px -40px; +} + +#fancybox-title-float-right { + padding: 0 0 0 15px; + background: image-url('vendor/fancy-box/fancybox.png') -55px -90px no-repeat; +} + +/* IE6, IE7, IE8 */ + +.fancybox-ie .fancybox-bg { background: transparent !important; } + +.fancybox-ie #fancybox-bg-n { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_n.png', sizingMethod='scale'); } +.fancybox-ie #fancybox-bg-ne { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_ne.png', sizingMethod='scale'); } +.fancybox-ie #fancybox-bg-e { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_e.png', sizingMethod='scale'); } +.fancybox-ie #fancybox-bg-se { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_se.png', sizingMethod='scale'); } +.fancybox-ie #fancybox-bg-s { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_s.png', sizingMethod='scale'); } +.fancybox-ie #fancybox-bg-sw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_sw.png', sizingMethod='scale'); } +.fancybox-ie #fancybox-bg-w { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_w.png', sizingMethod='scale'); } +.fancybox-ie #fancybox-bg-nw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_nw.png', sizingMethod='scale'); } \ No newline at end of file diff --git a/app/assets/stylesheets/vendor/fancy-buttons/README b/app/assets/stylesheets/vendor/fancy-buttons/README new file mode 100644 index 0000000..9ee6cc3 --- /dev/null +++ b/app/assets/stylesheets/vendor/fancy-buttons/README @@ -0,0 +1,3 @@ + Fancy Buttons by imathis + https://github.com/imathis/fancy-buttons + License: MIT \ No newline at end of file diff --git a/app/assets/stylesheets/vendor/fancy-buttons/_fancy-buttons.scss b/app/assets/stylesheets/vendor/fancy-buttons/_fancy-buttons.scss new file mode 100644 index 0000000..2e85caf --- /dev/null +++ b/app/assets/stylesheets/vendor/fancy-buttons/_fancy-buttons.scss @@ -0,0 +1,195 @@ +@import "compass/css3/gradient"; +@import "compass/css3/border-radius"; +@import "compass/css3/opacity"; +@import "compass/css3/text-shadow"; +@import "compass/css3/box-shadow"; +@import "compass/css3/background-clip"; +@import "fancy-gradient"; + +$fb-gradient-style: glossy !default; +$fb-invert-on-click: 1 !default; +$fb-font-size: 18px !default; +$fb-color: #444444 !default; +$fb-font-weight: bold !default; +$fb-border-width: 1px !default; +$fb-radius: 6px !default; +$fb-light-text: white !default; +$fb-dark-text: #222222 !default; +$fb-gradient: 1 !default; +$fb-image-path: image-url("vendor/fancy-buttons/button_bg.png") !default; +$fb-allow-disabled: false !default; +$fb-line-height: 1.2em !default; + +// Make a fancy button. +@mixin fancy-button($color: $fb-color, $font-size: $fb-font-size, $radius: $fb-radius, $border-width: $fb-border-width) { + @include fancy-button-structure($font-size, $radius, $border-width); + @include fancy-button-colors($color); +} + +// Style the button's colors, picking the most appropriate color set for the base color. +@mixin fancy-button-colors($color: $fb-color, $hover: 0, $active: 0, $fb-allow-disabled: $fb-allow-disabled) { + @include fb-color($color, "default"); + &:hover, &:focus { + @if $hover == 0 { + @include fb-color(darken($color, 3), "hover", $color); } + @else { + @include fb-color($hover, "hover"); } } + &:active { + @if $active == 0 { + @include fb-color(darken($color, 6), "active", $color); + @include box-shadow(darken($color, 15) 0 0.08em 0.2em 1px inset); } + @else { + @include fb-color($active, "active"); + @include box-shadow(darken($active, 9) 0 0.08em 0.1em 1px inset); } } + @include box-shadow(rgba(white, lightness($color) / 100) 0 0 0.1em 1px inset); + @include background-clip(padding-box); + @if $fb-allow-disabled { + &.disabled, &[disabled] { + @include disable-fancy-button($color); + } + } +} + +@mixin fancy-button-allow-disable($color: $fb-color, $font-size: $fb-font-size, $radius: $fb-radius, $border-width: $fb-border-width) { + $fb-disable-allowed: $fb-allow-disabled; + $fb-allow-disabled: true; + @include fancy-button-structure($font-size, $radius, $border-width); + @include fancy-button-colors-matte($color); + $fb-allow-disabled: $fb-disable-allowed; +} + +@mixin fancy-button-matte($color: $fb-color, $font-size: $fb-font-size, $radius: $fb-radius, $border-width: $fb-border-width) { + @include fancy-button-structure($font-size, $radius, $border-width); + @include fancy-button-colors-matte($color); +} + +@mixin fancy-button-custom($color: $fb-color, $font-size: $fb-font-size, $radius: $fb-radius, $border-width: $fb-border-width) { + @include fancy-button-structure($font-size, $radius, $border-width); + @include fancy-button-colors-custom($color, $font-size, $radius, $border-width); +} + +@mixin fancy-button-colors-matte($color: $fb-color, $hover: 0, $active: 0) { + $fb-current-style: $fb-gradient-style; + $fb-gradient-style: matte; + @include fancy-button-colors($color, $hover, $active); + $fb-gradient-style: $fb-current-style; +} + +@mixin fancy-button-colors-custom($color: $fb-color, $hover: 0, $active: 0) { + $fb-current-style: $fb-gradient-style; + $fb-gradient-style: custom; + @include fancy-button-colors($color, $hover, $active); + $fb-gradient-style: $fb-current-style; +} + +// Default state color settings +@mixin fb-color($color, $state, $lumins: $color) { + $gradient-top: lighten($color, 15); + $gradient-bottom: darken($color, 6); + $border-color: darken($color, 8); + @if $fb-invert-on-click != 0 { + $border-color: darken($color, 15); } + @if saturation($color) > 0 { + $color: saturate($color, 40); } + @else if lightness($lumins) >= lightness(#aaaaaa) { + $color: lighten($color, 20); } + @include fb-state-colors($color, $gradient-top, $gradient-bottom, $border-color, $state, $lumins); +} + +// Apply the button colors specified for the button state into which it is mixed. +@mixin fb-state-colors($color, $gradient-top, $gradient-bottom, $border, $state, $lumins: $color) { + background-color: $color; + @if $fb-gradient != 0 { + @if $fb-gradient-style == "glossy" { + @if $state == "active" { + @include fancy-gradient-active($gradient-top, $gradient-bottom); } + @else { + @include fancy-gradient($gradient-top, $gradient-bottom); } } + @else if $fb-gradient-style == "matte" { + @if $state == "active" { + @include fancy-matte-gradient-active($gradient-top, $gradient-bottom); } + @else { + @include fancy-matte-gradient($gradient-top, $gradient-bottom); } } + @else if $fb-gradient-style == "custom" { + @if $state == "active" { + @include custom-fancy-gradient-active($gradient-top, $gradient-bottom); } + @else { + @include custom-fancy-gradient($gradient-top, $gradient-bottom); } } } + border: { + color: $border; }; + $text-shadow-settings: unquote("0px 1px 1px"); + @if $fb-invert-on-click != 0 and $state == "active" { + $text-shadow-settings: unquote("0px -1px -1px"); } + @if lightness($lumins) < lightness(#aaaaaa) { + text-shadow: darken($color, 25) $text-shadow-settings; + &, &:visited { + color: $fb-light-text; } } + @else { + text-shadow: lighten($color, 15) $text-shadow-settings; + &, &:visited { + color: $fb-dark-text; } } +} + +@mixin fancy-button-text-colors($color, $hover: $color, $active: $color, $fb-allow-disabled: $fb-allow-disabled) { + &, &:visited { + color: $color; } + &:hover, &:focus { + color: $hover; } + &:active { + color: $active; } + @if $fb-allow-disabled { + &.disabled, &[disabled] { + color: $color; } } +} + +// Layout the button's box +@mixin fancy-button-structure($font-size: $fb-font-size, $radius: $fb-radius, $border-width: $fb-border-width, $line-height: $fb-line-height) { + @extend .fancy-button-reset-base-class; + @include fancy-button-size($font-size, $radius, $border-width, $line-height); +} + +@mixin fancy-button-size($font-size: $fb-font-size, $radius: $fb-radius, $border-width: $fb-border-width, $line-height: $fb-line-height) { + // better padding for smaller buttons + $v-padding: 0.3em; + $h-padding: 1em; + @if $radius > 0 { + @include border-radius($radius); } + font-size: $font-size; + line-height: $line-height; + @include fancy-button-padding($v-padding, $h-padding, $border-width); +} + +@mixin fancy-button-padding($v-padding, $h-padding, $border-width: $fb-border-width) { + padding: $v-padding $h-padding; + border-width: $border-width; +} + +// Reset the button's important properties to make sure they behave correctly +@mixin fb-reset($font-weight: $fb-font-weight) { + font-family: "Lucida Grande", Lucida, Arial, sans-serif; + background: #{$fb-image-path} repeat-x bottom left; + margin: 0; + width: auto; + overflow: visible; + display: inline-block; + cursor: pointer; + text-decoration: none; + border-style: solid; + font-weight: $font-weight; + &::-moz-focus-inner { + border: none; + padding: 0; } + &:focus { + outline: none; } +} + +@mixin disable-fancy-button($color: $fb-color, $opacity: 0.7) { + @include fb-color($color, "default"); + @include opacity($opacity); + @include box-shadow(none); + cursor: default !important; +} + +.fancy-button-reset-base-class { + @include fb-reset; +} diff --git a/app/assets/stylesheets/vendor/fancy-buttons/_fancy-gradient.scss b/app/assets/stylesheets/vendor/fancy-buttons/_fancy-gradient.scss new file mode 100644 index 0000000..da0baa9 --- /dev/null +++ b/app/assets/stylesheets/vendor/fancy-buttons/_fancy-gradient.scss @@ -0,0 +1,28 @@ +@mixin fancy-gradient($color1, $color2) { + $top_shine: lighten($color1, 18); + $bottom_glow: lighten($color2, 10); + $top_middle: $color1; + $middle: lighten($color2, 3); + $bottom_middle: $color2; + @include background-image(linear-gradient($top_shine, $top_middle 10%, $middle 50%, $bottom_middle 50%, $bottom_glow)); } + +@mixin fancy-gradient-active($color1, $color2) { + $top: lighten($color2, 6); + $bottom: lighten($color2, 14); + $top_middle: lighten($color2, 8); + $middle: lighten($color2, 4); + $bottom_middle: lighten($color2, 1); + @include background-image(linear-gradient($top, $top_middle 30%, $middle 50%, $bottom_middle 50%, $bottom)); } + +@mixin fancy-matte-gradient($color1, $color2) { + @include background-image(linear-gradient($color1, $color2)); } + +@mixin fancy-matte-gradient-active($color1, $color2) { + $top: lighten($color2, 5); + $bottom: lighten($color2, 15); + $middle: lighten($color2, 8); + @include background-image(linear-gradient($top, $middle 40%, $middle 85%, $bottom)); } + +/* incase an inverted custom gradient isn't specified */ +@mixin custom-fancy-gradient-active($color1, $color2) { + @include custom-fancy-gradient($color1, $color2); } diff --git a/app/assets/stylesheets/vendor/survival-kit/_blog.scss b/app/assets/stylesheets/vendor/survival-kit/_blog.scss new file mode 100644 index 0000000..5bec255 --- /dev/null +++ b/app/assets/stylesheets/vendor/survival-kit/_blog.scss @@ -0,0 +1,99 @@ +// Survival ✚ Kit + +// News Item +// ---------------------------------------- +//
    +//
    14 de Julio 2010
    +//

    Lorem My Ipsum

    +// Blog Thumb +//

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras nec ipsum magna. Duis porttitor, felis quis eleifend vehicula, mauris mi varius nibh, sit amet iaculis magna magna vitae justo...

    +//

    Nota Completa

    +//
    +@mixin news-item($date:#383838, $header:#1491EE) { + @include clearfix; + .date { + color:$date; + font:{ + size:11px; + weight:normal; + }; + } + img { + float:left; + padding: 4px 14px 50px 0; + } + p { + color:$link-color; + } + h3 { + margin-bottom:8px; + a{ + color:$header; + font-size:15px; + font-weight:bold; + text-decoration:none; + } + } +} + + +// Pagination Styling +// ---------------------------------------- +// + +// Notes for Later +//$active-state: (border (1px solid red), height 300px, ..[infinite]); +// Would Output: +// border: 1px solid red; heigh: 300px; + +// Normal, hover, active, disabled +//$pagination-font-weights: normal bold normal; +//$pagination-font-colors: #7F7F7F yellow #FFFFFF #4C7DB5; +//$pagination-borders:none (1px solid #4C7DB5) (none) (1px solid #D0D0D0); +//$pagination-backgrounds: #F5F5F5 #FFFFFF none none; +// color, background, border, weight +//@include pagination(#7F7F7F yellow #FFFFFF #4C7DB5, #F5F5F5 #FFFFFF none none, none (1px solid #4C7DB5) (none) (1px solid #D0D0D0), ); + +@mixin pagination() { + text-align:center; + * { + @include border-radius(4px); + } + .current { + font-weight:bold; + color:#0090BC; + font-size:14px; + padding: 3px 8px; + margin-right:2px; + } + .disabled { + color:#518CBC; + border:1px solid #518CBC; + } + a { + padding: 3px 8px; + @include gradient(#80DFFF, #3BBBE7); + @include box-shadow(0 2px 0px #EBEBEB); + text-decoration:none; + color: #FFF; + font-weight: bold; + border:1px solid #4DC6EF; + &:active { + @include box-shadow(0px 1px #96C5FA, inset 0px 1px #5D96CC); + background:#F6FAFC !important; + } + &:hover { + background:#D0F0FC; + border:1px solid #4DC6EF; + color:$link-hover-color; + @include box-shadow(none); + } + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/vendor/survival-kit/_effects.scss b/app/assets/stylesheets/vendor/survival-kit/_effects.scss new file mode 100644 index 0000000..488a83a --- /dev/null +++ b/app/assets/stylesheets/vendor/survival-kit/_effects.scss @@ -0,0 +1,97 @@ +// Survival ✚ Kit + +// Add a Bendy shadow to a squar element. +// @author Chris Eppstein +@mixin bendy-shadow($width, $angle: 5deg, $color: rgba(#333, 0.5)) { + @include box-shadow(0 10px 5px -5px $color); + position: relative; + z-index: 1; + &:before, &:after { + @include box-shadow(0 10px 10px 1px $color); + bottom: 2px; + content: ""; + height: 10px; + position: absolute; + width: $width / 2; + z-index: -1; + } + &:before { + @include rotate(-$angle); + left: 10px; + } + &:after { + @include rotate($angle); + right: 10px; + } +} + +// Sexy button ! +@mixin shiny-button($light-color: #92CE2F, $dark-mix-color: #32D17C, $mix-percent: 40%) { + // Params + $bg-light: $light-color; + $bg-dark: darken(mix($dark-mix-color, $bg-light, $mix-percent), 13%); + + $border-inset-color: $bg-light; + $border-inside-light: lighten($border-inset-color, 13%); + $border-inside-dark: $border-inset-color; + + $border-outside: darken($bg-dark, 9%); + $box-shadow: rgba(35, 35, 35, 0.2); + $text-shadow: darken($bg-dark, 7%); + + @extend .bradius-inner; + @include box-shadow(inset 1px 1px 0px $border-inside-light, inset -1px -1px 0px $border-inside-dark); + @include gradient($bg-light, $bg-dark); + @include text-shadow(2px 2px 1px $text-shadow); + border:1px solid $border-outside; + color:#FFF !important; + + font-size:size(13px); + font-weight: bold; + padding: 9px 60px; + text-decoration: none; + text-decoration: none !important; + &:hover { + @include box-shadow(inset 0px 0px 1px $border-inside-light, 0px 2px 1px $box-shadow); + @include gradient(lighten($bg-light, 6%), lighten($bg-dark, 6%)); + } + &:active { + @include box-shadow(inset 0px 2px 3px $bg-dark); + background: mix($bg-light, $bg-dark, 50%); + } + &.small { + font-size: 12px; + padding: 7px 22px; + } +} + +// +// @TODO: Add docs to shiny-button-colors! +// +@mixin shiny-button-colors($light-color: #92CE2F, $dark-mix-color: #32D17C, $mix-percent: 40%) { + // Params + $bg-light: $light-color; + $bg-dark: darken(mix($dark-mix-color, $bg-light, $mix-percent), 13%); + + $border-inset-color: $bg-light; + $border-inside-light: lighten($border-inset-color, 13%); + $border-inside-dark: $border-inset-color; + + $border-outside: darken($bg-dark, 9%); + $box-shadow: rgba(35, 35, 35, 0.2); + $text-shadow: darken($bg-dark, 7%); + + + @include box-shadow(inset 1px 1px 0px $border-inside-light, inset -1px -1px 0px $border-inside-dark); + @include gradient($bg-light, $bg-dark); + @include text-shadow(2px 2px 1px $text-shadow); + border:1px solid $border-outside; + &:hover { + @include box-shadow(inset 0px 0px 1px $border-inside-light, 0px 2px 1px $box-shadow); + @include gradient(lighten($bg-light, 6%), lighten($bg-dark, 6%)); + } + &:active { + @include box-shadow(inset 0px 2px 3px $bg-dark); + background: mix($bg-light, $bg-dark, 50%); + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/vendor/survival-kit/_forms.scss b/app/assets/stylesheets/vendor/survival-kit/_forms.scss new file mode 100644 index 0000000..7e82b87 --- /dev/null +++ b/app/assets/stylesheets/vendor/survival-kit/_forms.scss @@ -0,0 +1,313 @@ +// Survival ✚ Kit + +// A simple search box, generic. +// If $width contains a second argument, it won't output the width to the parent element, allowing you to use box-size. +// +// +@mixin search-box-simple { + // Preferences + $width: 210px; + $height: 27px; + $font-size: 12px; + + background: #FFF; + overflow: hidden; + height: $height; + width: $width; + + // Style + border:1px solid #4BC5ED; + margin-top: -3px; + @extend .bradius-inner; + @include gradient(#FFF, #F5F5F5); + + &.active { + @include box-shadow(0px 1px 2px transparentize(#000, 0.8)); + background:#FFF; + } + + // Calculations + $button-width: 27px; + $input-width: $width - $button-width - 2px; + + input, button { + background:transparent; + border: 0; + font-size: $font-size; + outline: none; + } + .text { + @include size($input-width, $height, 7px 10px); + color: #777; + float: left; + line-height: $height - (7px * 2); + } + button, .search { + cursor: pointer; + display: block; + float:right; + height: $height; + padding:0; + width: $button-width; + } + .search { + background:transparent image-url('redesign/vendor/survival-kit/search-13x16.png') center center no-repeat; + } +} + +// Search Box Simple dimention override +@mixin search-box-simple-size($width, $height, $button-width: 27px) { + $input-width: $width - $button-width - 2px; + height: $height; + width: $width; + .text { + @include size($input-width, $height, 7px 10px); + line-height: $height - (7px * 2); + } + button, .search { + height: $height; + width: $button-width; + } +} + + +// Inputs. +$input-shadow : inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.2) !default; +$input-hover-color : #7DBEF1 !default; +$input-hover-shadow : 0 0 6px #7DBEF1 !default; + +// +// Adds the Input state effects +// +@mixin input-effects() { + @if $input-shadow { @include box-shadow($input-shadow); } + border:1px solid #CCCCCC; + outline: 0; + &:focus { + @if $input-hover-shadow { + @include box-shadow($input-hover-shadow); + } + border:1px solid $input-hover-color; + } +} + +// +// Forms Styles (Survival Kit) +// This styles are meant to be used with Simple_Forms (Rails) +// Usage: +// simple-forms(default, option-1 option2) +// Options: +// block-hints : display the hints right after the inut field. +@mixin simple-forms($selector : "simple_form", $opts:false) { + // Setup + $size-modifier : 0px; + $input-width : 300px; + $input-font-size : $base-font-size + $size-modifier; + $vertical-spacing : 7px; + $horizontal-spacing : 10px; + $label-width :148px; + + // 7px = base padding at 0 size modifier. + $vertical-field-padding : floor((7px + $size-modifier) + ($size-modifier / 4.4) * 2); + $horizontal-field-padding: 6px; + + // Colors. + $hint-color : #6E6E6E; + + @if $selector == auto or $selector == default { + $selector: 'simple_form'; + } + + .hidden { display: none; } + // Force $opts into a list goddamnit. + $opts: join($opts, herp derp); + + .#{$selector} { + @include debug; + .hint { + @include debug(green); + display:inline-block; + padding:$vertical-field-padding 0 $vertical-field-padding ($label-width + $horizontal-spacing); + } + + // Fix a issue with the spacing. + input.date { + label { + width: 145px !important; + } + } + + + label { + @include debug(green); + vertical-align:middle; + width:$label-width; // double line labels. + display:inline-block; // works with already inline displayed items. + margin:0 $horizontal-spacing 0 0; + padding: $vertical-field-padding 0; + line-height:$input-font-size + ($input-font-size * 0.26); + text-align: right; + abbr { + @include debug(yellow); + @if index($opts, no-stars) { + display:none; + } @else { + color:#E62500; + float: right; + margin-left: $horizontal-spacing; + } + } + &.boolean, &.collection_radio_buttons { padding:$horizontal-spacing/2; width: auto;} + } + + .ext-sfr { + @include debug(yellow); + display: inline-block; + vertical-align: middle; + width: $label-width; + } + + .input { + @include debug(blue); + padding:$vertical-spacing 0; + .hint { + @extend .ext-sfr; + color: #8A8A8A; + display: block; + font-size: size(11px); + padding: 2px 0 0 ($label-width + $horizontal-spacing); + width: $input-width + ($horizontal-field-padding * 2) + $horizontal-spacing; + } + &.boolean { + padding: 2px 0 0 ($label-width + $horizontal-spacing); + } + } + + select { + border:1px solid #CCCCCC; + outline:none; + // floor(Font Size * Line Height) + (Vertical Input Padding * 2) + 1px) + $calc: floor(($input-font-size * $base-line-height ) + ($vertical-field-padding * 2)) + (1px); + height: $calc + 1px; + padding:(6px + $size-modifier) * $base-line-height ; + &:focus { + border:1px solid $input-hover-color; + } + } + + // Needs to be nested so it doesn't collide with date selects. + .select select, .country select { + width:$input-width + ($horizontal-field-padding * 2); + } + textarea, input[type=text], input[type=password], input[type=email] { + font-size:$input-font-size; + padding: $vertical-field-padding $horizontal-field-padding; + vertical-align:top; + width:$input-width; + // Input Effects + @include input-effects; + } + + textarea { + height:80px; + max-width:$input-width; + } + + input { + &.check_boxes, &.radio, &.boolean { + vertical-align:middle; + } + } + + .submit, .padded { + padding-left: $label-width + $horizontal-spacing; + } + + .form-actions { + background: #F7F7F7; + border-top: 1px solid #DDD; + padding: 17px 0px 18px $label-width + $horizontal-spacing; + } + + // Simple Form Button for the forms. + .button { + @extend .sk-button; + } + + + // Errors @todo: this should be in its own section. + span.error, .error { + @extend .ext-sfr; + color: #D65C5C; + font-size: 12px; + margin-left: 10px; + } + + #error_explanation { + @include box-shadow(#D4D4D4 0 0 10px); + background: #FFEBD6; + border: 1px solid #FFB36C; + color:#895334; + margin:$vertical-spacing * 4 0; + padding: 10px 14px; + h2 { + @include header-size(18px); + color:#AE4910; + margin-top:0; + } + } + + + // Colors for form validity + input:valid, textarea:valid {} + + input:invalid, textarea:invalid { + $error-color: #FF6161; + box-shadow:$input-shadow, inset -7px 0px 0px lighten($error-color, 15%) !important; + &:focus { + @if $input-hover-shadow { + @include box-shadow($input-hover-shadow, inset -7px 0px 0px $error-color !important ); + } + } + } + } + + // Rails 3 wraps errors in Divs + .field_with_errors { + display:inline; + } + + // Make this compatible when you have no javascript loaded! + @if not index($opts, no-browser-support) { + .ie7 { + select { margin-top:15px;} + } + } +} + +// Allows you to have different widths for different layouts. +@mixin simple-form-width($width:false, $label-width:false) { + $horizontal-field-padding : 6px; + $horizontal-spacing : 3px; + $input-width : $width; + + @if $width { + textarea, input[type=text], input[type=password] { + max-width: $width; + width:$width; + } + + .select select, .country select { + width:$input-width + ($horizontal-field-padding * 2); + } + } + + @if $label-width { + .input .hint { + width:$label-width; + } + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/vendor/survival-kit/_headers.scss b/app/assets/stylesheets/vendor/survival-kit/_headers.scss new file mode 100644 index 0000000..8b99808 --- /dev/null +++ b/app/assets/stylesheets/vendor/survival-kit/_headers.scss @@ -0,0 +1,36 @@ +// Survival ✚ Kit + +// Sets the font size specified in pixels using percents so that the base +// font size changes and 1em has the correct value. When nesting font size +// declarations, within the DOM tree, the base_font_size must be the parent's +// effective font-size in pixels. +// Usage Examples: +// .big +// +font-size(16px) +// .bigger +// +font-size(18px) +// .big .bigger +// +font-size(18px, 16px) +// +// For more information see the table found at http://developer.yahoo.com/yui/3/cssfonts/#fontsize +// From: compass-html5-boilerplate gem. + +@function size($size, $base-font-size: $base-font-size) { + @return ceil(percentage($size / $base-font-size)); +} + + +// Calculate margin and line height according to the given size. +@mixin header-size($size) { + font-size: size($size); +} + +// Calculate the Header based on the H1 Max size. +@mixin htags-sizes($max) { + $per: $max * 0.10; + @for $i from 1 through 6 { + h#{$i} { + @include header-size($max - ($per * $i) ); + } + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/vendor/survival-kit/_images.scss b/app/assets/stylesheets/vendor/survival-kit/_images.scss new file mode 100644 index 0000000..36e67cd --- /dev/null +++ b/app/assets/stylesheets/vendor/survival-kit/_images.scss @@ -0,0 +1,121 @@ +// Survival ✚ Kit + +@import "compass/typography/text/replacement"; + +// Replace an A tag with an a background-image. +// @var $image string path to the image +// @var $inline boolean embed via data. +@mixin image-link($image, $inline:false) { + @include image-background($image, $inline); + cursor:pointer; + @extend .ext-hide-text; +} + +// Replace an A tag with an a background-image sprite. You need to provide it with +// the dimentions of the image and the x-pos/y-pos +// +// @var $image string path to the image, inherit is useful. +// @var $height width +// @var $height pixels +// @var $x-pos pixels +// @var $y-pos pixels +// @var $inline boolean embed via data. +@mixin image-sprite-link($image, $width, $height, $x-pos, $y-pos, $inline: false) { + @include sk-background(transparent, $image, $x-pos, $y-pos, no-repeat, $inline); + width:$width; + height:$height; + @extend .ext-hide-text; +} + +// Replace a Header>a tag with a background image. Made specifically for logos. +// @var $image string path to the image +// @var $inline boolean embed via data. +@mixin logo($image, $inline:false) { + @include no-mp; + width: image-width($image); + height: image-height($image); + a { + @include image-link($image, $inline); + &:hover { opacity: 0.7;} + } +} + +// Area for a header link, meant to be used when it inherits a background image. +// This should be invoked on the H1-6 Tag and not in the link, the needed structure is:2 +//

    +@mixin logo-area($width, $height, $debugging: false) { + @include no-mp; + width:$width; + height:$height; + a { + @include link-area($width, $height, $debugging); + } +} + +// An area which should be clickable. It's meant to be a low level mixin, you should +// use the alternatuves. +// - debugging enables a background color to know the position. +@mixin link-area($width, $height, $debugging: false) { + width:$width; + height:$height; + @if $debugging { + @include debug($debugging); + } + @extend .ext-hide-text; +} + +// Mixin for quickly replacing images for any given element. +// @var $image string path to the image +// @var $inline boolean embed via data. +@mixin image-replace($image, $inline:false) { + @include image-background($image, $inline); + @extend .ext-hide-text; +} +@mixin image-replace-url($image, $width, $height) { + background:transparent url($image) left top no-repeat; + @include link-area($width, $height); +} + +// Just adds the image as a background and sets the width/height accordingly. +// @var $image string path to the image +// @var $inline boolean embed via data. +@mixin image-background($image, $inline:false) { + @include sk-background(transparent, $image, no-repeat, top, left, $inline); + width: image-width($image); + height: image-height($image); +} + +// Add a background by passing the exact same parameters as a normal one. With +// one more parameter $inline. Which will use inline-image and add backward +// compatibility to IE7 via *background. +// +// @var $color +// @var $image string can be a path to an image or inherit (will insert tags separately) +// @var $horizontal +// @var $vertical +// @var $repeat +// @var $inline +@mixin sk-background($color, $image, $horizontal, $vertical, $repeat, $inline: false) { + @if $image == inherit { + background-color: $color; + background-repeat: $repeat; + background-position: $horizontal $vertical; + } @else { + @if $inline == true { + background : $color inline-image($image) $horizontal $vertical $repeat; + *background : $color image-url($image) $horizontal $vertical $repeat; + } @else { + background: $color image-url($image) $horizontal $vertical $repeat; + } + } +} + + +// Common styles needed by our Image Mixins. +// Depends on Compass. +.ext-hide-text { + @include hide-text; + display:block; + direction: ltr; + outline:none; +} diff --git a/app/assets/stylesheets/vendor/survival-kit/_lists.scss b/app/assets/stylesheets/vendor/survival-kit/_lists.scss new file mode 100644 index 0000000..ea9670e --- /dev/null +++ b/app/assets/stylesheets/vendor/survival-kit/_lists.scss @@ -0,0 +1,37 @@ +// Survival ✚ Kit + +// Add docs to float-list! +@mixin float-list($side:left) { + @include no-mp; + list-style-type: none; + li { float:$side; } +} + +$tc-begin-color : #000 !default; +$tc-end-color : lighten(#646464, 30) !default; +$tc-base-font-size : 11px !default; +$tc-max-font-size : 20px !default; +$tc-how-many : 10 !default; +@mixin tag-cloud($tc-begin-color, $tc-end-color, $tc-base-font-size, $tc-max-font-size, $tc-how-many) { + $font-calculations : $tc-base-font-size; + + li { + display:inline; + background:none; + padding:0 2px; + } + + a { + // Stops words from breaking. + display:inline-block; + } + + @for $i from 1 through $tc-how-many { + // The last item gets the max-font size. + $font-calculations: round($font-calculations + (($tc-max-font-size - $tc-base-font-size) / $tc-how-many)); + a.tag-#{$i} { + font-size:$font-calculations; + color: mix($tc-end-color, $tc-begin-color, ( $i * (100 / $tc-how-many) )); + } + } +} diff --git a/app/assets/stylesheets/vendor/survival-kit/_loader.scss b/app/assets/stylesheets/vendor/survival-kit/_loader.scss new file mode 100644 index 0000000..c09a018 --- /dev/null +++ b/app/assets/stylesheets/vendor/survival-kit/_loader.scss @@ -0,0 +1,11 @@ +// Survival ✚ Kit + +// Load all the Libraries. +@import "blog"; +@import "forms"; +@import "images"; +@import "lists"; +@import "navigation"; +@import "tools"; +@import "headers"; +@import "effects"; diff --git a/app/assets/stylesheets/vendor/survival-kit/_navigation.scss b/app/assets/stylesheets/vendor/survival-kit/_navigation.scss new file mode 100644 index 0000000..5e6f13d --- /dev/null +++ b/app/assets/stylesheets/vendor/survival-kit/_navigation.scss @@ -0,0 +1,230 @@ +// Survival ✚ Kit + +// Horizontal Navigation Low-level Method. +// +// It's meant to be called from other predifined mixins to avoid calling so many variables per call. +// Used from ul/ol +@mixin horizontal-navigation( + $height, + $color, + $hover-color, + $active-color, + $text-shadow, + $bg, + $bg-hover, + $bg-active, + $box-shadow, + $box-shadow-hover, + $box-shadow-active, + $border-left, + $border-right, + $padding, + $margin, + $border-radius, + $font-weight, + $font-size, + $tab-space // Sets a tabbing space. + ) { + // $bg none or transparent will remove the background. + @if $tab-space == none { $tab-space:0;} + @if $bg == none { $bg:transparent;} + @if $bg-active == auto { $bg-active:$bg-hover; } + @if $active-color == auto { $active-color:$hover-color; } + + // Border Calculation + // ---------------------------------------- + // Check if borders are set to anything but none / auto. + @if $border-left != none and $border-right != none and $border-left != auto and $border-right != auto { + // Borders where explicitly set. + @include _sk-nav-borders($border-left, $border-right); + } @else if $border-left == auto and $border-right == auto and $bg != transparent{ + // Borders calculated magically. + @include _sk-nav-borders(lighten($bg, 10%), darken($bg, 10%)); + } + + height:$height; // instead of clearfix, to keep shadows alive. + margin: 0; + list-style:none; + + // Links and input + li, a { + display:block; + float:left; // this can make it inline or block level. + line-height:$height; + } + + + a { + @if $font-weight != none { + font-weight: $font-weight; + } + @if $padding != none { + padding:$padding; + } + @if $margin != none { + margin:$margin; + } + @if $font-size != none { + font-size:$font-size; + } + + text-decoration:none; + color:$color; + + @if $bg != transparent { + background:$bg; + } + + @if $box-shadow != none { + @include box-shadow($box-shadow); + } + + @if $text-shadow != none { + @include text-shadow($text-shadow, 1px, 1px, 1px); + } + + @if $border-radius != none { + @include border-radius($border-radius); + } + + // Feature for tabs. + @if $tab-space != 0 { + margin-top: -($tab-space); + } + + // States + // ---------------------------------------- + + &:hover{ + @include _sk-nav-effects($hover-color, $bg-hover, $text-shadow, $box-shadow-hover, $bg-hover); + text-decoration:none; + } + + &:visited { + color:$active-color; + } + &.active { + @include _sk-nav-effects($active-color, $bg-active, $text-shadow, $box-shadow-active, $bg-hover); + // Add tab space. + @if $tab-space != 0 { + height:$height + $tab-space; + } + } + } +} + +// Mixin used to generate Background effects by the horizontal-navigation mixin. +@mixin _sk-nav-effects($color, $bg, $text-shadow, $box-shadow, $bg-hover) { + @if $color != auto { + color:$color; + } + @if $bg != transparent { + @if $bg-hover == auto { + background:darken($bg,3%); + } @else { + background:$bg; + } + @if $box-shadow != none{ + @include box-shadow($box-shadow); + } + } + // Remove the text shadow of hover. + @if $text-shadow != none { + @include text-shadow(none); + } +} + +// Low level mixin. +// Invoked by other mixins. +// +// @var $left the left border. +// @var $right the right border +@mixin _sk-nav-borders($left, $right) { + li:first-child, li.first { + border-left:1px solid $right; + }// li:first-child + li:last-child, li.last { + border-right:1px solid $left; + } + a { + border:{ + left: 1px solid $left; + right: 1px solid $right; + }; + &.active, &.active:hover { + border:{ + left:1px solid transparent; + right:1px solid transparent; + }; + } + &:hover { + border:{ + left:1px solid transparent; + right:1px solid transparent; + }; + } + } +} + +// +// @TODO: Add docs to tabs! +// +@mixin navigation-classes($opts: tabs) { + $opts: join($opts, force list); + .nav { + list-style: none; + margin-bottom: $base-line-height; + margin-left: 0; + } + + // Make links block level + .nav > li > a { + display: block; + } + .nav > li > a:hover { + background-color: #EEEEEE; + text-decoration: none; + } + + // Common styles + .nav-tabs { + @extend .nav; + @include pie-clearfix(); + } + .nav-tabs > li, .nav-pills > li { + float: left; + } + .nav-tabs > li > a { + line-height: 14px; + margin-right: 2px; + padding-left: 12px; + padding-right: 12px; // keeps the overall height an even number + } + + .nav-tabs { + border-bottom: 1px solid #ddd; + } + + .nav-tabs > li { + margin-bottom: -1px; + } + + .nav-tabs > li > a { + @include border-radius(4px 4px 0 0); + border: 1px solid transparent; + padding-bottom: 9px; + padding-top: 9px; + &:hover { + border-color: #EEEEEE #EEEEEE #ddd; + } + } + .nav-tabs > .active { + a, a:hover { + background-color: #FFF; + border: 1px solid #ddd; + border-bottom-color: transparent; + color: gray; + cursor: default; + } + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/vendor/survival-kit/_secure.scss b/app/assets/stylesheets/vendor/survival-kit/_secure.scss new file mode 100644 index 0000000..f08dd11 --- /dev/null +++ b/app/assets/stylesheets/vendor/survival-kit/_secure.scss @@ -0,0 +1,3 @@ +/*! + This is a compiled file. +*/ \ No newline at end of file diff --git a/app/assets/stylesheets/vendor/survival-kit/_tools.scss b/app/assets/stylesheets/vendor/survival-kit/_tools.scss new file mode 100644 index 0000000..e753dfe --- /dev/null +++ b/app/assets/stylesheets/vendor/survival-kit/_tools.scss @@ -0,0 +1,267 @@ +// Survival ✚ Kit +$container-width : 1000px !default; +$compatibility-mode : true, ie ie7 ie8 ie9 ff2 chrome9 !default; + +// Function to know if we're in compatibility mode, if $version is set it'll return if there's a match for that browser. +@function in-compatibility-mode($version: false) { + @if $compatibility-mode { + @if $version { + @return index(nth($compatibility-mode, 2), $version); + } @else { + @return nth($compatibility-mode, 1); + } + } @else { + @return false; + } +} + +// Shortcut to remove margin an padding. +// Used on several @mixins. +@mixin no-mp($extend:false) { + @if $extend { + @extend .no-mp; + } @else { + margin:0; + padding:0; + } +} +// Sometimes it's better to extend a class. +.no-mp { + margin:0; + padding:0; +} + +// Center an element. +@mixin center-container($container-width, $vertical-margin:0, $padding:0) { + margin:$vertical-margin auto; + @if $padding == 0 { + width:$container-width; + } @else { + @include size($container-width, auto, $padding); + } +} + +// Inline Block CrossBrowser. +// Disregards FF2 and IE6 +@mixin inline-block { + display: inline-block; + @if in-compatibility-mode(ie7) { + zoom: 1; + *display:inline; + } +} + +// Shortcut to set absolute positioning. +@mixin pos($pos, $debug: false) { + @if length($pos) == 1 { + $pos: $pos 0 0 0; + } + @if length($pos) == 2 { + $pos: nth($pos,1) nth($pos,2) 0 0; + } + @if length($pos) == 3 { + $pos: nth($pos,1) nth($pos,2) nth($pos, 3) 0; + } + position:absolute; + @if "#{nth($pos, 1)}" != "0" { top: nth($pos, 1); } + @if "#{nth($pos, 2)}" != "0" { right: nth($pos, 2); } + @if "#{nth($pos, 3)}" != "0" { bottom: nth($pos, 3); } + @if "#{nth($pos, 4)}" != "0" { left: nth($pos, 4); } + @if $debug { @include debug($debug); } +} + +// Center a absolute element horizontally; optional offset. +@mixin pos-x-center($width, $offset:0) { + @include pos(0 50% 0 50%); + margin-left:$offset - ( $width / 2 ); + width:$width; +} + +// Center a absolute element vertically; optional offset. +@mixin pos-y-center($height, $offset:0) { + @include pos(50% 0 50% 0); + height:$height; + margin-top:$offset - ( $height / 2 ); +} + +// Set a debug variable. +@mixin debug($color:red) { + @if $debug != false { + @if $color == true { $color:red; } + background: rgba($color, 0.2); // incompatible with IE. + } +} + +// Class available to center container to 1000px +.w, .pagewidth { + @include center-container($container-width); +} + +// Crossbrowser linear gradient. +// Compatible Browsers: FF3.6+ Saf4+ Chrome IE6-IE9 +// @author SitePoint +@mixin background-gradient($from, $to, $start: top, $end: bottom, $fallback:$from, $ie:false) { + @include gradient($from, $to, $start, $end, $fallback); +} +@mixin gradient($from, $to, $start: top, $end: bottom, $fallback:$from){ + background-color: $fallback; + + @if $end == bottom and $start == top { + @if $start == 0 { + background-image: -webkit-gradient(linear, left $start, left bottom, from($from), to($to)); + } @else { + background-image: -webkit-gradient(linear, $start, left bottom, from($from), to($to)); + } + background-image: -webkit-linear-gradient($start, $from, $to); + background-image: -moz-linear-gradient($start, $from, $to); + background-image: -ms-linear-gradient($start, $from, $to); + background-image: -o-linear-gradient($start, $from, $to); + @if in-compatibility-mode() { + filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#{ie-hex-str($from)}', EndColorStr='#{ie-hex-str($to)}'); + } + } @else if $end == bottom { + background-image: -webkit-gradient(linear, left $start, 0 $end, from($from), to($to)); + background-image: -webkit-linear-gradient(top, $from $start+px, $to); + background-image: -moz-linear-gradient(top, $from $start+px, $to); + background-image: -ms-linear-gradient(top, $from $start+px, $to); + background-image: -o-linear-gradient(top, $from $start+px, $to); + + } @else { + background-image: -webkit-gradient(linear, left $start, 0 $end, from($from), to($to)); + background-image: -webkit-linear-gradient(top, $from $start+px, $to $end+px); + background-image: -moz-linear-gradient(top, $from $start+px, $to $end+px); + background-image: -ms-linear-gradient(top, $from $start+px, $to $end+px); + background-image: -o-linear-gradient(top, $from $start+px, $to $end+px); + // No IE support for positioned gradients + } +} + +// Mixin that allows you to set the size of the box to a fixed width/height +// taking into consideration the padding and borders for you. +// +// Examples: +// @include size(100px, 100px, 10px, 5px solid red); +// Will render a 100x100. +// +// $width: Pixel value for width +// $height: Pixel value for height +// $padding: Padding accepts: 1px or 1px 2px or 1px 2px 3px 4px +// $border: Border, accepts 1px solid #000 or 1px or 1px 2px or 1px 2px 3px 4px +// When passing a border declaration (1px solid #000) it'll add the CSS for you. +@mixin size($width, $height:auto, $padding: none, $border:none) { + // Prepare the borders, accept the following: + // 1px solid #000 or 1px or 1px 2px or 1px 2px 3px 4px + @if true { + @if $border == none { + $border:0; + } + + $border-len: length($border); + // Standardize padding to a list with 4 items. + @if $border-len == 3 { + border:$border; + $bw: nth($border, 1); + $border: $bw $bw $bw $bw; + } @else if $border-len == 1 { + $border: $border $border $border $border; + } @else if $border-len == 2 { + $border: join($border, $border); + } + } + + // Prepare padding, accept the following: + // 1px or 1px 2px or 1px 2px 3px 4px + @if true { + @if $padding == none { + $padding:0; + } @else { + padding:$padding; + } + + // Standardize padding to a list with 4 items. + $padding-len: length($padding); + @if $padding-len == 1 { + $padding: $padding $padding $padding $padding; + } @else if $padding-len == 2 { + $padding: join($padding, $padding); + } + } + + @if $width != auto { + width: $width - (nth($padding, 2) + nth($padding, 4)) - (nth($border, 2) + nth($border, 4)); + } + @if $height != auto { + height: $height - (nth($padding, 1) + nth($padding, 3)) - (nth($border, 1) + nth($border, 3)); + } +} + +// Float an element with a given width and a direction. Third parameter allows easy debugging. +// Yes, we override Compass :( +// @TODO: Make it use box-size and allow padding. +@mixin float($side, $size:auto, $debug-color:false) { + @if $size != auto { + @if length($size) == 1 { + width:$size; + } @else { + height:nth($size, 2); + width:nth($size, 1); + } + + } + @if in-compatibility-mode(ie6) { + display:inline; + } + float: $side; + @if $debug-color and $debug { + @include debug($debug-color); + } +} + +@mixin transition($property: all, $time: 400ms, $easing: ease-out){ + transition: $property $time $easing; + -moz-transition: $property $time $easing; + -ms-transition: $property $time $easing; + -o-transition: $property $time $easing; + -webkit-transition: $property $time $easing; +} + +// Calculate the Golden Ratio of a given value. +// ---------------------------------------- +@function golden-ratio($size, $type) { + $big : round($size / 1.61803); + $small : $size - $big; + @return if($type == large, $big, $small); +} + + +// +// @TODO: Add docs to link-colors! +// +@mixin link-colors($normal, $hover: false, $active: false, $visited: false, $focus: false) { + @if $normal == default { + $hover: $link-hover-color; + $normal: $link-color; + $visited: $link-visited-color; + } + color: $normal; + @if $visited { + &:visited { + color: $visited; } } + @if $focus { + &:focus { + color: $focus; } } + @if $hover { + &:hover { + color: $hover; } } + @if $active { + &:active { + color: $active; } } +} + +// Substract the Body to the Container width to get the sidebar. +@function sidebar($body-width, $container-width-over: false) { + @if $container-width-over == false { + $container-width-over : $container-width; + } + @return $container-width - $body-width; +} \ No newline at end of file diff --git a/app/controllers/access_authorizations_controller.rb b/app/controllers/access_authorizations_controller.rb new file mode 100644 index 0000000..54365e7 --- /dev/null +++ b/app/controllers/access_authorizations_controller.rb @@ -0,0 +1,68 @@ +class AccessAuthorizationsController < ApplicationController + load_and_authorize_resource :callthrough + load_and_authorize_resource :access_authorization, :through => [:callthrough] + + before_filter :set_parent_and_path_methods + before_filter :spread_breadcrumbs + + def index + end + + def show + end + + def new + @access_authorization = @parent.access_authorizations.build + @access_authorization.name = generate_a_new_name(@parent, @access_authorization) + @access_authorization.phone_numbers.build + @access_authorization.login = random_pin + random_pin + @access_authorization.pin = random_pin + end + + def create + @access_authorization = @parent.access_authorizations.build(params[:access_authorization]) + if @access_authorization.save + redirect_to @show_path_method.(@parent, @access_authorization), :notice => t('access_authorizations.controller.successfuly_created') + else + render :new + end + end + + def edit + end + + def update + if @access_authorization.update_attributes(params[:access_authorization]) + redirect_to @show_path_method.(@parent, @access_authorization), :notice => t('access_authorizations.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @access_authorization.destroy + redirect_to @index_path_method.(@parent), :notice => t('access_authorizations.controller.successfuly_destroyed') + end + + private + + def set_parent_and_path_methods + @parent = @callthrough + @show_path_method = method( :"#{@parent.class.name.underscore}_access_authorization_path" ) + @index_path_method = method( :"#{@parent.class.name.underscore}_access_authorizations_path" ) + @new_path_method = method( :"new_#{@parent.class.name.underscore}_access_authorization_path" ) + @edit_path_method = method( :"edit_#{@parent.class.name.underscore}_access_authorization_path" ) + end + + def spread_breadcrumbs + if @callthrough + add_breadcrumb t("#{@parent.class.name.underscore.pluralize}.index.page_title"), tenant_callthroughs_path(@callthrough.tenant) + add_breadcrumb @callthrough, tenant_callthrough_path(@callthrough.tenant, @callthrough) + add_breadcrumb t("access_authorizations.index.page_title"), callthrough_access_authorizations_path(@callthrough) + if @access_authorization && !@access_authorization.new_record? + add_breadcrumb @access_authorization, callthrough_access_authorization_path(@callthrough, @access_authorization) + end + end + end + +end diff --git a/app/controllers/acd_agents_controller.rb b/app/controllers/acd_agents_controller.rb new file mode 100644 index 0000000..1d119b3 --- /dev/null +++ b/app/controllers/acd_agents_controller.rb @@ -0,0 +1,73 @@ +class AcdAgentsController < ApplicationController + load_and_authorize_resource :automatic_call_distributor + load_and_authorize_resource :acd_agent, :through => [:automatic_call_distributor] + + before_filter :spread_breadcrumbs + + def index + if params[:active] + if params[:active].downcase == 'true' + @acd_agents = @acd_agents.where(:active => true) + elsif params[:active].downcase == 'false' + @acd_agents = @acd_agents.where(:active => false) + end + end + end + + def show + @acd_agent = AcdAgent.find(params[:id]) + end + + def new + @acd_agent = @automatic_call_distributor.acd_agents.build + i = @automatic_call_distributor.acd_agents.count + loop do + i += 1 + break unless @automatic_call_distributor.acd_agents.where(:name => "#{t('acd_agents.name')} #{i}").count > 0 + end + @acd_agent.name = "#{t('acd_agents.name')} #{i}" + @acd_agent.status = 'active' + @acd_agent.calls_answered = 0 + end + + def create + @acd_agent = @automatic_call_distributor.acd_agents.build(params[:acd_agent]) + if @acd_agent.save + redirect_to automatic_call_distributor_acd_agent_path(@automatic_call_distributor, @acd_agent), :notice => t('acd_agents.controller.successfuly_created') + else + render :new + end + end + + def edit + @acd_agent = AcdAgent.find(params[:id]) + end + + def update + @acd_agent = AcdAgent.find(params[:id]) + if @acd_agent.update_attributes(params[:acd_agent]) + redirect_to automatic_call_distributor_acd_agent_path(@automatic_call_distributor, @acd_agent), :notice => t('acd_agents.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @acd_agent = AcdAgent.find(params[:id]) + @acd_agent.destroy + redirect_to automatic_call_distributor_acd_agents_path(@automatic_call_distributor), :notice => t('acd_agents.controller.successfuly_destroyed') + end + + def spread_breadcrumbs + if @automatic_call_distributor.automatic_call_distributorable.class == User + add_breadcrumb t("#{@automatic_call_distributor.automatic_call_distributorable.class.name.underscore.pluralize}.index.page_title"), method( :"tenant_#{@automatic_call_distributor.automatic_call_distributorable.class.name.underscore.pluralize}_path" ).(@automatic_call_distributor.tenant) + add_breadcrumb @automatic_call_distributor.automatic_call_distributorable, method( :"tenant_#{@automatic_call_distributor.automatic_call_distributorable.class.name.underscore}_path" ).(@automatic_call_distributor.tenant, @automatic_call_distributor.automatic_call_distributorable) + end + add_breadcrumb t("automatic_call_distributors.index.page_title"), method( :"#{@automatic_call_distributor.automatic_call_distributorable.class.name.underscore}_automatic_call_distributors_path" ).(@automatic_call_distributor.automatic_call_distributorable) + add_breadcrumb @automatic_call_distributor, method( :"#{@automatic_call_distributor.automatic_call_distributorable.class.name.underscore}_automatic_call_distributor_path" ).(@automatic_call_distributor.automatic_call_distributorable, @automatic_call_distributor) + add_breadcrumb t("acd_agents.index.page_title"), automatic_call_distributor_acd_agents_path(@automatic_call_distributor) + if @acd_agent && !@acd_agent.new_record? + add_breadcrumb @acd_agent, automatic_call_distributor_acd_agent_path(@automatic_call_distributor, @acd_agent) + end + end +end diff --git a/app/controllers/acd_callers_controller.rb b/app/controllers/acd_callers_controller.rb new file mode 100644 index 0000000..ab58064 --- /dev/null +++ b/app/controllers/acd_callers_controller.rb @@ -0,0 +1,41 @@ +class AcdCallersController < ApplicationController + def index + @acd_callers = AcdCaller.all + end + + def show + @acd_caller = AcdCaller.find(params[:id]) + end + + def new + @acd_caller = AcdCaller.new + end + + def create + @acd_caller = AcdCaller.new(params[:acd_caller]) + if @acd_caller.save + redirect_to @acd_caller, :notice => t('acd_callers.controller.successfuly_created') + else + render :new + end + end + + def edit + @acd_caller = AcdCaller.find(params[:id]) + end + + def update + @acd_caller = AcdCaller.find(params[:id]) + if @acd_caller.update_attributes(params[:acd_caller]) + redirect_to @acd_caller, :notice => t('acd_callers.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @acd_caller = AcdCaller.find(params[:id]) + @acd_caller.destroy + redirect_to acd_callers_url, :notice => t('acd_callers.controller.successfuly_destroyed') + end +end diff --git a/app/controllers/addresses_controller.rb b/app/controllers/addresses_controller.rb new file mode 100644 index 0000000..a70b1f4 --- /dev/null +++ b/app/controllers/addresses_controller.rb @@ -0,0 +1,41 @@ +class AddressesController < ApplicationController + def index + @addresses = Address.all + end + + def show + @address = Address.find(params[:id]) + end + + def new + @address = Address.new + end + + def create + @address = Address.new(params[:address]) + if @address.save + redirect_to @address, :notice => t('addresses.controller.successfuly_created') + else + render :new + end + end + + def edit + @address = Address.find(params[:id]) + end + + def update + @address = Address.find(params[:id]) + if @address.update_attributes(params[:address]) + redirect_to @address, :notice => t('addresses.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @address = Address.find(params[:id]) + @address.destroy + redirect_to addresses_url, :notice => t('addresses.controller.successfuly_destroyed') + end +end diff --git a/app/controllers/api/rows_controller.rb b/app/controllers/api/rows_controller.rb new file mode 100644 index 0000000..6e815eb --- /dev/null +++ b/app/controllers/api/rows_controller.rb @@ -0,0 +1,91 @@ +class Api::RowsController < ApplicationController + before_filter :check_remote_ip_address_whitelist + + def index + @rows = Api::Row.all + + respond_to do |format| + format.xml { render xml: @rows } + end + end + + def show + if params[:user_name] + @row = Api::Row.find_by_user_name(params[:user_name]) + else + @row = Api::Row.find(params[:id]) + end + + respond_to do |format| + format.xml { render xml: @row } + end + end + + def new + @row = Api::Row.new + + respond_to do |format| + format.xml { render xml: @row } + end + end + + def edit + if params[:user_name] + @row = Api::Row.find_by_user_name(params[:user_name]) + else + @row = Api::Row.find(params[:id]) + end + end + + def create + @row = Api::Row.new(params[:row]) + + respond_to do |format| + if @row.save + @row.create_a_new_gemeinschaft_user + + format.xml { render xml: @row, status: :created, location: @row } + else + format.xml { render xml: @row.errors, status: :unprocessable_entity } + end + end + end + + def update + if params[:user_name] + @row = Api::Row.find_by_user_name(params[:user_name]) + else + @row = Api::Row.find(params[:id]) + end + + respond_to do |format| + if @row.update_attributes(params[:row]) + @row.update_user_data + format.xml { head :no_content } + else + format.xml { render xml: @row.errors, status: :unprocessable_entity } + end + end + end + + def destroy + if params[:user_name] + @row = Api::Row.find_by_user_name(params[:user_name]) + else + @row = Api::Row.find(params[:id]) + end + @row.destroy + + respond_to do |format| + format.xml { head :no_content } + end + end + + private + + def check_remote_ip_address_whitelist + if !(REMOTE_IP_ADDRESS_WHITELIST.empty? or REMOTE_IP_ADDRESS_WHITELIST.include?(ENV['REMOTE_ADDR'])) + redirect_to root_url + end + end +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb new file mode 100644 index 0000000..c675f5c --- /dev/null +++ b/app/controllers/application_controller.rb @@ -0,0 +1,161 @@ +class ApplicationController < ActionController::Base + + protect_from_forgery + + before_filter :set_locale + + before_filter :go_to_setup_if_new_installation + before_filter :home_breadcrumb + + helper_method :current_user + + helper_method :guess_local_ip_address + helper_method :guess_local_host + + helper_method :'have_https?' + + helper_method :random_pin + + + #TODO Add check_authorization. See + # https://github.com/ryanb/cancan + # https://github.com/ryanb/cancan/wiki/Ensure-Authorization + # and Gemeinschaft 4 + + # Generate a new name for an Object + # + def generate_a_new_name(parent, child = nil) + if child + i = parent.send(child.class.name.underscore.pluralize).count + loop do + i += 1 + if I18n.t("#{child.class.name.underscore.pluralize}.new_name_scaffold").include?('translation missing') + @guess_a_new_name = I18n.t(child.class.name.underscore.pluralize + '.name') + " #{i}" + else + @guess_a_new_name = I18n.t("#{child.class.name.underscore.pluralize}.new_name_scaffold", :counter => i.to_s) + end + break unless parent.send(child.class.name.underscore.pluralize).where(:name => "#{@guess_a_new_name}").count > 0 + end + else + i = parent.class.count + loop do + i += 1 + if I18n.t("#{parent.class.name.underscore.pluralize}.new_name_scaffold").include?('translation missing') + @guess_a_new_name = I18n.t(parent.class.name.underscore.pluralize + '.name') + " #{i}" + else + @guess_a_new_name = I18n.t("#{parent.class.name.underscore.pluralize}.new_name_scaffold", :counter => i.to_s) + end + break unless parent.class.where(:name => "#{@guess_a_new_name}").count > 0 + end + end + return @guess_a_new_name + end + + # Generate a new random PIN + # + def random_pin + if MINIMUM_PIN_LENGTH > 0 + (1..MINIMUM_PIN_LENGTH).map{|i| (0 .. 9).to_a.sample}.join + end + end + + # return the IP address (preferred) or hostname at which the + # current request arrived + def server_host + return ( + request.env['SERVER_ADDR'] || + request.env['SERVER_NAME'] || + request.env['HTTP_HOST'] + ) + end + + def have_https? + return Connectivity::port_open?( server_host(), 443 ) + end + + + def guess_local_ip_address + ret = nil + begin + ipsocket_addr_info = UDPSocket.open {|s| s.connect("255.255.255.254", 1); s.addr(false) } + ret = ipsocket_addr_info.last if ipsocket_addr_info + rescue + end + return ret + end + + def guess_local_host + ret = guess_local_ip_address() + if ! ret + begin + if request + ret = request.env['SERVER_NAME'] + end + rescue + end + end + if ret && [ + '', + 'localhost', + '127.0.0.1', + '0.0.0.0', + ].include?(ret) + ret = nil + end + return ret + end + + rescue_from CanCan::AccessDenied do |exception| + if @current_user + redirect_to root_url, :alert => 'Access denied! Please ask your admin to grant you the necessary rights.' + else + if Tenant.count == 0 && User.count == 0 + # This is a brand new system. We need to run a setup first. + redirect_to wizards_new_initial_setup_path + else + # You need to login first. + redirect_to log_in_path, :alert => 'Access denied! You need to login first.' + end + end + end + + private + + def current_user + begin + @current_user ||= User.find(session[:user_id]) if session[:user_id] + rescue ActiveRecord::RecordNotFound + session[:user_id] = nil + end + @current_user + end + + def go_to_setup_if_new_installation + if Rails.env != 'test' + if GemeinschaftSetup.all.count == 0 + redirect_to new_gemeinschaft_setup_path + end + end + end + + def home_breadcrumb + if current_user + if current_user && Tenant.find(current_user.current_tenant_id) + add_breadcrumb( current_user.current_tenant, tenant_path(current_user.current_tenant) ) + else + add_breadcrumb I18n.t('pages.controller.index.name'), :root_path + end + end + end + + def set_locale + if current_user && Language.find(current_user.language_id) + I18n.locale = current_user.language.code.downcase + else + logger.debug "* Accept-Language: #{request.env['HTTP_ACCEPT_LANGUAGE']}" + I18n.locale = request.compatible_language_from(Language.all.map{|x| x.code}) + end + logger.debug "* Locale set to '#{I18n.locale}'" + end + +end diff --git a/app/controllers/automatic_call_distributors_controller.rb b/app/controllers/automatic_call_distributors_controller.rb new file mode 100644 index 0000000..cc0c7e6 --- /dev/null +++ b/app/controllers/automatic_call_distributors_controller.rb @@ -0,0 +1,100 @@ +class AutomaticCallDistributorsController < ApplicationController + DEFAULT_STRATEGY = 'round_robin' + DEFAULT_MAX_CALLERS = 50 + DEFAULT_AGENT_TIMEOUT = 20 + DEFAULT_RETRY_TIMEOUT = 10 + DEFAULT_JOIN = 'agents_active' + DEFAULT_LEAVE = 'no_agents_active' + + load_resource :user + load_resource :tenant + load_and_authorize_resource :automatic_call_distributor, :through => [:user, :tenant ] + + before_filter :set_and_authorize_parent + before_filter :spread_breadcrumbs + + def index + @automatic_call_distributors = AutomaticCallDistributor.all + end + + def show + @automatic_call_distributor = AutomaticCallDistributor.find(params[:id]) + end + + def new + i = @parent.automatic_call_distributors.count + loop do + i += 1 + break unless @parent.automatic_call_distributors.where(:name => "#{t('automatic_call_distributors.name')} #{i}").count > 0 + end + @strategies = AutomaticCallDistributor::STRATEGIES.collect {|r| [ t("automatic_call_distributors.strategies.#{r.to_s}"), r.to_s ] } + @join_on = AutomaticCallDistributor::JOIN_ON.collect {|r| [ t("automatic_call_distributors.join_on.#{r.to_s}"), r.to_s ] } + @leave_on = AutomaticCallDistributor::LEAVE_ON.collect {|r| [ t("automatic_call_distributors.leave_on.#{r.to_s}"), r.to_s ] } + @automatic_call_distributor = @parent.automatic_call_distributors.build( + :name => "#{t('automatic_call_distributors.name')} #{i}", + :strategy => DEFAULT_STRATEGY, + :max_callers => DEFAULT_MAX_CALLERS, + :retry_timeout => DEFAULT_RETRY_TIMEOUT, + :agent_timeout => DEFAULT_AGENT_TIMEOUT, + :join => DEFAULT_JOIN, + :leave => DEFAULT_LEAVE, + ) + + end + + def create + @automatic_call_distributor = @parent.automatic_call_distributors.build(params[:automatic_call_distributor]) + if @automatic_call_distributor.save + m = method( :"#{@parent.class.name.underscore}_automatic_call_distributor_path" ) + redirect_to m.( @parent, @automatic_call_distributor ), :notice => t('automatic_call_distributors.controller.successfuly_created', :resource => @parent) + else + render :new + end + end + + def edit + @strategies = AutomaticCallDistributor::STRATEGIES.collect {|r| [ t("automatic_call_distributors.strategies.#{r.to_s}"), r.to_s ] } + @join_on = AutomaticCallDistributor::JOIN_ON.collect {|r| [ t("automatic_call_distributors.join_on.#{r.to_s}"), r.to_s ] } + @leave_on = AutomaticCallDistributor::LEAVE_ON.collect {|r| [ t("automatic_call_distributors.leave_on.#{r.to_s}"), r.to_s ] } + @automatic_call_distributor = AutomaticCallDistributor.find(params[:id]) + end + + def update + if @automatic_call_distributor.update_attributes(params[:automatic_call_distributor]) + m = method( :"#{@parent.class.name.underscore}_automatic_call_distributor_path" ) + redirect_to m.( @parent, @automatic_call_distributor ), :notice => t('automatic_call_distributors.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @automatic_call_distributor = AutomaticCallDistributor.find(params[:id]) + @automatic_call_distributor.destroy + m = method( :"#{@parent.class.name.underscore}_automatic_call_distributors_url" ) + redirect_to m.( @parent ), :notice => t('automatic_call_distributors.controller.successfuly_destroyed') + end + + private + def set_and_authorize_parent + @parent = @user || @tenant + authorize! :read, @parent + end + + def spread_breadcrumbs + if @user + add_breadcrumb t("users.index.page_title"), tenant_users_path(@user.current_tenant) + add_breadcrumb @user, tenant_user_path(@user.current_tenant, @user) + add_breadcrumb t("automatic_call_distributors.index.page_title"), user_automatic_call_distributors_path(@user) + if @automatic_call_distributor && !@automatic_call_distributor.new_record? + add_breadcrumb @automatic_call_distributor, user_automatic_call_distributor_path(@user, @automatic_call_distributor) + end + end + if @tenant + add_breadcrumb t("automatic_call_distributors.index.page_title"), tenant_automatic_call_distributors_path(@tenant) + if @automatic_call_distributor && !@automatic_call_distributor.new_record? + add_breadcrumb @automatic_call_distributor, tenant_automatic_call_distributor_path(@tenant, @automatic_call_distributor) + end + end + end +end diff --git a/app/controllers/call_forwards_controller.rb b/app/controllers/call_forwards_controller.rb new file mode 100644 index 0000000..5321b35 --- /dev/null +++ b/app/controllers/call_forwards_controller.rb @@ -0,0 +1,127 @@ +class CallForwardsController < ApplicationController + load_and_authorize_resource :phone_number + load_and_authorize_resource :call_forward, :through => [:phone_number] + + before_filter :spread_breadcrumbs + + class CallForwardingDestination + attr_accessor :id, :label + + def to_s + return label + end + end + + + def index + end + + def show + end + + def new + @call_forward = @phone_number.call_forwards.build + @call_forward.depth = DEFAULT_CALL_FORWARD_DEPTH + @call_forward.active = true + @call_forwarding_destinations = call_forwarding_destination_types() + @call_forward.destination = CALLFORWARD_DESTINATION_DEFAULT.to_s if defined?(CALLFORWARD_DESTINATION_DEFAULT) + + @available_call_forward_cases = [] + CallForwardCase.all.each do |available_call_forward_case| + if GuiFunction.display?("call_forward_case_#{available_call_forward_case.value}_field_in_call_forward_form", @current_user) + @available_call_forward_cases << available_call_forward_case + end + end + + if @phone_number.call_forwards.where( + :call_forward_case_id => CallForwardCase.find_by_value('noanswer').id, + :active => true + ).count == 0 + @call_forward.call_forward_case_id = CallForwardCase.find_by_value('noanswer').id + @call_forward.timeout = 45 + end + end + + def create + @call_forward = @phone_number.call_forwards.build( params[:call_forward] ) + + if @call_forward.save + redirect_to phone_number_call_forward_path( @phone_number, @call_forward ), :notice => t('call_forwards.controller.successfuly_created') + else + @available_call_forward_cases = CallForwardCase.all + render :new + end + end + + def edit + @available_call_forward_cases = CallForwardCase.all + @call_forwarding_destinations = call_forwarding_destination_types() + end + + def update + @available_call_forward_cases = CallForwardCase.all + if @call_forward.update_attributes(params[:call_forward]) + redirect_to phone_number_call_forward_path( @phone_number, @call_forward ), :notice => t('call_forwards.controller.successfuly_updated') + else + @call_forwarding_destinations = call_forwarding_destination_types() + render :edit + end + end + + def destroy + @call_forward.destroy + redirect_to phone_number_call_forwards_path( @phone_number ), :notice => t('call_forwards.controller.successfuly_destroyed') + end + + private + def spread_breadcrumbs + if @phone_number && @phone_number.phone_numberable_type == 'SipAccount' + @sip_account = @phone_number.phone_numberable + if @sip_account.sip_accountable_type == 'User' + @user = @phone_number.phone_numberable.sip_accountable + add_breadcrumb t("users.index.page_title"), tenant_users_path(@user.current_tenant) + add_breadcrumb @user, tenant_users_path(@user.current_tenant, @user) + add_breadcrumb t("sip_accounts.index.page_title"), user_sip_accounts_path(@user) + add_breadcrumb @sip_account, user_sip_account_path(@user, @sip_account) + end + if @sip_account.sip_accountable_type == 'Tenant' + @tenant = @sip_account.sip_accountable + add_breadcrumb t("sip_accounts.index.page_title"), tenant_sip_accounts_path(@tenant) + add_breadcrumb @sip_account, tenant_sip_account_path(@tenant, @sip_account) + end + add_breadcrumb t("phone_numbers.index.page_title"), sip_account_phone_numbers_path(@sip_account) + add_breadcrumb @phone_number, sip_account_phone_number_path(@sip_account, @phone_number) + add_breadcrumb t("call_forwards.index.page_title"), phone_number_call_forwards_path(@phone_number) + if @call_forward && !@call_forward.new_record? + add_breadcrumb @call_forward, phone_number_call_forward_path(@phone_number, @call_forward) + end + end + end + + def call_forwarding_destination_types + + phone_number_destination = CallForwardingDestination.new() + phone_number_destination.id = ':PhoneNumber' + phone_number_destination.label = 'Phone Number' + voice_mail_destination = CallForwardingDestination.new() + voice_mail_destination.id = ':Voicemail' + voice_mail_destination.label = 'Voice Mail' + + call_forwarding_destinations = [ + phone_number_destination, + voice_mail_destination, + ] + + if GuiFunction.display?('huntgroup_in_destination_field_in_call_forward_form', @current_user) + HuntGroup.all.each do |hunt_group| + hunt_group_destination = CallForwardingDestination.new() + hunt_group_destination.id = "#{hunt_group.id}:HuntGroup" + hunt_group_destination.label = "HuntGroup: #{hunt_group.to_s}" + call_forwarding_destinations.push(hunt_group_destination) + end + end + + return call_forwarding_destinations + end + +end diff --git a/app/controllers/call_histories_controller.rb b/app/controllers/call_histories_controller.rb new file mode 100644 index 0000000..f956f88 --- /dev/null +++ b/app/controllers/call_histories_controller.rb @@ -0,0 +1,100 @@ +class CallHistoriesController < ApplicationController + + load_resource :sip_account + + before_filter :set_and_authorize_parent + before_filter :spread_breadcrumbs + + before_filter { |controller| + if ! params[:type].blank? then + @type = params[:type].to_s + end + + if ! params[:page].blank? then + @pagination_page_number = params[:page].to_i + end + } + + def index + hunt_group_member_ids = PhoneNumber.where(:phone_numberable_type => 'HuntGroupMember', :number => @sip_account.phone_numbers.map {|a| a.number}).map {|a| a.phone_numberable_id} + hunt_group_ids = HuntGroupMember.where(:id => hunt_group_member_ids, :active => true).map {|a| a.hunt_group_id} + calls = CallHistory.where('(call_historyable_type = "SipAccount" AND call_historyable_id = ?) OR (call_historyable_type = "HuntGroup" AND call_historyable_id IN (?))', @sip_account.id, hunt_group_ids).order('start_stamp DESC') + + @call_histories = calls.paginate( + :page => @pagination_page_number, + :per_page => DEFAULT_PAGINATION_ENTRIES_PER_PAGE + ) + + @calls_count = calls.count + @calls_received_count = calls.where(:entry_type => 'received').count + @calls_dialed_count = calls.where(:entry_type => 'dialed').count + @calls_missed_count = calls.where(:entry_type => 'missed').count + @calls_forwarded_count = calls.where(:entry_type => 'forwarded').count + + if ! @type.blank? + @call_histories = @call_histories.where(:entry_type => @type) + end + end + + + def destroy + @call_history = CallHistory.where(:id => params[:id]).first + if can?(:destroy, @call_history) + @call_history.destroy + m = method( :"#{@parent.class.name.underscore}_call_histories_url" ) + redirect_to m.(), :notice => t('call_histories.controller.successfuly_destroyed') + end + end + + def destroy_multiple + if ! params[:selected_ids].blank? then + result = @sip_account.call_histories.where(:id => params[:selected_ids]).destroy_all(); + end + + m = method( :"#{@parent.class.name.underscore}_call_histories_url" ) + if result + redirect_to m.(), :notice => t('call_histories.controller.successfuly_destroyed') + else + redirect_to m.() + end + end + + def call + @call_history = CallHistory.where(:id => params[:id]).first + if can?(:call, @call_history) && @sip_account.registration + phone_number = @call_history.display_number + if ! phone_number.blank? + @sip_account.call(phone_number) + end + end + redirect_to(:back) + end + + private + def set_and_authorize_parent + @parent = @sip_account + + authorize! :read, @parent + + @show_path_method = method( :"#{@parent.class.name.underscore}_call_history_path" ) + @index_path_method = method( :"#{@parent.class.name.underscore}_call_histories_path" ) + @new_path_method = method( :"new_#{@parent.class.name.underscore}_call_history_path" ) + @edit_path_method = method( :"edit_#{@parent.class.name.underscore}_call_history_path" ) + end + + def spread_breadcrumbs + if @parent.class == SipAccount + if @sip_account.sip_accountable.class == User + add_breadcrumb t("#{@sip_account.sip_accountable.class.name.underscore.pluralize}.index.page_title"), method( :"tenant_#{@sip_account.sip_accountable.class.name.underscore.pluralize}_path" ).(@sip_account.tenant) + add_breadcrumb @sip_account.sip_accountable, method( :"tenant_#{@sip_account.sip_accountable.class.name.underscore}_path" ).(@sip_account.tenant, @sip_account.sip_accountable) + end + add_breadcrumb t("sip_accounts.index.page_title"), method( :"#{@sip_account.sip_accountable.class.name.underscore}_sip_accounts_path" ).(@sip_account.sip_accountable) + add_breadcrumb @sip_account, method( :"#{@sip_account.sip_accountable.class.name.underscore}_sip_account_path" ).(@sip_account.sip_accountable, @sip_account) + add_breadcrumb t("call_histories.index.page_title"), sip_account_call_histories_path(@sip_account) + if @call_history && !@call_history.new_record? + add_breadcrumb @call_history, sip_account_call_history_path(@sip_account, @call_history) + end + end + end + +end diff --git a/app/controllers/calls_controller.rb b/app/controllers/calls_controller.rb new file mode 100644 index 0000000..d5f3b42 --- /dev/null +++ b/app/controllers/calls_controller.rb @@ -0,0 +1,6 @@ +class CallsController < ApplicationController + + def index + @calls = Call.all + end +end diff --git a/app/controllers/callthroughs_controller.rb b/app/controllers/callthroughs_controller.rb new file mode 100644 index 0000000..f489622 --- /dev/null +++ b/app/controllers/callthroughs_controller.rb @@ -0,0 +1,75 @@ +class CallthroughsController < ApplicationController + load_and_authorize_resource :tenant + load_and_authorize_resource :callthrough, :through => [:tenant] + + before_filter :set_parent_and_path_methods + before_filter :spread_breadcrumbs + + def index + end + + def show + end + + def new + @callthrough = @tenant.callthroughs.build + @callthrough.name = generate_a_new_name(@tenant, @callthrough) + @callthrough.phone_numbers.build + @callthrough.access_authorizations.build(:name => "#{t('access_authorizations.name')} #{@callthrough.access_authorizations.count + 1}", :pin => random_pin).phone_numbers.build + @callthrough.whitelists.build.phone_numbers.build + end + + def create + @callthrough = @tenant.callthroughs.build(params[:callthrough]) + if @callthrough.save + redirect_to tenant_callthrough_path(@tenant, @callthrough), :notice => t('callthroughs.controller.successfuly_created') + else + @callthrough.phone_numbers.build if @callthrough.phone_numbers.size == 0 + render :new + end + end + + def edit + @callthrough.phone_numbers.build + @callthrough.access_authorizations.build.phone_numbers.build + if @callthrough.whitelisted_phone_numbers.count == 0 + if @callthrough.whitelists.count == 0 + @callthrough.whitelists.build.phone_numbers.build + else + @callthrough.whitelists.first.phone_numbers.build + end + end + end + + def update + if @callthrough.update_attributes(params[:callthrough]) + redirect_to tenant_callthrough_path(@tenant, @callthrough), :notice => t('callthroughs.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @callthrough.destroy + redirect_to tenant_callthroughs_path(@tenant), :notice => t('callthroughs.controller.successfuly_destroyed') + end + + private + + def set_parent_and_path_methods + @parent = @tenant + @show_path_method = method( :"#{@parent.class.name.underscore}_callthrough_path" ) + @index_path_method = method( :"#{@parent.class.name.underscore}_callthroughs_path" ) + @new_path_method = method( :"new_#{@parent.class.name.underscore}_callthrough_path" ) + @edit_path_method = method( :"edit_#{@parent.class.name.underscore}_callthrough_path" ) + end + + def spread_breadcrumbs + if @parent && @parent.class == Tenant + add_breadcrumb t("callthroughs.name").pluralize, tenant_callthroughs_path(@parent) + if @callthrough && !@callthrough.new_record? + add_breadcrumb @callthrough, tenant_callthrough_path(@parent, @callthrough) + end + end + end +end diff --git a/app/controllers/conference_invitees_controller.rb b/app/controllers/conference_invitees_controller.rb new file mode 100644 index 0000000..ce55b5a --- /dev/null +++ b/app/controllers/conference_invitees_controller.rb @@ -0,0 +1,93 @@ +class ConferenceInviteesController < ApplicationController + load_and_authorize_resource :conference + load_and_authorize_resource :conference_invitee, :through => [:conference] + + before_filter :spread_breadcrumbs + + def index + end + + def show + end + + def new + @conference_invitee = @conference.conference_invitees.build + @conference_invitee.speaker = true + @conference_invitee.moderator = false + @phone_number = @conference_invitee.build_phone_number + end + + def create + @conference_invitee = @conference.conference_invitees.build(params[:conference_invitee]) + + # Try to find this phone_number in phone_books the current_user can read. + # Save the found entry as phone_book_entry. + # + @conference_invitee.phone_number.parse_and_split_number! + phone_numbers = PhoneNumber.where(:number => @conference_invitee.phone_number.number). + where(:phone_numberable_type => 'PhoneBookEntry') + phone_numbers.each do |phone_number| + phone_book = phone_number.phone_numberable.phone_book + if can?(:read, phone_book) + @conference_invitee.phone_book_entry = phone_number.phone_numberable + break + end + end + + if @conference_invitee.save + # m = method( :"#{@parent_in_route.class.name.underscore}_path" ) + # redirect_to m.( @parent_in_route ), :notice => t('conference_invitees.controller.successfuly_created', :resource => @conference_invitees) + m = method( :"#{@conference_invitee.conference.conferenceable_type.underscore}_conference_path") + redirect_to m.( @conference_invitee.conference.conferenceable, @conference_invitee.conference), :notice => t('conference_invitees.controller.successfuly_created', :resource => @conference_invitees) + else + render :new + end + end + + def edit + authorize! :edit, @parent_in_route + end + + def update + if @conference_invitee.update_attributes(params[:conference_invitee]) + redirect_to @conference_invitee, :notice => t('conference_invitees.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @conference_invitee.destroy + redirect_to conference_invitees_url, :notice => t('conference_invitees.controller.successfuly_destroyed') + end + + private + + def spread_breadcrumbs + if @conference + @parent = @conference.conferenceable + if @parent && @parent.class == User + @user = @parent + add_breadcrumb t("users.index.page_title"), tenant_users_path(@user.current_tenant) + add_breadcrumb @user, tenant_users_path(@user.current_tenant, @user) + add_breadcrumb t("conferences.index.page_title"), user_conferences_path(@user) + if @conference && !@conference.new_record? + add_breadcrumb @conference, user_conference_path(@user, @conference) + end + end + if @parent && @parent.class == Tenant + @tenant = @parent + add_breadcrumb t("conferences.index.page_title"), tenant_conferences_path(@tenant) + if @conference && !@conference.new_record? + add_breadcrumb @conference, tenant_conference_path(@tenant, @conference) + end + end + + add_breadcrumb t("conference_invitees.index.page_title"), conference_conference_invitees_path(@conference) + if @conference_invitee && !@conference_invitee.new_record? + add_breadcrumb @conference_invitee, conference_conference_invitee_path(@conference, @conference_invitee) + end + end + end + +end diff --git a/app/controllers/conferences_controller.rb b/app/controllers/conferences_controller.rb new file mode 100644 index 0000000..302a23b --- /dev/null +++ b/app/controllers/conferences_controller.rb @@ -0,0 +1,82 @@ +class ConferencesController < ApplicationController + load_resource :user + load_resource :tenant + load_and_authorize_resource :conference, :through => [:user, :tenant] + + before_filter :set_and_authorize_parent + before_filter :spread_breadcrumbs + + def index + end + + def show + @phone_numbers = @conference.phone_numbers + end + + def new + @conference = @parent.conferences.build + @conference.name = generate_a_new_name(@parent, @conference) + @conference.start = nil + @conference.end = nil + @conference.open_for_anybody = true + @conference.max_members = DEFAULT_MAX_CONFERENCE_MEMBERS + @conference.pin = random_pin + + @conference.open_for_anybody = true + @conference.announce_new_member_by_name = true + @conference.announce_left_member_by_name = true + end + + def create + @conference = @parent.conferences.build(params[:conference]) + if @conference.save + m = method( :"#{@parent.class.name.underscore}_conference_path" ) + redirect_to m.( @parent, @conference ), :notice => t('conferences.controller.successfuly_created') + else + render :new + end + end + + def edit + end + + def update + if @conference.update_attributes(params[:conference]) + m = method( :"#{@parent.class.name.underscore}_conference_path" ) + redirect_to m.( @parent, @conference ), :notice => t('conferences.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @conference.destroy + m = method( :"#{@parent.class.name.underscore}_conferences_url" ) + redirect_to m.( @parent ), :notice => t('conferences.controller.successfuly_destroyed') + end + + private + + def set_and_authorize_parent + @parent = @tenant || @user + authorize! :read, @parent + end + + def spread_breadcrumbs + if @parent && @parent.class == User + add_breadcrumb t("users.index.page_title"), tenant_users_path(@user.current_tenant) + add_breadcrumb @user, tenant_user_path(@user.current_tenant, @user) + add_breadcrumb t("conferences.index.page_title"), user_conferences_path(@user) + if @conference && !@conference.new_record? + add_breadcrumb @conference, user_conference_path(@user, @conference) + end + end + if @parent && @parent.class == Tenant + add_breadcrumb t("conferences.index.page_title"), tenant_conferences_path(@tenant) + if @conference && !@conference.new_record? + add_breadcrumb @conference, tenant_conference_path(@tenant, @conference) + end + end + end + +end diff --git a/app/controllers/config_polycom_controller.rb b/app/controllers/config_polycom_controller.rb new file mode 100644 index 0000000..9d44e51 --- /dev/null +++ b/app/controllers/config_polycom_controller.rb @@ -0,0 +1,330 @@ +class ConfigPolycomController < ApplicationController + MAX_SIP_ACCOUNTS_COUNT = 11 + MAX_SOFTKEYS_COUNT = 12 + MAX_DIRECTORY_ENTRIES = 20 + SIP_DEFAULT_PORT = 5060 + + skip_authorization_check + + before_filter { |controller| + if ! params[:mac_address].blank? then + @mac_address = params[:mac_address].upcase.gsub(/[^0-9A-F]/,'') + @phone = Phone.where({ :mac_address => @mac_address }).first + elsif ! params[:phone].blank? then + @phone = Phone.where({ :id => params[:phone].to_i }).first + end + + if ! @phone + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return false + end + + if ! params[:sip_account].blank? + @sip_account = @phone.sip_accounts.where({ :id => params[:sip_account].to_i }).first + if ! @sip_account + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return false + end + end + + if ! params[:type].blank? + @type = params[:type].to_s.strip.downcase + end + } + + def config_files + if params[:mac_address].blank? then + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + end + + respond_to { |format| + format.any { + self.formats = [ :xml ] + render + } + } + end + + def settings + if ! request.env['HTTP_USER_AGENT'].index('polycom') + Rails.logger.info "---> User-Agent indicates not a Polycom phone (#{request.env['HTTP_USER_AGENT'].inspect})" + else + Rails.logger.info "---> Phone #{@mac_address.inspect}, IP address #{request.remote_ip.inspect}" + @phone.update_attributes({ :ip_address => request.remote_ip }) + end + + xml_applications_url = "#{request.protocol}#{request.host_with_port}/config_polycom/#{@phone.id}/0" + + @settings = { + 'device.sntp.serverName' => 'pool.ntp.org', + 'device.sntp.gmtOffset' => 3600, + 'up.welcomeSoundOnWarmBootEnabled' => 0, + 'up.welcomeSoundEnabled' => 0, + 'bg.hiRes.color.selection' => '2,1', + 'msg.mwi.1.callBackMode' => 'contact', + 'msg.mwi.1.callBack' => 'f-vmcheck', + 'feature.enhancedFeatureKeys.enabled' => 1, + 'softkey.feature.basicCallManagement.redundant' => 0, + 'softkey.feature.buddies' => 0, + 'softkey.feature.callers' => 0, + 'softkey.feature.directories' => 0, + 'softkey.feature.endcall' => 1, + 'softkey.feature.forward' => 0, + 'softkey.feature.mystatus' => 0, + 'softkey.feature.newcall' => 0, + 'call.directedCallPickupMethod' => 'legacy', + 'call.directedCallPickupString' => 'f-ia-', + 'call.advancedMissedCalls.enabled' => 0, + 'lineKey.reassignment.enabled' => 1, + 'lineKey.1.category' => 'Line', + 'lineKey.1.index' => 1, + } + + for key_index in 2..42 + @settings["lineKey.#{key_index}.category"] = 'Unassigned' + end + + for ring_class in 1..17 + @settings["se.rt.custom#{ring_class}.name"] = "Ringer#{ring_class-1}" + @settings["se.rt.custom#{ring_class}.ringer"] = "ringer#{ring_class}" + end + @settings["se.rt.custom1.type"] = 'visual' + + for ring_class in 1..17 + @settings["voIpProt.SIP.alertInfo.#{ring_class}.class"] = "custom#{ring_class}" + @settings["voIpProt.SIP.alertInfo.#{ring_class}.value"] = "Ringer#{ring_class-1}" + end + + softkey_index = 1 + blf_index = 0 + + @phone.sip_accounts.each do |sip_account| + sip_account_index = 0 + if (sip_account.sip_accountable_type == @phone.phoneable_type) and (sip_account.sip_accountable_id == @phone.phoneable_id) + sip_account_index += 1 + if sip_account_index == 1 + xml_applications_url = "#{request.protocol}#{request.host_with_port}/config_polycom/#{@phone.id}/#{sip_account.id}" + @settings['voIpProt.SIP.outboundProxy.address'] = sip_account.host + @settings['voIpProt.SIP.outboundProxy.port'] = SIP_DEFAULT_PORT + end + + @settings["reg.#{sip_account_index}.address"] = "#{sip_account.auth_name}@#{sip_account.host}" + @settings["reg.#{sip_account_index}.auth.password"] = sip_account.password + @settings["reg.#{sip_account_index}.auth.userId"] = sip_account.auth_name + @settings["reg.#{sip_account_index}.displayName"] = 'Call' + @settings["reg.#{sip_account_index}.label"] = sip_account.caller_name + @settings["voIpProt.server.#{sip_account_index}.address"] = sip_account.host + @settings["voIpProt.server.#{sip_account_index}.port"] = SIP_DEFAULT_PORT + @settings["call.missedCallTracking.#{sip_account_index}.enabled"] = 0 + + sip_account.softkeys.order(:position).each do |softkey| + softkey_index += 1 + if softkey.softkey_function + softkey_function = softkey.softkey_function.name + end + case softkey_function + when 'blf' + blf_index += 1 + @settings["lineKey.#{softkey_index}.category"] = 'BLF' + @settings["attendant.resourceList.#{blf_index}.address"] = "#{softkey.number}@#{sip_account.host}" + @settings["attendant.resourceList.#{blf_index}.label"] = softkey.label + end + end + end + end + + @settings['mb.idleDisplay.home'] = "#{xml_applications_url}/idle_screen.xml" + @settings['mb.idleDisplay.refresh'] = 60 + + @settings['efk.efklist.1.mname'] = "directory" + @settings['efk.efklist.1.status'] = 1 + @settings['efk.efklist.1.action.string'] = "#{xml_applications_url}/phone_book.xml" + @settings['efk.efklist.2.mname'] = "callhistory" + @settings['efk.efklist.2.status'] = 1 + @settings['efk.efklist.2.action.string'] = "#{xml_applications_url}/call_history.xml" + @settings['efk.efklist.3.mname'] = "applications" + @settings['efk.efklist.3.status'] = 1 + @settings['efk.efklist.3.action.string'] = "#{xml_applications_url}/applications.xml" + + @settings['softkey.1.action'] = "#{xml_applications_url}/phone_book.xml" + @settings['softkey.1.enable'] = 1 + @settings['softkey.1.insert'] = 1 + @settings['softkey.1.label'] = 'Directory' + @settings['softkey.1.precede'] = 1 + @settings['softkey.1.use.active'] = 1 + @settings['softkey.1.use.alerting'] = 0 + @settings['softkey.1.use.dialtone'] = 1 + @settings['softkey.1.use.hold'] = 1 + @settings['softkey.1.use.idle'] = 1 + @settings['softkey.1.use.proceeding'] = 0 + @settings['softkey.1.use.setup'] = 0 + @settings['softkey.2.action'] = "#{xml_applications_url}/call_history.xml" + @settings['softkey.2.enable'] = 1 + @settings['softkey.2.insert'] = 2 + @settings['softkey.2.label'] = 'Call History' + @settings['softkey.2.precede'] = 1 + @settings['softkey.2.use.active'] = 1 + @settings['softkey.2.use.alerting'] = 0 + @settings['softkey.2.use.dialtone'] = 1 + @settings['softkey.2.use.hold'] = 1 + @settings['softkey.2.use.idle'] = 1 + @settings['softkey.2.use.proceeding'] = 0 + @settings['softkey.2.use.setup'] = 0 + + respond_to { |format| + format.any { + self.formats = [ :xml ] + render + } + } + end + + + def settings_directory + respond_to { |format| + format.any { + self.formats = [ :xml ] + render + } + } + end + + + def call_history + + if ! @sip_account + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + if ['dialed', 'missed', 'received'].include? @type + @phone_xml_object = { + :name => "call_history", + :title => @type.titleize, + :entries => [] + } + + calls = @sip_account.call_histories.where(:entry_type => @type).order('start_stamp DESC').limit(MAX_DIRECTORY_ENTRIES) + + calls.each do |call| + display_name = call.display_name + phone_number = call.display_number + phone_book_entry = call.phone_book_entry_by_number(phone_number) + if display_name.blank? + display_name = phone_book_entry.to_s + end + + @phone_xml_object[:entries].push({ + :selected => false, + :number => phone_number, + :date => call.start_stamp.strftime('%d.%m %H:%M'), + :text => display_name, + :url => "tel:#{phone_number}", + }) + end + else + base_url = "#{request.protocol}#{request.host_with_port}#{request.fullpath.split("?")[0]}" + @phone_xml_object = { + :name => 'call_history_menu', + :title => 'Call History Lists', + :entries => [ + {:text => 'Missed Calls', :url => "#{base_url}?&type=missed", :selected => false}, + {:text => 'Received Calls', :url => "#{base_url}?&type=received", :selected => false}, + {:text => 'Placed Calls', :url => "#{base_url}?&type=dialed", :selected => false}, + ] + } + end + + respond_to { |format| + format.any { + self.formats = [ :xml ] + render :action => "_#{@phone_xml_object[:name]}", :content_type => Mime::HTML + } + } + + end + + + def phone_book + + if ! @sip_account + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + @phone_xml_object = { + :name => 'phone_book', + :title => "Phone Book".strip, + :entries => [], + :softkeys => [], + } + + phone_books = Array.new() + phone_books = phone_books + @sip_account.sip_accountable.try(:phone_books).all + if @sip_account.sip_accountable.class == User + phone_books = phone_books + @sip_account.sip_accountable.try(:current_tenant).try(:phone_books).all + end + + phone_book_ids = Array.new() + phone_books.each do |phone_book| + phone_book_ids << phone_book.id + end + + PhoneBookEntry.where(:phone_book_id => phone_book_ids).order(:last_name).order(:first_name).limit(MAX_DIRECTORY_ENTRIES).each do |phone_book_entry| + phone_numbers_count = 0 + phone_book_entry.phone_numbers.each do |phone_number| + phone_numbers_count += 1 + if phone_numbers_count > 1 + entry_name = '' + else + entry_name = phone_book_entry.to_s + end + + @phone_xml_object[:entries] << { :text => entry_name, :type => phone_number.name, :number => phone_number.number, :url => "tel:#{phone_number.number}" } + end + end + + respond_to { |format| + format.any { + self.formats = [ :xml ] + render :action => "_#{@phone_xml_object[:name]}", :content_type => Mime::HTML + } + } + + end + + + def idle_screen + respond_to { |format| + format.any { + self.formats = [ :xml ] + render :action => "idle_screen", :content_type => Mime::HTML + } + } + end +end diff --git a/app/controllers/config_siemens_controller.rb b/app/controllers/config_siemens_controller.rb new file mode 100644 index 0000000..f398b1a --- /dev/null +++ b/app/controllers/config_siemens_controller.rb @@ -0,0 +1,1239 @@ +require 'nokogiri' +#doc.search('Message/ItemList').each do |a| puts a.children end +class ConfigSiemensController < ApplicationController +#TODO Authentication + # No access for admins though as this contains personal data. + + # We can't use load_and_authorize_resource() here because + # ConfigSiemensController isn't a resource. + # We can try client certificates + MAX_DIRECTORY_ENTRIES = 20 + + skip_authorization_check + + before_filter { |controller| + if ! params[:phone].blank? + @phone = Phone.where({ :id => params[:phone].to_i }).first + end + + if ! params[:sip_account].blank? + @sip_account = SipAccount.where({ :id => params[:sip_account].to_i }).first + end + + if ! @sip_account && @phone + @sip_account = @phone.sip_accounts.where(:sip_accountable_id => @phone.phoneable_id, :sip_accountable_type => @phone.phoneable_type).first + end + } + + + def index + os40_keys=6 + os60_keys=8 + os80_keys=9 + doc = Nokogiri::XML(request.body.read) + #logger.debug("#{params[:WorkpointMessage].to_xml}") + #logger.debug("#{params[:WorkpointMessage][:Message][:ItemList].to_xml}") + @phone_items=Hash.new + contact_reason = params[:WorkpointMessage][:Message][:ReasonForContact] + fragment = params[:WorkpointMessage][:Message][:fragment] + + reply_status = doc.search('Message/ReasonForContact').first[:status] + reply_action = doc.search('Message/ReasonForContact').first[:action] + + doc.search('Message/ItemList/Item').each do |post_item| + @phone_items[post_item[:name]]=post_item.children.to_s + end + if @phone_items['mac-addr'] + mac_address = @phone_items['mac-addr'] + end + phone_type = @phone_items['device-type'] + if phone_type == "OpenStage 40" + max_keys = (os40_keys) * 2 + elsif phone_type == "OpenStage 60" + max_keys = (os60_keys) * 2 + elsif phone_type == "OpenStage 80" + max_keys = (os80_keys) * 2 + else + max_keys = 0 + end + + blf_keys_max = max_keys / 2 + shift_key_position = blf_keys_max + + #logger.debug(request.body.read) + if mac_address + @phone = Phone.find_by_mac_address(mac_address.gsub(':','').upcase) + + if ! @phone && PROVISIONING_AUTO_ADD_PHONE + tenant = Tenant.where(:id => PROVISIONING_AUTO_TENANT_ID).first + if ! tenant + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + @phone = tenant.phones.build + @phone.mac_address = mac_address + @phone.hot_deskable = true + @phone.phone_model = PhoneModel.where('name LIKE ?', "#{phone_type}").first + if ! @phone.save + render( + :status => 500, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + if ! PROVISIONING_AUTO_ADD_SIP_ACCOUNT + return + end + + caller_name_index = 0 + sip_account_last = tenant.sip_accounts.where('caller_name LIKE ?', "#{PROVISIONING_AUTO_SIP_ACCOUNT_CALLER_PREFIX}%").sort { |item1, item2| + item1.caller_name.gsub(/[^0-9]/, '').to_i <=> item2.caller_name.gsub(/[^0-9]/, '').to_i + }.last + + if sip_account_last + caller_name_index = sip_account_last.caller_name.gsub(/[^0-9]/, '').to_i + end + caller_name_index = caller_name_index + 1 + + @sip_account = tenant.sip_accounts.build + @sip_account.caller_name = "#{PROVISIONING_AUTO_SIP_ACCOUNT_CALLER_PREFIX}#{caller_name_index}" + @sip_account.call_waiting = CALL_WAITING + @sip_account.clir = DEFAULT_CLIR_SETTING + @sip_account.clip = DEFAULT_CLIP_SETTING + @sip_account.voicemail_pin = random_pin + @sip_account.callforward_rules_act_per_sip_account = CALLFORWARD_RULES_ACT_PER_SIP_ACCOUNT_DEFAULT + @sip_account.hotdeskable = false + loop do + @sip_account.auth_name = SecureRandom.hex(DEFAULT_LENGTH_SIP_AUTH_NAME) + break unless SipAccount.exists?(:auth_name => @sip_account.auth_name) + end + @sip_account.password = SecureRandom.hex(DEFAULT_LENGTH_SIP_PASSWORD) + + if ! @sip_account.save + render( + :status => 500, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + phone_sip_account = PhoneSipAccount.new() + phone_sip_account.phone_id = @phone.id + phone_sip_account.sip_account_id = @sip_account.id + + if ! phone_sip_account.save + render( + :status => 500, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + end + end + + + country = 'US' + language = 'en' + if ! @phone.nil? + @phone.update_attributes(:ip_address => request.remote_ip) + @sip_account = @phone.sip_accounts.where(:sip_accountable_type => @phone.phoneable_type, + :sip_accountable_id => @phone.phoneable_id).first + + if @phone.phoneable + if @phone.phoneable_type == 'Tenant' + tenant = @phone.phoneable + language = tenant.language.code + elsif @phone.phoneable_type == 'User' + language = @phone.phoneable.language.code + tenant = @phone.phoneable.current_tenant + end + end + + if tenant && tenant.country + country_map = { + '61' => 'AU', # Australia + '43' => 'AT', # Austria + '86' => 'CN', # China + '45' => 'DK', # Denmark + '33' => 'FA', # France + '49' => 'DE', # Germany + '44' => 'GB', # Great Britain + '91' => 'IN', # India + '39' => 'IT', # Italy + '81' => 'JP', # Japan + '52' => 'MX', # Mexico + '31' => 'NL', # Netherlands + '47' => 'NO', # Norway + '64' => 'NZ', # New Zealand + '34' => 'ES', # Spain + '46' => 'SE', # Sweden + '41' => 'CH', # Switzerland + } + if country_map.include?(tenant.country.country_code) + country = country_map[tenant.country.country_code] + end + end + end + + if ! @phone.nil? && ! @sip_account.blank? + #logger.debug(@phone_items) + @my_nonce = params[:WorkpointMessage][:Message][:nonce] + @new_settings = Array.new + + @new_settings << ['dhcp', nil, 'true'] + @new_settings << ['hostname', nil, mac_address.gsub(':', '') ] + #@new_settings << ['e164-hostname', nil, 'false'] + @new_settings << ['mobility-enabled', nil, 'false'] + @new_settings << ['mobility-password-on-logoff', nil, 'false'] + @new_settings << ['e164', nil, @sip_account.auth_name] + @new_settings << ['sip-user-id', nil, @sip_account.auth_name] + #Not supported + #@new_settings << ['reg-id', nil, @sip_account.auth_name] + #@new_settings << ['reg-number', nil, @sip_account.auth_name] + #@new_settings << ['fully-qualified-phone-no', nil, @sip_account.auth_name] + @new_settings << ['sip-pwd', nil, @sip_account.password] + @new_settings << ['sip-name', nil, @sip_account.caller_name] + @new_settings << ['register-by-name', nil, 'false'] + @new_settings << ['display-id-unicode', nil, @sip_account.caller_name] + @new_settings << ['use-display-id', nil, 'true'] + @new_settings << ['reg-addr', nil, @sip_account.sip_domain.host] + @new_settings << ['reg-port', nil, '5060'] + @new_settings << ['registrar-addr', nil, @sip_account.sip_domain.host] + @new_settings << ['registrar-port', nil, '5060'] + #@new_settings << ['outbound-proxy', nil, @sip_account.sip_domain.host] + @new_settings << ['outbound-proxy-user', nil, @sip_account.auth_name] + #@new_settings << ['sgnl-gateway-addr', nil, @sip_account.sip_domain.host] + #@new_settings << ['sgnl-gateway-port', nil, '5060' ] + @new_settings << ['sgnl-gateway-addr-user', nil, @sip_account.sip_domain.host] + @new_settings << ['sgnl-gateway-port-user', nil, '5060'] + @new_settings << ['sgnl-route', nil, '0' ] + @new_settings << ['mwi-e164', nil, '' ] + @new_settings << ['rtp-base-port', nil, '5004'] + @new_settings << ['default-domain', nil, '' ] + #@new_settings << ['sip-transport', nil, '0' ] + @new_settings << ['sip-transport-user', nil, '0' ] + @new_settings << ['server-type', nil, '0' ] + @new_settings << ['session-timer', nil, 'false' ] + @new_settings << ['session-duration', nil, '3600' ] + @new_settings << ['reg-ttl', nil, '3600' ] + @new_settings << ['realm', nil, @sip_account.sip_domain.realm] + @new_settings << ['emergency-e164', nil, '0110' ] + @new_settings << ['voice-mail-e164', nil, 'f-vmcheck'] + @new_settings << ['auto-answer', nil, 'false'] + @new_settings << ['beep-on-auto-answer', nil, 'true'] + @new_settings << ['auto-reconnect', nil, 'false' ] + @new_settings << ['beep-on-auto-reconnect', nil, 'true'] + #@new_settings << ['permit-decline-call', nil, 'true'] + @new_settings << ['transfer-on-ring', nil, 'false' ] + @new_settings << ['join-allowed-in-conference', nil, 'true'] + @new_settings << ['pickup-group-uri', nil, "f-ig-#{@sip_account.id}"] + @new_settings << ['pickup-group-uri', nil, '' ] + @new_settings << ['hot-line-warm-line-digits', nil, '' ] + @new_settings << ['initial-digit-timer', nil, '30' ] + @new_settings << ['conference-factory-uri', nil, ''] + @new_settings << ['callback-busy-allow', nil, 'false'] + @new_settings << ['callback-busy-code', nil, '' ] + @new_settings << ['callback-ring-allow', nil, 'false'] + @new_settings << ['callback-ring-code', nil, ''] + @new_settings << ['callback-cancel-code', nil, ''] + @new_settings << ['park-server', nil, ''] + #OPTIMIZE Callwaiting + @new_settings << ['call-waiting-enabled', nil, 'true'] + @new_settings << ['qos-layer2', nil, 'true'] + @new_settings << ['l2qos-voice', nil, '5' ] + @new_settings << ['l2qos-signalling', nil, '3' ] + @new_settings << ['l2qos-default', nil, '0'] + @new_settings << ['qos-layer3', nil, 'true'] + @new_settings << ['l3qos-voice', nil, '46'] + @new_settings << ['l3qos-signalling', nil, '26'] + @new_settings << ['vlan-method', nil, '1'] + #OPTIMIZE Timezone settings + @new_settings << ['time', nil, Time.new.localtime.to_i] + @new_settings << ['sntp-addr', nil, 'NULL'] + @new_settings << ['sntp-tz-offset', nil, (Time.new.utc_offset/60).to_i] + @new_settings << ['daylight-save', nil, 'true'] + @new_settings << ['daylight-save-minutes', nil, '0'] + @new_settings << ['auto-daylight-save', nil, 'true'] + @new_settings << ['daylight-save-zone-id', nil, '9'] + #OPTIMIZE Use SNMP? + @new_settings << ['snmp-trap-addr', nil, 'NULL'] + @new_settings << ['snmp-trap-port', nil, '162'] + @new_settings << ['snmp-trap-pwd', nil, 'snmp' ] + @new_settings << ['snmp-traps-active', nil, 'false' ] + @new_settings << ['diagnostic-trap-addr', nil, 'NULL'] + @new_settings << ['diagnostic-trap-port', nil, '162'] + @new_settings << ['diagnostic-trap-pwd', nil, 'snmp' ] + @new_settings << ['diagnostic-traps-active', nil, 'false' ] + @new_settings << ['diagnostic-snmp-active', nil, 'false'] + @new_settings << ['qdc-collection-unit-addr', nil, 'NULL'] + @new_settings << ['qdc-collection-unit-port', nil, '12010'] + + @new_settings << ['qdc-trap-pwd', nil, 'QOSDC'] + @new_settings << ['qdc-snmp-active', nil, 'false'] + @new_settings << ['qdc-qcu-active', nil, 'false'] + @new_settings << ['snmp-queries-allowed', nil, 'false'] + #@new_settings << ['snmp-pwd', nil, ''] + @new_settings << ['disable-microphone', nil, 'false'] + @new_settings << ['loudspeech-enabled', nil, 'true'] + @new_settings << ['audio-silence-suppression', nil, 'false'] + + @new_settings << ['port1', nil, '0' ] # 0=Automatic (speed) + @new_settings << ['port2', nil, '0' ] + @new_settings << ['port2-mode', nil, '1' ] + @new_settings << ['port2-auto-mdix-enabled', nil, 'true' ] + @new_settings << ['originating-line-preference', nil, '0'] + @new_settings << ['terminating-line-preference', nil, '0'] + @new_settings << ['line-key-operating-mode', nil, '0'] + @new_settings << ['line-rollover-type', nil, '2'] + @new_settings << ['line-rollover-volume', nil, '5' ]# 1-5 + @new_settings << ['line-registration-leds', nil, 'true'] + @new_settings << ['keyset-use-focus', nil, 'true' ] + @new_settings << ['keyset-remote-forward-ind', nil, 'true'] + @new_settings << ['keyset-reservation-timer', nil, '60' ] # 0-300 + @new_settings << ['dial-plan-enabled', nil, 'false' ] + @new_settings << ['Canonical-dialing-international-prefix', nil, ''] + @new_settings << ['Canonical-dialing-local-country-code', nil, ''] + @new_settings << ['Canonical-dialing-national-prefix', nil, ''] + @new_settings << ['Canonical-dialing-local-area-code', nil, ''] + @new_settings << ['Canonical-dialing-local-node', nil, ''] + @new_settings << ['Canonical-dialing-external-access', nil, '0'] + @new_settings << ['Canonical-dialing-operator-code', nil, ''] + @new_settings << ['Canonical-dialing-emergency-number', nil, ''] + @new_settings << ['Canonical-dialing-dial-needs-access-code', nil, '0'] + @new_settings << ['Canonical-dialing-dial-needs-intGWcode', nil, '1'] + @new_settings << ['Canonical-dialing-min-local-number-length', nil, '10'] + @new_settings << ['Canonical-dialing-extension-initial-digits', nil, ''] + @new_settings << ['Canonical-dialing-dial-internal-form', nil, '0' ] + @new_settings << ['Canonical-dialing-dial-external-form', nil, '0' ] + #@new_settings << ['Canonical-lookup-local-code', nil, '' ] + #@new_settings << ['Canonical-lookup-international-code', nil, ''] + @new_settings << ['hot-keypad-dialing', nil, 'false'] + @new_settings << ['ldap-transport', nil, '0'] + @new_settings << ['ldap-server-address', nil, 'NULL' ] + @new_settings << ['ldap-server-port', nil, '389' ] + @new_settings << ['ldap-authentication', nil, '1'] + @new_settings << ['ldap-user', nil, 'NULL' ] + @new_settings << ['ldap-pwd', nil, 'NULL' ] + @new_settings << ['ldap-max-responses', nil, '25'] + @new_settings << ['backup-addr', nil, 'NULL'] + @new_settings << ['backup-registration', nil, 'false'] + @new_settings << ['qdc-qcu-active', nil, 'false' ] + @new_settings << ['min-admin-passw-length', nil, '6' ] + #@new_settings << ['default-locked-config-menus', nil, 'true' ] + @new_settings << ['locked-config-menus', nil, 'true' ] + #@new_settings << ['default-locked-local-function-menus', nil, 'true' ] + @new_settings << ['locked-local-function-menus', nil, 'true' ] + #@new_settings << ['dls-mode-secure', nil, '0' ] + @new_settings << ['dls-chunk-size', nil, '9492'] + #@new_settings << ['default-passw-policy', nil, 'false'] + @new_settings << ['deflect-destination', nil, ''] + @new_settings << ['display-skin', nil, (@phone.phoneable_type == 'User' ? '0' : '1')] + @new_settings << ['enable-bluetooth-interface', nil, 'true'] + @new_settings << ['usb-access-enabled', nil, 'false' ] + @new_settings << ['usb-backup-enabled', nil, 'false' ] + @new_settings << ['line-button-mode', nil, '0' ] + @new_settings << ['lock-forwarding', nil, '' ] + @new_settings << ['loudspeaker-function-mode', nil, '0' ] + @new_settings << ['max-pin-retries', nil, '10' ] + @new_settings << ['screensaver-enabled', nil, 'false' ] + @new_settings << ['inactivity-timeout', nil, '60' ] + @new_settings << ['not-used-timeout', nil, '5' ] + @new_settings << ['passw-char-set', nil, '0' ] + @new_settings << ['refuse-call', nil, 'true' ] + @new_settings << ['restart-password', nil, '124816'] + #OPTIMIZE clock format + @new_settings << ['time-format', nil, '0' ]# 1=12 h + @new_settings << ['uaCSTA-enabled', nil, 'false' ] + @new_settings << ['enable-test-interface', nil, 'false'] + @new_settings << ['enable-WBM', nil, 'true'] + #@new_settings << ['pixelsaver-timeout', nil, '2' ]# 2 hours? + #@new_settings << ['voice-message-dial-tone', nil, '' ] + #@new_settings << ['call-pickup-allowed', nil, 'true' ] + @new_settings << ['group-pickup-tone-allowed', nil, 'true'] + @new_settings << ['group-pickup-as-ringer', nil, 'false'] + @new_settings << ['group-pickup-alert-type', nil, '0' ] + #@new_settings << ['default-profile', nil, '' ] + @new_settings << ['count-medium-priority', nil, '5'] + @new_settings << ['timer-medium-priority', nil, '60'] # 1 - 999 + @new_settings << ['timer-high-priority', nil, '5'] # 0 - 999 + @new_settings << ['dss-sip-detect-timer', nil, '10'] + @new_settings << ['dss-sip-deflect', nil, 'false' ] + @new_settings << ['dss-sip-refuse', nil, 'false' ] + @new_settings << ['feature-availability', nil, 'false'] + @new_settings << ['feature-availability', nil, 'true' ] + @new_settings << ['feature-availability', nil, 'true' ] + @new_settings << ['local-control-feature-availability', nil, 'false' ] + @new_settings << ['trace-level', nil, '0' ] # Off + #@new_settings << ['default-locked-function-keys', nil, 'true' ]# "unknown item" + @new_settings << ['blf-code', nil, 'f-ia-'] # pickup prefix for softkey function 59 (BLF) + @new_settings << ['stimulus-feature-code', nil, true] + @new_settings << ['stimulus-led-control-uri', nil, true] + + @new_settings << ['min-user-passw-length', nil, '6' ]# 6 - 24 + #OPTIMIZE language + @new_settings << ['country-iso', nil, country ] + @new_settings << ['language-iso', nil, language] + @new_settings << ['date-format', nil, '0' ] # DD.MM.YYYY + #OPTIMIZE ringtones + @new_settings << ['ringer-melody', nil, '1'] + + @new_settings << ['ringer-melody', nil, '2'] + @new_settings << ['ringer-tone-sequence', nil, '2'] + + 1.upto(8) do |index| + @new_settings << ['alert', index, "Ringer#{index}^#{index}^2^60"] + end + @new_settings << ['alert', 9, "Ringer9^1^1^60"] + @new_settings << ['alert', 10, "Ringer10^1^3^60"] + @new_settings << ['alert', 11, "Ringer0^0^2^60"] + + #Applications + @new_settings << ['XML-app-name', 1, 'call_history'] + @new_settings << ['XML-app-control-key', 1, '3'] + @new_settings << ['XML-app-action', 1, 'update'] + @new_settings << ['XML-app-display-name', 1, 'Call History'] + @new_settings << ['XML-app-program-name', 1, "config_siemens/#{@phone.id}/call_history.xml"] + @new_settings << ['XML-app-special-instance', 1, '3'] + @new_settings << ['XML-app-server-addr', 1, request.host] + @new_settings << ['XML-app-server-port', 1, '80'] + @new_settings << ['XML-app-transport', 1, '0'] + @new_settings << ['XML-app-proxy-enabled', 1, 'false'] + @new_settings << ['XML-app-remote-debug', 1, 'false'] + @new_settings << ['XML-app-debug-prog-name', 1, ''] + @new_settings << ['XML-app-num-tabs', 1, '3'] + @new_settings << ['XML-app-restart', 1, 'true'] + @new_settings << ['XML-app-auto-start', 1, 'true'] + @new_settings << ['XML-app-tab1-display-name', 1, 'Missed'] + @new_settings << ['XML-app-tab1-name', 1, 'call_history'] + @new_settings << ['XML-app-tab2-display-name', 1, 'Received'] + @new_settings << ['XML-app-tab2-name', 1, 'call_history_received'] + @new_settings << ['XML-app-tab3-display-name', 1, 'Dialed'] + @new_settings << ['XML-app-tab3-name', 1, 'call_history_dialed'] + + @new_settings << ['XML-app-name', 2, 'menu'] + @new_settings << ['XML-app-control-key', 2, '6'] + @new_settings << ['XML-app-action', 2, 'update'] + @new_settings << ['XML-app-display-name', 2, 'Menu'] + @new_settings << ['XML-app-program-name', 2, "config_siemens/#{@phone.id}/menu.xml"] + @new_settings << ['XML-app-special-instance', 2, '0'] + @new_settings << ['XML-app-server-addr', 2, request.host] + @new_settings << ['XML-app-server-port', 2, '80'] + @new_settings << ['XML-app-transport', 2, '0'] + @new_settings << ['XML-app-proxy-enabled', 2, 'false'] + @new_settings << ['XML-app-remote-debug', 2, 'false'] + @new_settings << ['XML-app-debug-prog-name', 2, ''] + @new_settings << ['XML-app-num-tabs', 2, '3'] + @new_settings << ['XML-app-restart', 2, 'true'] + @new_settings << ['XML-app-tab1-display-name', 2, "Gemeinschaft #{GEMEINSCHAFT_VERSION}"] + @new_settings << ['XML-app-tab1-name', 2, 'menu'] + @new_settings << ['XML-app-tab2-display-name', 2, 'Status'] + @new_settings << ['XML-app-tab2-name', 2, 'menu_status'] + @new_settings << ['XML-app-tab3-display-name', 2, 'Help'] + @new_settings << ['XML-app-tab3-name', 2, 'menu_help'] + + + @new_settings << ['clear-calllog', nil, 'true'] + @new_settings << ['server-based-features', nil, 'true'] + + + if ! @sip_account.call_forwards.blank? + call_forwarding_object = @sip_account.call_forwards.where(:call_forward_case_id => CallForwardCase.where(:value => 'always').first).first + if call_forwarding_object + @new_settings << ['key-functionality', 4002, '1'] + @new_settings << ['function-key-def', 4002, '63'] + @new_settings << ['stimulus-led-control-uri', 4002, "f-cftg-#{call_forwarding_object.id}" ] + @new_settings << ['send-url-address', 4002, request.host] + @new_settings << ['send-url-protocol', 4002, 3] # 0=https, 3=http + @new_settings << ['send-url-port', 4002, '80'] + @new_settings << ['send-url-path', 4002, "/config_siemens/#{@phone.id}/#{@sip_account.id}/call_forwarding.xml"] + @new_settings << ['send-url-query', 4002, "id=#{call_forwarding_object.id}&function=toggle"] + @new_settings << ['send-url-method', 4002, '0'] # 0=get, 1=post + else + @new_settings << ['key-functionality', 4002, '0'] + end + else + @new_settings << ['key-functionality', 4002, '0'] + end + + @new_settings << ['function-key-def', 4003, '10'] # Hold + + @new_settings << ['feature-availability', 2, 'false' ] # call forwarding + @new_settings << ['feature-availability', 11, 'false' ] # DND + @new_settings << ['feature-availability', 30, 'false'] # DSS + @new_settings << ['feature-availability', 31, 'false'] # feature toggle + @new_settings << ['feature-availability', 33, 'true'] # line overview + @new_settings << ['feature-availability', 33, 'false'] # phone lock + + + @soft_keys = Array.new + # Fill softkeys with keys dependent on limit of phone + @sip_account.softkeys.order(:position).each do |sk| + @soft_keys << sk + end + # Delete unset softkeys + # OPTIMIZE 40 should be enough for 2 modules, but for some reason array is empty o early + max_keys = max_keys + 50 + while @soft_keys.length <= max_keys + @soft_keys << Softkey.new + end + + @key_pos=1 + + #@soft_keys.each do |sk| + + while @key_pos < shift_key_position + + (1..shift_key_position-1).each do |idx| + first_level_keys(idx) + end + end + if @key_pos == shift_key_position + @new_settings << ['function-key-def', shift_key_position, '18'] + @new_settings << ['key-label', shift_key_position, 'Shift'] + @new_settings << ['key-label-unicode', shift_key_position, 'Shift'] + @key_pos = @key_pos+1 + end + + (1001..1000+shift_key_position-1).each do |idx| + second_level_keys(idx) + end + # First key-module first level + (301..311).each do |idx| + first_level_keys(idx) + end + # First key-module shift level + (1301..1311).each do |idx| + second_level_keys(idx) + end + # Second key-module first level + (401..411).each do |idx| + first_level_keys(idx) + end + # Second key-module shift level + (1401..1411).each do |idx| + second_level_keys(idx) + end + [312, 412].each do |idx| + @new_settings << ['function-key-def', idx, '18'] + @new_settings << ['key-label', idx, 'Shift'] + @new_settings << ['key-label-unicode', idx, 'Shift'] + end + #end + logger.debug(@new_settings) + end + + if (@phone.nil? || @sip_account.blank?) && fragment != "final" + @new_settings = Array.new + @my_nonce = params[:WorkpointMessage][:Message][:nonce] + @new_settings << ['e164', nil, 'NULL'] + @new_settings << ['sip-user-id', nil, ""] + @new_settings << ['sip-pwd', nil, ""] + @new_settings << ['sip-name', nil, ""] + @new_settings << ['display-id-unicode', nil, ""] + @new_settings << ['reg-addr', nil, ""] + @new_settings << ['registrar-addr', nil, "NULL"] + @new_settings << ['outbound-proxy-user', nil, ""] + @new_settings << ['sgnl-gateway-addr-user', nil, ""] + @new_settings << ['realm', nil, ""] + @new_settings << ['pickup-group-uri', nil, ""] + logger.debug(@new_settings) + + respond_to { |format| + format.xml { render :action => "write" } + } + elsif contact_reason == 'local-changes' + respond_to { |format| + format.xml { render :action => "clean-up" } + } + elsif (reply_status == 'accepted' && contact_reason == 'reply-to' && reply_action == 'ReadAllItems') + respond_to { |format| + format.xml { render :action => "write" } + } + + elsif ["reply-to"].include? contact_reason + respond_to { |format| + format.xml { render :action => "clean-up" } + } + + else + respond_to { |format| + format.xml { render :action => "index" } + } + end + + end + + def first_level_keys(key_idx) + sk = @soft_keys.shift + if sk.softkey_function + softkey_function = sk.softkey_function.name + end + case softkey_function + when 'blf' + @new_settings << ['function-key-def', key_idx, '59'] + @new_settings << ['stimulus-led-control-uri', key_idx, sk.number ] + @new_settings << ['stimulus-DTMF-sequence', key_idx, sk.number ] + @new_settings << ['blf-popup', key_idx, 'true'] + when 'log_out' + @new_settings << ['function-key-def', key_idx, '1'] + @new_settings << ['select-dial', key_idx, 'f-lo' ] + @new_settings << ['stimulus-led-control-uri', key_idx, '' ] + @new_settings << ['stimulus-DTMF-sequence', key_idx, '' ] + when 'log_in' + @new_settings << ['function-key-def', key_idx, '1'] + @new_settings << ['select-dial', key_idx, "f-li-#{sk.number}" ] + @new_settings << ['stimulus-led-control-uri', key_idx, '' ] + @new_settings << ['stimulus-DTMF-sequence', key_idx, '' ] + when 'hold' + @new_settings << ['function-key-def', key_idx, '10'] + @new_settings << ['select-dial', key_idx, '' ] + @new_settings << ['stimulus-led-control-uri', key_idx, '' ] + @new_settings << ['stimulus-DTMF-sequence', key_idx, '' ] + when 'dtmf' + @new_settings << ['function-key-def', key_idx, '54'] + @new_settings << ['stimulus-DTMF-sequence', key_idx, sk.number ] + @new_settings << ['stimulus-led-control-uri', key_idx, '' ] + @new_settings << ['stimulus-DTMF-sequence', key_idx, '' ] + when 'call_forwarding' + @new_settings << ['function-key-def', key_idx, '63'] + @new_settings << ['stimulus-led-control-uri', key_idx, "f-cftg-#{sk.call_forward_id}" ] + @new_settings << ['send-url-address', key_idx, request.host] + @new_settings << ['send-url-protocol', key_idx, 3] + @new_settings << ['send-url-port', key_idx, '80'] + @new_settings << ['send-url-path', key_idx, "/config_siemens/#{@phone.id}/#{@sip_account.id}/call_forwarding.xml"] + @new_settings << ['send-url-query', key_idx, "id=#{sk.call_forward_id}&function=toggle"] + @new_settings << ['send-url-method', key_idx, '0'] + @new_settings << ['blf-popup', key_idx, 'false'] + when 'call_forwarding_always' + phone_number = PhoneNumber.where(:number => sk.number, :phone_numberable_type => 'SipAccount').first + if phone_number + account_param = (phone_number.phone_numberable_id != @sip_account.id ? "&account=#{phone_number.phone_numberable_id}" : '') + else + phone_number = @sip_account.phone_numbers.first + account_param = '' + end + + if phone_number + @new_settings << ['function-key-def', key_idx, '63'] + @new_settings << ['stimulus-led-control-uri', key_idx, "f-cfutg-#{phone_number.id}" ] + @new_settings << ['send-url-address', key_idx, request.host] + @new_settings << ['send-url-protocol', key_idx, 3] # 0=https, 3=http + @new_settings << ['send-url-port', key_idx, '80'] + @new_settings << ['send-url-path', key_idx, "/config_siemens/#{@phone.id}/#{@sip_account.id}/call_forwarding.xml"] + @new_settings << ['send-url-query', key_idx, "type=always&function=toggle#{account_param}"] + @new_settings << ['send-url-method', key_idx, '0'] # 0=get, 1=post + # @new_settings << ['send-url-user-id', key_idx, 'user'] + # @new_settings << ['send-url-passwd', key_idx, 'secret'] + @new_settings << ['blf-popup', key_idx, 'false'] + end + when 'call_forwarding_assistant' + phone_number = PhoneNumber.where(:number => sk.number, :phone_numberable_type => 'SipAccount').first + if phone_number + account_param = (phone_number.phone_numberable_id != @sip_account.id ? "&account=#{phone_number.phone_numberable_id}" : '') + else + phone_number = @sip_account.phone_numbers.first + account_param = '' + end + + if phone_number + @new_settings << ['function-key-def', key_idx, '63'] + @new_settings << ['stimulus-led-control-uri', key_idx, "f-cfatg-#{phone_number.id}" ] + @new_settings << ['send-url-address', key_idx, request.host] + @new_settings << ['send-url-protocol', key_idx, 3] # 0=https, 3=http + @new_settings << ['send-url-port', key_idx, '80'] + @new_settings << ['send-url-path', key_idx, "/config_siemens/#{@phone.id}/#{@sip_account.id}/call_forwarding.xml"] + @new_settings << ['send-url-query', key_idx, "type=assistant&function=toggle#{account_param}"] + @new_settings << ['send-url-method', key_idx, '0'] # 0=get, 1=post + @new_settings << ['blf-popup', key_idx, 'false'] + end + when 'hunt_group_membership' + phone_number = PhoneNumber.where(:number => sk.number, :phone_numberable_type => 'HuntGroup').first + if phone_number + hunt_group = HuntGroup.where(:id => phone_number.phone_numberable_id).first + end + + sip_account_phone_numbers = Array.new() + @sip_account.phone_numbers.each do |pn| + sip_account_phone_numbers.push(pn.number) + end + + hunt_group_member_numbers = PhoneNumber.where(:number => sip_account_phone_numbers, :phone_numberable_type => 'HuntGroupMember') + + hunt_group_member = nil + if hunt_group and hunt_group_member_numbers + hunt_group_member_numbers.each do |hunt_group_member_number| + hunt_group_member = hunt_group.hunt_group_members.where(:id => hunt_group_member_number.phone_numberable_id).first + if hunt_group_member + break + end + end + end + + if hunt_group_member + @new_settings << ['function-key-def', key_idx, '63'] + @new_settings << ['stimulus-led-control-uri', key_idx, "f-hgmtg-#{hunt_group_member.id}" ] + @new_settings << ['send-url-address', key_idx, request.host] + @new_settings << ['send-url-protocol', key_idx, 3] # 0=https, 3=http + @new_settings << ['send-url-port', key_idx, '80'] + @new_settings << ['send-url-path', key_idx, "/config_siemens/#{@phone.id}/#{@sip_account.id}/hunt_group.xml"] + @new_settings << ['send-url-query', key_idx, "group=#{hunt_group.id}&account=#{hunt_group_member.id}&function=toggle"] + @new_settings << ['send-url-method', key_idx, '0'] # 0=get, 1=post + @new_settings << ['blf-popup', key_idx, 'false'] + end + when nil + @new_settings << ['function-key-def', key_idx, '0'] + @new_settings << ['stimulus-led-control-uri', key_idx, '' ] + @new_settings << ['stimulus-DTMF-sequence', key_idx, '' ] + else + @new_settings << ['function-key-def', key_idx, '1'] + @new_settings << ['select-dial', key_idx, sk.number ] + @new_settings << ['stimulus-led-control-uri', key_idx, '' ] + @new_settings << ['stimulus-DTMF-sequence', key_idx, '' ] + end + @new_settings << ['key-label', key_idx, sk.label ] + @new_settings << ['key-label-unicode', key_idx, sk.label ] + @key_pos = @key_pos+1 + end + + def second_level_keys(key_idx) + sk = @soft_keys.shift + softkey_function = nil + if sk.softkey_function + softkey_function = sk.softkey_function.name + end + case softkey_function + when 'log_out' + @new_settings << ['function-key-def', key_idx, '1'] + @new_settings << ['select-dial', key_idx, 'f-lo' ] + when 'log_in' + @new_settings << ['function-key-def', key_idx, '1'] + @new_settings << ['select-dial', key_idx, "f-li-#{sk.number}" ] + when 'dtmf' + @new_settings << ['function-key-def', key_idx, '54'] + @new_settings << ['stimulus-DTMF-sequence', key_idx, sk.number ] + when nil + @new_settings << ['function-key-def', key_idx, '0'] + else + @new_settings << ['function-key-def', key_idx, '1'] + @new_settings << ['select-dial', key_idx, sk.number ] + end + @new_settings << ['key-label', key_idx, sk.label ] + @new_settings << ['key-label-unicode', key_idx, sk.label ] + @key_pos = @key_pos+1 + end + + def call_history + if ! params[:number].blank? + number = params[:number] + end + + if ! params[:function].blank? + function = params[:function].to_s.downcase + end + + if ! params[:sip_account].blank? + @sip_account = SipAccount.where({ :id => params[:sip_account].to_i }).first + end + + if ! @sip_account and ! params[:phonenumber].blank? + @sip_account = SipAccount.where(:auth_name => params[:phonenumber]).first + end + + if ! params[:type].blank? + @type = params[:type] + elsif ! params[:tab].blank? + @type = params[:tab].rpartition("_")[2] + end + + if ! ['dialed', 'missed', 'received'].include? @type + @type = 'missed' + end + + if ! @sip_account + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + base_url = "#{request.protocol}#{request.host_with_port}#{request.fullpath.split("?")[0]}" + + @phone_xml_object = { + :name => "menu_list", + :columns => 1, + :url => base_url, + :make_call => (function.to_s == 'dial' ? number.to_s : nil), + :hidden => {:sip_account => @sip_account.id, :type => @type}, + :commands => [{ + :type => 'SELECT', + :label => 'Dial', + :display_on => 'LISTITEM', + :key => 'function', + :value => 'dial', + }], + :entries => [], + } + + if function.to_s == 'clear_notification' + @sip_account.call_histories.update_all({:read_flag => true}) + end + + last_missed_call = @sip_account.call_histories.where(:entry_type => 'missed').order('start_stamp DESC').first + if last_missed_call and !last_missed_call.read_flag + @phone_xml_object[:led] = true + else + @phone_xml_object[:led] = false + end + + calls = @sip_account.call_histories.where(:entry_type => @type).order('start_stamp DESC').limit(MAX_DIRECTORY_ENTRIES) + + if @type == 'missed' && @phone_xml_object[:led] == true + @phone_xml_object[:commands].push({ + :type => 'SELECT', + :label => 'Clear Notification', + :key => 'function', + :value => 'clear_notification', + }) + end + + auto_reload_time = 60 + + SIEMENS_HISTORY_RELOAD_TIMES.each_pair do |time_range, reload_value| + if time_range === Time.now.localtime.hour + auto_reload_time = reload_value + end + end + + @phone_xml_object[:commands].push({ + :type => 'UPDATE', + :auto => auto_reload_time, + :label => 'Update', + }) + + calls.each do |call| + display_name = call.display_name + phone_number = call.display_number + phone_book_entry = call.phone_book_entry_by_number(phone_number) + if display_name.blank? + display_name = phone_book_entry.to_s + end + + @phone_xml_object[:entries].push({ + :selected => false, + :key => 'number', + :value => phone_number, + :text => "#{call_date_compact(call.start_stamp)} #{display_name} #{phone_number}", + }) + end + + respond_to { |format| + format.any { + self.formats = [ :xml ] + render :action => "_#{@phone_xml_object[:name]}" + } + } + end + + def call_forwarding + if ! params[:type].blank? + @type = params[:type] + end + + if ! params[:function].blank? + @function = params[:function] + end + + if ! params[:id].blank? + @call_forwarding_id = params[:id].to_i + end + + if ! params[:sip_account].blank? + @sip_account = SipAccount.where({ :id => params[:sip_account].to_i }).first + end + + if ! params[:account].blank? + @sip_account = SipAccount.where({ :id => params[:account].to_i }).first + end + + if ! @sip_account + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + if @function == 'toggle' + if @call_forwarding_id + call_forwarding = @sip_account.call_forwards.where(:id => @call_forwarding_id).first + + if !call_forwarding and @sip_account.softkeys.where(:call_forward_id => @call_forwarding_id).count > 0 + call_forwarding = CallForward.where(:id => @call_forwarding_id).first + end + + if call_forwarding + call_forwarding.toggle + end + elsif @type + call_forwarding = @sip_account.call_forwarding_toggle(@type) + end + if !call_forwarding + render( + :status => 500, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + if !call_forwarding.errors.blank? + error_messages = Array.new() + call_forwarding.errors.messages.each_pair do |key, message| + error_messages.push(message.join(';')) + end + render( + :status => 500, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + elsif call_forwarding.active + render( + :status => 200, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + else + render( + :status => 200, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + end + return + end + + base_url = "#{request.protocol}#{request.host_with_port}#{request.fullpath.split("?")[0]}" + + @phone_xml_object = { + :name => "number_list", + :columns => 1, + :url => base_url, + :hidden => {:sip_account => @sip_account.id, :type => @type}, + :entries => [] + } + + respond_to { |format| + format.any { + self.formats = [ :xml ] + render + } + } + end + + + def hunt_group + if ! params[:goto].blank? + redirect_to params[:goto] + return; + end + + if ! params[:function].blank? + @function = params[:function] + end + + if ! params[:group].blank? + @hunt_group = HuntGroup.where({ :id => params[:group].to_i }).first + end + + if ! @sip_account + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + if ! params[:account].blank? + hunt_group_member = @hunt_group.hunt_group_members.where({ :id => params[:account].to_i }).first + end + + base_url = "#{request.protocol}#{request.host_with_port}#{request.fullpath.split("?")[0]}" + + if @function == 'toggle' + if ! hunt_group_member + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + if hunt_group_member.can_switch_status_itself == true + if hunt_group_member.active + hunt_group_member.active = false + else + hunt_group_member.active = true + end + + if ! hunt_group_member.save + render( + :status => 500, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + else + render( + :status => 200, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + end + return + end + elsif @function == 'members' + commands = [{ + :type => 'UPDATE', + :auto => 20, + :label => 'Update', + },{ + :type => 'BACK', + :label => 'Back', + :display_on => 'OPTIONS', + },{ + :type => 'EXIT', + :label => 'Exit', + :display_on => 'OPTIONS', + },{ + :type => 'SELECT', + :label => 'Show', + :display_on => 'LISTITEM', + }] + + @phone_xml_object = { + :name => "menu_list", + :columns => 1, + :url => base_url, + :hidden => {:function => @function, :group => @hunt_group.id}, + :entries => [], + :commands => commands, + } + + @hunt_group.hunt_group_members.where(:active => true).each do |member| + @phone_xml_object[:entries].push({ + :selected => false, + :value => member.id, + :text => member.name, + }) + end + else + hunt_groups = Array.new() + phone_numbers = Array.new() + @sip_account.phone_numbers.each do |phone_number| + phone_numbers.push(phone_number.number) + assistant_call_forwardings = phone_number.call_forwards.where(:call_forward_case_id => CallForwardCase.where(:value => 'assistant').first.id) + assistant_call_forwardings.each do |assistant_call_forwarding| + if assistant_call_forwarding.call_forwardable_type == 'HuntGroup' && assistant_call_forwarding.call_forwardable_id.to_i > 0 + hunt_groups.push(assistant_call_forwarding.call_forwardable_id.to_i) + end + end + end + + hunt_group_members = Array.new() + if phone_numbers.length > 0 + hunt_group_members = PhoneNumber.where(:phone_numberable_type => 'HuntGroupMember', :number => phone_numbers) + end + + hunt_group_members.each do |hunt_group| + hunt_groups.push(hunt_group.phone_numberable.hunt_group_id) + end + + hunt_groups = HuntGroup.where(:id => hunt_groups) + + @phone_xml_object = { + :name => "menu_list", + :columns => 1, + :url => base_url, + :hidden => {:function => 'members'}, + :entries => [], + :commands => [{ + :type => 'EXIT', + :label => 'Exit', + :display_on => 'OPTIONS', + },{ + :type => 'BACK', + :label => 'Back', + :display_on => 'OPTIONS', + },{ + :type => 'SELECT', + :label => 'Select', + :display_on => 'LISTITEM', + }], + } + + hunt_groups.each do |hunt_group| + @phone_xml_object[:entries].push({ + :selected => false, + :key => 'group', + :value => hunt_group.id, + :text => hunt_group.name, + }) + end + + end + + respond_to { |format| + format.any { + self.formats = [ :xml ] + render :action => "_#{@phone_xml_object[:name]}" + } + } + end + + + def menu + if ! @phone or ! @sip_account + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + type = 'menu' + if ! params[:type].blank? + type = params[:type] + elsif ! params[:tab].blank? + tab = params[:tab].rpartition("_") + if tab[1] != '' + type = tab[2] + end + end + + if ! params[:item].blank? + item = params[:item] + end + + menu_url = "#{request.protocol}#{request.host_with_port}#{request.fullpath.split("?")[0]}" + base_url = "#{request.protocol}#{request.host_with_port}/config_siemens/#{@phone.id}" + + @phone_xml_object = { + :name => "menu_list", + :columns => 1, + :url => menu_url, + :hidden => {:type => type}, + :entries => [] + } + + case type + when 'menu' + items = [ + { + :value => 'phone_directory', + :text => "Directory", + :url => "#{menu_url}?type=#{type}", + },{ + :value => 'call_history', + :text => "Call History", + :url => "#{menu_url}?type=call_history", + }, + ] + when 'status' + items = [ + { + :value => 'hunt_group', + :text => "Hunt Group", + :url => "#{base_url}/hunt_group.xml" + }, + ] + + commands = [ + { + :type => 'UPDATE', + :auto => 10, + :label => 'Update', + } + ] + when 'help' + items = [ + { + :key => 'item', + :value => 'help', + :text => "Help", + :url => "#{menu_url}?type=#{type}", + }, + ] + when 'call_history' + items = [ + { + :value => 'missed', + :text => "Missed", + :url => "#{base_url}/call_history.xml?type=missed", + },{ + :value => 'dialed', + :text => "Dialed", + :url => "#{base_url}/call_history.xml?type=dialed", + },{ + :value => 'received', + :text => "Received", + :url => "#{base_url}/call_history.xml?type=received", + }, + ] + end + + if item + items.each do |entry| + if entry[:value] == item + redirect_to entry[:url] + return; + end + end + end + + @phone_xml_object[:entries] = items + @phone_xml_object[:commands] = commands + + respond_to { |format| + format.any { + self.formats = [ :xml ] + render :action => "_#{@phone_xml_object[:name]}" + } + } + end + + def call_date_compact(date) + if date.strftime('%Y%m%d') == DateTime::now.strftime('%Y%m%d') + return date.strftime('%H:%M') + end + return date.strftime('%d.%m %H:%M') + end +end diff --git a/app/controllers/config_siemens_sort_controller.rb b/app/controllers/config_siemens_sort_controller.rb new file mode 100644 index 0000000..c0739e5 --- /dev/null +++ b/app/controllers/config_siemens_sort_controller.rb @@ -0,0 +1,371 @@ +require 'nokogiri' +#doc.search('Message/ItemList').each do |a| puts a.children end +class ConfigSiemensController < ApplicationController +#TODO Authentication + # No access for admins though as this contains personal data. + + # We can't use load_and_authorize_resource() here because + # ConfigSiemensController isn't a resource. + # We can try client certificates + + skip_authorization_check + + + def index + os40_keys=7 + os60_keys=8 + os80_keys=9 + doc = Nokogiri::XML(request.body.read) + #logger.debug("#{params[:WorkpointMessage].to_xml}") + #logger.debug("#{params[:WorkpointMessage][:Message][:ItemList].to_xml}") + @phone_items=Hash.new + contact_reason = params[:WorkpointMessage][:Message][:ReasonForContact] + reply_status = doc.search('Message/ReasonForContact').first[:status] + reply_action = doc.search('Message/ReasonForContact').first[:action] + + doc.search('Message/ItemList/Item').each do |post_item| + @phone_items[post_item[:name]]=post_item.children.to_s + end + + mac_address = @phone_items['mac-addr'] + phone_type = @phone_items['device-type'] + if phone_type == "OpenStage 40" + max_keys = (os40_keys) * 2 + elsif phone_type == "OpenStage 60" + max_keys = (os60_keys) * 2 + elsif phone_type == "OpenStage 80" + max_keys = (os80_keys) * 2 + else + max_keys = 0 + end + + blf_keys_max = max_keys / 2 + shift_key_position = blf_keys_max - 1 + + #logger.debug(request.body.read) + @phone = Phone.find_by_mac_address(mac_address.gsub(':','').upcase) + if ! @phone.nil? + @phone.update_attributes(:ip_address => request.remote_ip) + sip_account = SipAccount.where(:sip_accountable_type == @phone.phoneable_type, + :sip_accountable_id == @phone.phoneable_id).first + end + + if ! @phone.nil? && ! sip_account.nil? + #logger.debug(@phone_items) + @my_nonce = params[:WorkpointMessage][:Message][:nonce] + @new_settings = Array.new + + @new_settings << ['dhcp', nil, 'true'] + @new_settings << ['hostname', nil, mac_address.gsub(':', '') ] + @new_settings << ['e164-hostname', nil, 'false'] + @new_settings << ['mobility-enabled', nil, 'false'] + @new_settings << ['mobility-password-on-logoff', nil, 'false'] + @new_settings << ['e164', nil, sip_account.try(:phone_numbers).first.number] + @new_settings << ['sip-user-id', nil, sip_account.auth_name] + @new_settings << ['reg-id', nil, sip_account.auth_name] + @new_settings << ['reg-number', nil, sip_account.auth_name] + @new_settings << ['fully-qualified-phone-no', nil, sip_account.auth_name] + @new_settings << ['sip-pwd', nil, sip_account.password] + @new_settings << ['sip-name', nil, sip_account.caller_name] + @new_settings << ['register-by-name', nil, 'false'] + #OPTIMIZE Display ID ? + @new_settings << ['display-id', nil, sip_account.try(:phone_numbers).first.number] + @new_settings << ['display-id-unicode', nil, sip_account.caller_name] + @new_settings << ['use-display-id', nil, 'true'] + @new_settings << ['reg-addr', nil, sip_account.sip_domain.host] + @new_settings << ['reg-port', nil, '5060'] + @new_settings << ['registrar-addr', nil, sip_account.sip_domain.host] + @new_settings << ['registrar-port', nil, '5060'] + @new_settings << ['outbound-proxy', nil, sip_account.sip_domain.host] + @new_settings << ['outbound-proxy-user', nil, sip_account.sip_domain.host] + @new_settings << ['sgnl-gateway-addr', nil, sip_account.sip_domain.host] + @new_settings << ['sgnl-gateway-addr-user', nil, sip_account.sip_domain.host] + @new_settings << ['sgnl-gateway-port', nil, '5060' ] + @new_settings << ['sgnl-gateway-port-user', nil, '5060'] + @new_settings << ['sgnl-route', nil, '0' ] + @new_settings << ['mwi-e164', nil, '' ] + @new_settings << ['rtp-base-port', nil, '5004'] + @new_settings << ['default-domain', nil, '' ] + @new_settings << ['sip-transport', nil, '0' ] + @new_settings << ['sip-transport-user', nil, '0' ] + @new_settings << ['server-type', nil, '0' ] + @new_settings << ['session-timer', nil, 'true'] + @new_settings << ['session-duration', nil, '3600' ] + @new_settings << ['reg-ttl', nil, '3600' ] + @new_settings << ['realm', nil, sip_account.sip_domain.realm] + @new_settings << ['emergency-e164', nil, '0110' ] + @new_settings << ['voice-mail-e164', nil, 'voicemail'] + @new_settings << ['auto-answer', nil, 'false'] + @new_settings << ['beep-on-auto-answer', nil, 'true'] + @new_settings << ['auto-reconnect', nil, 'false' ] + @new_settings << ['beep-on-auto-reconnect', nil, 'true'] + @new_settings << ['permit-decline-call', nil, 'true'] + @new_settings << ['transfer-on-ring', nil, 'false' ] + @new_settings << ['join-allowed-in-conference', nil, 'true'] + @new_settings << ['pickup-group-uri', nil, '*8*'] + @new_settings << ['pickup-group-uri', nil, '' ] + @new_settings << ['hot-line-warm-line-digits', nil, '' ] + @new_settings << ['initial-digit-timer', nil, '30' ] + @new_settings << ['conference-factory-uri', nil, ''] + @new_settings << ['callback-busy-allow', nil, 'false'] + @new_settings << ['callback-busy-code', nil, '' ] + @new_settings << ['callback-ring-allow', nil, 'false'] + @new_settings << ['callback-ring-code', nil, ''] + @new_settings << ['callback-cancel-code', nil, ''] + @new_settings << ['park-server', nil, ''] + #OPTIMIZE Callwaiting + @new_settings << ['call-waiting-enabled', nil, 'true'] + @new_settings << ['qos-layer2', nil, 'true'] + @new_settings << ['l2qos-voice', nil, '5' ] + @new_settings << ['l2qos-signalling', nil, '3' ] + @new_settings << ['l2qos-default', nil, '0'] + @new_settings << ['qos-layer3', nil, 'true'] + @new_settings << ['l3qos-voice', nil, '46'] + @new_settings << ['l3qos-signalling', nil, '26'] + @new_settings << ['vlan-method', nil, '1'] + #OPTIMIZE Timezone + @new_settings << ['sntp-tz-offset', nil, ''] + @new_settings << ['daylight-save', nil, ''] + @new_settings << ['daylight-save-minutes', nil, ''] + #OPTIMIZE Use SNMP? + @new_settings << ['snmp-trap-addr', nil, ''] + @new_settings << ['snmp-trap-port', nil, ''] + @new_settings << ['snmp-trap-pwd', nil, 'snmp' ] + @new_settings << ['snmp-traps-active', nil, 'false' ] + @new_settings << ['diagnostic-trap-addr', nil, ''] + @new_settings << ['diagnostic-trap-port', nil, ''] + @new_settings << ['diagnostic-trap-pwd', nil, 'snmp' ] + @new_settings << ['diagnostic-traps-active', nil, 'false' ] + @new_settings << ['diagnostic-snmp-active', nil, 'false'] + @new_settings << ['qdc-collection-unit-addr', nil, ''] + @new_settings << ['qdc-collection-unit-port', nil, '12010'] + + @new_settings << ['qdc-trap-pwd', nil, 'QOSDC'] + @new_settings << ['qdc-snmp-active', nil, 'false'] + @new_settings << ['qdc-qcu-active', nil, 'false'] + @new_settings << ['snmp-queries-allowed', nil, 'false'] + @new_settings << ['snmp-pwd', nil, ''] + @new_settings << ['disable-microphone', nil, 'false'] + @new_settings << ['loudspeech-enabled', nil, 'true'] + @new_settings << ['audio-silence-suppression', nil, 'false'] + + @new_settings << ['port1', nil, '0' ] # 0=Automatic (speed) + @new_settings << ['port2', nil, '0' ] + @new_settings << ['port2-mode', nil, '1' ] + @new_settings << ['port2-auto-mdix-enabled', nil, 'true' ] + @new_settings << ['originating-line-preference', nil, '0'] + @new_settings << ['terminating-line-preference', nil, '0'] + @new_settings << ['line-key-operating-mode', nil, '0'] + @new_settings << ['line-rollover-type', nil, '2'] + @new_settings << ['line-rollover-volume', nil, '5' ]# 1-5 + @new_settings << ['line-registration-leds', nil, 'true'] + @new_settings << ['keyset-use-focus', nil, 'true' ] + @new_settings << ['keyset-remote-forward-ind', nil, 'true'] + @new_settings << ['keyset-reservation-timer', nil, '60' ] # 0-300 + @new_settings << ['dial-plan-enabled', nil, '' ] + @new_settings << ['Canonical-dialing-international-prefix', nil, ''] + @new_settings << ['Canonical-dialing-local-country-code', nil, ''] + @new_settings << ['Canonical-dialing-national-prefix', nil, ''] + @new_settings << ['Canonical-dialing-local-area-code', nil, ''] + @new_settings << ['Canonical-dialing-local-node', nil, ''] + @new_settings << ['Canonical-dialing-external-access', nil, '0'] + @new_settings << ['Canonical-dialing-operator-code', nil, ''] + @new_settings << ['Canonical-dialing-emergency-number', nil, ''] + @new_settings << ['Canonical-dialing-dial-needs-access-code', nil, '0'] + @new_settings << ['Canonical-dialing-dial-needs-intGWcode', nil, '0'] + @new_settings << ['Canonical-dialing-min-local-number-length', nil, '10'] + @new_settings << ['Canonical-dialing-extension-initial-digits', nil, ''] + @new_settings << ['Canonical-dialing-dial-internal-form', nil, '0' ] + @new_settings << ['Canonical-dialing-dial-external-form', nil, '0' ] + @new_settings << ['Canonical-lookup-local-code', nil, '' ] + @new_settings << ['Canonical-lookup-international-code', nil, ''] + @new_settings << ['hot-keypad-dialing', nil, ''] + @new_settings << ['ldap-transport', nil, '0'] + @new_settings << ['ldap-server-address', nil, '' ] + @new_settings << ['ldap-server-port', nil, '389' ] + @new_settings << ['ldap-authentication', nil, '1'] + @new_settings << ['ldap-user', nil, '' ] + @new_settings << ['ldap-pwd', nil, '' ] + @new_settings << ['ldap-max-responses', nil, '25'] + @new_settings << ['backup-addr', nil, ''] + @new_settings << ['backup-registration', nil, 'false'] + @new_settings << ['qdc-qcu-active', nil, 'false' ] + @new_settings << ['min-admin-passw-length', nil, '6' ] + @new_settings << ['default-locked-config-menus', nil, 'true' ] + @new_settings << ['locked-config-menus', nil, 'true' ] + @new_settings << ['default-locked-local-function-menus', nil, 'true' ] + @new_settings << ['locked-local-function-menus', nil, 'true' ] + @new_settings << ['dls-mode-secure', nil, '0' ] + @new_settings << ['dls-chunk-size', nil, '9492'] + @new_settings << ['default-passw-policy', nil, 'false'] + @new_settings << ['deflect-destination', nil, ''] + @new_settings << ['display-skin', nil, ''] + @new_settings << ['enable-bluetooth-interface', nil, 'true'] + @new_settings << ['usb-access-enabled', nil, 'false' ] + @new_settings << ['usb-backup-enabled', nil, 'false' ] + @new_settings << ['line-button-mode', nil, '0' ] + @new_settings << ['lock-forwarding', nil, '' ] + @new_settings << ['loudspeaker-function-mode', nil, '0' ] + @new_settings << ['max-pin-retries', nil, '' ] + @new_settings << ['inactivity-timeout', nil, '30' ] + @new_settings << ['not-used-timeout', nil, '2' ] + @new_settings << ['passw-char-set', nil, '0' ] + @new_settings << ['refuse-call', nil, 'true' ] + @new_settings << ['restart-password', nil, ''] + #OPTIMIZE clock format + @new_settings << ['time-format', nil, '0' ]# 1=12 h + @new_settings << ['uaCSTA-enabled', nil, 'false' ] + @new_settings << ['enable-test-interface', nil, 'false'] + @new_settings << ['enable-WBM', nil, 'true'] + @new_settings << ['pixelsaver-timeout', nil, '2' ]# 2 hours? + @new_settings << ['voice-message-dial-tone', nil, '' ] + @new_settings << ['call-pickup-allowed', nil, 'true' ] + @new_settings << ['group-pickup-tone-allowed', nil, 'true'] + @new_settings << ['group-pickup-as-ringer', nil, 'false'] + @new_settings << ['group-pickup-alert-type', nil, '0' ] + @new_settings << ['default-profile', nil, '' ] + @new_settings << ['count-medium-priority', nil, '5'] + @new_settings << ['timer-medium-priority', nil, '60'] # 1 - 999 + @new_settings << ['timer-high-priority', nil, '5'] # 0 - 999 + @new_settings << ['dss-sip-detect-timer', nil, '10'] + @new_settings << ['dss-sip-deflect', nil, 'false' ] + @new_settings << ['dss-sip-refuse', nil, 'false' ] + @new_settings << ['feature-availability', nil, 'false'] + @new_settings << ['feature-availability', nil, 'true' ] + @new_settings << ['feature-availability', nil, 'true' ] + @new_settings << ['local-control-feature-availability', nil, 'false' ] + @new_settings << ['trace-level', nil, '0' ] # Off + @new_settings << ['default-locked-function-keys', nil, 'true' ]# "unknown item" + #OPTIMIZE Put pickup prefix into database/global constant? + @new_settings << ['blf-code', nil, 'f_ia_'] # pickup prefix for softkey function 59 (BLF) + @new_settings << ['stimulus-feature-code', nil, true] + @new_settings << ['stimulus-led-control-uri', nil, true] + + + @new_settings << ['min-user-passw-length', nil, '6' ]# 6 - 24 + #OPTIMIZE language + @new_settings << ['country-iso', nil, 'DE' ] + @new_settings << ['language-iso', nil, 'de'] + @new_settings << ['date-format', nil, '0' ] # DD.MM.YYYY + #OPTIMIZE ringtones + @new_settings << ['ringer-melody', nil, '1'] + + @new_settings << ['ringer-melody', nil, '2'] + @new_settings << ['ringer-tone-sequence', nil, '2'] + + soft_keys = Array.new + # Getting BLF keys only for the first level + blf_keys = sip_account.softkeys.find( + :all, + :conditions => {:function => ['blf', 'conference']}, + :limit => blf_keys_max) + #Getting other keys + non_blf_keys = sip_account.softkeys.find( + :all, + :conditions => {:function => ['speed_dial']}) + + # Fill softkey array with BLF keys up to shift key + blf_keys.each do |k| + soft_keys << k + end + # Fill sofkey with other keys up to end + non_blf_keys.each do |k| + if soft_keys.length < max_keys + soft_keys << k + end + end + # Delete unset softkeys + while soft_keys.length < max_keys + soft_keys << Softkey.new + end + + key_pos=1 + + #soft_keys.each do |sk| + + while key_pos < shift_key_position + + (1..shift_key_position-1).each do |key_idx| + sk = soft_keys.shift + logger.debug(sk.function, key_idx) + if sk.function == "blf" + @new_settings << ['function-key-def', key_idx, '59'] + @new_settings << ['select-dial', key_idx, sk.number ] + elsif sk.function == "log_out" + @new_settings << ['function-key-def', key_idx, '1'] + @new_settings << ['select-dial', key_idx, 'f_lo' ] + elsif sk.function == "log_in" + @new_settings << ['function-key-def', key_idx, '1'] + @new_settings << ['select-dial', key_idx, "f_li_#{sk.number}" ] + elsif sk.function == "dtmf" + @new_settings << ['function-key-def', key_idx, '54'] + @new_settings << ['stimulus-DTMF-sequence', key_idx, sk.number ] + elsif sk.function.nil? + @new_settings << ['function-key-def', key_idx, '0'] + else + @new_settings << ['function-key-def', key_idx, '1'] + @new_settings << ['select-dial', key_idx, sk.number ] + end + @new_settings << ['key-label', key_idx, sk.label ] + @new_settings << ['key-label-unicode', key_idx, sk.label ] + key_pos = key_pos+1 + + end + end + if key_pos == shift_key_position + @new_settings << ['function-key-def', shift_key_position, '18'] + @new_settings << ['key-label', shift_key_position, 'Shift'] + @new_settings << ['key-label-unicode', shift_key_position, 'Shift'] + key_pos = key_pos+1 + end + + (1001..1000+shift_key_position-1).each do |key_idx| + sk = soft_keys.shift + if sk.function == "log_out" + @new_settings << ['function-key-def', key_idx, '1'] + @new_settings << ['select-dial', key_idx, 'f_lo' ] + elsif sk.function == "log_in" + @new_settings << ['function-key-def', key_idx, '1'] + @new_settings << ['select-dial', key_idx, "f_li_#{sk.number}" ] + elsif sk.function == "dtmf" + @new_settings << ['function-key-def', key_idx, '54'] + @new_settings << ['stimulus-DTMF-sequence', key_idx, sk.number ] + elsif sk.function.nil? + @new_settings << ['function-key-def', key_idx, '0'] + else + @new_settings << ['function-key-def', key_idx, '1'] + @new_settings << ['select-dial', key_idx, sk.number ] + end + @new_settings << ['key-label', key_idx, sk.label ] + @new_settings << ['key-label-unicode', key_idx, sk.label ] + key_pos = key_pos+1 + + end + + #end + logger.debug(@new_settings) + end + + if @phone.nil? || sip_account.nil? + respond_to { |format| + format.xml { render :action => "clean-up" } + } + + elsif (reply_status == 'accepted' && contact_reason == 'reply-to' && reply_action == 'ReadAllItems') + respond_to { |format| + format.xml { render :action => "write" } + } + + elsif ["reply-to"].include? contact_reason + respond_to { |format| + format.xml { render :action => "clean-up" } + } + + else + respond_to { |format| + format.xml { render :action => "index" } + } + end + + end +end diff --git a/app/controllers/config_snom_controller.rb b/app/controllers/config_snom_controller.rb new file mode 100644 index 0000000..40f0c4e --- /dev/null +++ b/app/controllers/config_snom_controller.rb @@ -0,0 +1,1169 @@ +class ConfigSnomController < ApplicationController + MAX_SIP_ACCOUNTS_COUNT = 11 + MAX_SOFTKEYS_COUNT = 12 + (42 * 3) - 1 + MAX_DIRECTORY_ENTRIES = 20 + KEYPAD_TO_CHAR = { + '0' => [' ','-','.',',','0'], + '1' => [' ','-','.',',','1'], + '2' => ['a','b','c','2'], + '3' => ['d','e','f','3'], + '4' => ['g','h','i','4'], + '5' => ['j','k','l','5'], + '6' => ['m','n','o','6'], + '7' => ['p','q','r','s','7'], + '8' => ['t','u','v','8'], + '9' => ['w','x','y','z','9'], + } + + skip_authorization_check + + before_filter { |controller| + @mac_address = params[:mac_address].to_s.upcase.gsub(/[^0-9A-F]/,'') + @provisioning_authenticated = false + + if !params[:provisioning_key].blank? + @phone = Phone.where({ :provisioning_key => params[:provisioning_key] }).first + if @phone + @provisioning_authenticated = true + @mac_address = @phone.mac_address + end + end + + if ! @mac_address.blank? then + if !@phone + @phone = Phone.where({ :mac_address => @mac_address }).first + end + + if ! @phone && PROVISIONING_AUTO_ADD_PHONE + tenant = Tenant.where(:id => PROVISIONING_AUTO_TENANT_ID).first + if ! tenant + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + @phone = tenant.phones.build + @phone.mac_address = @mac_address + @phone.hot_deskable = true + + mac_address_to_model = { + '00041325' => 'Snom 300', + '00041328' => 'Snom 300', + '0004132D' => 'Snom 300', + '0004132F' => 'Snom 300', + '00041334' => 'Snom 300', + '00041350' => 'Snom 300', + '0004133B' => 'Snom 300', + '00041337' => 'Snom 300', + '00041324' => 'Snom 320', + '00041327' => 'Snom 320', + '0004132C' => 'Snom 320', + '00041331' => 'Snom 320', + '00041335' => 'Snom 320', + '00041338' => 'Snom 320', + '00041351' => 'Snom 320', + '00041323' => 'Snom 360', + '00041329' => 'Snom 360', + '0004132B' => 'Snom 360', + '00041339' => 'Snom 360', + '00041390' => 'Snom 360', + '00041326' => 'Snom 370', + '0004132E' => 'Snom 370', + '0004133A' => 'Snom 370', + '00041352' => 'Snom 370', + '00041340' => 'Snom 820', + '00041345' => 'Snom 821', + '00041348' => 'Snom 821', + '00041341' => 'Snom 870', + } + + @phone.phone_model = PhoneModel.where(:name => mac_address_to_model[@mac_address[0, 8]]).first + if ! @phone.save + render( + :status => 500, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + if ! PROVISIONING_AUTO_ADD_SIP_ACCOUNT + return + end + + caller_name_index = 0 + sip_account_last = tenant.sip_accounts.where('caller_name LIKE ?', "#{PROVISIONING_AUTO_SIP_ACCOUNT_CALLER_PREFIX}%").sort { |item1, item2| + item1.caller_name.gsub(/[^0-9]/, '').to_i <=> item2.caller_name.gsub(/[^0-9]/, '').to_i + }.last + + if sip_account_last + caller_name_index = sip_account_last.caller_name.gsub(/[^0-9]/, '').to_i + end + caller_name_index = caller_name_index + 1 + + @sip_account = tenant.sip_accounts.build + @sip_account.caller_name = "#{PROVISIONING_AUTO_SIP_ACCOUNT_CALLER_PREFIX}#{caller_name_index}" + @sip_account.call_waiting = CALL_WAITING + @sip_account.clir = DEFAULT_CLIR_SETTING + @sip_account.clip = DEFAULT_CLIP_SETTING + @sip_account.voicemail_pin = random_pin + @sip_account.callforward_rules_act_per_sip_account = CALLFORWARD_RULES_ACT_PER_SIP_ACCOUNT_DEFAULT + @sip_account.hotdeskable = false + loop do + @sip_account.auth_name = SecureRandom.hex(DEFAULT_LENGTH_SIP_AUTH_NAME) + break unless SipAccount.exists?(:auth_name => @sip_account.auth_name) + end + @sip_account.password = SecureRandom.hex(DEFAULT_LENGTH_SIP_PASSWORD) + + if ! @sip_account.save + render( + :status => 500, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + phone_sip_account = PhoneSipAccount.new() + phone_sip_account.phone_id = @phone.id + phone_sip_account.sip_account_id = @sip_account.id + + if ! phone_sip_account.save + render( + :status => 500, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + end + elsif ! params[:phone].blank? then + @phone = Phone.where({ :id => params[:phone].to_i }).first + end + + if ! @phone + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + end + + if ! params[:sip_account].blank? + @sip_account = @phone.sip_accounts.where({ :id => params[:sip_account].to_i }).first + if ! @sip_account + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + end + end + + if ! params[:type].blank? + @type = params[:type].to_s.strip.downcase + end + + if ! params[:keys].blank? + @dialpad_keys = params[:keys].to_s.strip + end + } + + + def show + send_sensitve = @provisioning_authenticated || !@phone.provisioning_key_active + @phone_settings = Hash.new() + + if defined?(PROVISIONING_KEY_LENGTH) && PROVISIONING_KEY_LENGTH > 0 + if @phone.provisioning_key.blank? + @phone.update_attributes({ :provisioning_key => SecureRandom.hex(PROVISIONING_KEY_LENGTH), :provisioning_key_active => false }) + elsif @provisioning_authenticated + @phone.update_attributes({ :provisioning_key_active => true }) + end + + if send_sensitve + if defined?(PROVISIONING_PROTOCOL) && PROVISIONING_PROTOCOL + provisioning_protocol = PROVISIONING_PROTOCOL + else + provisioning_protocol = request.protocol + end + @phone_settings[:setting_server] = "#{provisioning_protocol}#{request.host_with_port}/snom-#{@phone.provisioning_key}.xml" + end + end + + if defined?(PROVISIONING_SET_HTTP_USER) && @phone.http_user.blank? + if PROVISIONING_SET_HTTP_USER.class == Fixnum + @phone.update_attributes({ :http_user => SecureRandom.hex(PROVISIONING_SET_HTTP_USER) }) + elsif PROVISIONING_SET_HTTP_USER.class == String + @phone.update_attributes({ :http_user => PROVISIONING_SET_HTTP_USER }) + end + end + + if defined?(PROVISIONING_SET_HTTP_PASSWORD) && @phone.http_password.blank? + if PROVISIONING_SET_HTTP_PASSWORD.class == Fixnum + @phone.update_attributes({ :http_password => SecureRandom.hex(PROVISIONING_SET_HTTP_PASSWORD) }) + elsif PROVISIONING_SET_HTTP_PASSWORD.class == String + @phone.update_attributes({ :http_password => PROVISIONING_SET_HTTP_PASSWORD }) + end + end + + if send_sensitve + @phone_settings[:http_user] = @phone.http_user + @phone_settings[:http_pass] = @phone.http_password + if defined?(PROVISIONING_ADMIN_PASSWORD) + if PROVISIONING_ADMIN_PASSWORD.class == TrueClass + @phone_settings[:admin_mode_password] = @phone.http_password + elsif PROVISIONING_ADMIN_PASSWORD.class == String + @phone_settings[:admin_mode_password] = PROVISIONING_ADMIN_PASSWORD + end + end + end + + if ! request.env['HTTP_USER_AGENT'].index('snom') + Rails.logger.info "---> User-Agent indicates not a Snom phone (#{request.env['HTTP_USER_AGENT'].inspect})" + else + Rails.logger.info "---> Phone #{@mac_address.inspect}, IP address #{request.remote_ip.inspect}" + @phone.update_attributes({ :ip_address => request.remote_ip }) + end + + @softkeys = Array.new() + @sip_accounts = Array.new() + + if send_sensitve + @phone.sip_accounts.each do |sip_account| + if (sip_account.sip_accountable_type == @phone.phoneable_type) and (sip_account.sip_accountable_id == @phone.phoneable_id) + snom_sip_account = { + :id => sip_account.id, + :active => 'on', + :pname => sip_account.auth_name, + :pass => sip_account.password, + :host => sip_account.host, + :outbound => sip_account.host, + :name => sip_account.auth_name, + :realname => 'Call', + :idle_text => sip_account.caller_name, + :mailbox => "" + } + @sip_accounts.push(snom_sip_account) + sip_account_index = @sip_accounts.length + sip_account.softkeys.order(:position).each do |softkey| + if softkey.softkey_function + softkey_function = softkey.softkey_function.name + end + case softkey_function + when 'blf' + @softkeys.push({:context => sip_account_index, :label => softkey.label, :data => "blf |f-ia-"}) + when 'speed_dial' + @softkeys.push({:context => sip_account_index, :label => softkey.label, :data => "speed #{softkey.number}"}) + when 'dtmf' + @softkeys.push({:context => sip_account_index, :label => softkey.label, :data => "dtmf #{softkey.number}"}) + when 'log_out' + @softkeys.push({:context => sip_account_index, :label => softkey.label, :data => "speed f-lo"}) + when 'log_in' + @softkeys.push({:context => sip_account_index, :label => softkey.label, :data => "speed f-li-#{softkey.number}"}) + when 'conference' + @softkeys.push({:context => sip_account_index, :label => softkey.label, :data => "blf |f-ta-"}) + when 'call_forwarding' + @softkeys.push({ + :context => sip_account_index, + :function => softkey.function, + :label => softkey.label, + :softkey => softkey, + :general_type => t("softkeys.functions.#{softkey.softkey_function.name}"), + :subscription => { + :to => "f-cftg-#{softkey.call_forward_id}@#{sip_account.host}", + :for => "#{sip_account.auth_name}@#{sip_account.host}" + }, + :actions => [{ + :type => :url, + :target => "#{request.protocol}#{request.host_with_port}/config_snom/#{@phone.id}/#{snom_sip_account[:id]}/call_forwarding.xml?id=#{softkey.call_forward_id}&function=toggle", + :when => 'on press', + }], + }) + when 'call_forwarding_always' + phone_number = PhoneNumber.where(:number => softkey.number, :phone_numberable_type => 'SipAccount').first + if phone_number + account_param = (phone_number.phone_numberable_id != snom_sip_account[:id] ? "&account=#{phone_number.phone_numberable_id}" : '') + else + phone_number = sip_account.phone_numbers.first + account_param = '' + end + + @softkeys.push({ + :context => sip_account_index, + :function => softkey.function, + :label => softkey.label, + :softkey => softkey, + :general_type => t("softkeys.functions.#{softkey.softkey_function.name}"), + :subscription => { + :to => "f-cfutg-#{phone_number.id}@#{sip_account.host}", + :for => "#{sip_account.auth_name}@#{sip_account.host}" + }, + :actions => [{ + :type => :url, + :target => "#{request.protocol}#{request.host_with_port}/config_snom/#{@phone.id}/#{snom_sip_account[:id]}/call_forwarding.xml?type=always&function=toggle#{account_param}", + :when => 'on press', + }], + }) + when 'call_forwarding_assistant' + phone_number = PhoneNumber.where(:number => softkey.number, :phone_numberable_type => 'SipAccount').first + if phone_number + account_param = (phone_number.phone_numberable_id != snom_sip_account[:id] ? "&account=#{phone_number.phone_numberable_id}" : '') + else + phone_number = sip_account.phone_numbers.first + account_param = '' + end + + @softkeys.push({ + :context => sip_account_index, + :function => softkey.function, + :label => softkey.label, + :softkey => softkey, + :general_type => t("softkeys.functions.#{softkey.softkey_function.name}"), + :subscription => { + :to => "f-cfatg-#{phone_number.id}@#{sip_account.host}", + :for => "#{sip_account.auth_name}@#{sip_account.host}" + }, + :actions => [{ + :type => :url, + :target => "#{request.protocol}#{request.host_with_port}/config_snom/#{@phone.id}/#{snom_sip_account[:id]}/call_forwarding.xml?type=assistant&function=toggle#{account_param}", + :when => 'on press', + }], + }) + when 'hunt_group_membership' + phone_number = PhoneNumber.where(:number => softkey.number, :phone_numberable_type => 'HuntGroup').first + if phone_number + hunt_group = HuntGroup.where(:id => phone_number.phone_numberable_id).first + end + + sip_account_phone_numbers = Array.new() + SipAccount.where(:id => @sip_accounts.first[:id]).first.phone_numbers.each do |phone_number| + sip_account_phone_numbers.push(phone_number.number) + end + + hunt_group_member_numbers = PhoneNumber.where(:number => sip_account_phone_numbers, :phone_numberable_type => 'HuntGroupMember') + + hunt_group_member = nil + if hunt_group and hunt_group_member_numbers + hunt_group_member_numbers.each do |hunt_group_member_number| + hunt_group_member = hunt_group.hunt_group_members.where(:id => hunt_group_member_number.phone_numberable_id).first + if hunt_group_member + break + end + end + end + + if hunt_group_member + @softkeys.push({ + :context => sip_account_index, + :function => softkey.function, + :label => softkey.label, + :softkey => softkey, + :general_type => t("softkeys.functions.#{softkey.softkey_function.name}"), + :subscription => { + :to => "f-hgmtg-#{hunt_group_member.id}@#{sip_account.host}", + :for => "#{sip_account.auth_name}@#{sip_account.host}" + }, + :actions => [{ + :type => :url, + :target => "#{request.protocol}#{request.host_with_port}/config_snom/#{@phone.id}/#{snom_sip_account[:id]}/hunt_group.xml?group=#{hunt_group.id}&account=#{hunt_group_member.id}&function=toggle", + :when => 'on press', + }], + }) + else + @softkeys.push({:context => sip_account_index, :label => softkey.label, :data => 'none'}) + end + when 'acd_membership' + acd_agent = nil + phone_number = PhoneNumber.where(:number => softkey.number, :phone_numberable_type => 'AutomaticCallDistributor').first + if phone_number + acd = AutomaticCallDistributor.where(:id => phone_number.phone_numberable_id).first + if acd + acd_agent = acd.acd_agents.where(:destination_type => 'SipAccount', :destination_id => sip_account.id).first + end + end + + if acd_agent + @softkeys.push({ + :context => sip_account_index, + :function => softkey.function, + :label => softkey.label, + :softkey => softkey, + :general_type => t("softkeys.functions.#{softkey.softkey_function.name}"), + :subscription => { + :to => "f-acdmtg-#{acd_agent.id}@#{sip_account.host}", + :for => "#{sip_account.auth_name}@#{sip_account.host}" + }, + :actions => [{ + :type => :url, + :target => "#{request.protocol}#{request.host_with_port}/config_snom/#{@phone.id}/#{snom_sip_account[:id]}/acd.xml?acd=#{acd.id}&agent=#{acd_agent.id}&function=toggle", + :when => 'on press', + }], + }) + else + @softkeys.push({:context => sip_account_index, :label => softkey.label, :data => 'none'}) + end + when 'hold' + @softkeys.push({:context => sip_account_index, :label => softkey.label, :data => "keyevent F_R"}) + else + @softkeys.push({:label => softkey.label, :data => 'none'}) + end + end + end + end + end + + languages_map = { + 'ca' => 'Catalan', + 'bs' => 'Bosanski', + 'da' => 'Dansk', + 'de' => 'Deutsch', + 'cs' => 'Cestina', + 'en' => 'English', + 'es' => 'Espanol', + 'fi' => 'Suomi', + 'et' => 'Estonian', + 'fr' => 'Francais', + 'he' => 'Hebrew', + 'hu' => 'Hungarian', + 'it' => 'Italiano', + 'nl' => 'Dutch', + 'no' => 'Norsk', + 'pl' => 'Polski', + 'pt' => 'Portugues', + 'si' => 'Slovenian', + 'sk' => 'Slovencina', + 'ru' => 'Russian', + 'sv' => 'Svenska', + 'tr' => 'Turkce', + } + + tone_schemes_map = { + '1' => 'USA', # United States + '61' => 'AUS', # Australia + '43' => 'AUT', # Austria + '86' => 'CHN', # China + '45' => 'DNK', # Denmark + '33' => 'FRA', # France + '49' => 'GER', # Germany + '44' => 'GBR', # Great Britain + '91' => 'IND', # India + '39' => 'ITA', # Italy + '81' => 'JPN', # Japan + '52' => 'MEX', # Mexico + '31' => 'NLD', # Netherlands + '47' => 'NOR', # Norway + '64' => 'NZL', # New Zealand + '34' => 'ESP', # Spain + '46' => 'SWE', # Sweden + '41' => 'SWI', # Switzerland + } + + if @phone.phoneable + if @phone.phoneable_type == 'Tenant' + tenant = @phone.phoneable + language = tenant.language.code + elsif @phone.phoneable_type == 'User' + tenant = @phone.phoneable.current_tenant + language = @phone.phoneable.language.code + end + end + + if tenant && tenant.country + tone_scheme = tenant.country.country_code + end + + @phone_settings[:tone_scheme] = tone_schemes_map.include?(tone_scheme.to_s) ? tone_schemes_map[tone_scheme.to_s] : 'USA' + @phone_settings[:language] = languages_map.include?(language.to_s) ? languages_map[language.to_s] : 'English' + + xml_applications_url = "#{request.protocol}#{request.host_with_port}/config_snom/#{@phone.id}/#{(@sip_accounts.blank? ? '0' : @sip_accounts.first[:id])}" + @dkeys = { + :menu => 'keyevent F_SETTINGS', + :retrieve => 'speed f-vmcheck', + :conf => 'keyevent F_CONFERENCE', + :redial => "url #{xml_applications_url}/call_history.xml?type=dialed", + :directory => "url #{xml_applications_url}/phone_book.xml", + :idle_ok => "url #{xml_applications_url}/call_history.xml?type=dialed", + :idle_cancel => "keyevent F_CANCEL", + :idle_up => "keyevent F_PREV_ID", + :idle_down => "keyevent F_NEXT_ID", + :idle_left => "url #{xml_applications_url}/call_history.xml?type=received", + :idle_right => "url #{xml_applications_url}/call_history.xml?type=missed", + } + + # Remap conference key to first conference if found + #conference = Conference.where(:conferenceable_type => @phone.phoneable_type, :conferenceable_id => @phone.phoneable_id).first + #if conference and conference.phone_numbers + # @dkeys[:conf] = "speed f_ta_#{conference.phone_numbers.first.number}" + #end + + @sip_accounts.length().upto(MAX_SIP_ACCOUNTS_COUNT) do |index| + snom_sip_account = { + :id => index, + :active => 'off', + :pname => '', + :pass => '', + :host => '', + :outbound => '', + :name => '', + :realname => '', + :idle_text => '', + } + @sip_accounts.push(snom_sip_account) + end + + @softkeys.length().upto(MAX_SOFTKEYS_COUNT) do |index| + @softkeys.push({:label => "", :data => "none"}) + end + + @state_settings_url = "#{request.protocol}#{request.host_with_port}/config_snom/#{@phone.id}/state_settings.xml" + + respond_to { |format| + format.any { + self.formats = [ :xml ] + render + } + } + end + + def idle_screen + + snom_360_bg = 'Qk0+BAAAAAAAAD4AAAAoAAAAgAAAAEAAAAABAAEAAAAAAAAEAAATCwAAEwsAAAIAAAACAAAA//// +AAAAAAAAAAAAAAAAAAAAAbbZxzbbAAAAAAAAAAAAAAG222222wAAAAAAAAAAAAAB9ttttt8AAAAA +AAAAAAAAAbbbbbbbAAAAAAAAAAAAAAG222222wAAAAAAAAAAAAABttttttsAAAAAAAAAAAAAAOPx +xx+OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkkkkkkkkkkkkkkAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAJJJJJJJJJJJJJJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAACSSSSSSSSSSSSSQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAA' + + @phone_xml_object = { + :image => { + :data => snom_360_bg, + :location_x => 0, + :location_y => 0, + :invert => 0 + }, + :clock => { + :location_x => 128, + :location_y => 0, + }, + :date => { + :location_x => 100, + :location_y => 40, + }, + :line => { + :location_x => 0, + :location_y => 0, + }, + } + + respond_to { |format| + format.any { + self.formats = [ :xml ] + render + } + } + end + + def log_in + + base_url = "#{request.protocol}#{request.host_with_port}#{request.fullpath.split("?")[0]}" + exit_url = "#{request.protocol}#{request.host_with_port}#{request.fullpath.rpartition("/")[0]}/exit.xml" + + log_in_number = params[:log_in].to_s.gsub(/[^0-9]/,'') + pin = params[:pin].to_s.gsub(/[^0-9]/,'') + + if ! params[:user].blank? + user = User.where(:id => params[:user].to_i).first + phone_number = PhoneNumber.where(:number => log_in_number, :phone_numberable_type => 'SipAccount').first + if phone_number + sip_account = phone_number.phone_numberable + end + elsif ! params[:log_in].blank? + phone_number = PhoneNumber.where(:number => log_in_number, :phone_numberable_type => 'SipAccount').first + if phone_number && phone_number.phone_numberable && phone_number.phone_numberable.sip_accountable && phone_number.phone_numberable.sip_accountable_type == 'User' + user = phone_number.phone_numberable.sip_accountable + end + end + + @phone_xml_object = { + :name => "snom_phone_text", + :title => "Error", + :prompt => "Log in", + :text => 'Log in failed!', + :fetch_url => base_url, + :fetch_mil => '2000', + } + + if ! user + @phone_xml_object = { + :name => "snom_phone_input", + :title => "Log In", + :prompt => "Log In", + :url => base_url, + :display_name => "Log In", + :query_string_param => "log_in", + :default_value => log_in_number, + :input_flags => "n", + :softkeys => [ + {:name => "F1", :label => "Exit", :url => exit_url} + ] + } + elsif pin.blank? + @phone_xml_object = { + :name => "snom_phone_input", + :title => "PIN", + :prompt => "PIN", + :url => base_url, + :display_name => "PIN", + :query_string_param => "user=#{user.id}&log_in=#{log_in_number}&pin", + :default_value => "", + :input_flags => "pn", + :softkeys => [ + {:name => "F1", :label => "Exit", :url => exit_url} + ] + } + elsif user.authenticate_by_pin?(pin) + if @phone.user_login(user, sip_account) + @phone_xml_object = { + :name => "snom_phone_text", + :title => "Log in successful", + :prompt => "Log in", + :text => "#{user.to_s} logged in", + :fetch_url => exit_url, + :fetch_mil => '1000', + } + end + end + + respond_to { |format| + format.any { + self.formats = [ :xml ] + render :action => "_#{@phone_xml_object[:name]}" + } + } + end + + def log_out + if ! @phone + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + exit_url = "#{request.protocol}#{request.host_with_port}#{request.fullpath.rpartition("/")[0]}/exit.xml" + + if @phone.user_logout() + @phone_xml_object = { + :name => "snom_phone_text", + :title => "Log out successful", + :prompt => "Log out", + :text => 'Log out successful', + :fetch_url => exit_url, + :fetch_mil => '1000', + } + else + @phone_xml_object = { + :name => "snom_phone_text", + :title => "Error", + :prompt => "Log out", + :text => 'Log out failed!', + :fetch_url => exit_url, + :fetch_mil => '2000', + } + end + + respond_to { |format| + format.any { + self.formats = [ :xml ] + render :action => "_#{@phone_xml_object[:name]}" + } + } + end + + def phone_book + + if ! @sip_account + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + @phone_xml_object = { + :name => 'snom_phone_directory', + :title => "$(lang:menu100_phone_book) #{@dialpad_keys}".strip, + :entries => [], + :softkeys => [], + } + + phone_books = Array.new() + phone_books = phone_books + @sip_account.sip_accountable.try(:phone_books).all + if @sip_account.sip_accountable.class == User + phone_books = phone_books + @sip_account.sip_accountable.try(:current_tenant).try(:phone_books).all + end + + phone_book_ids = Array.new() + phone_books.each do |phone_book| + phone_book_ids << phone_book.id + end + + PhoneBookEntry.where(:phone_book_id => phone_book_ids).order(:last_name).order(:first_name).limit(MAX_DIRECTORY_ENTRIES).each do |phone_book_entry| + if phone_book_entry.phone_numbers.count > 1 + @phone_xml_object[:entries] << { :text => phone_book_entry.to_s, :number => phone_book_entry.phone_numbers.first } + end + phone_book_entry.phone_numbers.each do |phone_number| + if phone_book_entry.phone_numbers.count > 1 + entry_name = " #{phone_number.name} #{phone_number.number}" + else + entry_name = "#{phone_book_entry.to_s} #{phone_number.number}" + end + + @phone_xml_object[:entries] << { :text => entry_name, :number => phone_number.number } + end + end + + base_url = "#{request.protocol}#{request.host_with_port}#{request.fullpath.split("?")[0]}" + phone_book_url = "#{base_url}?type=#{@type.to_s}" + for key_id in (0..9) + @phone_xml_object[:softkeys] << {:name => key_id, :url => "#{phone_book_url}&keys=#{@dialpad_keys.to_s}#{key_id}" } + end + @phone_xml_object[:softkeys] << {:name => '*', :url => "#{phone_book_url}&keys=#{@dialpad_keys.to_s[0..-2]}" } + @phone_xml_object[:softkeys] << {:name => '#', :url => "#{phone_book_url}&keys=" } + + respond_to { |format| + format.any { + self.formats = [ :xml ] + render :action => "_#{@phone_xml_object[:name]}" + } + } + + end + + def call_history + + if ! @sip_account + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + if ['dialed', 'missed', 'received'].include? @type + @phone_xml_object = { + :name => "snom_phone_directory", + :title => "$(lang:menu100_call_lists) - #{@type.to_s.camelize}", + :entries => [] + } + + if @type == 'missed' + hunt_group_member_ids = PhoneNumber.where(:phone_numberable_type => 'HuntGroupMember', :number => @sip_account.phone_numbers.map {|a| a.number}).map {|a| a.phone_numberable_id} + hunt_group_ids = HuntGroupMember.where(:id => hunt_group_member_ids, :active => true).map {|a| a.hunt_group_id} + calls = CallHistory.where('entry_type = ? AND ((call_historyable_type = "SipAccount" AND call_historyable_id = ?) OR (call_historyable_type = "HuntGroup" AND call_historyable_id IN (?)))', @type, @sip_account.id, hunt_group_ids).order('start_stamp DESC').limit(MAX_DIRECTORY_ENTRIES) + else + calls = @sip_account.call_histories.where(:entry_type => @type).order('start_stamp DESC').limit(MAX_DIRECTORY_ENTRIES) + end + + calls.each do |call| + display_name = call.display_name + phone_number = call.display_number + phone_book_entry = call.phone_book_entry_by_number(phone_number) + if display_name.blank? + display_name = phone_book_entry.to_s + end + + @phone_xml_object[:entries].push({ + :selected => false, + :number => phone_number, + :text => "#{call_date_compact(call.start_stamp)} #{display_name} #{call.display_number}", + }) + end + else + base_url = "#{request.protocol}#{request.host_with_port}#{request.fullpath.split("?")[0]}" + @phone_xml_object = { + :name => 'snom_phone_menu', + :title => '$(lang:menu100_call_lists)', + :entries => [ + {:text => '$(lang:list_missed)', :url => "#{base_url}?&type=missed", :selected => false}, + {:text => '$(lang:list_taken)', :url => "#{base_url}?&type=received", :selected => false}, + {:text => '$(lang:list_dialed)', :url => "#{base_url}?&type=dialed", :selected => false}, + ] + } + end + + respond_to { |format| + format.any { + self.formats = [ :xml ] + render :action => "_#{@phone_xml_object[:name]}" + } + } + + end + + def state_settings + @base_url = "#{request.protocol}#{request.host_with_port}#{request.fullpath.rpartition("/")[0]}" + + @sip_account_ids = Array.new() + @phone.sip_accounts.each do |sip_account| + if (sip_account.sip_accountable_type == @phone.phoneable_type) and (sip_account.sip_accountable_id == @phone.phoneable_id) + @sip_account_ids.push(sip_account.id) + end + end + + if @phone.hot_deskable + @enable_login = true + if @phone.phoneable_type != 'Tenant' + @enable_logout = true + end + end + + respond_to { |format| + format.any { + self.formats = [ :xml ] + render + } + } + end + + def call_forwarding + if ! params[:type].blank? + @type = params[:type] + end + + if ! params[:function].blank? + @function = params[:function] + end + + if ! params[:id].blank? + @call_forwarding_id = params[:id].to_i + end + + if ! params[:sip_account].blank? + @sip_account = SipAccount.where({ :id => params[:sip_account].to_i }).first + end + + if ! params[:account].blank? + @sip_account = SipAccount.where({ :id => params[:account].to_i }).first + end + + + if ! @sip_account + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + exit_url = "#{request.protocol}#{request.host_with_port}#{request.fullpath.rpartition("/")[0]}/exit.xml" + + if @function == 'toggle' + if @call_forwarding_id + call_forwarding = @sip_account.call_forwards.where(:id => @call_forwarding_id).first + + if !call_forwarding and @sip_account.softkeys.where(:call_forward_id => @call_forwarding_id).count > 0 + call_forwarding = CallForward.where(:id => @call_forwarding_id).first + end + + if call_forwarding + call_forwarding.toggle + end + elsif @type + call_forwarding = @sip_account.call_forwarding_toggle(@type) + end + if !call_forwarding + render( + :status => 500, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + if !call_forwarding.errors.blank? + error_messages = Array.new() + call_forwarding.errors.messages.each_pair do |key, message| + error_messages.push(message.join(';')) + end + @phone_xml_object = { + :name => 'snom_phone_text', + :title => t("call_forwards.name"), + :prompt => t("call_forwards.name"), + :text => "ERROR #{error_messages.join(',')} #{call_forwarding.to_s})", + :fetch_url => exit_url, + :fetch_mil => '1000', + } + elsif call_forwarding.active + @phone_xml_object = { + :name => 'snom_phone_text', + :title => t("call_forwards.name"), + :prompt => t("call_forwards.name"), + :text => "ON #{call_forwarding.to_s})", + :fetch_url => exit_url, + :fetch_mil => '1000', + } + else + @phone_xml_object = { + :name => 'snom_phone_text', + :title => t("call_forwards.name"), + :prompt => t("call_forwards.name"), + :text => "OFF #{call_forwarding.to_s}", + :fetch_url => exit_url, + :fetch_mil => '1000', + } + end + end + + respond_to { |format| + format.any { + self.formats = [ :xml ] + render :action => "_#{@phone_xml_object[:name]}" + } + } + end + + def hunt_group + if ! params[:function].blank? + @function = params[:function] + end + + if ! params[:sip_account].blank? + @sip_account = SipAccount.where({ :id => params[:sip_account].to_i }).first + end + + if ! params[:group].blank? + @hunt_group = HuntGroup.where({ :id => params[:group].to_i }).first + end + + if ! @sip_account + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + if ! @hunt_group + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + if ! params[:account].blank? + hunt_group_member = @hunt_group.hunt_group_members.where({ :id => params[:account].to_i }).first + end + + if ! hunt_group_member + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + exit_url = "#{request.protocol}#{request.host_with_port}#{request.fullpath.rpartition("/")[0]}/exit.xml" + + if @function == 'toggle' + if hunt_group_member.can_switch_status_itself == true + if hunt_group_member.active + hunt_group_member.active = false + else + hunt_group_member.active = true + end + + if ! hunt_group_member.save + render( + :status => 500, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + end + + if hunt_group_member.active + @phone_xml_object = { + :name => 'snom_phone_text', + :title => 'Hunt Group', + :prompt => 'Hunt Group', + :text => "#{@hunt_group.name} on", + :fetch_url => exit_url, + :fetch_mil => '1000', + } + else + @phone_xml_object = { + :name => 'snom_phone_text', + :title => 'Hunt Group', + :prompt => 'Hunt Group', + :text => "#{@hunt_group.name} off", + :fetch_url => exit_url, + :fetch_mil => '1000', + } + end + + respond_to { |format| + format.any { + self.formats = [ :xml ] + render :action => "_#{@phone_xml_object[:name]}" + } + } + end + end + + def acd + if ! params[:function].blank? + @function = params[:function] + end + + if ! params[:sip_account].blank? + @sip_account = SipAccount.where({ :id => params[:sip_account].to_i }).first + end + + if ! params[:acd].blank? + @acd = AutomaticCallDistributor.where({ :id => params[:acd].to_i }).first + end + + if ! @sip_account + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + if ! @acd + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + if ! params[:agent].blank? + acd_agent = @acd.acd_agents.where({ :id => params[:agent].to_i }).first + end + + if ! acd_agent + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + exit_url = "#{request.protocol}#{request.host_with_port}#{request.fullpath.rpartition("/")[0]}/exit.xml" + + if @function == 'toggle' + if acd_agent.status == 'active' + acd_agent.status = 'inactive' + else + acd_agent.status = 'active' + end + + if ! acd_agent.save + render( + :status => 500, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + if acd_agent.status == 'active' + @phone_xml_object = { + :name => 'snom_phone_text', + :title => 'ACD', + :prompt => 'ACD', + :text => "#{@acd.name} on", + :fetch_url => exit_url, + :fetch_mil => '1000', + } + else + @phone_xml_object = { + :name => 'snom_phone_text', + :title => 'ACD', + :prompt => 'ACD', + :text => "#{@acd.name} off", + :fetch_url => exit_url, + :fetch_mil => '1000', + } + end + + respond_to { |format| + format.any { + self.formats = [ :xml ] + render :action => "_#{@phone_xml_object[:name]}" + } + } + end + end + + def exit + render( + :status => 200, + :layout => false, + :content_type => 'text/xml', + :text => "", + ) + end + + def call_date_compact(date) + if date.strftime('%Y%m%d') == DateTime::now.strftime('%Y%m%d') + return date.strftime('%H:%M') + end + return date.strftime('%d.%m %H:%M') + end + +end diff --git a/app/controllers/fax_accounts_controller.rb b/app/controllers/fax_accounts_controller.rb new file mode 100644 index 0000000..ce03bc5 --- /dev/null +++ b/app/controllers/fax_accounts_controller.rb @@ -0,0 +1,82 @@ +class FaxAccountsController < ApplicationController + load_resource :user + load_resource :user_group + load_and_authorize_resource :fax_account, :through => [:user, :user_group] + + before_filter :set_and_authorize_parent + before_filter :spread_breadcrumbs + + def index + end + + def show + end + + def new + @fax_account = @parent.fax_accounts.build + @fax_account.name = generate_a_new_name(@parent, @fax_account) + @fax_account.days_till_auto_delete = DAYS_TILL_AUTO_DELETE + @fax_account.retries = DEFAULT_NUMBER_OF_RETRIES + @fax_account.station_id = @parent.to_s + @fax_account.phone_numbers.build + if @parent.class == User && !@parent.email.blank? + @fax_account.email = @parent.email + end + end + + def create + @fax_account = @parent.fax_accounts.build(params[:fax_account]) + if @fax_account.save + m = method( :"#{@parent.class.name.underscore}_fax_account_path" ) + redirect_to m.( @parent, @fax_account ), :notice => t('fax_accounts.controller.successfuly_created') + else + render :new + end + end + + def edit + end + + def update + if @fax_account.update_attributes(params[:fax_account]) + m = method( :"#{@parent.class.name.underscore}_fax_account_path" ) + redirect_to m.( @parent, @fax_account ), :notice => t('fax_accounts.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @fax_account.destroy + m = method( :"#{@parent.class.name.underscore}_fax_accounts_url" ) + redirect_to m.( @parent ), :notice => t('fax_accounts.controller.successfuly_destroyed') + end + + private + def set_and_authorize_parent + @parent = @user || @user_group + authorize! :read, @parent + end + + def spread_breadcrumbs + if @parent && @parent.class == User + add_breadcrumb t("users.index.page_title"), tenant_users_path(@user.current_tenant) + add_breadcrumb @user, tenant_user_path(@user.current_tenant, @user) + add_breadcrumb t("fax_accounts.index.page_title"), user_fax_accounts_path(@user) + if @fax_account && !@fax_account.new_record? + add_breadcrumb @fax_account, user_fax_account_path(@user, @fax_account) + end + end + + if @parent && @parent.class == UserGroup + @user_group = @parent + add_breadcrumb t("user_groups.index.page_title"), tenant_user_groups_path(@user_group.tenant) + add_breadcrumb @user_group, tenant_user_group_path(@user_group.tenant, @user_group) + add_breadcrumb t("fax_accounts.index.page_title"), user_group_fax_accounts_path(@user_group) + if @fax_account && !@fax_account.new_record? + add_breadcrumb @fax_account, user_group_fax_account_path(@user_group, @fax_account) + end + end + end + +end diff --git a/app/controllers/fax_documents_controller.rb b/app/controllers/fax_documents_controller.rb new file mode 100644 index 0000000..eff9604 --- /dev/null +++ b/app/controllers/fax_documents_controller.rb @@ -0,0 +1,82 @@ +class FaxDocumentsController < ApplicationController + load_and_authorize_resource :fax_account + load_and_authorize_resource :fax_document, :through => [:fax_account] + + before_filter :spread_breadcrumbs + + def index + @fax_documents = @fax_documents.order(:created_at).reverse_order + end + + def show + respond_to do |format| + @fax_document = FaxDocument.find(params[:id]) + format.html + format.xml { render :xml => @fax_document } + format.pdf { + caller_number = @fax_document.caller_id_number.to_s.gsub(/[^0-9]/, '') + if caller_number.blank? + caller_number = 'anonymous' + end + + if @fax_document.document.path + send_file @fax_document.document.path, :type => "application/pdf", + :filename => "#{@fax_document.created_at.strftime('%Y%m%d-%H%M%S')}-#{caller_number}.pdf" + else + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + end + } + end + end + + def new + @fax_document = @fax_account.fax_documents.build + @phone_number = @fax_document.build_destination_phone_number + end + + def create + @fax_document = @fax_account.fax_documents.build(params[:fax_document]) + @fax_document.retry_counter = @fax_account.retries + if @fax_document.save + @fax_document.queue_for_sending! + redirect_to fax_account_fax_document_path(@fax_document.fax_account, @fax_document), :notice => t('fax_documents.controller.successfuly_created') + else + render :new + end + end + + def destroy + @fax_account = FaxAccount.find(params[:fax_account_id]) + @fax_document = @fax_account.fax_documents.find(params[:id]) + @fax_document.destroy + redirect_to fax_account_fax_documents_url, :notice => t('fax_documents.controller.successfuly_destroyed') + end + + private + def spread_breadcrumbs + breadcrumbs = [] + breadcrumbs = case @fax_account.fax_accountable.class.to_s + when 'User' ; [ + [@fax_account.fax_accountable.to_s, user_path(@fax_account.fax_accountable)], + [t('fax_accounts.name').pluralize, user_fax_accounts_path(@fax_account.fax_accountable)], + [t('fax_documents.name').pluralize, fax_account_fax_documents_path(@fax_account)], + ] + when 'UserGroup' ; [ + [@fax_account.fax_accountable, user_group_path(@fax_account.fax_accountable)], + [t('fax_accounts.name').pluralize, user_group_fax_accounts_path(@fax_account.fax_accountable)], + [t('fax_documents.name').pluralize, fax_account_fax_documents_path(@fax_account)], + ] + end + if !breadcrumbs.blank? + breadcrumbs.each do |breadcrumb| + add_breadcrumb breadcrumb[0], breadcrumb[1] + end + end + end + +end diff --git a/app/controllers/freeswitch_voicemail_msgs_controller.rb b/app/controllers/freeswitch_voicemail_msgs_controller.rb new file mode 100644 index 0000000..085db3d --- /dev/null +++ b/app/controllers/freeswitch_voicemail_msgs_controller.rb @@ -0,0 +1,7 @@ +class FreeswitchVoicemailMsgsController < ApplicationController + load_and_authorize_resource :sip_account + load_and_authorize_resource :freeswitch_voicemail_msg, :through => [:sip_account] + + def index + end +end diff --git a/app/controllers/gemeinschaft_setups_controller.rb b/app/controllers/gemeinschaft_setups_controller.rb new file mode 100644 index 0000000..cafb8a3 --- /dev/null +++ b/app/controllers/gemeinschaft_setups_controller.rb @@ -0,0 +1,61 @@ +class GemeinschaftSetupsController < ApplicationController + load_and_authorize_resource :gemeinschaft_setup + + skip_before_filter :go_to_setup_if_new_installation + # before_filter :redirect_if_not_a_fresh_installation + + def new + @user = @gemeinschaft_setup.build_user( + :user_name => t('gemeinschaft_setups.initial_setup.admin_name'), + :male => true, + :email => 'admin@localhost', + ) + @sip_domain = @gemeinschaft_setup.build_sip_domain( + :host => guess_local_host(), + :realm => guess_local_host(), + ) + @gemeinschaft_setup.country = Country.find_by_name('Germany') + @gemeinschaft_setup.language = Language.find_by_name('Deutsch') + end + + def create + if @gemeinschaft_setup.save + super_tenant = Tenant.create( + :name => SUPER_TENANT_NAME, + :country_id => @gemeinschaft_setup.country.id, + :language_id => @gemeinschaft_setup.language_id, + :description => t('gemeinschaft_setups.initial_setup.super_tenant_description'), + ) + + # Admin + user = @gemeinschaft_setup.user + super_tenant.tenant_memberships.create(:user_id => user.id) + user.update_attributes(:current_tenant_id => super_tenant.id) + + # Create the Super-Tenant's group: + super_tenant_super_admin_group = super_tenant.user_groups.create(:name => t('gemeinschaft_setups.initial_setup.super_admin_group_name')) + super_tenant_super_admin_group.user_group_memberships.create(:user_id => user.id) + + # Auto-Login: + session[:user_id] = user.id + + # Redirect to the user + redirect_to new_tenant_url, :notice => t('gemeinschaft_setups.initial_setup.successful_setup') + else + render :new + end + end + + private + + def redirect_if_not_a_fresh_installation + if GemeinschaftSetup.all.count > 0 + if current_user + redirect_to root_url , :alert => t('gemeinschaft_setups.initial_setup.access_denied_only_available_on_a_new_system') + else + redirect_to log_in_path , :alert => t('gemeinschaft_setups.initial_setup.access_denied_only_available_on_a_new_system') + end + end + end + +end diff --git a/app/controllers/gs_cluster_sync_log_entries_controller.rb b/app/controllers/gs_cluster_sync_log_entries_controller.rb new file mode 100644 index 0000000..3e65037 --- /dev/null +++ b/app/controllers/gs_cluster_sync_log_entries_controller.rb @@ -0,0 +1,25 @@ +class GsClusterSyncLogEntriesController < ApplicationController + + # GET /gs_cluster_sync_log_entries/new.json + def new + @gs_cluster_sync_log_entry = GsClusterSyncLogEntry.new + + respond_to do |format| + format.json { render json: @gs_cluster_sync_log_entry } + end + end + + # POST /gs_cluster_sync_log_entries.json + def create + @gs_cluster_sync_log_entry = GsClusterSyncLogEntry.new(params[:gs_cluster_sync_log_entry]) + + respond_to do |format| + if @gs_cluster_sync_log_entry.save + format.json { render json: @gs_cluster_sync_log_entry, status: :created, location: @gs_cluster_sync_log_entry } + else + format.json { render json: @gs_cluster_sync_log_entry.errors, status: :unprocessable_entity } + end + end + end + +end diff --git a/app/controllers/gs_nodes_controller.rb b/app/controllers/gs_nodes_controller.rb new file mode 100644 index 0000000..3667775 --- /dev/null +++ b/app/controllers/gs_nodes_controller.rb @@ -0,0 +1,170 @@ +class GsNodesController < ApplicationController + + load_and_authorize_resource :gs_node, :only => [:index, :show, :new, :create, :edit, :update, :destroy] + + before_filter :spread_breadcrumbs + + def index + + end + + def show + + end + + def new + @gs_node = GsNode.new + @gs_node.push_updates_to = true + @gs_node.accepts_updates_from = true + @gs_node.element_name = 'gs_cluster_sync_log_entry' + end + + def create + @gs_node = GsNode.new(params[:gs_node]) + if @gs_node.save + redirect_to @gs_node, :notice => t('gs_nodes.controller.successfuly_created') + else + render :new + end + end + + def edit + @gs_node = GsNode.find(params[:id]) + end + + def update + @gs_node = GsNode.find(params[:id]) + if @gs_node.update_attributes(params[:gs_node]) + redirect_to @gs_node, :notice => t('gs_nodes.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @gs_node = GsNode.find(params[:id]) + @gs_node.destroy + redirect_to gs_nodes_url, :notice => t('gs_nodes.controller.successfuly_destroyed') + end + + def sync + if !GsNode.where(:ip_address => request.remote_ip).first + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + return + end + + if ! params[:newer].blank? + @newer_as = Time.at(params[:newer].to_i) + else + @newer_as = Time.at(0) + end + + if ! params[:class].blank? + @request_class = params[:class].to_s + else + @request_class = ''; + end + + @node = GsNode.where(:ip_address => HOMEBASE_IP_ADDRESS).first + + if @request_class.blank? || @request_class == "tenants" + @tenants = Tenant.where('updated_at > ?', @newer_as) + end + + if @request_class.blank? || @request_class == "user_groups" + @user_groups = UserGroup.where('updated_at > ?', @newer_as) + end + + if @request_class.blank? || @request_class == "users" + @users = User.where('updated_at > ?', @newer_as) + end + + if @request_class.blank? || @request_class == "user_group_memberships" + @user_group_memberships = UserGroupMembership.where('updated_at > ?', @newer_as) + end + + if @request_class.blank? || @request_class == "sip_accounts" + @sip_accounts = SipAccount.where('updated_at > ?',@newer_as) + end + + if @request_class.blank? || @request_class == "conferences" + @conferences = Conference.where('updated_at > ?', @newer_as) + end + + if @request_class.blank? || @request_class == "fax_accounts" + @fax_accounts = FaxAccount.where('updated_at > ?', @newer_as) + end + + if @request_class.blank? || @request_class == "phone_books" + @phone_books = PhoneBook.where('updated_at > ?',@newer_as) + end + + if @request_class.blank? || @request_class == "phone_book_entries" + @phone_book_entries = PhoneBookEntry.where('updated_at > ?',@newer_as) + end + + if @request_class.blank? || @request_class == "phone_numbers" + @phone_numbers = PhoneNumber.where('updated_at > ?', @newer_as) + end + + if @request_class.blank? || @request_class == "call_forwards" + @call_forwards = CallForward.where('updated_at > ?', @newer_as) + end + + if @request_class.blank? || @request_class == "softkeys" + @softkeys = Softkey.where('updated_at > ?', @newer_as) + end + + if @request_class.blank? || @request_class == "ringtones" + @ringtones = Ringtone.where('updated_at > ?', @newer_as) + end + + if @request_class.blank? || @request_class == "conference_invitees" + @conference_invitees = ConferenceInvitee.where('updated_at > ?', @newer_as) + end + + if @request_class == "fax_documents" + @fax_documents = FaxDocument.where('updated_at > ?', @newer_as) + end + + if @request_class == "call_histories" + @call_histories = CallHistory.where('updated_at > ?', @newer_as) + end + + if @request_class.blank? || @request_class == "deleted_items" + @deleted_items = Array.new + deleted_items_log = GsClusterSyncLogEntry.where('action = "destroy" AND updated_at > ?', @newer_as) + deleted_items_log.each do |deleted_item_log_entry| + content = JSON(deleted_item_log_entry.content) + content['class_name'] = deleted_item_log_entry.class_name + if content['uuid'] + @deleted_items << content + end + end + end + + if params[:image].to_s == 'false' + @image_include = false + else + @image_include = true + end + + end + + private + + def spread_breadcrumbs + if @gs_node + add_breadcrumb t("gs_nodes.index.page_title"), gs_nodes_path + + if @gs_node && !@gs_node.new_record? + add_breadcrumb @gs_node, gs_node_path(@gs_node) + end + end + end +end diff --git a/app/controllers/gui_functions_controller.rb b/app/controllers/gui_functions_controller.rb new file mode 100644 index 0000000..2ab2c5e --- /dev/null +++ b/app/controllers/gui_functions_controller.rb @@ -0,0 +1,73 @@ +class GuiFunctionsController < ApplicationController + before_filter :load_user_groups + before_filter :spread_breadcrumbs + + def index + @gui_functions = GuiFunction.order(:category, :name) + end + + def show + @gui_function = GuiFunction.find(params[:id]) + end + + def new + @gui_function = GuiFunction.new + + @user_groups.each do |user_group| + if @gui_function.user_groups.where(:id => user_group.id).count == 0 + @gui_function.gui_function_memberships.build(:user_group_id => user_group.id, :activated => true) + end + end + end + + def create + @gui_function = GuiFunction.new(params[:gui_function]) + + if @gui_function.save + redirect_to @gui_function, :notice => t('gui_functions.controller.successfuly_created') + else + render :new + end + end + + def edit + @gui_function = GuiFunction.find(params[:id]) + @user_groups.each do |user_group| + if @gui_function.user_groups.where(:id => user_group.id).count == 0 + @gui_function.gui_function_memberships.build(:user_group_id => user_group.id, :activated => true) + end + end + end + + def update + @gui_function = GuiFunction.find(params[:id]) + if @gui_function.update_attributes(params[:gui_function]) + redirect_to @gui_function, :notice => t('gui_functions.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @gui_function = GuiFunction.find(params[:id]) + @gui_function.destroy + redirect_to gui_functions_url, :notice => t('gui_functions.controller.successfuly_destroyed') + end + + private + def load_user_groups + @user_groups = Tenant.find(@current_user.current_tenant).user_groups.order(:position) + end + + def spread_breadcrumbs + if @tenant + add_breadcrumb t("user_groups.index.page_title"), tenant_user_groups_path(@tenant) + if @user_group && !@user_group.new_record? + add_breadcrumb @user_group, tenant_user_group_path(@tenant, @user_group) + end + end + + add_breadcrumb t("gui_functions.index.page_title"), gui_functions_path + end + +end diff --git a/app/controllers/hunt_group_members_controller.rb b/app/controllers/hunt_group_members_controller.rb new file mode 100644 index 0000000..90206ee --- /dev/null +++ b/app/controllers/hunt_group_members_controller.rb @@ -0,0 +1,67 @@ +class HuntGroupMembersController < ApplicationController + load_and_authorize_resource :hunt_group + load_and_authorize_resource :hunt_group_member, :through => [:hunt_group] + + before_filter :spread_breadcrumbs + + def index + if params[:active] + if params[:active].downcase == 'true' + @hunt_group_members = @hunt_group_members.where(:active => true) + elsif params[:active].downcase == 'false' + @hunt_group_members = @hunt_group_members.where(:active => false) + end + end + end + + def show + end + + def new + @hunt_group_member = @hunt_group.hunt_group_members.build + + i = @hunt_group.hunt_group_members.count + loop do + i += 1 + break unless @hunt_group.hunt_group_members.where(:name => "#{t('hunt_group_members.name')} #{i}").count > 0 + end + @hunt_group_member.name = "#{t('hunt_group_members.name')} #{i}" + @hunt_group_member.active = true + @hunt_group_member.can_switch_status_itself = true + end + + def create + @hunt_group_member = @hunt_group.hunt_group_members.build(params[:hunt_group_member]) + if @hunt_group_member.save + redirect_to hunt_group_hunt_group_member_path(@hunt_group, @hunt_group_member), :notice => t('hunt_group_members.controller.successfuly_created') + else + render :new + end + end + + def edit + end + + def update + if @hunt_group_member.update_attributes(params[:hunt_group_member]) + redirect_to hunt_group_hunt_group_member_path(@hunt_group, @hunt_group_member), :notice => t('hunt_group_members.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @hunt_group_member.destroy + redirect_to hunt_group_hunt_group_members_path(@hunt_group), :notice => t('hunt_group_members.controller.successfuly_destroyed') + end + + def spread_breadcrumbs + add_breadcrumb t("hunt_groups.index.page_title"), tenant_hunt_groups_path(@hunt_group.tenant) + add_breadcrumb @hunt_group, tenant_hunt_group_path(@hunt_group.tenant, @hunt_group) + add_breadcrumb t("hunt_group_members.index.page_title"), hunt_group_hunt_group_members_path(@hunt_group) + if @hunt_group_member && !@hunt_group_member.new_record? + add_breadcrumb @hunt_group_member, hunt_group_hunt_group_member_path(@hunt_group, @hunt_group_member) + end + end + +end diff --git a/app/controllers/hunt_groups_controller.rb b/app/controllers/hunt_groups_controller.rb new file mode 100644 index 0000000..13a556a --- /dev/null +++ b/app/controllers/hunt_groups_controller.rb @@ -0,0 +1,55 @@ +class HuntGroupsController < ApplicationController + load_and_authorize_resource :tenant + load_and_authorize_resource :hunt_group, :through => [:tenant] + + before_filter :spread_breadcrumbs + + def index + end + + def show + end + + def new + i = @tenant.hunt_groups.count + loop do + i += 1 + break unless @tenant.hunt_groups.where(:name => "#{t('hunt_groups.name')} #{i}").count > 0 + end + @hunt_group = @tenant.hunt_groups.build(:name => "#{t('hunt_groups.name')} #{i}") + end + + def create + @hunt_group = @tenant.hunt_groups.build(params[:hunt_group]) + if @hunt_group.save + redirect_to tenant_hunt_group_path(@tenant, @hunt_group), :notice => t('hunt_groups.controller.successfuly_created') + else + render :new + end + end + + def edit + end + + def update + @hunt_group = HuntGroup.find(params[:id]) + if @hunt_group.update_attributes(params[:hunt_group]) + redirect_to tenant_hunt_group_path(@tenant, @hunt_group), :notice => t('hunt_groups.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @hunt_group.destroy + redirect_to tenant_hunt_groups_path(@tenant), :notice => t('hunt_groups.controller.successfuly_destroyed') + end + + private + def spread_breadcrumbs + add_breadcrumb t("hunt_groups.index.page_title"), tenant_hunt_groups_path(@tenant) + if @hunt_group && !@hunt_group.new_record? + add_breadcrumb @hunt_group, tenant_hunt_group_path(@tenant, @hunt_group) + end + end +end diff --git a/app/controllers/manufacturers_controller.rb b/app/controllers/manufacturers_controller.rb new file mode 100644 index 0000000..1bcf9de --- /dev/null +++ b/app/controllers/manufacturers_controller.rb @@ -0,0 +1,49 @@ +class ManufacturersController < ApplicationController + load_and_authorize_resource :manufacturer + + before_filter :spread_breadcrumbs + + def index + end + + def show + end + + def new + end + + def create + @manufacturer = Manufacturer.new(params[:manufacturer]) + if @manufacturer.save + redirect_to @manufacturer, :notice => t('manufacturers.controller.successfuly_created') + else + render :new + end + end + + def edit + end + + def update + if @manufacturer.update_attributes(params[:manufacturer]) + redirect_to @manufacturer, :notice => t('manufacturers.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @manufacturer.destroy + redirect_to manufacturers_url, :notice => t('manufacturers.controller.successfuly_destroyed') + end + + private + + def spread_breadcrumbs + add_breadcrumb t("manufacturers.index.page_title"), manufacturers_path + if @manufacturer && !@manufacturer.new_record? + add_breadcrumb @manufacturer, manufacturer_path(@manufacturer) + end + end + +end diff --git a/app/controllers/page_controller.rb b/app/controllers/page_controller.rb new file mode 100644 index 0000000..1f37449 --- /dev/null +++ b/app/controllers/page_controller.rb @@ -0,0 +1,24 @@ +class PageController < ApplicationController + # load_and_authorize_resource :class => false + # CanCan doesn't work here really good because Page is not a resource. + + before_filter :if_fresh_system_then_go_to_wizard + skip_before_filter :home_breadcrumb, :only => [:index] + + def index;end + def conference;end + + private + def if_fresh_system_then_go_to_wizard + if Tenant.count == 0 && User.count == 0 + # This is a brand new system. We need to run a setup first. + redirect_to wizards_new_initial_setup_path + else + if current_user.nil? + # You need to login first. + redirect_to log_in_path, :alert => I18n.t('pages.controller.access_denied_login_first') + end + end + end + +end diff --git a/app/controllers/phone_book_entries_controller.rb b/app/controllers/phone_book_entries_controller.rb new file mode 100644 index 0000000..823d50e --- /dev/null +++ b/app/controllers/phone_book_entries_controller.rb @@ -0,0 +1,135 @@ +class PhoneBookEntriesController < ApplicationController + load_and_authorize_resource :phone_book + load_and_authorize_resource :phone_book_entry, :through => :phone_book, :shallow => true + + before_filter :spread_breadcrumbs + + def index + # In case this is a search params[:q] or params[:name] will contain the query. + # + @query = params[:q] + @query ||= params[:name] + @query = @query.strip if @query + + if !@query.blank? + if @query.match(/^\+?\d+$/) != nil + # Find by phone number + phone_book_entries_ids = @phone_book_entries.map{|entry| entry.id} + @found_phone_numbers = PhoneNumber. + where(:phone_numberable_type => 'PhoneBookEntry', :phone_numberable_id => phone_book_entries_ids). + where('number LIKE ?', "#{@query}%") + @search_result = @phone_book_entries.where(:id => @found_phone_numbers.map{|entry| entry.phone_numberable_id}) + elsif @query.match(/^[\"\'](.*)[\"\']$/) != nil + # The User searched for =>'example'<= so he wants an EXACT search for that. + # This is the fasted and most accurate way of searching. + # The order to search is: last_name, first_name and organization. + # It stops searching as soon as it finds results. + # + @query = $1 + @search_result = @phone_book_entries.where(:last_name => @query) + @search_result = @phone_book_entries.where(:first_name => @query) if @search_result.count == 0 + @search_result = @phone_book_entries.where(:organization => @query) if @search_result.count == 0 + + @exact_search = true + else + # Search with SQL LIKE + # + @search_result = @phone_book_entries. + where( '( ( last_name LIKE ? ) OR ( first_name LIKE ? ) OR ( organization LIKE ? ) )', + "#{@query}%", "#{@query}%", "#{@query}%" ) + + @exact_search = false + end + + # Let's have a run with our phonetic search. + # + phonetic_query = PhoneBookEntry.koelner_phonetik(@query) + @phonetic_search_result = @phone_book_entries.where(:last_name_phonetic => phonetic_query) + @phonetic_search_result = @phone_book_entries.where(:first_name_phonetic => phonetic_query) if @phonetic_search_result.count == 0 + @phonetic_search_result = @phone_book_entries.where(:organization_phonetic => phonetic_query) if @phonetic_search_result.count == 0 + + if @phonetic_search_result.count == 0 + # Let's try the search with SQL LIKE. Just in case. + # + @phonetic_search_result = @phone_book_entries.where( 'last_name_phonetic LIKE ?', "#{phonetic_query}%" ) + @phonetic_search_result = @phone_book_entries.where( 'first_name_phonetic LIKE ?', "#{phonetic_query}%" ) if @phonetic_search_result.count == 0 + @phonetic_search_result = @phone_book_entries.where( 'organization_phonetic LIKE ?', "#{phonetic_query}%" ) if @phonetic_search_result.count == 0 + end + + @phonetic_search = true if @phonetic_search_result.count > 0 + + @phone_book_entries = @search_result + + if @phone_book_entries.count == 0 && @exact_search == false && @phonetic_search + @phone_book_entries = @phonetic_search_result + end + end + + # Let's sort the results and do pagination. + # + @phone_book_entries = @phone_book_entries. + order([ :last_name, :first_name, :organization ]). + paginate( + :page => @pagination_page_number, + :per_page => DEFAULT_PAGINATION_ENTRIES_PER_PAGE + ) + end + + def show + end + + def new + @phone_book_entry = @phone_book.phone_book_entries.build + @phone_book_entry.is_male = true + end + + def create + @phone_book_entry = @phone_book.phone_book_entries.build( params[:phone_book_entry] ) + if @phone_book_entry.save + redirect_to phone_book_phone_book_entry_path( @phone_book, @phone_book_entry ), :notice => t('phone_book_entries.controller.successfuly_created', :resource => @phone_book_entry) + else + render :new + end + end + + def edit + end + + def update + if @phone_book_entry.update_attributes(params[:phone_book_entry]) + redirect_to @phone_book_entry, :notice => t('phone_book_entries.controller.successfuly_updated', :resource => @phone_book_entry) + else + render :edit + end + end + + def destroy + @phone_book_entry.destroy + redirect_to phone_book_entries_url, :notice => t('phone_book_entries.controller.successfuly_destroyed') + end + + private + + def spread_breadcrumbs + if @phone_book + if @phone_book.phone_bookable.class == Tenant + add_breadcrumb t("phone_books.index.page_title"), tenant_phone_books_path(@phone_book.phone_bookable) + add_breadcrumb @phone_book, tenant_phone_book_path(@phone_book.phone_bookable, @phone_book) + add_breadcrumb t("phone_book_entries.index.page_title"), phone_book_phone_book_entries_path(@phone_book) + end + + if @phone_book.phone_bookable.class == User + add_breadcrumb t("users.index.page_title"), tenant_users_path(@phone_book.phone_bookable.current_tenant) + add_breadcrumb @phone_book.phone_bookable, tenant_user_path(@phone_book.phone_bookable.current_tenant, @phone_book.phone_bookable) + add_breadcrumb t("phone_books.index.page_title"), user_phone_books_path(@phone_book.phone_bookable) + add_breadcrumb @phone_book, user_phone_book_path(@phone_book.phone_bookable, @phone_book) + add_breadcrumb t("phone_book_entries.index.page_title"), phone_book_phone_book_entries_path(@phone_book) + end + + if @phone_book_entry && !@phone_book_entry.new_record? + add_breadcrumb @phone_book_entry, phone_book_phone_book_entry_path(@phone_book, @phone_book_entry) + end + end + end + +end diff --git a/app/controllers/phone_books_controller.rb b/app/controllers/phone_books_controller.rb new file mode 100644 index 0000000..54e7889 --- /dev/null +++ b/app/controllers/phone_books_controller.rb @@ -0,0 +1,105 @@ +class PhoneBooksController < ApplicationController + load_resource :user + load_resource :user_group + load_resource :tenant + load_and_authorize_resource :phone_book, :through => [:user, :user_group, :tenant] + + before_filter :set_and_authorize_parent + before_filter :spread_breadcrumbs + + def index + end + + def show + @by_name = params[:name] + + @pagination_page_number = params[:page].to_i + @pagination_page_number = 1 if @pagination_page_number < 1 + + if @by_name.blank? + @phone_book_entries = @phone_book. + phone_book_entries. + order([ :last_name, :first_name ]). + paginate( + :page => @pagination_page_number, + :per_page => DEFAULT_PAGINATION_ENTRIES_PER_PAGE + ) + else + # search by name + @by_name = @by_name. + gsub( /[^A-Za-z0-9#]/, '' ). + gsub('*','?'). + gsub('%','_'). + gsub(/^#/,''). + upcase + + @phone_book_entries = @phone_book. + phone_book_entries. + where( '( ( last_name LIKE ? ) OR ( first_name LIKE ? ) )', "#{@by_name}%", "#{@by_name}%" ). + order([ :last_name, :first_name ]). + paginate( + :page => @pagination_page_number, + :per_page => DEFAULT_PAGINATION_ENTRIES_PER_PAGE + ) + end + end + + def new + @phone_book = @parent.phone_books.build + @phone_book.name = generate_a_new_name(@parent, @phone_book) + end + + def create + @phone_book = @parent.phone_books.build( params[:phone_book] ) + if @phone_book.save + m = method( :"#{@parent.class.name.underscore}_phone_book_path" ) + redirect_to m.( @parent, @phone_book ), :notice => t('phone_books.controller.successfuly_created') + else + render :new + end + end + + def edit + end + + def update + if @phone_book.update_attributes(params[:phone_book]) + m = method( :"#{@parent.class.name.underscore}_phone_book_path" ) + redirect_to m.( @parent, @phone_book ), :notice => t('phone_books.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @phone_book.destroy + m = method( :"#{@parent.class.name.underscore}_phone_books_url" ) + redirect_to m.( @parent ), :notice => t('phone_books.controller.successfuly_destroyed') + end + + private + def set_and_authorize_parent + @parent = @user || @user_group || @tenant + authorize! :read, @parent + end + + def spread_breadcrumbs + if @parent.class == Tenant + add_breadcrumb t("phone_books.index.page_title"), tenant_phone_books_path(@tenant) + if @phone_book && !@phone_book.new_record? + add_breadcrumb @phone_book, tenant_phone_book_path(@tenant, @phone_book) + end + end + + if @parent.class == User + add_breadcrumb t("users.index.page_title"), tenant_users_path(@user.current_tenant) + add_breadcrumb @user, tenant_user_path(@user.current_tenant, @user) + add_breadcrumb t("phone_books.index.page_title"), user_phone_books_path(@user) + if @phone_book && !@phone_book.new_record? + add_breadcrumb @phone_book, user_phone_book_path(@user, @phone_book) + end + end + + end + +end diff --git a/app/controllers/phone_models_controller.rb b/app/controllers/phone_models_controller.rb new file mode 100644 index 0000000..59facdf --- /dev/null +++ b/app/controllers/phone_models_controller.rb @@ -0,0 +1,52 @@ +class PhoneModelsController < ApplicationController + load_and_authorize_resource :manufacturer + load_and_authorize_resource :phone_model, :through => [:manufacturer] + + before_filter :spread_breadcrumbs + + def index + end + + def show + end + + def new + @phone_model = @manufacturer.phone_models.build + end + + def create + @phone_model = @manufacturer.phone_models.build.new(params[:phone_model]) + if @phone_model.save + redirect_to manufacturer_phone_model_path( @manufacturer, @phone_model ), :notice => t('phone_models.controller.successfuly_created') + else + render :new + end + end + + def edit + end + + def update + if @phone_model.update_attributes(params[:phone_model]) + redirect_to manufacturer_phone_model_path( @manufacturer, @phone_model ), :notice => t('phone_models.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @phone_model.destroy + redirect_to manufacturer_phone_models_url( @manufacturer ), :notice => t('phone_models.controller.successfuly_destroyed') + end + + private + + def spread_breadcrumbs + add_breadcrumb t("manufacturers.index.page_title"), manufacturers_path + add_breadcrumb @manufacturer, manufacturer_path(@manufacturer) + add_breadcrumb t("phone_models.index.page_title"), manufacturer_phone_models_path(@manufacturer) + if @phone_model && !@phone_model.new_record? + add_breadcrumb @phone_model, manufacturer_phone_model_path(@manufacturer, @phone_model) + end + end +end diff --git a/app/controllers/phone_number_ranges_controller.rb b/app/controllers/phone_number_ranges_controller.rb new file mode 100644 index 0000000..a4e7238 --- /dev/null +++ b/app/controllers/phone_number_ranges_controller.rb @@ -0,0 +1,56 @@ +class PhoneNumberRangesController < ApplicationController + load_and_authorize_resource :tenant + load_and_authorize_resource :phone_number_range, :through => [:tenant] + + before_filter :set_parent + before_filter :spread_breadcrumbs + + def index + end + + def show + end + + def new + @phone_number_range = @parent.phone_number_ranges.build + end + + def create + @phone_number_range = @parent.phone_number_ranges.build(params[:phone_number_range]) + if @phone_number_range.save + redirect_to @phone_number_range, :notice => t('phone_number_ranges.controller.successfuly_created') + else + render :new + end + end + + def edit + end + + def update + if @phone_number_range.update_attributes(params[:phone_number_range]) + redirect_to @phone_number_range, :notice => t('phone_number_ranges.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @phone_number_range.destroy + redirect_to phone_number_ranges_url, :notice => t('phone_number_ranges.controller.successfuly_destroyed') + end + + private + + def set_parent + @parent = @tenant + end + + def spread_breadcrumbs + add_breadcrumb t("phone_number_ranges.index.page_title"), tenant_phone_number_ranges_path(@tenant) + if @phone_number_range && !@phone_number_range.new_record? + add_breadcrumb t("phone_number_ranges.ranges.#{@phone_number_range}.label"), tenant_phone_number_range_path(@tenant, @phone_number_range) + end + end + +end diff --git a/app/controllers/phone_numbers_controller.rb b/app/controllers/phone_numbers_controller.rb new file mode 100644 index 0000000..065934c --- /dev/null +++ b/app/controllers/phone_numbers_controller.rb @@ -0,0 +1,226 @@ +class PhoneNumbersController < ApplicationController + load_resource :phone_book_entry + load_resource :sip_account + load_resource :conference + load_resource :fax_account + load_resource :phone_number_range + load_resource :callthrough + load_resource :whitelist + load_resource :access_authorization + load_resource :hunt_group + load_resource :hunt_group_member + load_resource :automatic_call_distributor + load_and_authorize_resource :phone_number, :through => [:phone_book_entry, :sip_account, :conference, + :fax_account, :phone_number_range, :callthrough, + :whitelist, :access_authorization, :hunt_group, + :hunt_group_member, :automatic_call_distributor] + + before_filter :set_and_authorize_parent + before_filter :spread_breadcrumbs + + def index + end + + def show + @ringtoneable_classes = { + 'SipAccount' => true, + 'HuntGroup' => true, + 'AutomaticCallDistributor' => true, + 'PhoneBookEntry' => true, + } + @forwardable_classes = { + 'SipAccount' => true, + 'HuntGroup' => true, + 'AutomaticCallDistributor' => true, + } + end + + def new + @phone_number = @parent.phone_numbers.build() + end + + def create + @phone_number = @parent.phone_numbers.new( params[:phone_number] ) + if @phone_number.save + m = method( :"#{@parent.class.name.underscore}_phone_number_path" ) + redirect_to m.( @parent, @phone_number ), :notice => t('phone_numbers.controller.successfuly_created') + else + render :new + end + end + + def edit + end + + def update + if @phone_number.update_attributes(params[:phone_number]) + m = method( :"#{@parent.class.name.underscore}_phone_number_path" ) + redirect_to m.( @parent, @phone_number ), :notice => t('phone_numbers.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @phone_number.destroy + m = method( :"#{@parent.class.name.underscore}_phone_numbers_url" ) + redirect_to m.(), :notice => t('phone_numbers.controller.successfuly_destroyed') + end + + def move_higher + @phone_number.move_higher + redirect_to :back + end + + def move_lower + @phone_number.move_lower + redirect_to :back + end + + private + def set_and_authorize_parent + @parent = @phone_book_entry || @sip_account || @conference || @fax_account || + @phone_number_range || @callthrough || @whitelist || @access_authorization || + @hunt_group || @hunt_group_member || @automatic_call_distributor + + authorize! :read, @parent + + @show_path_method = method( :"#{@parent.class.name.underscore}_phone_number_path" ) + @index_path_method = method( :"#{@parent.class.name.underscore}_phone_numbers_path" ) + @new_path_method = method( :"new_#{@parent.class.name.underscore}_phone_number_path" ) + @edit_path_method = method( :"edit_#{@parent.class.name.underscore}_phone_number_path" ) + end + + def spread_breadcrumbs + if @parent.class == Callthrough + add_breadcrumb t("#{@parent.class.name.underscore.pluralize}.index.page_title"), tenant_callthroughs_path(@parent.tenant) + add_breadcrumb @callthrough, tenant_callthrough_path(@parent.tenant, @callthrough) + add_breadcrumb t("phone_numbers.index.page_title"), callthrough_phone_numbers_path(@parent) + if @phone_number && !@phone_number.new_record? + add_breadcrumb @phone_number, callthrough_phone_number_path(@callthrough, @phone_number) + end + end + + if @parent.class == SipAccount + if @sip_account.sip_accountable.class == User + add_breadcrumb t("#{@sip_account.sip_accountable.class.name.underscore.pluralize}.index.page_title"), method( :"tenant_#{@sip_account.sip_accountable.class.name.underscore.pluralize}_path" ).(@sip_account.tenant) + add_breadcrumb @sip_account.sip_accountable, method( :"tenant_#{@sip_account.sip_accountable.class.name.underscore}_path" ).(@sip_account.tenant, @sip_account.sip_accountable) + end + add_breadcrumb t("sip_accounts.index.page_title"), method( :"#{@sip_account.sip_accountable.class.name.underscore}_sip_accounts_path" ).(@sip_account.sip_accountable) + add_breadcrumb @sip_account, method( :"#{@sip_account.sip_accountable.class.name.underscore}_sip_account_path" ).(@sip_account.sip_accountable, @sip_account) + add_breadcrumb t("phone_numbers.index.page_title"), sip_account_phone_numbers_path(@sip_account) + if @phone_number && !@phone_number.new_record? + add_breadcrumb @phone_number, sip_account_phone_number_path(@sip_account, @phone_number) + end + end + + if @parent.class == Conference + @conference = @parent + conference_parent = @conference.conferenceable + if conference_parent && conference_parent.class == User + @user = conference_parent + add_breadcrumb t("users.index.page_title"), tenant_users_path(@user.current_tenant) + add_breadcrumb @user, tenant_user_path(@user.current_tenant, @user) + add_breadcrumb t("conferences.index.page_title"), user_conferences_path(@user) + add_breadcrumb @conference, user_conference_path(@user, @conference) + end + if conference_parent && conference_parent.class == Tenant + @tenant = conference_parent + add_breadcrumb t("conferences.index.page_title"), tenant_conferences_path(@tenant) + add_breadcrumb @conference, tenant_conference_path(@tenant, @conference) + end + add_breadcrumb t("phone_numbers.index.page_title"), conference_phone_numbers_path(@conference) + if @phone_number && !@phone_number.new_record? + add_breadcrumb @phone_number, conference_phone_number_path(@conference, @phone_number) + end + end + + if @parent.class == HuntGroup + add_breadcrumb t("#{@parent.class.name.underscore.pluralize}.index.page_title"), tenant_hunt_groups_path(@parent.tenant) + add_breadcrumb @hunt_group, tenant_hunt_group_path(@parent.tenant, @hunt_group) + add_breadcrumb t("phone_numbers.index.page_title"), hunt_group_phone_numbers_path(@parent) + end + + if @parent.class == HuntGroupMember + add_breadcrumb t("hunt_groups.index.page_title"), tenant_hunt_groups_path(@parent.hunt_group.tenant) + add_breadcrumb @parent.hunt_group, tenant_hunt_group_path(@parent.hunt_group.tenant, @parent.hunt_group) + add_breadcrumb t("hunt_group_members.index.page_title"), hunt_group_hunt_group_members_path(@parent.hunt_group) + add_breadcrumb @parent, hunt_group_hunt_group_member_path(@parent.hunt_group, @parent) + add_breadcrumb t("phone_numbers.index.page_title"), hunt_group_member_phone_numbers_path(@parent) + if @phone_number && !@phone_number.new_record? + add_breadcrumb @phone_number, hunt_group_member_phone_number_path(@parent, @phone_number) + end + end + + if @parent.class == AccessAuthorization + if @parent.access_authorizationable.class == Callthrough + callthrough = @parent.access_authorizationable + tenant = callthrough.tenant + add_breadcrumb t("callthroughs.index.page_title"), tenant_callthroughs_path(tenant) + add_breadcrumb callthrough, tenant_callthrough_path(tenant, callthrough) + add_breadcrumb t("access_authorizations.index.page_title"), callthrough_access_authorizations_path(callthrough) + add_breadcrumb @parent, callthrough_access_authorization_path(callthrough, @parent) + add_breadcrumb t("phone_numbers.index.page_title"), access_authorization_phone_numbers_path(@parent) + if @phone_number && !@phone_number.new_record? + add_breadcrumb @phone_number, access_authorization_phone_number_path(@parent, @phone_number) + end + end + end + + if @parent.class == PhoneBookEntry + @phone_book = @parent.phone_book + if @parent.phone_book.phone_bookable.class == Tenant + @tenant = @parent.phone_book.phone_bookable + add_breadcrumb t("phone_books.index.page_title"), tenant_phone_books_path(@tenant) + add_breadcrumb @phone_book, tenant_phone_book_path(@tenant, @phone_book) + add_breadcrumb @phone_book_entry, phone_book_phone_book_entry_path(@phone_book, @phone_book_entry) + + if @phone_number && !@phone_number.new_record? + add_breadcrumb @phone_number, phone_book_entry_phone_number_path(@phone_book_entry, @phone_number) + end + end + + if @parent.phone_book.phone_bookable.class == User + @user = @parent.phone_book.phone_bookable + add_breadcrumb t("users.index.page_title"), tenant_users_path(@user.current_tenant) + add_breadcrumb @user, tenant_user_path(@user.current_tenant, @user) + add_breadcrumb t("phone_books.index.page_title"), user_phone_books_path(@user) + add_breadcrumb @phone_book, user_phone_book_path(@user, @phone_book) + add_breadcrumb @phone_book_entry, phone_book_phone_book_entry_path(@phone_book, @phone_book_entry) + + if @phone_number && !@phone_number.new_record? + add_breadcrumb @phone_number, phone_book_entry_phone_number_path(@phone_book_entry, @phone_number) + end + end + end + + if @parent.class == Whitelist + @tenant = @parent.whitelistable.tenant + @callthrough = @parent.whitelistable + @whitelist = @parent + add_breadcrumb t("callthroughs.name").pluralize, tenant_callthroughs_path(@tenant) + add_breadcrumb @callthrough, tenant_callthrough_path(@tenant, @callthrough) + add_breadcrumb t("whitelists.index.page_title"), callthrough_whitelists_path(@callthrough) + add_breadcrumb @whitelist, callthrough_whitelist_path(@callthrough, @whitelist) + add_breadcrumb t("phone_numbers.index.page_title"), whitelist_phone_numbers_path(@whitelist) + if @phone_number && !@phone_number.new_record? + add_breadcrumb @phone_number, whitelist_phone_number_path(@whitelist, @phone_number) + end + end + + if @parent.class == AutomaticCallDistributor + if @automatic_call_distributor.automatic_call_distributorable.class == User + add_breadcrumb t("#{@automatic_call_distributor.automatic_call_distributorable.class.name.underscore.pluralize}.index.page_title"), method( :"tenant_#{@automatic_call_distributor.automatic_call_distributorable.class.name.underscore.pluralize}_path" ).(@automatic_call_distributor.tenant) + add_breadcrumb @automatic_call_distributor.automatic_call_distributorable, method( :"tenant_#{@automatic_call_distributor.automatic_call_distributorable.class.name.underscore}_path" ).(@automatic_call_distributor.tenant, @automatic_call_distributor.automatic_call_distributorable) + end + add_breadcrumb t("automatic_call_distributors.index.page_title"), method( :"#{@automatic_call_distributor.automatic_call_distributorable.class.name.underscore}_automatic_call_distributors_path" ).(@automatic_call_distributor.automatic_call_distributorable) + add_breadcrumb @automatic_call_distributor, method( :"#{@automatic_call_distributor.automatic_call_distributorable.class.name.underscore}_automatic_call_distributor_path" ).(@automatic_call_distributor.automatic_call_distributorable, @automatic_call_distributor) + add_breadcrumb t("phone_numbers.index.page_title"), automatic_call_distributor_phone_numbers_path(@automatic_call_distributor) + if @phone_number && !@phone_number.new_record? + add_breadcrumb @phone_number, automatic_call_distributor_phone_number_path(@automatic_call_distributor, @phone_number) + end + end + + end + +end diff --git a/app/controllers/phone_sip_accounts_controller.rb b/app/controllers/phone_sip_accounts_controller.rb new file mode 100644 index 0000000..8558c55 --- /dev/null +++ b/app/controllers/phone_sip_accounts_controller.rb @@ -0,0 +1,60 @@ +class PhoneSipAccountsController < ApplicationController + load_and_authorize_resource :phone + load_and_authorize_resource :phone_sip_account, :through => [:phone] + + before_filter :spread_breadcrumbs + + def index + end + + def show + end + + def new + @available_sip_accounts = @phone.phoneable.sip_accounts + + # Ensure a SipAccount is used on a single phone only. + # + @available_sip_accounts = @available_sip_accounts.delete_if { |x| x.phone_sip_account_ids.count > 0 } + + if @available_sip_accounts.count == 0 + redirect_to method( :"new_#{@phone.phoneable.class.name.underscore}_sip_account_path" ).(@phone.phoneable), :alert => t('phone_sip_accounts.controller.no_existing_sip_accounts_warning') + else + @phone_sip_account = @phone.phone_sip_accounts.build(:sip_account_id => @available_sip_accounts.first.try(:id)) + end + end + + def create + @phone_sip_account = @phone.phone_sip_accounts.build(params[:phone_sip_account]) + if @phone_sip_account.save + redirect_to method( :"#{@phone_sip_account.phone.phoneable.class.name.underscore}_phone_path" ).(@phone_sip_account.phone.phoneable, @phone_sip_account.phone), :notice => t('phone_sip_accounts.controller.successfuly_created') + else + render :new + end + end + + def destroy + @phone_sip_account.destroy + redirect_to method( :"#{@phone_sip_account.phone.phoneable.class.name.underscore}_phone_path" ).(@phone_sip_account.phone.phoneable, @phone_sip_account.phone), :notice => t('phone_sip_accounts.controller.successfuly_destroyed') + end + + private + + def spread_breadcrumbs + if @phone.phoneable.class == User + user = @phone.phoneable + add_breadcrumb t('users.index.page_title'), tenant_users_path(user.current_tenant) + add_breadcrumb user, tenant_user_path(user.current_tenant, user) + add_breadcrumb t('phones.index.page_title'), user_phones_path(user) + elsif @phone.phoneable.class == Tenant + tenant = @phone.phoneable + add_breadcrumb t('phones.index.page_title'), tenant_phones_path(tenant) + end + add_breadcrumb @phone, method( :"#{@phone.phoneable.class.name.underscore}_phone_path" ).(@phone.phoneable, @phone) + add_breadcrumb t('phone_sip_accounts.index.page_title'), phone_phone_sip_accounts_path(@phone) + if @phone_sip_account && !@phone_sip_account.new_record? + add_breadcrumb @phone_sip_account, phone_phone_sip_account_path(@phone, @phone_sip_account) + end + end + +end diff --git a/app/controllers/phones_controller.rb b/app/controllers/phones_controller.rb new file mode 100644 index 0000000..d46bf86 --- /dev/null +++ b/app/controllers/phones_controller.rb @@ -0,0 +1,72 @@ +class PhonesController < ApplicationController + load_resource :tenant + load_resource :user + load_and_authorize_resource :phone, :through => [:tenant, :user] + + before_filter :set_and_authorize_parent + before_filter :spread_breadcrumbs + + def index + end + + def show + end + + def new + @phone = @phoneable.phones.build() + + # Use the last phone.phone_model as the default. + # + @phone.phone_model_id = Phone.last.try(:phone_model).try(:id) + end + + def create + @phone = @phoneable.phones.build(params[:phone]) + if @phone.save + m = method( :"#{@phoneable.class.name.underscore}_phone_path" ) + redirect_to m.( @phoneable, @phone ), :notice => t('phones.controller.successfuly_created') + else + render :new + end + end + + def edit + end + + def update + if @phone.update_attributes(params[:phone]) + m = method( :"#{@phoneable.class.name.underscore}_phone_path" ) + redirect_to m.( @phoneable, @phone ), :notice => t('phones.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @phone.destroy + m = method( :"#{@phoneable.class.name.underscore}_phones_url" ) + redirect_to m.( @phoneable ), :notice => t('phones.controller.successfuly_destroyed') + end + + private + def set_and_authorize_parent + @phoneable = (@user || @tenant) + @parent = @phoneable + authorize! :read, @parent + @nesting_prefix = @phoneable ? "#{@phoneable.class.name.underscore}_" : '' + end + + def spread_breadcrumbs + if @user + add_breadcrumb t('users.index.page_title'), tenant_users_path(@user.current_tenant) + add_breadcrumb @user, tenant_user_path(@user.current_tenant, @user) + add_breadcrumb t('phones.index.page_title'), user_phones_path(@user) + elsif @tenant + add_breadcrumb t('phones.index.page_title'), tenant_phones_path(@tenant) + end + if @phone && !@phone.new_record? + add_breadcrumb @phone, method( :"#{@phone.phoneable.class.name.underscore}_phone_path" ).(@phone.phoneable, @phone) + end + end + +end diff --git a/app/controllers/ringtones_controller.rb b/app/controllers/ringtones_controller.rb new file mode 100644 index 0000000..7ffe30e --- /dev/null +++ b/app/controllers/ringtones_controller.rb @@ -0,0 +1,67 @@ +class RingtonesController < ApplicationController + load_resource :phone_number + load_resource :boss_assistant_cooperation + load_and_authorize_resource :ringtone, :through => [:phone_number, :boss_assistant_cooperation] + + before_filter :set_parent + before_filter :spread_breadcrumbs + + def index + end + + def show + end + + def new + @ringtone = @parent.ringtones.build + end + + def create + @ringtone = @parent.ringtones.build(params[:ringtone]) + if @ringtone.save + redirect_to phone_number_ringtone_path(@parent, @ringtone), :notice => t('ringtones.controller.successfuly_created') + else + render :new + end + end + + def edit + end + + def update + if @ringtone.update_attributes(params[:ringtone]) + redirect_to method( :"#{@parent.class.name.underscore}_ringtone_path" ).(@ringtone.ringtoneable, @ringtone), :notice => t('ringtones.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @ringtone.destroy + redirect_to phone_number_ringtones_path(@parent), :notice => t('ringtones.controller.successfuly_destroyed') + end + + private + def set_parent + @parent = @phone_number || @boss_assistant_cooperation + end + + def spread_breadcrumbs + if @parent.class == PhoneNumber && @parent.phone_numberable.class == SipAccount + @sip_account = @parent.phone_numberable + if @sip_account.sip_accountable.class == User + add_breadcrumb t("#{@sip_account.sip_accountable.class.name.underscore.pluralize}.index.page_title"), method( :"tenant_#{@sip_account.sip_accountable.class.name.underscore.pluralize}_path" ).(@sip_account.tenant) + add_breadcrumb @sip_account.sip_accountable, method( :"tenant_#{@sip_account.sip_accountable.class.name.underscore}_path" ).(@sip_account.tenant, @sip_account.sip_accountable) + end + add_breadcrumb t("sip_accounts.index.page_title"), method( :"#{@sip_account.sip_accountable.class.name.underscore}_sip_accounts_path" ).(@sip_account.sip_accountable) + add_breadcrumb @sip_account, method( :"#{@sip_account.sip_accountable.class.name.underscore}_sip_account_path" ).(@sip_account.sip_accountable, @sip_account) + add_breadcrumb t("phone_numbers.index.page_title"), sip_account_phone_numbers_path(@sip_account) + add_breadcrumb @phone_number, sip_account_phone_number_path(@sip_account, @phone_number) + add_breadcrumb t("ringtones.index.page_title"), phone_number_ringtones_path(@phone_number) + if @ringtone && !@ringtone.new_record? + add_breadcrumb @ringtone, phone_number_ringtone_path(@phone_number, @ringtone) + end + end + end + +end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb new file mode 100644 index 0000000..f92ae1c --- /dev/null +++ b/app/controllers/sessions_controller.rb @@ -0,0 +1,44 @@ +class SessionsController < ApplicationController + + before_filter :redirect_to_https + skip_before_filter :home_breadcrumb + + def new + end + + def create + user = User.find_by_email(params[:sessions][:login_data].downcase.strip) + if user.nil? + user = User.find_by_user_name(params[:sessions][:login_data].downcase.strip) + end + if user && user.authenticate(params[:sessions][:password]) + session[:user_id] = user.id + redirect_to tenant_user_path(user.current_tenant, user), :notice => t('sessions.controller.successfully_created', :resource => user) + elsif user && !user.email.blank? && params[:sessions][:reset_password] =~ (/(1|t|y|yes|true)$/i) + password = SecureRandom.base64(8)[0..7] + if user.update_attributes(:password => password) + Notifications.new_password(user, password).deliver + flash.now.notice = t('sessions.flash_messages.password_recovery_successful', :resource => user) + else + flash.now.alert = t('sessions.flash_messages.password_recovery_failed', :resource => user) + end + render "new" + else + flash.now.alert = t('sessions.flash_messages.invalid_email_or_password', :resource => user) + render "new" + end + end + + def destroy + session[:user_id] = nil + redirect_to root_url, :notice => t('sessions.controller.successfully_destroyed') + end + + private + def redirect_to_https + if GUI_REDIRECT_HTTPS and ! request.ssl? + redirect_to :protocol => "https://" + end + end + +end diff --git a/app/controllers/sip_accounts_controller.rb b/app/controllers/sip_accounts_controller.rb new file mode 100644 index 0000000..1f3166e --- /dev/null +++ b/app/controllers/sip_accounts_controller.rb @@ -0,0 +1,98 @@ +class SipAccountsController < ApplicationController + load_resource :user + load_resource :tenant + load_and_authorize_resource :sip_account, :through => [:user, :tenant ] + + before_filter :set_and_authorize_parent + before_filter :spread_breadcrumbs + + def index + end + + def show + end + + def new + @sip_account = @parent.sip_accounts.build + @sip_account.caller_name = @parent + @sip_account.call_waiting = CALL_WAITING + @sip_account.clir = DEFAULT_CLIR_SETTING + @sip_account.clip = DEFAULT_CLIP_SETTING + @sip_account.voicemail_pin = random_pin + @sip_account.callforward_rules_act_per_sip_account = CALLFORWARD_RULES_ACT_PER_SIP_ACCOUNT_DEFAULT + @sip_account.hotdeskable = true + + # Make sure that we don't use an already taken auth_name + # + loop do + @sip_account.auth_name = SecureRandom.hex(DEFAULT_LENGTH_SIP_AUTH_NAME) + + break unless SipAccount.exists?(:auth_name => @sip_account.auth_name) + end + @sip_account.password = SecureRandom.hex(DEFAULT_LENGTH_SIP_PASSWORD) + end + + def create + @sip_account = @parent.sip_accounts.build(params[:sip_account]) + + if @sip_account.auth_name.blank? + loop do + @sip_account.auth_name = SecureRandom.hex(DEFAULT_LENGTH_SIP_AUTH_NAME) + + break unless SipAccount.exists?(:auth_name => @sip_account.auth_name) + end + end + if @sip_account.password.blank? + @sip_account.password = SecureRandom.hex(DEFAULT_LENGTH_SIP_PASSWORD) + end + + if @sip_account.save + m = method( :"#{@parent.class.name.underscore}_sip_account_path" ) + redirect_to m.( @parent, @sip_account ), :notice => t('sip_accounts.controller.successfuly_created', :resource => @parent) + else + render :new + end + end + + def edit + end + + def update + if @sip_account.update_attributes(params[:sip_account]) + m = method( :"#{@parent.class.name.underscore}_sip_account_path" ) + redirect_to m.( @parent, @sip_account ), :notice => t('sip_accounts.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @sip_account.destroy + m = method( :"#{@parent.class.name.underscore}_sip_accounts_url" ) + redirect_to m.( @parent ), :notice => t('sip_accounts.controller.successfuly_destroyed') + end + + private + def set_and_authorize_parent + @parent = @user || @tenant + authorize! :read, @parent + end + + def spread_breadcrumbs + if @user + add_breadcrumb t("users.index.page_title"), tenant_users_path(@user.current_tenant) + add_breadcrumb @user, tenant_user_path(@user.current_tenant, @user) + add_breadcrumb t("sip_accounts.index.page_title"), user_sip_accounts_path(@user) + if @sip_account && !@sip_account.new_record? + add_breadcrumb @sip_account, user_sip_account_path(@user, @sip_account) + end + end + if @tenant + add_breadcrumb t("sip_accounts.index.page_title"), tenant_sip_accounts_path(@tenant) + if @sip_account && !@sip_account.new_record? + add_breadcrumb @sip_account, tenant_sip_account_path(@tenant, @sip_account) + end + end + end + +end diff --git a/app/controllers/sip_domains_controller.rb b/app/controllers/sip_domains_controller.rb new file mode 100644 index 0000000..7301192 --- /dev/null +++ b/app/controllers/sip_domains_controller.rb @@ -0,0 +1,41 @@ +class SipDomainsController < ApplicationController + def index + @sip_domains = SipDomain.all + end + + def show + @sip_domain = SipDomain.find(params[:id]) + end + + def new + @sip_domain = SipDomain.new + end + + def create + @sip_domain = SipDomain.new(params[:sip_domain]) + if @sip_domain.save + redirect_to @sip_domain, :notice => t('sip_domains.controller.successfuly_created') + else + render :new + end + end + + def edit + @sip_domain = SipDomain.find(params[:id]) + end + + def update + @sip_domain = SipDomain.find(params[:id]) + if @sip_domain.update_attributes(params[:sip_domain]) + redirect_to @sip_domain, :notice => t('sip_domains.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @sip_domain = SipDomain.find(params[:id]) + @sip_domain.destroy + redirect_to sip_domains_url, :notice => t('sip_domains.controller.successfuly_destroyed') + end +end diff --git a/app/controllers/softkeys_controller.rb b/app/controllers/softkeys_controller.rb new file mode 100644 index 0000000..d2a2bb9 --- /dev/null +++ b/app/controllers/softkeys_controller.rb @@ -0,0 +1,91 @@ +class SoftkeysController < ApplicationController + load_and_authorize_resource :sip_account + load_and_authorize_resource :softkey, :through => [:sip_account] + + before_filter :set_available_call_forwards_and_softkey_functions, :only => [ :new, :edit, :update ] + before_filter :spread_breadcrumbs + + def index + end + + def show + end + + def new + @softkey = @sip_account.softkeys.build + + delete_call_forward_softkey_if_no_callforward_is_available + end + + def create + @softkey = @sip_account.softkeys.build(params[:softkey]) + if @softkey.save + redirect_to sip_account_softkey_path(@softkey.sip_account, @softkey), :notice => t('softkeys.controller.successfuly_created') + else + render :new + end + end + + def edit + delete_call_forward_softkey_if_no_callforward_is_available + end + + def update + if @softkey.update_attributes(params[:softkey]) + redirect_to sip_account_softkey_path(@softkey.sip_account, @softkey), :notice => t('softkeys.controller.successfuly_updated') + else + delete_call_forward_softkey_if_no_callforward_is_available + render :edit + end + end + + def destroy + @softkey.destroy + redirect_to sip_account_softkeys_path(@softkey.sip_account), :notice => t('softkeys.controller.successfuly_destroyed') + end + + def move_higher + @softkey.move_higher + redirect_to :back + end + + def move_lower + @softkey.move_lower + redirect_to :back + end + + private + + def set_available_call_forwards_and_softkey_functions + @available_call_forwards = @softkey.possible_blf_call_forwards + + @softkey_functions = [] + SoftkeyFunction.accessible_by(current_ability, :read).each do |softkey_function| + if GuiFunction.display?("softkey_function_#{softkey_function.name.downcase}_field_in_softkey_form", @current_user) + @softkey_functions << softkey_function + end + end + end + + def spread_breadcrumbs + if @sip_account.sip_accountable.class == User + add_breadcrumb t('users.name'), tenant_users_path(@sip_account.sip_accountable.current_tenant) + add_breadcrumb @sip_account.sip_accountable, tenant_user_path(@sip_account.sip_accountable.current_tenant, @sip_account.sip_accountable) + add_breadcrumb t('sip_accounts.index.page_title'), user_sip_accounts_path(@sip_account.sip_accountable) + add_breadcrumb @sip_account, user_sip_account_path(@sip_account.sip_accountable, @sip_account) + add_breadcrumb t('softkeys.index.page_title'), sip_account_softkeys_path(@sip_account) + elsif @sip_account.sip_accountable.class == Tenant + add_breadcrumb t('sip_accounts.index.page_title'), tenant_sip_accounts_path(@sip_account.sip_accountable) + add_breadcrumb @sip_account, tenant_sip_account_path(@sip_account.sip_accountable, @sip_account) + add_breadcrumb t('softkeys.index.page_title'), sip_account_softkeys_path(@sip_account) + end + end + + def delete_call_forward_softkey_if_no_callforward_is_available + # Don't display the call_forward option if there aren't any call_forwards to choose from. + # + if @softkey.sip_account.phone_numbers.map{|phone_number| phone_number.call_forwards}.flatten.count == 0 + @softkey_functions.delete_if { |softkey_function| softkey_function == SoftkeyFunction.find_by_name('call_forwarding') } + end + end +end diff --git a/app/controllers/system_messages_controller.rb b/app/controllers/system_messages_controller.rb new file mode 100644 index 0000000..d7fe515 --- /dev/null +++ b/app/controllers/system_messages_controller.rb @@ -0,0 +1,30 @@ +class SystemMessagesController < ApplicationController + load_and_authorize_resource :user + load_and_authorize_resource :system_message, :through => [:user] + + def index + @system_messages = @system_messages.where(:created_at => Time.now - 6.hours .. Time.now) + end + + def show + end + + def new + @system_message = @user.system_messages.build + end + + def create + @system_message = @user.system_messages.build(params[:system_message]) + if @system_message.save + # Push the new message via AJAX to the browser. + # + # PrivatePub.publish_to("/users/#{@system_message.user.id}/system_messages", + # "$('#system_message').empty();$('#system_message').append('#{(I18n.l @system_message.created_at, :format => :short )} #{@system_message.content}');$('#system_message_display').fadeIn();" + # ) + + redirect_to user_system_message_path(@user, @system_message), :notice => t('system_messages.controller.successfuly_created') + else + render :new + end + end +end diff --git a/app/controllers/tenants_controller.rb b/app/controllers/tenants_controller.rb new file mode 100644 index 0000000..724d179 --- /dev/null +++ b/app/controllers/tenants_controller.rb @@ -0,0 +1,91 @@ +class TenantsController < ApplicationController + load_and_authorize_resource :tenant + + def index + end + + def show + end + + def new + @tenant.name = generate_a_new_name(@tenant) + @tenant.sip_domain = SipDomain.last + @tenant.country = GemeinschaftSetup.first.country + @tenant.language = GemeinschaftSetup.first.language + @tenant.internal_extension_ranges = '10-99' + @tenant.from_field_voicemail_email = 'admin@localhost' + @tenant.from_field_pin_change_email = 'admin@localhost' + end + + def create + if @tenant.save + # Become a member of this tenant. + # + @tenant.tenant_memberships.create(:user_id => @current_user.id) + + # Groups + # + admin_group = @tenant.user_groups.create(:name => t('gemeinschaft_setups.initial_setup.admin_group_name')) + admin_group.users << @current_user + + user_group = @tenant.user_groups.create(:name => t('gemeinschaft_setups.initial_setup.user_group_name')) + user_group.users << @current_user + + @current_user.update_attributes!(:current_tenant_id => @tenant.id) + + # Generate the internal_extensions + # + if !@tenant.internal_extension_ranges.blank? + if @tenant.array_of_internal_extension_numbers.count < 105 + # This can be done more or less quick. + @tenant.generate_internal_extensions + else + # Better be on the save side and start a delayed job for this. + @tenant.delay.generate_internal_extensions + end + end + + # Generate the external numbers (DIDs) + # + if !@tenant.did_list.blank? + if @tenant.array_of_dids.count < 105 + # This can be done more or less quick. + @tenant.generate_dids + else + # Better be on the save side and start a delayed job for this. + @tenant.delay.generate_dids + end + end + + if Delayed::Job.count > 0 + redirect_to @tenant, :notice => t('tenants.controller.successfuly_created_plus_delayed_jobs', + :resource => @tenant, + :amount_of_numbers => @tenant.array_of_internal_extension_numbers.count + @tenant.array_of_dids.count + ) + else + redirect_to @tenant, :notice => t('tenants.controller.successfuly_created', + :resource => @tenant + ) + end + else + render :new + end + end + + def edit + end + + def update + if @tenant.update_attributes(params[:tenant]) + redirect_to @tenant, :notice => t('tenants.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @tenant.destroy + redirect_to tenants_url, :notice => t('tenants.controller.successfuly_destroyed') + end + +end diff --git a/app/controllers/user_group_memberships_controller.rb b/app/controllers/user_group_memberships_controller.rb new file mode 100644 index 0000000..1cbbd48 --- /dev/null +++ b/app/controllers/user_group_memberships_controller.rb @@ -0,0 +1,48 @@ +class UserGroupMembershipsController < ApplicationController + load_and_authorize_resource :user_group + load_and_authorize_resource :user_group_membership, :through => [:user_group] + + before_filter :spread_breadcrumbs + + def index + @potential_users_count = @user_group.tenant.users.count - @user_group.users.count + end + + def show + end + + def new + @user_group_membership = @user_group.user_group_memberships.build + @potential_users = (@user_group.tenant.users.order(:last_name) - @user_group.users) + if @potential_users.count == 0 + redirect_to user_group_user_group_memberships_path(@user_group), :alert => t('user_group_memberships.controller.no_more_user_to_add') + end + end + + def create + @user_group_membership = @user_group.user_group_memberships.build(params[:user_group_membership]) + if @user_group_membership.save + redirect_to user_group_user_group_membership_path(@user_group, @user_group_membership), :notice => t('user_group_memberships.controller.successfuly_created') + else + render :new + end + end + + def destroy + @user_group_membership.destroy + redirect_to user_group_user_group_memberships_path(@user_group), :notice => t('user_group_memberships.controller.successfuly_destroyed') + end + + private + + def spread_breadcrumbs + add_breadcrumb t("user_groups.index.page_title"), tenant_user_groups_path(@user_group.tenant) + add_breadcrumb @user_group, tenant_user_group_path(@user_group.tenant, @user_group) + add_breadcrumb t("user_group_memberships.index.page_title"), user_group_user_group_memberships_path(@user_group) + + if @user_group_membership && !@user_group_membership.new_record? + add_breadcrumb @user_group_membership, user_group_user_group_membership_path(@user_group, @user_group_membership) + end + end + +end diff --git a/app/controllers/user_groups_controller.rb b/app/controllers/user_groups_controller.rb new file mode 100644 index 0000000..158abaa --- /dev/null +++ b/app/controllers/user_groups_controller.rb @@ -0,0 +1,69 @@ +class UserGroupsController < ApplicationController + load_resource :tenant + load_resource :user + load_and_authorize_resource :user_group, :through => [:tenant, :user] + + before_filter :set_and_authorize_parent + before_filter :spread_breadcrumbs + + def index + end + + def show + end + + def new + @user_group = @parent.user_groups.build + end + + def create + @user_group = @parent.user_groups.build(params[:user_group]) + if @user_group.save + redirect_to @user_group, :notice => t('user_groups.controller.successfuly_created') + else + render :new + end + end + + def edit + end + + def update + if @user_group.update_attributes(params[:user_group]) + redirect_to @user_group, :notice => t('user_groups.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @user_group.destroy + redirect_to user_groups_url, :notice => t('user_groups.controller.successfuly_destroyed') + end + + private + + def set_and_authorize_parent + @parent = @user || @tenant + authorize! :read, @parent + end + + def spread_breadcrumbs + if @tenant + add_breadcrumb t("user_groups.index.page_title"), tenant_user_groups_path(@tenant) + if @user_group && !@user_group.new_record? + add_breadcrumb @user_group, tenant_user_group_path(@tenant, @user_group) + end + end + + if @user + add_breadcrumb t("users.index.page_title"), tenant_users_path(@parent) + add_breadcrumb @user, tenant_user_path(@user.current_tenant, @user) + add_breadcrumb t("user_groups.index.page_title"), user_user_groups_path(@user) + if @user_group && !@user_group.new_record? + add_breadcrumb @user_group, user_user_group_path(@user, @user_group) + end + end + end + +end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 0000000..454c26b --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,85 @@ +class UsersController < ApplicationController + load_resource :tenant + load_resource :user_group + load_and_authorize_resource :user, :through => [:tenant, :user_group] + + before_filter :set_and_authorize_parent + before_filter :spread_breadcrumbs + + def index + end + + def show + @phone_books = PhoneBook.accessible_by( Ability.new( @user ) ).all + end + + def new + @user = @parent.users.build(params[:user]) + @user.male = true + @user.send_voicemail_as_email_attachment = true + end + + def create + @user = @parent.users.build(params[:user]) + if @user.save + if @parent.class == Tenant + @parent.tenant_memberships.create(:user => @user) + if @parent.user_groups.exists?(:name => 'Users') + @parent.user_groups.where(:name => 'Users').first.user_group_memberships.create(:user => @user) + end + redirect_to tenant_user_url( @parent, @user), :notice => t('users.controller.successfuly_created', :resource => @user) + else + redirect_to tenant_user_path(@user.current_tenant, @user), :notice => t('users.controller.successfuly_created_and_login', :resource => @user) + end + else + render :new + end + end + + def edit + end + + def update + if @user.update_attributes(params[:user]) + # Make sure that the flash notice gets rendered in the correct language. + I18n.locale = @user.language.code.downcase + + redirect_to tenant_user_path(@user.current_tenant, @user), :notice => t('users.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @user.destroy + redirect_to @parent, :notice => t('users.controller.successfuly_destroyed') + end + + def destroy_avatar + user = User.find(params[:user_id]) + user.remove_image = true # https://github.com/jnicklas/carrierwave/issues/360 + user.remove_image! + user.save + user.reload + user.image.remove! + user.save + redirect_to @parent, :notice => t('users.controller.avatar_destroyed') + end + + private + def set_and_authorize_parent + @parent = @tenant || @user_group + authorize! :read, @parent + end + + def spread_breadcrumbs + if @tenant + add_breadcrumb t("users.index.page_title"), tenant_users_path(@tenant) + + if @user && !@user.new_record? + add_breadcrumb @user, tenant_user_path(@tenant, @user) + end + end + end + +end diff --git a/app/controllers/voicemail_messages_controller.rb b/app/controllers/voicemail_messages_controller.rb new file mode 100644 index 0000000..58f5265 --- /dev/null +++ b/app/controllers/voicemail_messages_controller.rb @@ -0,0 +1,140 @@ +class VoicemailMessagesController < ApplicationController + + load_resource :sip_account + load_and_authorize_resource :voicemail_message, :through => [:sip_account] + + before_filter :set_and_authorize_parent + before_filter :spread_breadcrumbs + + before_filter { |controller| + if ! params[:type].blank? then + @type = params[:type].to_s + end + + if ! params[:page].blank? then + @pagination_page_number = params[:page].to_i + end + } + + def index + @messages_count = @sip_account.voicemail_messages.count + @messages_unread_count = @sip_account.voicemail_messages.where(:read_epoch => 0).count + @messages_read_count = @messages_count - @messages_unread_count + + if @type == 'read' + @voicemail_messages = @sip_account.voicemail_messages.where('read_epoch > 0').order('created_epoch DESC').paginate( + :page => @pagination_page_number, + :per_page => DEFAULT_PAGINATION_ENTRIES_PER_PAGE + ) + elsif @type == 'unread' + @voicemail_messages = @sip_account.voicemail_messages.where(:read_epoch => 0).order('created_epoch DESC').paginate( + :page => @pagination_page_number, + :per_page => DEFAULT_PAGINATION_ENTRIES_PER_PAGE + ) + else + @voicemail_messages = @sip_account.voicemail_messages.order('created_epoch DESC').paginate( + :page => @pagination_page_number, + :per_page => DEFAULT_PAGINATION_ENTRIES_PER_PAGE + ) + end + end + + def show + respond_to do |format| + format.wav { + if @voicemail_message.file_path + send_file @voicemail_message.file_path, :type => "audio/x-wav", + :filename => "#{Time.at(@voicemail_message.created_epoch).strftime('%Y%m%d-%H%M%S')}-#{@voicemail_message.cid_number}.wav" + else + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "", + ) + end + } + end + end + + def new + end + + def create + end + + def edit + end + + def update + end + + def destroy + @voicemail_message.destroy + m = method( :"#{@parent.class.name.underscore}_voicemail_messages_url" ) + redirect_to m.(), :notice => t('voicemail_messages.controller.successfuly_destroyed') + end + + def destroy_multiple + result = false + if ! params[:selected_uuids].blank? then + voicemail_messages = @sip_account.voicemail_messages.where(:uuid => params[:selected_uuids]) + voicemail_messages.each do |voicemail_message| + result = voicemail_message.destroy + end + end + + m = method( :"#{@parent.class.name.underscore}_voicemail_messages_url" ) + if result + redirect_to m.(), :notice => t('voicemail_messages.controller.successfuly_destroyed') + else + redirect_to m.() + end + end + + def call + phone_number = @voicemail_message.cid_number + if ! phone_number.blank? && @sip_account.registration + @sip_account.call(phone_number) + end + redirect_to(:back) + end + + def mark_read + @voicemail_message.mark_read + redirect_to(:back) + end + + def mark_unread + @voicemail_message.mark_read(false) + redirect_to(:back) + end + + private + def set_and_authorize_parent + @parent = @sip_account + + authorize! :read, @parent + + @show_path_method = method( :"#{@parent.class.name.underscore}_voicemail_message_path" ) + @index_path_method = method( :"#{@parent.class.name.underscore}_voicemail_messages_path" ) + @new_path_method = method( :"new_#{@parent.class.name.underscore}_voicemail_message_path" ) + @edit_path_method = method( :"edit_#{@parent.class.name.underscore}_voicemail_message_path" ) + end + + def spread_breadcrumbs + if @parent.class == SipAccount + if @sip_account.sip_accountable.class == User + add_breadcrumb t("#{@sip_account.sip_accountable.class.name.underscore.pluralize}.index.page_title"), method( :"tenant_#{@sip_account.sip_accountable.class.name.underscore.pluralize}_path" ).(@sip_account.tenant) + add_breadcrumb @sip_account.sip_accountable, method( :"tenant_#{@sip_account.sip_accountable.class.name.underscore}_path" ).(@sip_account.tenant, @sip_account.sip_accountable) + end + add_breadcrumb t("sip_accounts.index.page_title"), method( :"#{@sip_account.sip_accountable.class.name.underscore}_sip_accounts_path" ).(@sip_account.sip_accountable) + add_breadcrumb @sip_account, method( :"#{@sip_account.sip_accountable.class.name.underscore}_sip_account_path" ).(@sip_account.sip_accountable, @sip_account) + add_breadcrumb t("voicemail_messages.index.page_title"), sip_account_voicemail_messages_path(@sip_account) + if @voicemail_message && !@voicemail_message.new_record? + add_breadcrumb @voicemail_message, sip_account_voicemail_message_path(@sip_account, @voicemail_message) + end + end + end + +end diff --git a/app/controllers/voicemail_settings_controller.rb b/app/controllers/voicemail_settings_controller.rb new file mode 100644 index 0000000..d31de8f --- /dev/null +++ b/app/controllers/voicemail_settings_controller.rb @@ -0,0 +1,91 @@ +class VoicemailSettingsController < ApplicationController + load_resource :sip_account + load_and_authorize_resource :voicemail_setting, :through => :sip_account, :singleton => true + + before_filter :set_and_authorize_parent + before_filter :spread_breadcrumbs + before_filter :voicemail_defaults, :only => [:index, :show, :new, :create, :edit] + + def index + render :edit + end + + def show + render :edit + end + + def new + render :edit + end + + def create + @sip_account = SipAccount.where(:id => params[:sip_account_id]).first + params[:voicemail_setting][:username] = @sip_account.auth_name + params[:voicemail_setting][:domain] = @sip_account.sip_domain.try(:host) + @voicemail_setting = VoicemailSetting.new(params[:voicemail_setting]) + if @voicemail_setting.save + redirect_to sip_account_voicemail_settings_path(@sip_account), :notice => t('voicemail_settings.controller.successfuly_created') + else + render :action => 'edit' + end + end + + def edit + + end + + def update + if @voicemail_setting.update_attributes(params[:voicemail_setting]) + redirect_to sip_account_voicemail_settings_path(@sip_account), :notice => t('voicemail_settings.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + + end + + private + def set_and_authorize_parent + @parent = @sip_account + + authorize! :read, @parent + + @show_path_method = method( :"#{@parent.class.name.underscore}_voicemail_setting_path" ) + @index_path_method = method( :"#{@parent.class.name.underscore}_voicemail_settings_path" ) + @new_path_method = method( :"new_#{@parent.class.name.underscore}_voicemail_setting_path" ) + @edit_path_method = method( :"edit_#{@parent.class.name.underscore}_voicemail_setting_path" ) + end + + def spread_breadcrumbs + if @parent.class == SipAccount + if @sip_account.sip_accountable.class == User + add_breadcrumb t("#{@sip_account.sip_accountable.class.name.underscore.pluralize}.index.page_title"), method( :"tenant_#{@sip_account.sip_accountable.class.name.underscore.pluralize}_path" ).(@sip_account.tenant) + add_breadcrumb @sip_account.sip_accountable, method( :"tenant_#{@sip_account.sip_accountable.class.name.underscore}_path" ).(@sip_account.tenant, @sip_account.sip_accountable) + end + add_breadcrumb t("sip_accounts.index.page_title"), method( :"#{@sip_account.sip_accountable.class.name.underscore}_sip_accounts_path" ).(@sip_account.sip_accountable) + add_breadcrumb @sip_account, method( :"#{@sip_account.sip_accountable.class.name.underscore}_sip_account_path" ).(@sip_account.sip_accountable, @sip_account) + add_breadcrumb t("voicemail_settings.index.page_title"), sip_account_voicemail_settings_path(@sip_account) + end + end + + def voicemail_defaults + path = "/opt/freeswitch/storage/voicemail/default/#{@sip_account.sip_domain.host}/#{@sip_account.auth_name}/" + @greeting_files = Dir.glob("#{path}*greeting*.wav").collect {|r| [ File.basename(r), File.expand_path(r) ] } + @name_files = Dir.glob("#{path}*name*.wav").collect {|r| [ File.basename(r), File.expand_path(r) ] } + + if @voicemail_setting.blank? then + @voicemail_setting = @sip_account.voicemail_setting + end + + if @voicemail_setting.blank? + @voicemail_setting = VoicemailSetting.new + @voicemail_setting.notify = true + @voicemail_setting.attachment = true + @voicemail_setting.mark_read = true + @voicemail_setting.purge = false + end + end + +end diff --git a/app/controllers/whitelists_controller.rb b/app/controllers/whitelists_controller.rb new file mode 100644 index 0000000..0526844 --- /dev/null +++ b/app/controllers/whitelists_controller.rb @@ -0,0 +1,61 @@ +class WhitelistsController < ApplicationController + load_and_authorize_resource :callthrough + load_and_authorize_resource :whitelist, :through => [:callthrough] + + before_filter :set_parent_and_path_methods + before_filter :spread_breadcrumbs + + def index + end + + def show + end + + def new + @whitelist.phone_numbers.build + end + + def create + @whitelist = @parent.whitelists.build(params[:whitelist]) + if @whitelist.save + redirect_to @show_path_method.(@parent, @whitelist), :notice => t('whitelists.controller.successfuly_created') + else + render :new + end + end + + def edit + end + + def update + if @whitelist.update_attributes(params[:whitelist]) + redirect_to @show_path_method.(@parent, @whitelist), :notice => t('whitelists.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @whitelist.destroy + redirect_to @index_path_method.(@parent), :notice => t('whitelists.controller.successfuly_destroyed') + end + + private + + def set_parent_and_path_methods + @parent = @callthrough + @show_path_method = method( :"#{@parent.class.name.underscore}_whitelist_path" ) + @index_path_method = method( :"#{@parent.class.name.underscore}_whitelists_path" ) + @new_path_method = method( :"new_#{@parent.class.name.underscore}_whitelist_path" ) + @edit_path_method = method( :"edit_#{@parent.class.name.underscore}_whitelist_path" ) + end + + def spread_breadcrumbs + if @parent && @parent.class == Callthrough + add_breadcrumb t("#{@parent.class.name.underscore.pluralize}.name").pluralize, tenant_callthroughs_path(@parent.tenant) + add_breadcrumb @callthrough, tenant_callthrough_path(@parent.tenant, @callthrough) + add_breadcrumb t("whitelists.index.page_title"), callthrough_whitelists_path(@parent) + end + end + +end diff --git a/app/helpers/access_authorizations_helper.rb b/app/helpers/access_authorizations_helper.rb new file mode 100644 index 0000000..d16f5c6 --- /dev/null +++ b/app/helpers/access_authorizations_helper.rb @@ -0,0 +1,2 @@ +module AccessAuthorizationsHelper +end diff --git a/app/helpers/acd_agents_helper.rb b/app/helpers/acd_agents_helper.rb new file mode 100644 index 0000000..5be92a8 --- /dev/null +++ b/app/helpers/acd_agents_helper.rb @@ -0,0 +1,2 @@ +module AcdAgentsHelper +end diff --git a/app/helpers/acd_callers_helper.rb b/app/helpers/acd_callers_helper.rb new file mode 100644 index 0000000..534b99c --- /dev/null +++ b/app/helpers/acd_callers_helper.rb @@ -0,0 +1,2 @@ +module AcdCallersHelper +end diff --git a/app/helpers/addresses_helper.rb b/app/helpers/addresses_helper.rb new file mode 100644 index 0000000..5f4dc13 --- /dev/null +++ b/app/helpers/addresses_helper.rb @@ -0,0 +1,2 @@ +module AddressesHelper +end diff --git a/app/helpers/api/rows_helper.rb b/app/helpers/api/rows_helper.rb new file mode 100644 index 0000000..a18dab4 --- /dev/null +++ b/app/helpers/api/rows_helper.rb @@ -0,0 +1,2 @@ +module Api::RowsHelper +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb new file mode 100644 index 0000000..de6be79 --- /dev/null +++ b/app/helpers/application_helper.rb @@ -0,0 +1,2 @@ +module ApplicationHelper +end diff --git a/app/helpers/automatic_call_distributors_helper.rb b/app/helpers/automatic_call_distributors_helper.rb new file mode 100644 index 0000000..19a9828 --- /dev/null +++ b/app/helpers/automatic_call_distributors_helper.rb @@ -0,0 +1,2 @@ +module AutomaticCallDistributorsHelper +end diff --git a/app/helpers/call_forward_cases_helper.rb b/app/helpers/call_forward_cases_helper.rb new file mode 100644 index 0000000..63a4939 --- /dev/null +++ b/app/helpers/call_forward_cases_helper.rb @@ -0,0 +1,2 @@ +module CallForwardCasesHelper +end diff --git a/app/helpers/call_forwards_helper.rb b/app/helpers/call_forwards_helper.rb new file mode 100644 index 0000000..ffb6977 --- /dev/null +++ b/app/helpers/call_forwards_helper.rb @@ -0,0 +1,2 @@ +module CallForwardsHelper +end diff --git a/app/helpers/callthroughs_helper.rb b/app/helpers/callthroughs_helper.rb new file mode 100644 index 0000000..2ee0b9b --- /dev/null +++ b/app/helpers/callthroughs_helper.rb @@ -0,0 +1,2 @@ +module CallthroughsHelper +end diff --git a/app/helpers/conference_invitees_helper.rb b/app/helpers/conference_invitees_helper.rb new file mode 100644 index 0000000..dab6843 --- /dev/null +++ b/app/helpers/conference_invitees_helper.rb @@ -0,0 +1,2 @@ +module ConferenceInviteesHelper +end diff --git a/app/helpers/conferences_helper.rb b/app/helpers/conferences_helper.rb new file mode 100644 index 0000000..edfcfdd --- /dev/null +++ b/app/helpers/conferences_helper.rb @@ -0,0 +1,2 @@ +module ConferencesHelper +end diff --git a/app/helpers/config_siemens_helper.rb b/app/helpers/config_siemens_helper.rb new file mode 100644 index 0000000..7ff8c5b --- /dev/null +++ b/app/helpers/config_siemens_helper.rb @@ -0,0 +1,2 @@ +module ConfigSiemensHelper +end diff --git a/app/helpers/error_messages_helper.rb b/app/helpers/error_messages_helper.rb new file mode 100644 index 0000000..8e9c4d3 --- /dev/null +++ b/app/helpers/error_messages_helper.rb @@ -0,0 +1,23 @@ +module ErrorMessagesHelper + # Render error messages for the given objects. The :message and :header_message options are allowed. + def error_messages_for(*objects) + options = objects.extract_options! + options[:header_message] ||= I18n.t(:"activerecord.errors.header", :default => "Invalid Fields") + options[:message] ||= I18n.t(:"activerecord.errors.message", :default => "Correct the following errors and try again.") + messages = objects.compact.map { |o| o.errors.full_messages }.flatten + unless messages.empty? + content_tag(:div, :class => "error_messages") do + list_items = messages.map { |msg| content_tag(:li, msg.html_safe) } + content_tag(:h2, options[:header_message].html_safe) + content_tag(:p, options[:message].html_safe) + content_tag(:ul, list_items.join.html_safe) + end + end + end + + module FormBuilderAdditions + def error_messages(options = {}) + @template.error_messages_for(@object, options) + end + end +end + +ActionView::Helpers::FormBuilder.send(:include, ErrorMessagesHelper::FormBuilderAdditions) diff --git a/app/helpers/fax_accounts_helper.rb b/app/helpers/fax_accounts_helper.rb new file mode 100644 index 0000000..529c4fb --- /dev/null +++ b/app/helpers/fax_accounts_helper.rb @@ -0,0 +1,2 @@ +module FaxAccountsHelper +end diff --git a/app/helpers/fax_documents_helper.rb b/app/helpers/fax_documents_helper.rb new file mode 100644 index 0000000..c168948 --- /dev/null +++ b/app/helpers/fax_documents_helper.rb @@ -0,0 +1,2 @@ +module FaxDocumentsHelper +end diff --git a/app/helpers/gemeinschaft_setups_helper.rb b/app/helpers/gemeinschaft_setups_helper.rb new file mode 100644 index 0000000..f241900 --- /dev/null +++ b/app/helpers/gemeinschaft_setups_helper.rb @@ -0,0 +1,2 @@ +module GemeinschaftSetupsHelper +end diff --git a/app/helpers/gs_cluster_sync_log_entries_helper.rb b/app/helpers/gs_cluster_sync_log_entries_helper.rb new file mode 100644 index 0000000..9eef5de --- /dev/null +++ b/app/helpers/gs_cluster_sync_log_entries_helper.rb @@ -0,0 +1,2 @@ +module GsClusterSyncLogEntriesHelper +end diff --git a/app/helpers/gs_nodes_helper.rb b/app/helpers/gs_nodes_helper.rb new file mode 100644 index 0000000..9ba2a39 --- /dev/null +++ b/app/helpers/gs_nodes_helper.rb @@ -0,0 +1,2 @@ +module GsNodesHelper +end diff --git a/app/helpers/gui_functions_helper.rb b/app/helpers/gui_functions_helper.rb new file mode 100644 index 0000000..35324cd --- /dev/null +++ b/app/helpers/gui_functions_helper.rb @@ -0,0 +1,2 @@ +module GuiFunctionsHelper +end diff --git a/app/helpers/hunt_group_members_helper.rb b/app/helpers/hunt_group_members_helper.rb new file mode 100644 index 0000000..e198542 --- /dev/null +++ b/app/helpers/hunt_group_members_helper.rb @@ -0,0 +1,2 @@ +module HuntGroupMembersHelper +end diff --git a/app/helpers/hunt_groups_helper.rb b/app/helpers/hunt_groups_helper.rb new file mode 100644 index 0000000..d1b3b05 --- /dev/null +++ b/app/helpers/hunt_groups_helper.rb @@ -0,0 +1,2 @@ +module HuntGroupsHelper +end diff --git a/app/helpers/layout_helper.rb b/app/helpers/layout_helper.rb new file mode 100644 index 0000000..1dad619 --- /dev/null +++ b/app/helpers/layout_helper.rb @@ -0,0 +1,70 @@ +# These helper methods can be called in your template to set +# variables to be used in the layout. +# This module should be included in all views globally, +# to do so you may need to add this line to your +# ApplicationController +# helper :layout +# +module LayoutHelper + + def title( page_title, show_title = true ) + content_for(:title) { strip_tags(page_title.to_s) } + @show_title = show_title + end + + def show_title? + @show_title + end + + def stylesheet( *args ) + content_for(:head) { stylesheet_link_tag( *args ) } + end + + def javascript( *args ) + content_for(:head) { javascript_include_tag( *args ) } + end + + def translation_missing?( output ) + (output =~ /span/ or output.empty?) + end + + def conditional_hint( translation_key ) + output = t( translation_key ) + return output unless translation_missing?( output ) + false + end + + def conditional_t( translation_key ) + output = t( translation_key ) + strip_tags( output ) + end + + def resolve_flash_sign( type ) + return case type.to_s + when 'alert' ; '!' + when 'warning' ; '!' + else ; 'i' + end + end + + # Returns navigation as an array. + # + def navigation_items + unless @io + @io = [] + + if can?( :index, PhoneBookEntry ) + @io << { :url => phone_book_entries_path , :title => t('phone_book_entries.index.page_title' ) } + end + + # This could be a link to VoiceMails. + # + # if can?( :index, Object ) + # @io << { :url => "#" , :title => t('voice_mail') } + # end + + end + @io + end + +end diff --git a/app/helpers/manufacturers_helper.rb b/app/helpers/manufacturers_helper.rb new file mode 100644 index 0000000..3f9e083 --- /dev/null +++ b/app/helpers/manufacturers_helper.rb @@ -0,0 +1,2 @@ +module ManufacturersHelper +end diff --git a/app/helpers/page_helper.rb b/app/helpers/page_helper.rb new file mode 100644 index 0000000..625cfe4 --- /dev/null +++ b/app/helpers/page_helper.rb @@ -0,0 +1,2 @@ +module PageHelper +end diff --git a/app/helpers/phone_book_entries_helper.rb b/app/helpers/phone_book_entries_helper.rb new file mode 100644 index 0000000..db24cae --- /dev/null +++ b/app/helpers/phone_book_entries_helper.rb @@ -0,0 +1,2 @@ +module PhoneBookEntriesHelper +end diff --git a/app/helpers/phone_books_helper.rb b/app/helpers/phone_books_helper.rb new file mode 100644 index 0000000..55ebf19 --- /dev/null +++ b/app/helpers/phone_books_helper.rb @@ -0,0 +1,2 @@ +module PhoneBooksHelper +end diff --git a/app/helpers/phone_models_helper.rb b/app/helpers/phone_models_helper.rb new file mode 100644 index 0000000..2cc6545 --- /dev/null +++ b/app/helpers/phone_models_helper.rb @@ -0,0 +1,2 @@ +module PhoneModelsHelper +end diff --git a/app/helpers/phone_number_ranges_helper.rb b/app/helpers/phone_number_ranges_helper.rb new file mode 100644 index 0000000..f4d5897 --- /dev/null +++ b/app/helpers/phone_number_ranges_helper.rb @@ -0,0 +1,2 @@ +module PhoneNumberRangesHelper +end diff --git a/app/helpers/phone_numbers_helper.rb b/app/helpers/phone_numbers_helper.rb new file mode 100644 index 0000000..cb4f200 --- /dev/null +++ b/app/helpers/phone_numbers_helper.rb @@ -0,0 +1,2 @@ +module PhoneNumbersHelper +end diff --git a/app/helpers/phone_sip_accounts_helper.rb b/app/helpers/phone_sip_accounts_helper.rb new file mode 100644 index 0000000..f834d2c --- /dev/null +++ b/app/helpers/phone_sip_accounts_helper.rb @@ -0,0 +1,2 @@ +module PhoneSipAccountsHelper +end diff --git a/app/helpers/phones_helper.rb b/app/helpers/phones_helper.rb new file mode 100644 index 0000000..69ebd13 --- /dev/null +++ b/app/helpers/phones_helper.rb @@ -0,0 +1,2 @@ +module PhonesHelper +end diff --git a/app/helpers/phones_sip_accounts_helper.rb b/app/helpers/phones_sip_accounts_helper.rb new file mode 100644 index 0000000..03e3fd2 --- /dev/null +++ b/app/helpers/phones_sip_accounts_helper.rb @@ -0,0 +1,2 @@ +module PhonesSipAccountsHelper +end diff --git a/app/helpers/ringtones_helper.rb b/app/helpers/ringtones_helper.rb new file mode 100644 index 0000000..33deac9 --- /dev/null +++ b/app/helpers/ringtones_helper.rb @@ -0,0 +1,2 @@ +module RingtonesHelper +end diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb new file mode 100644 index 0000000..309f8b2 --- /dev/null +++ b/app/helpers/sessions_helper.rb @@ -0,0 +1,2 @@ +module SessionsHelper +end diff --git a/app/helpers/sip_accounts_helper.rb b/app/helpers/sip_accounts_helper.rb new file mode 100644 index 0000000..1e666fd --- /dev/null +++ b/app/helpers/sip_accounts_helper.rb @@ -0,0 +1,2 @@ +module SipAccountsHelper +end diff --git a/app/helpers/sip_domains_helper.rb b/app/helpers/sip_domains_helper.rb new file mode 100644 index 0000000..c1d85ee --- /dev/null +++ b/app/helpers/sip_domains_helper.rb @@ -0,0 +1,2 @@ +module SipDomainsHelper +end diff --git a/app/helpers/softkeys_helper.rb b/app/helpers/softkeys_helper.rb new file mode 100644 index 0000000..e551779 --- /dev/null +++ b/app/helpers/softkeys_helper.rb @@ -0,0 +1,2 @@ +module SoftkeysHelper +end diff --git a/app/helpers/system_messages_helper.rb b/app/helpers/system_messages_helper.rb new file mode 100644 index 0000000..fef2386 --- /dev/null +++ b/app/helpers/system_messages_helper.rb @@ -0,0 +1,2 @@ +module SystemMessagesHelper +end diff --git a/app/helpers/tenants_helper.rb b/app/helpers/tenants_helper.rb new file mode 100644 index 0000000..b7bb45d --- /dev/null +++ b/app/helpers/tenants_helper.rb @@ -0,0 +1,2 @@ +module TenantsHelper +end diff --git a/app/helpers/user_groups_helper.rb b/app/helpers/user_groups_helper.rb new file mode 100644 index 0000000..83cd8f3 --- /dev/null +++ b/app/helpers/user_groups_helper.rb @@ -0,0 +1,2 @@ +module UserGroupsHelper +end diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb new file mode 100644 index 0000000..2310a24 --- /dev/null +++ b/app/helpers/users_helper.rb @@ -0,0 +1,2 @@ +module UsersHelper +end diff --git a/app/helpers/whitelists_helper.rb b/app/helpers/whitelists_helper.rb new file mode 100644 index 0000000..083be60 --- /dev/null +++ b/app/helpers/whitelists_helper.rb @@ -0,0 +1,2 @@ +module WhitelistsHelper +end diff --git a/app/mailers/.gitkeep b/app/mailers/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/mailers/notifications.rb b/app/mailers/notifications.rb new file mode 100644 index 0000000..2c7f2ce --- /dev/null +++ b/app/mailers/notifications.rb @@ -0,0 +1,110 @@ +class Notifications < ActionMailer::Base + default from: "admin@example.com" + + # Subject can be set in your I18n file at config/locales/en.yml + # with the following lookup: + # + # en.notifications.new_pin.subject + # + def new_pin(conference) + @conference = conference + + @pin = Hash.new() + if conference.conferenceable_type == 'User' + user = conference.conferenceable + + if ! user.first_name.blank? + @pin[:greeting] = user.first_name + else + @pin[:greeting] = user.user_name + end + else + @pin[:greeting] = conference.conferenceable.to_s + end + + @pin[:conference] = conference.to_s + @pin[:pin] = conference.pin + @pin[:phone_numbers] = conference.phone_numbers.join(', ') + + mail(from: Tenant.find(DEFAULT_API_TENANT_ID).from_field_pin_change_email,to: "#{conference.conferenceable.email}", :subject => "Conference PIN changed: #{@pin[:conference]}") + end + + def new_password(user, password) + @password = password + + @message = Hash.new() + if ! user.first_name.blank? + @message[:greeting] = user.first_name + else + @message[:greeting] = user.user_name + end + + mail(from: Tenant.find(DEFAULT_API_TENANT_ID).from_field_pin_change_email, to: "#{user.email}", :subject => "Password recovery") + end + + def new_voicemail(freeswitch_voicemail_msg, attach_file = false) + sip_account = SipAccount.find_by_auth_name(freeswitch_voicemail_msg.username) + user = sip_account.sip_accountable + + @voicemail = Hash.new() + if ! user.first_name.blank? + @voicemail[:greeting] = user.first_name + else + @voicemail[:greeting] = user.user_name + end + + @voicemail[:destination] = freeswitch_voicemail_msg.in_folder + @voicemail[:from] = "#{freeswitch_voicemail_msg.cid_number} #{freeswitch_voicemail_msg.cid_name}" + @voicemail[:to] = sip_account.to_s + @voicemail[:date] = Time.at(freeswitch_voicemail_msg.created_epoch).getlocal.to_s + @voicemail[:duration] = Time.at(freeswitch_voicemail_msg.message_len).utc.strftime('%T') + + if attach_file + caller_number = freeswitch_voicemail_msg.cid_number.gsub(/[^0-9]/, '') + if caller_number.blank? + caller_number = 'anonymous' + end + attachments["#{Time.at(freeswitch_voicemail_msg.created_epoch).getlocal.strftime('%Y%m%d-%H%M%S')}-#{caller_number}.wav"] = File.read(freeswitch_voicemail_msg.file_path) + end + + mail(from: Tenant.find(DEFAULT_API_TENANT_ID).from_field_voicemail_email, to: "#{user.email}", :subject => "New Voicemail from #{@voicemail[:from]}, received #{Time.at(freeswitch_voicemail_msg.created_epoch).getlocal.to_s}") + end + + def new_fax(fax_document) + fax_account = fax_document.fax_account + + if !fax_account || fax_account.email.blank? + return false + end + + caller_number = fax_document.caller_id_number.gsub(/[^0-9]/, '') + if caller_number.blank? + caller_number = 'anonymous' + end + + @fax = { + :greeting => '', + :account_name => fax_account.name, + :from => "#{caller_number} #{fax_document.caller_id_name}", + :remote_station_id => fax_document.remote_station_id, + :local_station_id => fax_document.local_station_id, + :date => fax_document.created_at, + } + + if fax_account.fax_accountable + if fax_account.fax_accountable_type == 'User' + user = fax_account.fax_accountable + if ! user.first_name.blank? + @fax[:greeting] = user.first_name + else + @fax[:greeting] = user.user_name + end + elsif fax_account.fax_accountable_type == 'Tenant' + @fax[:greeting] = fax_account.fax_accountable.name + end + end + attachments["#{fax_document.created_at.strftime('%Y%m%d-%H%M%S')}-#{caller_number}.pdf"] = File.read(fax_document.document.path) + mail(from: Tenant.find(DEFAULT_API_TENANT_ID).from_field_voicemail_email, to: "#{fax_account.email}", :subject => "New Fax Document from #{@fax[:from]}, received #{fax_document.created_at}") + end + +end diff --git a/app/models/.gitkeep b/app/models/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/models/ability.rb b/app/models/ability.rb new file mode 100644 index 0000000..d9ec74a --- /dev/null +++ b/app/models/ability.rb @@ -0,0 +1,170 @@ +class Ability + include CanCan::Ability + + def initialize( user ) + # See the wiki for details: https://github.com/ryanb/cancan/wiki/Defining-Abilities + if user && user.current_tenant != nil + if GemeinschaftSetup.count == 1 && Tenant.count == 1 && User.count == 1 && UserGroup.count == 1 + # This is a new installation with a Master-Tenant and a Super-Admin. + # + can [:read, :create], Tenant + else + tenant = user.current_tenant + + if user.current_tenant.user_groups.where(:name => 'Admins').first \ + && user.current_tenant.user_groups.where(:name => 'Admins').first.users.include?(user) + # ADMIN ABILITIES + # With great power comes great responsibility! + # + can :manage, :all + + # Manufacturers and PhoneModels can not be changed + # + cannot [:create, :destroy, :edit, :update], Manufacturer + cannot [:create, :destroy, :edit, :update], PhoneModel + + # Super-Tenant can not be destroyed or edited + # + cannot [:create, :destroy, :edit, :update], Tenant, :id => 1 + + cannot :manage, PhoneBook + + # Phonebooks and PhoneBookEntries + # + can :manage, PhoneBook, :phone_bookable_type => 'Tenant', :phone_bookable_id => tenant.id + can :manage, PhoneBookEntry, :phone_book => { :phone_bookable_type => 'Tenant', :phone_bookable_id => tenant.id } + + can :manage, PhoneBook, :phone_bookable_type => 'UserGroup', :phone_bookable_id => tenant.user_group_ids + tenant.user_groups.each do |user_group| + can :manage, PhoneBookEntry, :phone_book => { :id => user_group.phone_book_ids } + end + + # Personal Phonebooks and PhoneBookEntries + # + can :manage, PhoneBook, :phone_bookable_type => 'User', :phone_bookable_id => user.id + can :manage, PhoneBookEntry, :phone_book => { :phone_bookable_type => 'User', :phone_bookable_id => user.id } + + can :read, PhoneBook, :phone_bookable_type => 'Tenant', :phone_bookable_id => tenant.id + can :read, PhoneBookEntry, :phone_book => { :phone_bookable_type => 'Tenant', :phone_bookable_id => tenant.id } + + can :read, PhoneBook, :phone_bookable_type => 'UserGroup', :phone_bookable_id => user.user_group_ids + user.user_groups.each do |user_group| + can :read, PhoneBookEntry, :phone_book => { :id => user_group.phone_book_ids } + end + + # SystemMessages + # + cannot [:destroy, :edit, :update], SystemMessage + + # A FacDocument can't be changed + # + cannot [:edit, :update], FaxDocument + + # Can manage GsNodes + # + can :manage, GsNode + + # Can't phones/1/phone_sip_accounts/1/edit + # + cannot :edit, PhoneSipAccount + + # Dirty hack to disable PhoneNumberRange in the GUI + # + if STRICT_INTERNAL_EXTENSION_HANDLING == false + cannot :manage, PhoneNumberRange + end + else + # Any user can do the following stuff. + # + + # Own Tenant and own User + # + can :read, Tenant, :id => user.current_tenant.id + can [ :read, :edit, :update ], User, :id => user.id + + # Destroy his own avatar + # + can :destroy_avatar, User, :id => user.id + + # Phonebooks and PhoneBookEntries + # + cannot :manage, PhoneBook + + can :manage, PhoneBook, :phone_bookable_type => 'User', :phone_bookable_id => user.id + can :manage, PhoneBookEntry, :phone_book => { :phone_bookable_type => 'User', :phone_bookable_id => user.id } + can :manage, PhoneNumber, :phone_numberable_type => 'PhoneBookEntry', :phone_numberable_id => user.phone_books.map{ |phone_book| phone_book.phone_book_entry_ids}.flatten + + can :read, PhoneBook, :phone_bookable_type => 'Tenant', :phone_bookable_id => tenant.id + can :read, PhoneBookEntry, :phone_book => { :phone_bookable_type => 'Tenant', :phone_bookable_id => tenant.id } + + can :read, PhoneBook, :phone_bookable_type => 'UserGroup', :phone_bookable_id => user.user_group_ids + user.user_groups.each do |user_group| + can :read, PhoneBookEntry, :phone_book => { :id => user_group.phone_book_ids } + end + + # UserGroups + # + can :read, UserGroupMembership, :user_id => user.id + can :read, UserGroup, :users => { :user_group_memberships => { :user_id => user.id }} + + # SipAccounts and Phones + # + can :read, SipAccount, :sip_accountable_type => 'User', :sip_accountable_id => user.id + user.sip_accounts.each do |sip_account| + can :read, PhoneNumber, :id => sip_account.phone_number_ids + can :manage, CallForward, :phone_number_id => sip_account.phone_number_ids + can :manage, Ringtone, :ringtoneable_type => 'PhoneNumber', :ringtoneable_id => sip_account.phone_number_ids + can [:read, :destroy, :call] , CallHistory, :id => sip_account.call_history_ids + end + can :read, Phone, :phoneable_type => 'User', :phoneable_id => user.id + + # Softkeys + # + can :manage, Softkey, :sip_account => { :id => user.sip_account_ids } + + # Fax + # + can :read, FaxAccount, :fax_accountable_type => 'User', :fax_accountable_id => user.id + user.fax_accounts.each do |fax_account| + can :read, PhoneNumber, :id => fax_account.phone_number_ids + can [:read, :create, :delete], FaxDocument, :fax_account_id => fax_account.id + end + + # Conferences + # + can [ :read, :edit, :update, :destroy ], Conference, :id => user.conference_ids + user.conferences.each do |conference| + can :read, PhoneNumber, :id => conference.phone_number_ids + can :manage, ConferenceInvitee, :conference_id => conference.id + end + + # User can manage CallForwards of the PhoneNumbers of his + # own SipAccounts: + # + can :manage, CallForward, :phone_number_id => user.phone_number_ids + + # SystemMessages + # + can :read, SystemMessage, :user_id => user.id + + # SoftkeyFunctions + # + can :read, SoftkeyFunction + + # Voicemail + # + can :manage, VoicemailMessage + can :manage, VoicemailSetting + end + end + else + if GemeinschaftSetup.count == 0 && Tenant.count == 0 && User.count == 0 + # This is a fresh system. + # + can :create, GemeinschaftSetup + can :manage, SipDomain + end + end + + end +end diff --git a/app/models/access_authorization.rb b/app/models/access_authorization.rb new file mode 100644 index 0000000..ef33115 --- /dev/null +++ b/app/models/access_authorization.rb @@ -0,0 +1,41 @@ +class AccessAuthorization < ActiveRecord::Base + attr_accessible :name, :login, :pin, :phone_numbers_attributes, :sip_account_id + + belongs_to :access_authorizationable, :polymorphic => true + + validates_uniqueness_of :name, :scope => [ :access_authorizationable_type, :access_authorizationable_id ], + :allow_nil => true, :allow_blank => true + + # The login is optional. But if set has to be done with digits only. + # + validates_format_of :login, :with => /\A([0-9]+)\Z/, + :allow_nil => true, :allow_blank => true, + :message => "must be numeric." + + # The PIN is optional. But when set it has to be a proper PIN. + # + validates_format_of :pin, :with => /\A([0-9]+)\Z/, + :allow_nil => true, :allow_blank => true, + :message => "must be numeric." + + validates_length_of :pin, :minimum => MINIMUM_PIN_LENGTH, :maximum => MAXIMUM_PIN_LENGTH, + :allow_nil => true, :allow_blank => true + + has_many :phone_numbers, :as => :phone_numberable, :dependent => :destroy + accepts_nested_attributes_for :phone_numbers, + :reject_if => lambda { |phone_number| phone_number[:number].blank? }, + :allow_destroy => true + + # Optional SIP account. + # + belongs_to :sip_account + + validates_presence_of :sip_account, :if => Proc.new{ |access_authorization| !access_authorization.sip_account_id.blank? }, + :message => 'Given SIP account does not exist.' + + acts_as_list :scope => [ :access_authorizationable_type, :access_authorizationable_id ] + + def to_s + self.name || I18n.t('access_authorizations.name') + ' ID ' + self.id.to_s + end +end diff --git a/app/models/acd_agent.rb b/app/models/acd_agent.rb new file mode 100644 index 0000000..a00ac4b --- /dev/null +++ b/app/models/acd_agent.rb @@ -0,0 +1,39 @@ +class AcdAgent < ActiveRecord::Base + DESTINATION_TYPES = ['SipAccount'] + STATUSES = ['active', 'inactive'] + + attr_accessible :uuid, :name, :status, :automatic_call_distributor_id, :last_call, :calls_answered, :destination_type, :destination_id + + belongs_to :automatic_call_distributor + + belongs_to :destination, :polymorphic => true + + after_save :set_presence + + def to_s + self.name || I18n.t('acd_agents.name') + ' ID ' + self.id.to_s + end + + private + def set_presence + dialplan_function = nil + + state = 'early' + if self.status == 'active' + state = 'confirmed' + elsif self.status == 'inactive' + state = 'terminated' + end + + require 'freeswitch_event' + event = FreeswitchEvent.new("PRESENCE_IN") + event.add_header("proto", "sip") + event.add_header("from", "f-acdmtg-#{self.id}@#{SipDomain.first.host}") + event.add_header("event_type", "presence") + event.add_header("alt_event_type", "dialog") + event.add_header("presence-call-direction", "outbound") + event.add_header("answer-state", state) + event.add_header("unique-id", "acd_agent_#{self.id}") + return event.fire() + end +end diff --git a/app/models/acd_caller.rb b/app/models/acd_caller.rb new file mode 100644 index 0000000..1be48b9 --- /dev/null +++ b/app/models/acd_caller.rb @@ -0,0 +1,6 @@ +class AcdCaller < ActiveRecord::Base + attr_accessible :channel_uuid, :automatic_call_distributor_id, :status, :enter_time, :agent_answer_time, :callback_number, :callback_attempts + + has_one :channel, :class_name => 'FreeswitchChannel', :foreign_key => 'uuid', :primary_key => 'channel_uuid' + belongs_to :automatic_call_distributor +end diff --git a/app/models/address.rb b/app/models/address.rb new file mode 100644 index 0000000..bcf3474 --- /dev/null +++ b/app/models/address.rb @@ -0,0 +1,8 @@ +class Address < ActiveRecord::Base + attr_accessible :phone_book_entry_id, :line1, :line2, :street, :zip_code, :city, :country_id, :position, :uuid + + belongs_to :country + + validates_presence_of :uuid + validates_uniqueness_of :uuid +end diff --git a/app/models/api.rb b/app/models/api.rb new file mode 100644 index 0000000..557d875 --- /dev/null +++ b/app/models/api.rb @@ -0,0 +1,5 @@ +module Api + def self.table_name_prefix + 'api_' + end +end diff --git a/app/models/api/row.rb b/app/models/api/row.rb new file mode 100644 index 0000000..ac35516 --- /dev/null +++ b/app/models/api/row.rb @@ -0,0 +1,152 @@ +class Api::Row < ActiveRecord::Base + + # This is the place to do some basic mapping. + # + alias_attribute :UserName, :user_name + alias_attribute :LastName, :last_name + alias_attribute :FirstName, :first_name + alias_attribute :PhoneOffice, :office_phone_number + alias_attribute :VoipNr, :internal_extension + alias_attribute :CellPhone, :mobile_phone_number + alias_attribute :Fax, :fax_phone_number + alias_attribute :Email, :email + alias_attribute :PIN, :pin + alias_attribute :PIN_LastUpdate, :pin_updated_at + alias_attribute :Photo, :photo_file_name + + belongs_to :user + + # Validations + # + validates_presence_of :user_name + validates_uniqueness_of :user_name + + after_destroy :destroy_user + + def to_s + self.user_name + end + + def create_a_new_gemeinschaft_user + tenant = Tenant.find(DEFAULT_API_TENANT_ID) + + # Find or create the user + # + if tenant.users.where(:user_name => self.user_name).count > 0 + user = tenant.users.where(:user_name => self.user_name).first + else + user = tenant.users.create( + :user_name => self.user_name, + :last_name => self.last_name, + :first_name => self.first_name, + :middle_name => self.middle_name, + :email => self.email, + :new_pin => self.pin, + :new_pin_confirmation => self.pin, + :password => self.pin, + :password_confirmation => self.pin, + :language_id => tenant.language_id, + ) + end + + self.update_attributes({:user_id => user.id}) + + # Find or create a sip_account + # + if user.sip_accounts.count > 0 + sip_account = user.sip_accounts.first + else + sip_account = user.sip_accounts.create( + :caller_name => self.user.to_s, + :voicemail_pin => self.pin, + ) + end + + # Create phone_numbers to this sip_account (BTW: phone_numbers are unqiue) + # + sip_account.phone_numbers.create(:number => self.internal_extension) + sip_account.phone_numbers.create(:number => self.office_phone_number) + + + # Find or create a fax account + # + if user.fax_accounts.count > 0 + fax_account = user.fax_accounts.first + else + fax_account = user.fax_accounts.create( + :name => 'Default Fax', + :station_id => user.to_s, + :email => self.email, + :days_till_auto_delete => 90, + :retries => 3, + ) + end + + # Create phone_numbers to this fax_account + # + fax_account.phone_numbers.create(:number => self.fax_phone_number) + + end + + def destroy_user + self.user.destroy + end + + def update_user_data + user = self.user + user.update_attributes( + :user_name => self.user_name, + :last_name => self.last_name, + :first_name => self.first_name, + :middle_name => self.middle_name, + :email => self.email, + :new_pin => self.pin, + :new_pin_confirmation => self.pin, + :password => self.pin, + :password_confirmation => self.pin, + ) + + # Find or create a sip_account + # + if user.sip_accounts.count > 0 + sip_account = user.sip_accounts.first + else + sip_account = user.sip_accounts.create( + :caller_name => self.user.to_s, + :voicemail_pin => self.pin, + ) + end + + # Delete old phone_numbers + # + sip_account.phone_numbers.destroy_all + + # Create phone_numbers to this sip_account (BTW: phone_numbers are unqiue) + # + sip_account.phone_numbers.create(:number => self.internal_extension) + sip_account.phone_numbers.create(:number => self.office_phone_number) + + # Find or create a fax account + # + if user.fax_accounts.count > 0 + fax_account = user.fax_accounts.first + else + fax_account = user.fax_accounts.create( + :name => 'Default Fax', + :station_id => user.to_s, + :email => self.email, + :days_till_auto_delete => 90, + :retries => 3, + ) + end + + # Delete old phone_number + # + fax_account.phone_numbers.destroy_all + + # Create phone_numbers to this fax_account + # + fax_account.phone_numbers.create(:number => self.fax_phone_number) + end + +end diff --git a/app/models/area_code.rb b/app/models/area_code.rb new file mode 100644 index 0000000..6a9d946 --- /dev/null +++ b/app/models/area_code.rb @@ -0,0 +1,22 @@ +class AreaCode < ActiveRecord::Base + + # Associations: + # + belongs_to :country + + # Validations: + # + validates_presence_of :country + validates_presence_of :name + validates_presence_of :area_code + + validates_uniqueness_of :area_code, :scope => [ :country_id, :central_office_code ] + + + def to_s + "#{self.name} (#{self.area_code}" + + (self.central_office_code.blank? ? '' : "-#{self.central_office_code}") + + ')' + end + +end diff --git a/app/models/automatic_call_distributor.rb b/app/models/automatic_call_distributor.rb new file mode 100644 index 0000000..678e0eb --- /dev/null +++ b/app/models/automatic_call_distributor.rb @@ -0,0 +1,21 @@ +class AutomaticCallDistributor < ActiveRecord::Base + attr_accessible :uuid, :name, :strategy, :automatic_call_distributorable_type, :automatic_call_distributorable_id, :max_callers, :agent_timeout, :retry_timeout, :join, :leave, :gs_node_id, :announce_position, :announce_call_agents, :greeting, :goodbye, :music + + belongs_to :automatic_call_distributorable, :polymorphic => true + + has_many :acd_agents, :dependent => :destroy + has_many :phone_numbers, :as => :phone_numberable, :dependent => :destroy + accepts_nested_attributes_for :phone_numbers, + :reject_if => lambda { |phone_number| phone_number[:number].blank? }, + :allow_destroy => true + + validates_presence_of :strategy + + STRATEGIES = ['ring_all', 'round_robin'] + JOIN_ON = ['agents_available', 'agents_active', 'always'] + LEAVE_ON = ['no_agents_available_timeout', 'no_agents_active_timeout', 'no_agents_available', 'no_agents_active', 'timeout', 'never'] + + def to_s + self.name + end +end diff --git a/app/models/call.rb b/app/models/call.rb new file mode 100644 index 0000000..57961ec --- /dev/null +++ b/app/models/call.rb @@ -0,0 +1,36 @@ +class Call < ActiveRecord::Base + self.table_name = 'channels' + self.primary_key = 'uuid' + + # Makes sure that this is a readonly model. + def readonly? + return true + end + + # Prevent objects from being destroyed + def before_destroy + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def self.delete_all + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def delete + raise ActiveRecord::ReadOnlyRecord + end + + def sip_account + auth_name = self.name.match('^.+[/:](.+)@.+$') + if auth_name && ! auth_name[1].blank? + return SipAccount.where(:auth_name => auth_name[1]).first + end + end + + def kill + require 'freeswitch_event' + return FreeswitchAPI.execute('uuid_kill', self.uuid, true); + end +end diff --git a/app/models/call_forward.rb b/app/models/call_forward.rb new file mode 100644 index 0000000..0018cfb --- /dev/null +++ b/app/models/call_forward.rb @@ -0,0 +1,262 @@ +class CallForward < ActiveRecord::Base + + attr_accessor :to_voicemail, :hunt_group_id + + attr_accessible :phone_number_id, :call_forward_case_id, :timeout, + :destination, :source, :depth, :active, :to_voicemail, + :hunt_group_id, + :call_forwardable_type, :call_forwardable_id, + :call_forwarding_destination, :position, :uuid + + belongs_to :phone_number + belongs_to :call_forwardable, :polymorphic => true + has_many :softkeys + + acts_as_list :scope => [ :phone_number_id, :call_forward_case_id ] + + validates_presence_of :phone_number + validates_presence_of :call_forward_case_id + validates_presence_of :destination, :if => Proc.new { |cf| cf.call_forwardable_type.to_s.downcase == 'phonenumber' || cf.call_forwardable_type.blank? } + + validates_inclusion_of :destination, + :in => [ nil, '' ], + :if => Proc.new { |cf| cf.to_voicemail == true } + + belongs_to :call_forward_case + + validates_presence_of :depth + validates_numericality_of :depth, + :only_integer => true, + :greater_than_or_equal_to => 1, + :less_than_or_equal_to => MAX_CALL_FORWARD_DEPTH + + before_validation { + self.timeout = nil if self.call_forward_case_id != 3 + } + + validates_numericality_of :timeout, + :if => Proc.new { |cf| cf.call_forward_case_id == 3 }, + :only_integer => true, + :greater_than_or_equal_to => 1, + :less_than_or_equal_to => 120 + + validates_inclusion_of :timeout, + :in => [ nil ], + :if => Proc.new { |cf| cf.call_forward_case_id != 3 } + + validate :validate_empty_hunt_group, :if => Proc.new { |cf| cf.active == true && cf.call_forwardable_type == 'HuntGroup' && cf.call_forward_case.value == 'assistant' } + + validates_presence_of :uuid + validates_uniqueness_of :uuid + + # Make sure the call forward's parent can't be changed: + before_validation { |cfwd| + if cfwd.id \ + && cfwd.phone_number_id != cfwd.phone_number_id_was + errors.add( :phone_number_id, "cannot be changed." ) + end + } + + #before_validation :set_call_forwardable + before_save :split_and_format_destination_numbers + after_save :set_presence + after_save :work_through_callforward_rules_act_per_sip_account + after_save :deactivate_concurring_entries, :if => Proc.new { |cf| cf.active == true } + before_destroy :check_if_other_callforward_rules_have_to_be_destroyed + before_destroy :deactivate_connected_softkeys + + def case_string + return self.call_forward_case ? self.call_forward_case.value : nil + end + + def to_s + if self.call_forwardable_type.blank? + self.call_forwardable_type = '' + else + call_forwardable_type = " #{self.call_forwardable_type}" + end + if self.call_forwardable + destination = "#{self.call_forwardable}#{call_forwardable_type}" + else + destination = "#{self.destination}#{call_forwardable_type}" + end + "#{self.phone_number} (#{I18n.t("call_forward_cases.#{self.call_forward_case}")}) -> #{destination}" + end + + def set_this_callforward_rule_to_all_phone_numbers_of_the_parent_sip_account + # This is to make sure that no recursion kicks in. + # + if ! self.phone_number.phone_numberable.respond_to? :callforward_rules_act_per_sip_account + return false + end + + old_value_of_callforward_rules_act_per_sip_account = self.phone_number.phone_numberable.callforward_rules_act_per_sip_account + self.phone_number.phone_numberable.update_attributes({:callforward_rules_act_per_sip_account => false}) + + attributes_of_this_call_forward = self.attributes.delete_if {|key, value| ['id','updated_at','created_at','phone_number_id','call_forward_case_id', 'uuid'].include?(key)} + phone_numbers = self.phone_number.phone_numberable.phone_numbers.where('id != ?', self.phone_number.id) + + phone_numbers.each do |phone_number| + # Problem + call_forward = phone_number.call_forwards.find_or_create_by_call_forward_case_id_and_position(self.call_forward_case_id, self.position, attributes_of_this_call_forward) + call_forward.update_attributes(attributes_of_this_call_forward) + end + + self.phone_number.phone_numberable.update_attributes({:callforward_rules_act_per_sip_account => old_value_of_callforward_rules_act_per_sip_account}) + end + + def destroy_all_similar_callforward_rules_of_the_parent_sip_account + # This is to make sure that no recursion kicks in. + # + if ! self.phone_number.phone_numberable.respond_to? :callforward_rules_act_per_sip_account + return false + end + + old_value_of_callforward_rules_act_per_sip_account = self.phone_number.phone_numberable.callforward_rules_act_per_sip_account + self.phone_number.phone_numberable.update_attributes({:callforward_rules_act_per_sip_account => false}) + + phone_numbers_of_parent_sip_account = self.phone_number.phone_numberable.phone_numbers.where('id != ?', self.phone_number.id) + + phone_numbers_of_parent_sip_account.each do |phone_number| + if self.call_forwardable_type != 'Voicemail' + phone_number.call_forwards.where(:call_forward_case_id => self.call_forward_case_id, :destination => self.destination).destroy_all + else + phone_number.call_forwards.where(:call_forward_case_id => self.call_forward_case_id, :call_forwardable_type => self.call_forwardable_type).destroy_all + end + end + + self.phone_number.phone_numberable.update_attributes({:callforward_rules_act_per_sip_account => old_value_of_callforward_rules_act_per_sip_account}) + end + + def call_forwarding_destination + "#{self.call_forwardable_id}:#{self.call_forwardable_type}" + end + + def call_forwarding_destination=(destination_record) + self.call_forwardable_id, delimeter, self.call_forwardable_type = destination_record.to_s.partition(':') + end + + def toggle + self.active = ! self.active + return self.save + end + + def deactivate_connected_softkeys + softkey_function_deactivated = SoftkeyFunction.find_by_name('deactivated') + self.softkeys.each do |softkey| + if softkey.softkey_function_id != softkey_function_deactivated.id + softkey.update_attributes(:call_forward_id => nil, :softkey_function_id => softkey_function_deactivated.id) + end + end + end + + private + def split_and_format_destination_numbers + if !self.destination.blank? + destinations = self.destination.gsub(/[^+0-9\,]/,'').gsub(/[\,]+/,',').split(/\,/).delete_if{|x| x.blank?} + self.destination = nil + if destinations.count > 0 + destinations.each do |single_destination| + self.destination = self.destination.to_s + ", #{PhoneNumber.parse_and_format(single_destination)}" + end + end + self.destination = self.destination.to_s.gsub(/[^+0-9\,]/,'').gsub(/[\,]+/,',').split(/\,/).sort.delete_if{|x| x.blank?}.join(', ') + end + end + + def set_presence + state = 'terminated' + + if self.active + if self.call_forwardable_type and self.call_forwardable_type.downcase() == 'voicemail' + state = 'early' + else + state = 'confirmed' + end + end + + return send_presence_event(state) + + #if self.call_forward_case_id_changed? + # call_forwarding_service = CallForwardCase.where(:id => self.call_forward_case_id_was).first + # if call_forwarding_service + # send_presence_event(call_forwarding_service.value, state) + # end + #end + + #return send_presence_event(self.call_forward_case.value, state) + end + + def set_call_forwardable + if @hunt_group_id && HuntGroup.where(:id => @hunt_group_id.to_i).count > 0 + self.call_forwardable = HuntGroup.where(:id => @hunt_group_id.to_i).first + end + + if @to_voicemail && @to_voicemail.first.downcase == 'true' + self.call_forwardable_type = 'Voicemail' + self.call_forwardable_id = nil + end + end + + def work_through_callforward_rules_act_per_sip_account + if ! self.phone_number.phone_numberable.respond_to? :callforward_rules_act_per_sip_account + return false + end + + if self.phone_number.phone_numberable.callforward_rules_act_per_sip_account == true + self.set_this_callforward_rule_to_all_phone_numbers_of_the_parent_sip_account + end + end + + def check_if_other_callforward_rules_have_to_be_destroyed + if ! self.phone_number.phone_numberable.respond_to? :callforward_rules_act_per_sip_account + return false + end + + if self.phone_number.phone_numberable.callforward_rules_act_per_sip_account == true + self.destroy_all_similar_callforward_rules_of_the_parent_sip_account + end + end + + def send_presence_event(state, call_forwarding_service = nil) + dialplan_function = "cftg-#{self.id}" + unique_id = "call_forwarding_#{self.id}" + + if call_forwarding_service == 'always' + dialplan_function = "cfutg-#{self.phone_number.id}" + unique_id = "call_forwarding_number_#{self.phone_number.id}" + elsif call_forwarding_service == 'assistant' + dialplan_function = "cfatg-#{self.phone_number.id}" + unique_id = "call_forwarding_number_#{self.phone_number.id}" + end + + if dialplan_function + require 'freeswitch_event' + event = FreeswitchEvent.new("PRESENCE_IN") + event.add_header("proto", "sip") + event.add_header("from", "f-#{dialplan_function}@#{SipDomain.first.host}") + event.add_header("event_type", "presence") + event.add_header("alt_event_type", "dialog") + event.add_header("presence-call-direction", "outbound") + event.add_header("answer-state", state) + event.add_header("unique-id", unique_id) + return event.fire() + end + end + + def deactivate_concurring_entries + CallForward.where(:phone_number_id => self.phone_number_id, :call_forward_case_id => self.call_forward_case_id, :active => true).each do |call_forwarding_entry| + if call_forwarding_entry.id != self.id + call_forwarding_entry.update_attributes(:active => false) + end + end + end + + def validate_empty_hunt_group + hunt_group = self.call_forwardable + if hunt_group && hunt_group.hunt_group_members.where(:active => true).count == 0 + errors.add(:call_forwarding_destination, 'HuntGroup has no active members') + end + end + +end diff --git a/app/models/call_forward_case.rb b/app/models/call_forward_case.rb new file mode 100644 index 0000000..a0b872b --- /dev/null +++ b/app/models/call_forward_case.rb @@ -0,0 +1,13 @@ +class CallForwardCase < ActiveRecord::Base + + attr_accessible :value + + has_many :call_forwards + + validates_presence_of :value + + def to_s + self.value + end + +end diff --git a/app/models/call_history.rb b/app/models/call_history.rb new file mode 100644 index 0000000..4db056a --- /dev/null +++ b/app/models/call_history.rb @@ -0,0 +1,199 @@ +class CallHistory < ActiveRecord::Base + belongs_to :call_historyable, :polymorphic => true + belongs_to :caller_account, :polymorphic => true + belongs_to :callee_account, :polymorphic => true + belongs_to :auth_account, :polymorphic => true + + def display_number + if self.entry_type == 'dialed' + return self.destination_number.to_s + else + return self.caller_id_number.to_s + end + end + + def display_name + if self.entry_type == 'dialed' + begin + account = self.callee_account + rescue + account = nil + end + name_str = self.callee_id_name + else + begin + account = self.caller_account + rescue + account = nil + end + name_str = self.caller_id_name + end + + if name_str.blank? + if account.class == SipAccount + return account.caller_name.to_s + elsif account + return account.to_s + end + else + return name_str.to_s + end + end + + def display_auth_account_name + begin + account = self.auth_account + rescue + return nil + end + + if account.class == SipAccount + return account.caller_name.to_s + elsif account + return account.to_s + end + end + + def display_image(image_size = :mini, phone_book_entry) + if phone_book_entry + image = phone_book_entry.image_url(image_size) + if ! image.blank? + return image + end + end + + begin + if self.entry_type == 'dialed' + account = self.callee_account + else + account = self.caller_account + end + rescue + return nil + end + + if account.class == SipAccount && account.sip_accountable.class == User + return account.sip_accountable.image_url(image_size).to_s + end + end + + def display_call_date(date_format, date_today_format) + if self.start_stamp.strftime('%Y%m%d') == DateTime::now.strftime('%Y%m%d') + return self.start_stamp.strftime(date_today_format) + end + return self.start_stamp.strftime(date_format) + end + + def display_duration + if self.duration.to_i > 0 + minutes = (self.duration / 1.minutes).to_i + seconds = self.duration - minutes.minutes.seconds + return '%i:%02i' % [minutes, seconds] + end + end + + def phone_book_entry_by_number(number) + begin + call_historyable = self.call_historyable + rescue + return nil + end + + if ! call_historyable + return nil + end + + if call_historyable.class == SipAccount + owner = call_historyable.sip_accountable + end + + if owner.class == User + phone_books = owner.phone_books.all + phone_books.concat(owner.current_tenant.phone_books.all) + elsif owner.class == Tenant + phone_books = owner.phone_books.all + end + + if ! phone_books + return nil + end + + phone_books.each do |phone_book| + phone_book_entry = phone_book.find_entry_by_number(number) + if phone_book_entry + return phone_book_entry + end + end + + return nil + + end + + def voicemail_message + begin + return self.call_historyable.voicemail_messages.where(:forwarded_by => self.caller_channel_uuid).first + rescue + return nil + end + end + + def call_historyable_uuid + begin + return self.call_historyable.uuid + rescue + return nil + end + end + + def call_historyable_uuid=(uuid) + begin + return self.call_historyable_id = self.call_historyable_type.constantize.where(:uuid => uuid).first.id + rescue + end + end + + def caller_account_uuid + begin + return self.caller_account.uuid + rescue + return nil + end + end + + def caller_account_uuid=(uuid) + begin + return self.caller_account_id = self.caller_account_type.constantize.where(:uuid => uuid).first.id + rescue + end + end + + def callee_account_uuid + begin + return self.callee_account.uuid + rescue + return nil + end + end + + def callee_account_uuid=(uuid) + begin + return self.callee_account_id = self.callee_account_type.constantize.where(:uuid => uuid).first.id + rescue + end + end + + def auth_account_uuid + begin + return self.auth_account.uuid + rescue + return nil + end + end + + def auth_account_uuid=(uuid) + begin + return self.auth_account_id = self.auth_account_type.constantize.where(:uuid => uuid).first.id + rescue + end + end +end diff --git a/app/models/callthrough.rb b/app/models/callthrough.rb new file mode 100644 index 0000000..c057fa6 --- /dev/null +++ b/app/models/callthrough.rb @@ -0,0 +1,60 @@ +class Callthrough < ActiveRecord::Base + attr_accessible :name, :clip_no_screening, + :phone_numbers_attributes, :access_authorizations_attributes, + :whitelists_attributes + + # Validations and Associations + # + belongs_to :tenant + + validates_presence_of :tenant_id + validates_presence_of :tenant + + # These are the phone_numbers for this callthrough. + # One has to dial this number to access the callthrough. + # + has_many :phone_numbers, :as => :phone_numberable, :dependent => :destroy + + accepts_nested_attributes_for :phone_numbers, + :reject_if => lambda { |phone_number| phone_number[:number].blank? }, + :allow_destroy => true + + validate :requires_at_least_one_phone_number + + # These are the access authorizations for this callthrough. + # One has to be known by his phone number or by a login/pin or even both. + # + has_many :access_authorizations, :as => :access_authorizationable, :dependent => :destroy + + accepts_nested_attributes_for :access_authorizations, + :reject_if => lambda { |access_authorization| access_authorization[:login].blank? && access_authorization[:pin].blank? && access_authorization[:phone_numbers_attributes]['0'][:number].blank? }, + :allow_destroy => true + + has_many :access_authorization_phone_numbers, :source => :phone_numbers, + :through => :access_authorizations, :readonly => true + + # These are the whitelists of the phone numbers which can be called through this callthrough. + # + has_many :whitelists, :as => :whitelistable, :dependent => :destroy + + accepts_nested_attributes_for :whitelists, + :reject_if => lambda { |whitelist| whitelist[:phone_numbers_attributes]['0']['number'].blank? }, + :allow_destroy => true + + has_many :whitelisted_phone_numbers, :source => :phone_numbers, + :through => :whitelists, :readonly => true + + # Delegations: + # + delegate :sip_domain, :to => :tenant, :allow_nil => true + + def to_s + self.name || I18n.t('callthroughs.name') + ' ID ' + self.id + end + + + private + def requires_at_least_one_phone_number + errors.add(:base, "You must provide at least one phone number") if !self.phone_numbers.map{|phone_number| phone_number.valid?}.include?(true) + end +end diff --git a/app/models/conference.rb b/app/models/conference.rb new file mode 100644 index 0000000..8be9f21 --- /dev/null +++ b/app/models/conference.rb @@ -0,0 +1,63 @@ +class Conference < ActiveRecord::Base + attr_accessible :name, :start, :end, :description, :pin, + :open_for_anybody, :max_members, :announce_new_member_by_name, + :announce_left_member_by_name + + belongs_to :conferenceable, :polymorphic => true + has_many :conference_invitees, :dependent => :destroy + has_many :phone_numbers, :as => :phone_numberable, :dependent => :destroy + + validates_presence_of :conferenceable_type, :conferenceable_id + validates_presence_of :conferenceable + validates_presence_of :name + validates_presence_of :start, :if => Proc.new { |conference| !conference.end.blank? } + validates_presence_of :end, :if => Proc.new { |conference| !conference.start.blank? } + validates_presence_of :max_members + validates_numericality_of :max_members, :only_integer => true, + :greater_than => 0, + :less_than => (MAXIMUM_NUMBER_OF_PEOPLE_IN_A_CONFERENCE + 1), + :allow_nil => false, + :allow_blank => false + + validates_inclusion_of :open_for_anybody, :in => [true, false] + + validates_numericality_of :pin, :only_integer => true, + :greater_than => 0, + :allow_nil => true, + :allow_blank => true + validates_length_of :pin, :minimum => MINIMUM_PIN_LENGTH, + :allow_nil => true, + :allow_blank => true + + validate :start_and_end_dates_must_make_sense, :if => Proc.new { |conference| !conference.start.blank? && !conference.end.blank? } + + after_save :send_pin_email_when_pin_has_changed + + default_scope where(:state => 'active').order(:start) + + # State Machine stuff + state_machine :initial => :active do + end + + def sip_domain + self.conferenceable.try(:sip_domain) + end + + def to_s + name + end + + private + + def start_and_end_dates_must_make_sense + errors.add(:start, 'must be in the future') if self.start < Time.now - 10.minutes + errors.add(:end, 'must be later than the start') if self.end < self.start + end + + def send_pin_email_when_pin_has_changed + if self.conferenceable.class == User && self.pin_changed? + Notifications.new_pin(self).deliver + end + end + +end diff --git a/app/models/conference_invitee.rb b/app/models/conference_invitee.rb new file mode 100644 index 0000000..7de20de --- /dev/null +++ b/app/models/conference_invitee.rb @@ -0,0 +1,39 @@ +class ConferenceInvitee < ActiveRecord::Base + attr_accessible :pin, :speaker, :moderator, :phone_number, :phone_number_attributes + + belongs_to :conference + belongs_to :phone_book_entry + has_one :phone_number, :as => :phone_numberable, :dependent => :destroy + accepts_nested_attributes_for :phone_number + + validates_presence_of :conference_id + validates_presence_of :conference + validates_presence_of :phone_number + validates_numericality_of :pin, :only_integer => true, + :greater_than => 0, + :allow_nil => true, + :allow_blank => true + validates_length_of :pin, :minimum => MINIMUM_PIN_LENGTH, + :allow_nil => true, + :allow_blank => true + + validates_inclusion_of :speaker, :in => [true, false] + validates_inclusion_of :moderator, :in => [true, false] + + validate :uniqueness_of_phone_number_in_the_parent_conference + validates_uniqueness_of :phone_book_entry_id, :scope => :conference_id, :allow_nil => true + + def to_s + "ID #{self.id}" + end + + private + + def uniqueness_of_phone_number_in_the_parent_conference + if self.conference.conference_invitees.where('id != ?', self.id).count > 0 && + self.conference.conference_invitees.where('id != ?', self.id).map{|x| x.phone_number.number}. + include?(self.phone_number.number) + errors.add(:base, 'Phone number is not unique within the conference.') + end + end +end diff --git a/app/models/country.rb b/app/models/country.rb new file mode 100644 index 0000000..018e348 --- /dev/null +++ b/app/models/country.rb @@ -0,0 +1,21 @@ +class Country < ActiveRecord::Base + + has_many :area_codes, :dependent => :destroy + has_many :tenants + has_many :phone_number_ranges, :as => :phone_number_rangeable, :dependent => :destroy + + validates_presence_of :name + validates_presence_of :country_code + validates_presence_of :international_call_prefix + + validates_numericality_of :country_code, + :only_integer => true + + validates_uniqueness_of :name, :scope => [ :country_code ], + :case_sensitive => false + + def to_s + self.name + end + +end diff --git a/app/models/dial_in_number_store.rb b/app/models/dial_in_number_store.rb new file mode 100644 index 0000000..17c2202 --- /dev/null +++ b/app/models/dial_in_number_store.rb @@ -0,0 +1,16 @@ +class DialInNumberStore < ActiveRecord::Base + # Associations and Validations + # + validates_presence_of :dial_in_number_storeable_type + validates_presence_of :dial_in_number_storeable_id + + belongs_to :dial_in_number_storeable, :polymorphic => true + + validates_presence_of :dial_in_number_storeable + + has_many :phone_numbers, :as => :phone_numberable, :dependent => :destroy + + # Delegations: + # + delegate :tenant, :to => :dial_in_number_storeable, :allow_nil => true +end diff --git a/app/models/fax_account.rb b/app/models/fax_account.rb new file mode 100644 index 0000000..683447a --- /dev/null +++ b/app/models/fax_account.rb @@ -0,0 +1,77 @@ +# encoding: UTF-8 + +class FaxAccount < ActiveRecord::Base + attr_accessible :name, :email, :station_id, :days_till_auto_delete, :phone_numbers_attributes, :retries + + # Validations: + # + validates_presence_of :fax_accountable_type, :fax_accountable_id + validates_presence_of :fax_accountable + validates_presence_of :name + validates_presence_of :tenant_id + validates_presence_of :tenant + + validates_numericality_of :days_till_auto_delete, :allow_nil => true + validates_numericality_of :retries, :only_integer => true, :greater_than_or_equal_to => 0 + + validates_uniqueness_of :name, :scope => [:fax_accountable_type, :fax_accountable_id] + + # Associations: + # + has_many :phone_numbers, :as => :phone_numberable, :dependent => :destroy + has_many :fax_documents, :dependent => :destroy + + belongs_to :fax_accountable, :polymorphic => true + belongs_to :tenant + + accepts_nested_attributes_for :phone_numbers + + # Hooks + # + before_validation :find_and_set_tenant_id + before_validation :convert_umlauts + + def to_s + name + end + + private + def require_at_least_one_phone_number + if self.phone_numbers.count < 1 + errors.add(:base, 'needs at least one valid phone number') + end + end + + def find_and_set_tenant_id + if self.new_record? and self.tenant_id != nil + return + else + tenant = case self.fax_accountable_type + when 'UserGroup' ; fax_accountable.tenant + when 'User' ; fax_accountable.current_tenant || fax_accountable.tenants.last + else nil + end + self.tenant_id = tenant.id if tenant != nil + end + end + + def convert_umlauts + self.name = self.name.sub(/ä/,'ae'). + sub(/Ä/,'Ae'). + sub(/ü/,'ue'). + sub(/Ü/,'Ue'). + sub(/ö/,'oe'). + sub(/Ö/,'Oe'). + sub(/ß/,'ss') + self.name = self.name.gsub(/[^a-zA-Z0-9\-\,\:\.\+ ]/,'_') + self.station_id = self.station_id.sub(/ä/,'ae'). + sub(/Ä/,'Ae'). + sub(/ü/,'ue'). + sub(/Ü/,'Ue'). + sub(/ö/,'oe'). + sub(/Ö/,'Oe'). + sub(/ß/,'ss') + self.station_id = self.station_id.gsub(/[^a-zA-Z0-9\-\,\:\.\+ ]/,'_') + end + +end diff --git a/app/models/fax_document.rb b/app/models/fax_document.rb new file mode 100644 index 0000000..67bdea9 --- /dev/null +++ b/app/models/fax_document.rb @@ -0,0 +1,82 @@ +class FaxDocument < ActiveRecord::Base +# attr_accessible :inbound, :transmission_time, :sent_at, :document_total_pages, :document_transferred_pages, :ecm_requested, :ecm_used, :image_resolution, :image_size, :local_station_id, :result_code, :result_text, :remote_station_id, :success, :transfer_rate, :t38_gateway_format, :t38_peer, :document + + mount_uploader :document, DocumentUploader + mount_uploader :tiff, TiffUploader + + validates_presence_of :document + validates_numericality_of :retry_counter, :only_integer => true, :greater_than_or_equal_to => 0 + + belongs_to :fax_account + belongs_to :fax_resolution + + validates_presence_of :fax_resolution_id + validates_presence_of :fax_resolution + + has_one :destination_phone_number, :class_name => 'PhoneNumber', :as => :phone_numberable, :dependent => :destroy + accepts_nested_attributes_for :destination_phone_number + + has_many :fax_thumbnails, :order => :position, :dependent => :destroy + + after_create :render_thumbnails + after_create :convert_pdf_to_tiff + + # Scopes + scope :inbound, where(:state => 'inbound') + scope :outbound, where(:state => ['queued_for_sending','sending','successful','unsuccessful']) + + # State Machine stuff + state_machine :initial => :new do + event :queue_for_sending do + transition [:new] => :queued_for_sending + end + + event :send_now do + transition [:queued_for_sending] => :sending + end + + event :cancel do + transition [:sending, :queued_for_sending] => :unsuccessful + end + + event :successful_sent do + transition [:sending, :queued_for_sending] => :successful + end + + event :mark_as_inbound do + transition [:new] => :inbound + end + end + + def to_s + name + end + + private + def render_thumbnails + directory = "/tmp/GS-#{GEMEINSCHAFT_VERSION}/fax_thumbnails/#{self.id}" + system('mkdir -p ' + directory) + system("cd #{directory} && convert #{Rails.root.to_s}/public#{self.document.to_s}[0-100] -colorspace Gray PNG:'fax_page.png'") + number_of_thumbnails = Dir["#{directory}/fax_page-*.png"].count + (0..(number_of_thumbnails-1)).each do |i| + fax_thumbnail = self.fax_thumbnails.build + fax_thumbnail.thumbnail = File.open("#{directory}/fax_page-#{i}.png") + fax_thumbnail.save! + end + system("rm -rf #{directory}") + self.update_attributes(:document_total_pages => number_of_thumbnails) if self.document_total_pages.nil? + end + + def convert_pdf_to_tiff + page_size_a4 = '595 842' + page_size_command = "<< /Policies << /PageSize 3 >> /InputAttributes currentpagedevice /InputAttributes get dup { pop 1 index exch undef } forall dup 0 << /PageSize [ #{page_size_a4} ] >> put >> setpagedevice" + directory = "/tmp/GS-#{GEMEINSCHAFT_VERSION}/faxes/#{self.id}" + system('mkdir -p ' + directory) + tiff_file_name = File.basename(self.document.to_s.downcase, ".pdf") + '.tiff' + system "cd #{directory} && gs -q -r#{self.fax_resolution.resolution_value} -dNOPAUSE -dBATCH -dSAFER -sDEVICE=tiffg3 -sOutputFile=\"#{tiff_file_name}\" -c \"#{page_size_command}\" -- \"#{Rails.root.to_s}/public#{self.document.to_s}\"" + self.tiff = File.open("#{directory}/#{tiff_file_name}") + self.save + system("rm -rf #{directory}") + end + +end diff --git a/app/models/fax_resolution.rb b/app/models/fax_resolution.rb new file mode 100644 index 0000000..c9093fb --- /dev/null +++ b/app/models/fax_resolution.rb @@ -0,0 +1,15 @@ +class FaxResolution < ActiveRecord::Base + validates_presence_of :name + validates_presence_of :resolution_value + + validates_uniqueness_of :name + validates_uniqueness_of :resolution_value + + has_many :fax_documents, :dependent => :destroy + + acts_as_list + + def to_s + self.name + end +end diff --git a/app/models/fax_thumbnail.rb b/app/models/fax_thumbnail.rb new file mode 100644 index 0000000..a29c9ad --- /dev/null +++ b/app/models/fax_thumbnail.rb @@ -0,0 +1,8 @@ +class FaxThumbnail < ActiveRecord::Base + mount_uploader :thumbnail, ThumbnailUploader + validates_presence_of :thumbnail + + belongs_to :fax_document + + acts_as_list :scope => :fax_document +end diff --git a/app/models/freeswitch_alias.rb b/app/models/freeswitch_alias.rb new file mode 100644 index 0000000..9953edb --- /dev/null +++ b/app/models/freeswitch_alias.rb @@ -0,0 +1,23 @@ +class FreeswitchAlias < ActiveRecord::Base + self.table_name = 'aliases' + + # Makes sure that this is a readonly model. + def readonly? + return true + end + + # Prevent objects from being destroyed + def before_destroy + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def self.delete_all + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def delete + raise ActiveRecord::ReadOnlyRecord + end +end diff --git a/app/models/freeswitch_call.rb b/app/models/freeswitch_call.rb new file mode 100644 index 0000000..95b2cdd --- /dev/null +++ b/app/models/freeswitch_call.rb @@ -0,0 +1,24 @@ +class FreeswitchCall < ActiveRecord::Base + self.table_name = 'calls' + self.primary_key = 'call_uuid' + + # Makes sure that this is a readonly model. + def readonly? + return true + end + + # Prevent objects from being destroyed + def before_destroy + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def self.delete_all + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def delete + raise ActiveRecord::ReadOnlyRecord + end +end diff --git a/app/models/freeswitch_cdr.rb b/app/models/freeswitch_cdr.rb new file mode 100644 index 0000000..fd0eb75 --- /dev/null +++ b/app/models/freeswitch_cdr.rb @@ -0,0 +1,4 @@ +class FreeswitchCdr < ActiveRecord::Base + self.table_name = 'cdrs' + self.primary_key = 'uuid' +end diff --git a/app/models/freeswitch_channel.rb b/app/models/freeswitch_channel.rb new file mode 100644 index 0000000..489e17d --- /dev/null +++ b/app/models/freeswitch_channel.rb @@ -0,0 +1,24 @@ +class FreeswitchChannel < ActiveRecord::Base + self.table_name = 'channels' + self.primary_key = 'uuid' + + # Makes sure that this is a readonly model. + def readonly? + return true + end + + # Prevent objects from being destroyed + def before_destroy + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def self.delete_all + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def delete + raise ActiveRecord::ReadOnlyRecord + end +end diff --git a/app/models/freeswitch_complete.rb b/app/models/freeswitch_complete.rb new file mode 100644 index 0000000..e7ff465 --- /dev/null +++ b/app/models/freeswitch_complete.rb @@ -0,0 +1,23 @@ +class FreeswitchComplete < ActiveRecord::Base + self.table_name = 'complete' + + # Makes sure that this is a readonly model. + def readonly? + return true + end + + # Prevent objects from being destroyed + def before_destroy + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def self.delete_all + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def delete + raise ActiveRecord::ReadOnlyRecord + end +end diff --git a/app/models/freeswitch_fifo_bridge.rb b/app/models/freeswitch_fifo_bridge.rb new file mode 100644 index 0000000..06167f3 --- /dev/null +++ b/app/models/freeswitch_fifo_bridge.rb @@ -0,0 +1,23 @@ +class FreeswitchFifoBridge < ActiveRecord::Base + self.table_name = 'fifo_bridge' + + # Makes sure that this is a readonly model. + def readonly? + return true + end + + # Prevent objects from being destroyed + def before_destroy + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def self.delete_all + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def delete + raise ActiveRecord::ReadOnlyRecord + end +end diff --git a/app/models/freeswitch_fifo_caller.rb b/app/models/freeswitch_fifo_caller.rb new file mode 100644 index 0000000..50c1fb5 --- /dev/null +++ b/app/models/freeswitch_fifo_caller.rb @@ -0,0 +1,23 @@ +class FreeswitchFifoCaller < ActiveRecord::Base + self.table_name = 'fifo_callers' + + # Makes sure that this is a readonly model. + def readonly? + return true + end + + # Prevent objects from being destroyed + def before_destroy + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def self.delete_all + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def delete + raise ActiveRecord::ReadOnlyRecord + end +end diff --git a/app/models/freeswitch_fifo_outbound.rb b/app/models/freeswitch_fifo_outbound.rb new file mode 100644 index 0000000..029c21d --- /dev/null +++ b/app/models/freeswitch_fifo_outbound.rb @@ -0,0 +1,23 @@ +class FreeswitchFifoOutbound < ActiveRecord::Base + self.table_name = 'fifo_outbound' + + # Makes sure that this is a readonly model. + def readonly? + return true + end + + # Prevent objects from being destroyed + def before_destroy + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def self.delete_all + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def delete + raise ActiveRecord::ReadOnlyRecord + end +end diff --git a/app/models/freeswitch_interface.rb b/app/models/freeswitch_interface.rb new file mode 100644 index 0000000..1602d62 --- /dev/null +++ b/app/models/freeswitch_interface.rb @@ -0,0 +1,23 @@ +class FreeswitchInterface < ActiveRecord::Base + self.table_name = 'interfaces' + + # Makes sure that this is a readonly model. + def readonly? + return true + end + + # Prevent objects from being destroyed + def before_destroy + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def self.delete_all + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def delete + raise ActiveRecord::ReadOnlyRecord + end +end diff --git a/app/models/freeswitch_nat.rb b/app/models/freeswitch_nat.rb new file mode 100644 index 0000000..8baf2bf --- /dev/null +++ b/app/models/freeswitch_nat.rb @@ -0,0 +1,23 @@ +class FreeswitchNat < ActiveRecord::Base + self.table_name = 'nat' + + # Makes sure that this is a readonly model. + def readonly? + return true + end + + # Prevent objects from being destroyed + def before_destroy + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def self.delete_all + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def delete + raise ActiveRecord::ReadOnlyRecord + end +end diff --git a/app/models/freeswitch_registration.rb b/app/models/freeswitch_registration.rb new file mode 100644 index 0000000..7e80815 --- /dev/null +++ b/app/models/freeswitch_registration.rb @@ -0,0 +1,23 @@ +class FreeswitchRegistration < ActiveRecord::Base + self.table_name = 'registrations' + + # Makes sure that this is a readonly model. + def readonly? + return true + end + + # Prevent objects from being destroyed + def before_destroy + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def self.delete_all + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def delete + raise ActiveRecord::ReadOnlyRecord + end +end diff --git a/app/models/freeswitch_task.rb b/app/models/freeswitch_task.rb new file mode 100644 index 0000000..6e964d2 --- /dev/null +++ b/app/models/freeswitch_task.rb @@ -0,0 +1,23 @@ +class FreeswitchTask < ActiveRecord::Base + self.table_name = 'tasks' + + # Makes sure that this is a readonly model. + def readonly? + return true + end + + # Prevent objects from being destroyed + def before_destroy + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def self.delete_all + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def delete + raise ActiveRecord::ReadOnlyRecord + end +end diff --git a/app/models/freeswitch_voicemail_pref.rb b/app/models/freeswitch_voicemail_pref.rb new file mode 100644 index 0000000..b2400e8 --- /dev/null +++ b/app/models/freeswitch_voicemail_pref.rb @@ -0,0 +1,23 @@ +class FreeswitchVoicemailPref < ActiveRecord::Base + self.table_name = 'voicemail_prefs' + + # Makes sure that this is a readonly model. + def readonly? + return true + end + + # Prevent objects from being destroyed + def before_destroy + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def self.delete_all + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def delete + raise ActiveRecord::ReadOnlyRecord + end +end diff --git a/app/models/gemeinschaft_setup.rb b/app/models/gemeinschaft_setup.rb new file mode 100644 index 0000000..b445b21 --- /dev/null +++ b/app/models/gemeinschaft_setup.rb @@ -0,0 +1,8 @@ +class GemeinschaftSetup < ActiveRecord::Base + belongs_to :user + accepts_nested_attributes_for :user + belongs_to :sip_domain + accepts_nested_attributes_for :sip_domain + belongs_to :country + belongs_to :language +end diff --git a/app/models/gs_cluster_sync_log_entry.rb b/app/models/gs_cluster_sync_log_entry.rb new file mode 100644 index 0000000..063ff23 --- /dev/null +++ b/app/models/gs_cluster_sync_log_entry.rb @@ -0,0 +1,99 @@ +class GsClusterSyncLogEntry < ActiveRecord::Base + attr_accessible :gs_node_id, :class_name, :action, :content, :status, :history, + :homebase_ip_address, :waiting_to_be_synced, :association_method, + :association_uuid + + validates :class_name, + :presence => true + + validates :action, + :presence => true + + validates :content, + :presence => true + + after_create :apply_to_local_database + + def apply_to_local_database + if self.homebase_ip_address != HOMEBASE_IP_ADDRESS + if self.class_name.constantize.new.attribute_names.include?('is_native') + case self.action + when 'create' + new_local_copy = self.class_name.constantize.new( + JSON(self.content). + delete_if{|key, value| ['id','updated_at','created_at']. + include?(key) }, + :without_protection => true) + new_local_copy.is_native = false + find_and_connect_to_an_association(new_local_copy) + if new_local_copy.save(:validate => false) + logger.info "Created local copy of #{self.class_name} with the ID #{new_local_copy.id}. #{new_local_copy.to_s}" + else + logger.error "Couldn't create a local copy of #{self.class_name} with the ID #{new_local_copy.id}. #{new_local_copy.errors.to_yaml}" + end + + when 'update' + local_copy = find_local_copy + if local_copy + # Only update an object if the update it self is newer than the local object. + # + if local_copy.updated_at < JSON(self.content)['updated_at'].to_time + local_copy.update_attributes(JSON(self.content).delete_if{|key, value| ['id','updated_at','created_at'].include?(key) }, :without_protection => true) + find_and_connect_to_an_association(local_copy) + if local_copy.save(:validate => false) + logger.info "Updated local copy of #{self.class_name} with the ID #{local_copy.id}. #{local_copy.to_s}" + else + logger.error "Couldn't update local copy of #{self.class_name} with the ID #{local_copy.id}. #{local_copy.errors.to_yaml}" + end + else + logger.error "Didn't update local copy of #{self.class_name} with the ID #{local_copy.id} because of a race condition (the local version was newer than the update). Please check GsClusterSyncLogEntry ID #{self.id}." + end + else + logger.error "Couldn't find local copy of #{self.class_name}. #{self.content}" + end + + when 'destroy' + local_copy = find_local_copy + if local_copy + local_copy.destroy + logger.info "Destroyed local copy of #{self.class_name} with the ID #{local_copy.id}. #{local_copy.to_s}" + else + logger.error "Couldn't find local copy of #{self.class_name}. #{self.content}" + end + end + else + logger.error "The class #{self.class_name} doesn't offer the attribute is_native. Can't synchronize without." + end + end + end + + def find_local_copy + self.class_name.constantize.find_by_uuid(JSON(self.content)['uuid']) + end + + # Connect to the association (e.g. User to a SipAccount) + # + def find_and_connect_to_an_association(local_copy) + if !(self.association_method.blank? || self.association_uuid.blank?) && (self.association_method_changed? || self.association_uuid_changed?) + name_of_the_association_type = local_copy.attribute_names.delete_if{|x| !x.include?('_type')}.first + association = local_copy.send(name_of_the_association_type).constantize.where(:uuid => self.association_uuid).first + if association + local_copy.send "#{association_method}=", association + end + end + end + + def populate_other_cluster_nodes + if self.homebase_ip_address == HOMEBASE_IP_ADDRESS && self.waiting_to_be_synced == true + if GsNode.where(:push_updates_to => true).count > 0 + GsNode.where(:push_updates_to => true).each do |gs_node| + RemoteGsNode::GsClusterSyncLogEntry.site = gs_node.site + remote_enty = RemoteGsNode::GsClusterSyncLogEntry.create(self.attributes.delete_if{|key, value| ['id','updated_at','created_at'].include?(key) }) + self.update_attributes(:waiting_to_be_synced => false) + self.save + end + end + end + end + +end diff --git a/app/models/gs_node.rb b/app/models/gs_node.rb new file mode 100644 index 0000000..229ceb2 --- /dev/null +++ b/app/models/gs_node.rb @@ -0,0 +1,30 @@ +class GsNode < ActiveRecord::Base + attr_accessible :name, :ip_address, :site, :element_name, :push_updates_to, :accepts_updates_from + + has_many :phone_numbers, :foreign_key => :gs_node_id, :dependent => :destroy + has_many :users, :foreign_key => :gs_node_id, :dependent => :destroy + has_many :sip_accounts, :foreign_key => :gs_node_id, :dependent => :destroy + has_many :hunt_groups, :foreign_key => :gs_node_id, :dependent => :destroy + + validates :name, + :presence => true + + validates :ip_address, + :presence => true + + validates :site, + :presence => true + + validates :element_name, + :presence => true + + def to_s + name + end + + def synced + self.last_sync = Time.now + return self.save + end + +end diff --git a/app/models/gui_function.rb b/app/models/gui_function.rb new file mode 100644 index 0000000..e27a8d2 --- /dev/null +++ b/app/models/gui_function.rb @@ -0,0 +1,40 @@ +class GuiFunction < ActiveRecord::Base + attr_accessible :category, :name, :description, :gui_function_memberships_attributes + + has_many :gui_function_memberships, :dependent => :destroy + has_many :user_groups, :through => :gui_function_memberships + + accepts_nested_attributes_for :gui_function_memberships + + validates :name, :presence => true, + :format => { :with => /\A[a-z_0-9]+\z/, :message => "Only lower case letters allowed" }, + :length => { :in => 3..255 }, + :uniqueness => true + + def to_s + self.name + end + + def self.display?(function_name = nil, user) + if function_name.blank? || GemeinschaftSetup.count == 0 + true + else + if !user || user.class != User || function_name.class != String + false + else + function_name = function_name.downcase + + activated_gui_function_names = GuiFunctionMembership.where(:user_group_id => user.user_group_ids, :activated => true).map{|gui_function_membership| gui_function_membership.gui_function.name}.uniq + deactivated_gui_function_names = GuiFunctionMembership.where(:user_group_id => user.user_group_ids, :activated => false).map{|gui_function_membership| gui_function_membership.gui_function.name}.uniq + + deactivated_gui_function_names = deactivated_gui_function_names - activated_gui_function_names + + if deactivated_gui_function_names.include?(function_name) + false + else + true + end + end + end + end +end diff --git a/app/models/gui_function_membership.rb b/app/models/gui_function_membership.rb new file mode 100644 index 0000000..d2bc7cd --- /dev/null +++ b/app/models/gui_function_membership.rb @@ -0,0 +1,7 @@ +class GuiFunctionMembership < ActiveRecord::Base + belongs_to :gui_function + belongs_to :user_group + + validates_associated :gui_function + validates_associated :user_group +end diff --git a/app/models/hunt_group.rb b/app/models/hunt_group.rb new file mode 100644 index 0000000..276ae53 --- /dev/null +++ b/app/models/hunt_group.rb @@ -0,0 +1,43 @@ +class HuntGroup < ActiveRecord::Base + attr_accessible :name, :strategy, :seconds_between_jumps, :phone_numbers_attributes + + belongs_to :tenant + has_many :call_forwards, :as => :call_forwardable, :dependent => :destroy + + validates_uniqueness_of :name, :scope => :tenant_id, + :allow_nil => true, :allow_blank => true + + validates_presence_of :strategy + validates_inclusion_of :strategy, :in => HUNT_GROUP_STRATEGIES + + validates_presence_of :seconds_between_jumps, + :if => Proc.new{ |hunt_group| hunt_group.strategy != 'ring_all' } + validates_numericality_of :seconds_between_jumps, + :only_integer => true, + :greater_than_or_equal_to => VALID_SECONDS_BETWEEN_JUMPS_VALUES.min, + :less_than_or_equal_to => VALID_SECONDS_BETWEEN_JUMPS_VALUES.max, + :if => Proc.new{ |hunt_group| hunt_group.strategy != 'ring_all' } + validates_inclusion_of :seconds_between_jumps, + :in => VALID_SECONDS_BETWEEN_JUMPS_VALUES, + :if => Proc.new{ |hunt_group| hunt_group.strategy != 'ring_all' } + validates_inclusion_of :seconds_between_jumps, + :in => [nil], + :if => Proc.new{ |hunt_group| hunt_group.strategy == 'ring_all' } + + validates_presence_of :uuid + validates_uniqueness_of :uuid + + has_many :hunt_group_members, :dependent => :destroy, :order => :position + + has_many :phone_numbers, :as => :phone_numberable, :dependent => :destroy + accepts_nested_attributes_for :phone_numbers, + :reject_if => lambda { |phone_number| phone_number[:number].blank? }, + :allow_destroy => true + + has_many :hunt_group_members, :dependent => :destroy + + def to_s + self.name || I18n.t('hunt_groups.name') + ' ID ' + self.id.to_s + end + +end diff --git a/app/models/hunt_group_member.rb b/app/models/hunt_group_member.rb new file mode 100644 index 0000000..7d9d3e0 --- /dev/null +++ b/app/models/hunt_group_member.rb @@ -0,0 +1,67 @@ +class HuntGroupMember < ActiveRecord::Base + attr_accessible :name, :active, :can_switch_status_itself, :phone_numbers_attributes + + belongs_to :hunt_group + validates_presence_of :hunt_group + + has_many :phone_numbers, :as => :phone_numberable, :dependent => :destroy + accepts_nested_attributes_for :phone_numbers, + :reject_if => lambda { |phone_number| phone_number[:number].blank? }, + :allow_destroy => true + + acts_as_list :scope => :hunt_group + + after_save :set_presence + after_save :trigger_connected_call_forward_if_necessary + + def to_s + self.name || I18n.t('hunt_group_members.name') + ' ID ' + self.id.to_s + end + + private + def set_presence + dialplan_function = nil + state = 'terminated' + + if self.active + state = 'confirmed' + end + + require 'freeswitch_event' + event = FreeswitchEvent.new("PRESENCE_IN") + event.add_header("proto", "sip") + event.add_header("from", "f-hgmtg-#{self.id}@#{SipDomain.first.host}") + event.add_header("event_type", "presence") + event.add_header("alt_event_type", "dialog") + event.add_header("presence-call-direction", "outbound") + event.add_header("answer-state", state) + event.add_header("unique-id", "hunt_group_member_#{self.id}") + return event.fire() + end + + # Turn on/off a connected CallForward. + # The last member who leaves the hunt_group deactivates the CallForward and the + # first member actives it. + # + def trigger_connected_call_forward_if_necessary + if self.active_changed? && self.hunt_group.hunt_group_members.count > 0 + # deactive CallForward + # + if self.hunt_group.hunt_group_members.where(:active => false).count == self.hunt_group.hunt_group_members.count + self.hunt_group.call_forwards.where(:active => true).each do |x| + x.update_attributes({:active => false}) + end + end + + # active CallForward + # + if self.hunt_group.hunt_group_members.where(:active => true).count > 0 + self.hunt_group.call_forwards.where(:active => false).each do |x| + x.update_attributes({:active => true}) + end + end + end + end + + +end diff --git a/app/models/language.rb b/app/models/language.rb new file mode 100644 index 0000000..1b9c2c0 --- /dev/null +++ b/app/models/language.rb @@ -0,0 +1,11 @@ +class Language < ActiveRecord::Base + has_many :tenants + has_many :users + + validates_presence_of :name + validates_presence_of :code + + def to_s + name + end +end diff --git a/app/models/manufacturer.rb b/app/models/manufacturer.rb new file mode 100644 index 0000000..03d2bb7 --- /dev/null +++ b/app/models/manufacturer.rb @@ -0,0 +1,46 @@ +class Manufacturer < ActiveRecord::Base + attr_accessible :name, :ieee_name, :homepage_url + + # Associations: + # + has_many :ouis, :dependent => :destroy + has_many :phone_models, :order => :name, :dependent => :destroy + + + # Validations: + # + validates_presence_of :name + validates_presence_of :ieee_name + + validates_uniqueness_of :name, :case_sensitive => false + + validate :validate_homepage_url + + # State Machine stuff + default_scope where(:state => 'active').order(:name) + state_machine :initial => :active do + + event :deactivate do + transition [:active] => :deactivated + end + + event :activate do + transition [:deactivated] => :active + end + end + + def to_s + self.name + end + + private + + def validate_homepage_url + if ! self.homepage_url.blank? + if ! CustomValidators.validate_url( self.homepage_url ) + errors.add( :homepage_url, "is invalid." ) + end + end + end + +end diff --git a/app/models/oui.rb b/app/models/oui.rb new file mode 100644 index 0000000..9a5bb1f --- /dev/null +++ b/app/models/oui.rb @@ -0,0 +1,17 @@ +class Oui < ActiveRecord::Base + attr_accessible :value + + validates_presence_of :manufacturer + validates_presence_of :value + + belongs_to :manufacturer + + # State Machine stuff + default_scope where(:state => 'active') + state_machine :initial => :active do + end + + def to_s + value + end +end diff --git a/app/models/phone.rb b/app/models/phone.rb new file mode 100644 index 0000000..89371eb --- /dev/null +++ b/app/models/phone.rb @@ -0,0 +1,240 @@ +require 'scanf' + +class Phone < ActiveRecord::Base + + attr_accessible :mac_address, :ip_address, :http_user, :http_password, + :phone_model_id, :hot_deskable, :nightly_reboot, + :provisioning_key, :provisioning_key_active + + # Associations + # + belongs_to :phone_model + belongs_to :phoneable, :polymorphic => true + + has_many :phone_sip_accounts, :dependent => :destroy, :uniq => true, :order => :position + has_many :sip_accounts, :through => :phone_sip_accounts + + # Validations + # + before_validation :sanitize_mac_address + + validates_presence_of :mac_address + validate_mac_address :mac_address + validates_uniqueness_of :mac_address + + validates_uniqueness_of :ip_address, + :if => Proc.new { |me| ! me.ip_address.blank? } + validate_ip_address :ip_address, + :if => Proc.new { |me| ! me.ip_address.blank? } + + validates_presence_of :phone_model + validates_presence_of :phoneable + + before_save :save_last_ip_address + before_save :destroy_phones_sip_accounts_if_phoneable_changed + before_save :remove_ip_address_when_mac_address_was_changed + + # State machine: + # + default_scope where(:state => 'active') + state_machine :initial => :active do + + event :deactivate do + transition [:active] => :deactivated + end + + event :activate do + transition [:deactivated] => :active + end + end + + def to_s + "%s %s %s" % [ + pretty_mac_address, + "(#{self.phone_model})", + self.ip_address ? "(#{self.ip_address})" : "", + ] + end + + def pretty_mac_address + return [].fill('%02X', 0, 6).join(':') % self.mac_address.scanf( '%2X' * 6 ) + end + + + def resync(reboot = false, sip_account = nil) + if ! self.phone_model || ! self.phone_model.manufacturer + return false + end + + if self.phone_model.manufacturer.ieee_name == 'SNOM Technology AG' + if !sip_account + self.sip_accounts.where(:sip_accountable_type => self.phoneable_type).each do |sip_account_associated| + if sip_account_associated.registration + sip_account = sip_account_associated + break + end + end + end + + if ! sip_account or ! sip_account.registration + require 'open-uri' + begin + if open("http://#{self.ip_address}/advanced_update.htm?reboot=Reboot", :http_basic_authentication=>[self.http_user, self.http_password], :proxy => nil) + return true + end + rescue + return false + end + end + + require 'freeswitch_event' + event = FreeswitchEvent.new("NOTIFY") + event.add_header("profile", "gemeinschaft") + event.add_header("event-string", "check-sync;reboot=#{reboot.to_s}") + event.add_header("user", sip_account.auth_name) + event.add_header("host", sip_account.sip_domain.host) + event.add_header("content-type", "application/simple-message-summary") + return event.fire() + + elsif self.phone_model.manufacturer.ieee_name == 'Siemens Enterprise CommunicationsGmbH & Co. KG' + require 'open-uri' + begin + if open("http://#{self.ip_address}:8085/contact_dls.html/ContactDLS", :http_basic_authentication=>[self.http_user, self.http_password], :proxy => nil) + return true + end + rescue + return false + end + end + + return false + end + + + # OPTIMIZE i18n translations + def user_login(user, sip_account = nil) + if ! self.hot_deskable + errors.add(:hot_deskable, "Phone not hot-deskable") + return false + end + + phones_affected = Hash.new() + sip_accounts = Array.new(1, sip_account) + + if !sip_account + sip_accounts = user.sip_accounts.where(:hotdeskable => true).all + end + + if sip_accounts.blank? + errors.add(:sip_accounts, "No hot-deskable Sip Accounts available") + return false + end + + sip_account_resync = self.sip_accounts.where(:sip_accountable_type => self.phoneable_type).first + + phones_affected.each_pair do |id,phone| + if phone.id != self.id + phone.user_logout() + end + end + + self.phoneable = user + sip_accounts.each do |sip_account| + if ! self.sip_accounts.where(:id => sip_account.id).first + self.sip_accounts.push(sip_account) + end + end + + @not_destroy_phones_sip_accounts = true + if ! self.save + return false + end + + sleep(0.5) + + if ! self.resync(true, sip_account_resync) + errors.add(:resync, "Resync failed") + return false + end + + return true + end + + + # OPTIMIZE i18n translations + def user_logout + if ! self.hot_deskable or self.phoneable_type == 'Tenant' + errors.add(:hot_deskable, "Phone not hot-deskable") + return false + end + + sip_account = self.sip_accounts.where(:sip_accountable_type => self.phoneable_type).first + + tenant_sip_account = self.sip_accounts.where(:sip_accountable_type => 'Tenant').first + if tenant_sip_account + tenant = tenant_sip_account.sip_accountable + end + + sip_account_ids = Array.new() + self.sip_accounts.where(:sip_accountable_type => 'User', :hotdeskable => true).each do |sip_account| + sip_account_ids.push(sip_account.id) + end + + if tenant + self.phoneable = tenant + @not_destroy_phones_sip_accounts = true + if ! self.save + errors.add(:phoneable, "Could not change owner") + return false + end + end + + if ! PhoneSipAccount.destroy_all(:sip_account_id => sip_account_ids) + errors.add(:sip_accounts, "Could not delete sip_accounts") + return false + end + + sleep(0.5) + + if ! self.resync(true, sip_account) + errors.add(:resync, "Resync failed") + return false + end + + return true + end + + private + + # Sanitize MAC address. + # + def sanitize_mac_address + self.mac_address = self.mac_address.to_s.upcase.gsub( /[^A-F0-9]/, '' ) + end + + # Saves the last IP address. + # + def save_last_ip_address + if self.ip_address_changed? \ + && self.ip_address != self.ip_address_was + self.last_ip_address = self.ip_address_was + end + end + + # When ever the parent of a phone changes all the SIP accounts associations + # are destroyed unless this is a user logout operation + # + def destroy_phones_sip_accounts_if_phoneable_changed + if (self.phoneable_type_changed? || self.phoneable_id_changed?) && ! @not_destroy_phones_sip_accounts + self.phone_sip_accounts.destroy_all + end + end + + def remove_ip_address_when_mac_address_was_changed + if self.mac_address_changed? + self.ip_address = nil + self.last_ip_address = nil + end + end + +end diff --git a/app/models/phone_book.rb b/app/models/phone_book.rb new file mode 100644 index 0000000..3603eae --- /dev/null +++ b/app/models/phone_book.rb @@ -0,0 +1,33 @@ +class PhoneBook < ActiveRecord::Base + attr_accessible :name, :description, :uuid + + belongs_to :phone_bookable, :polymorphic => true + has_many :phone_book_entries, :dependent => :destroy + + validates_presence_of :name + validates_uniqueness_of :name, :scope => [ :phone_bookable_type, :phone_bookable_id ] + + validates_length_of :name, :within => 1..50 + + validates_presence_of :uuid + validates_uniqueness_of :uuid + + # State Machine stuff + default_scope where(:state => 'active') + state_machine :initial => :active do + end + + def to_s + name + end + + def find_entry_by_number(number) + phone_book_entries_ids = self.phone_book_entries.map{|phone_book_entry| phone_book_entry.id} + + phone_number = PhoneNumber.where(:phone_numberable_id => phone_book_entries_ids, :phone_numberable_type => 'PhoneBookEntry', :number => number).first + + if phone_number + return phone_number.phone_numberable + end + end +end diff --git a/app/models/phone_book_entry.rb b/app/models/phone_book_entry.rb new file mode 100644 index 0000000..db2b44b --- /dev/null +++ b/app/models/phone_book_entry.rb @@ -0,0 +1,109 @@ +# encoding: UTF-8 + +class PhoneBookEntry < ActiveRecord::Base + before_save :run_phonetic_algorithm + before_save :save_value_of_to_s + + attr_accessible :first_name, :middle_name, :last_name, :title, :nickname, :organization, :is_organization, :department, :job_title, :is_male, :birthday, :birth_name, :description, :homepage_personal, :homepage_organization, :twitter_account, :facebook_account, :google_plus_account, :xing_account, :linkedin_account, :mobileme_account, :image + + belongs_to :phone_book + has_many :conference_invitees, :dependent => :destroy + + acts_as_list :scope => :phone_book + + validates_presence_of :phone_book + + validates_presence_of :last_name, + :unless => Proc.new { |entry| entry.is_organization } + + validates_presence_of :organization, + :if => Proc.new { |entry| entry.is_organization } + + validates_inclusion_of :is_male, :in => [true, false, 1, '1', 'on'], + :unless => Proc.new { |entry| entry.is_organization } + + has_many :phone_numbers, :as => :phone_numberable, :dependent => :destroy + + has_many :addresses, :dependent => :destroy + + # Avatar like photo + mount_uploader :image, ImageUploader + + # TODO Validate homepage URLs and social media accounts. + + + default_scope where(:state => 'active') + + # State Machine stuff + state_machine :initial => :active do + end + + def to_s + if self.is_organization + "#{self.organization}".strip + else + [self.last_name.strip, self.first_name.strip].join(', ') + end + end + + def self.koelner_phonetik(input) + if input.blank? + nil + else + # TODO: koelner_phonetik() needs to be tested. + + # Umwandeln in Grossbuchstaben + phonetik = input.upcase.gsub(/[^A-ZÜüÖöÄäß]/,'').strip + + # Umwandeln anhand der Tabelle auf + # http://de.wikipedia.org/wiki/K%C3%B6lner_Verfahren + phonetik = phonetik.gsub(/([XKQ])X/, '\1'+'8') + phonetik = phonetik.gsub(/[DT]([CSZ])/, '8'+'\1') + phonetik = phonetik.gsub(/C([^AHKOQUX])/, '8'+'\1') + phonetik = phonetik.gsub(/^C([^AHKLOQRUX])/, '8'+'\1') + phonetik = phonetik.gsub(/([SZ])C/, '\1'+'8') + phonetik = phonetik.gsub(/[SZß]/, '8') + phonetik = phonetik.gsub(/R/, '7') + phonetik = phonetik.gsub(/[MN]/, '6') + phonetik = phonetik.gsub(/L/, '5') + phonetik = phonetik.gsub(/X/, '48') + phonetik = phonetik.gsub(/([^SZ])C([AHKOQUX])/, '\1'+'4'+'\2' ) + phonetik = phonetik.gsub(/^C([AHKLOQRUX])/, '4'+'\1') + phonetik = phonetik.gsub(/[GKQ]/, '4') + phonetik = phonetik.gsub(/PH/, '3H') + phonetik = phonetik.gsub(/[FVW]/, '3') + phonetik = phonetik.gsub(/[DT]([^CSZ])/, '2'+'\1') + phonetik = phonetik.gsub(/[BP]/, '1') + phonetik = phonetik.gsub(/H/, '') + phonetik = phonetik.gsub(/[AEIJOUYÜüÖöÄä]/, '0') + + # Regeln für Buchstaben am Ende des Wortes + phonetik = phonetik.gsub(/P/, '1') + phonetik = phonetik.gsub(/[DT]/, '2') + phonetik = phonetik.gsub(/C/, '8') + + # Entfernen aller doppelten + phonetik = phonetik.gsub(/([0-9])\1+/, '\1') + + # Entfernen aller Codes "0" außer am Anfang. + phonetik = phonetik.gsub(/^0/, 'X') + phonetik = phonetik.gsub(/0/, '') + phonetik = phonetik.gsub(/^X/, '0') + + phonetik + end + end + + private + + def run_phonetic_algorithm + self.first_name_phonetic = PhoneBookEntry.koelner_phonetik(self.first_name) if self.first_name_changed? + self.last_name_phonetic = PhoneBookEntry.koelner_phonetik(self.last_name) if self.last_name_changed? + self.organization_phonetic = PhoneBookEntry.koelner_phonetik(self.organization) if self.organization_changed? + end + + def save_value_of_to_s + self.value_of_to_s = self.to_s + end + +end diff --git a/app/models/phone_model.rb b/app/models/phone_model.rb new file mode 100644 index 0000000..e00e0e3 --- /dev/null +++ b/app/models/phone_model.rb @@ -0,0 +1,56 @@ +class PhoneModel < ActiveRecord::Base + attr_accessible :name, :product_manual_homepage_url, :product_homepage_url, :uuid + + # Associations + # + belongs_to :manufacturer + + has_many :phones, :dependent => :destroy + + # Validations + # + validates_presence_of :name + validate :validate_product_manual_homepage_url + validate :validate_product_homepage_url + + validates_presence_of :uuid + validates_uniqueness_of :uuid + + def to_s + self.name + end + + # State machine: + # + default_scope where(:state => 'active') + state_machine :initial => :active do + + event :deactivate do + transition [:active] => :deactivated + end + + event :activate do + transition [:deactivated] => :active + end + end + + + private + + def validate_product_manual_homepage_url + if ! self.product_manual_homepage_url.blank? + if ! CustomValidators.validate_url( self.product_manual_homepage_url ) + errors.add( :product_manual_homepage_url, "is invalid." ) + end + end + end + + def validate_product_homepage_url + if ! self.product_homepage_url.blank? + if ! CustomValidators.validate_url( self.product_homepage_url ) + errors.add( :product_homepage_url, "is invalid." ) + end + end + end + +end diff --git a/app/models/phone_number.rb b/app/models/phone_number.rb new file mode 100644 index 0000000..4c0cf46 --- /dev/null +++ b/app/models/phone_number.rb @@ -0,0 +1,304 @@ +class PhoneNumber < ActiveRecord::Base + NUMBER_TYPES_INBOUND = ['SipAccount', 'Conference', 'FaxAccount', 'Callthrough', 'HuntGroup'] + + attr_accessible :name, :number, :gs_node_id, :access_authorization_user_id + + has_many :call_forwards, :dependent => :destroy + + has_many :ringtones, :as => :ringtoneable, :dependent => :destroy + + belongs_to :phone_numberable, :polymorphic => true + + belongs_to :gs_node + + validates_uniqueness_of :number, :scope => [:phone_numberable_type, :phone_numberable_id] + + validate :validate_inbound_uniqueness + + before_save :save_value_of_to_s + after_create :copy_existing_call_forwards_if_necessary + before_validation :'parse_and_split_number!' + validate :validate_number, :if => Proc.new { |phone_number| STRICT_INTERNAL_EXTENSION_HANDLING && STRICT_DID_HANDLING } + validate :check_if_number_is_available, :if => Proc.new { |phone_number| STRICT_INTERNAL_EXTENSION_HANDLING && STRICT_DID_HANDLING } + + acts_as_list :scope => [:phone_numberable_id, :phone_numberable_type] + + # Sync other nodes when this is a cluster. + # + validates_presence_of :uuid + validates_uniqueness_of :uuid + after_create { self.create_on_other_gs_nodes('phone_numberable', self.phone_numberable.try(:uuid)) } + after_destroy :destroy_on_other_gs_nodes + after_update { self.update_on_other_gs_nodes('phone_numberable', self.phone_numberable.try(:uuid)) } + + # State machine: + # + default_scope where(:state => 'active') + state_machine :initial => :active do + + event :deactivate do + transition [:active] => :deactivated + end + + event :activate do + transition [:deactivated] => :active + end + end + + + def to_s + parts = [] + parts << "+#{self.country_code}" if self.country_code + parts << self.area_code if self.area_code + parts << self.central_office_code if self.central_office_code + parts << self.subscriber_number if self.subscriber_number + + if parts.empty? + return self.number + end + return parts.join("-") + end + + # Parse a number in a tenant's context (respect the tenant's country) + # + def self.parse( number, tenant=nil ) + number = number.to_s.gsub( /[^0-9+]/, '' ) + + if tenant.class.name == 'Tenant' + country = tenant.country + else + tenant = nil + country = GemeinschaftSetup.first.try(:country) + country ||= Country.where(:name => "Germany").first + end + + parts = { + :country_code => nil, + :area_code => nil, + :central_office_code => nil, + :subscriber_number => nil, + :extension => nil, + } + + if country + if ! country.international_call_prefix.blank? + number = number.gsub( /^#{Regexp.escape( country.international_call_prefix )}/, '+' ) + end + if ! country.trunk_prefix.blank? + number = number.gsub( /^#{Regexp.escape( country.trunk_prefix )}/, "+#{country.country_code}" ) + end + end + + if number.match( /^[+]/ ) + parts = self.parse_international_number( number.gsub(/[^0-9]/,'') ) + return nil if parts.nil? + else + # Check if the number is an internal extension. + if tenant + internal_extension_range = tenant.phone_number_ranges.where(:name => INTERNAL_EXTENSIONS).first + if internal_extension_range + if internal_extension_range.phone_numbers.where(:number => number).length > 0 + parts[:extension] = number + end + end + end + + # Otherwise assume the number is a special number such as an emergency number. + if ! parts[:extension] + parts[:subscriber_number] = number + end + end + + # return nil if all parts are blank: + return nil if ( + parts[:country_code].blank? && + parts[:area_code].blank? && + parts[:central_office_code].blank? && + parts[:subscriber_number].blank? && + parts[:extension].blank? + ) + parts # return value + end + + def self.parse_and_format( number, tenant=nil ) + attributes = PhoneNumber.parse(number, tenant) + if attributes + formated_number = attributes.map{|key,value| value}.delete_if{|x| x.nil?}.join('-') + formated_number = "+#{formated_number}" if attributes[:country_code] + return formated_number + end + return number + end + + # Parse an international number. + # Assumed format for +number+ is e.g. "49261200000" + # + def self.parse_international_number( number ) + number = number.to_s.gsub( /[^0-9]/, '' ) + + parts = { + :country_code => nil, + :area_code => nil, + :central_office_code => nil, + :subscriber_number => nil, + :extension => nil, + } + + # Find country by country code: + country = Country.where( :country_code => number[0, 3]).first + country ||= Country.where( :country_code => number[0, 2]).first + country ||= Country.where( :country_code => number[0, 1]).first + + return nil if ! country # invalid number format + + parts[:country_code] = country.country_code + remainder = number[ parts[:country_code].length, 999 ] # e.g. "261200000" + + case parts[:country_code] + + when '1' + # Assure an NANP number + return nil if ! remainder.match(/[2-9]{1}[0-9]{2}[2-9]{1}[0-9]{2}[0-9]{4}/) + + # Shortcut for NANPA closed dialplan: + parts[:area_code ] = remainder[ 0, 3] + parts[:central_office_code ] = remainder[ 3, 3] + parts[:subscriber_number ] = remainder[ 6, 4] + else + # variable-length dialplan, e.g. Germany + + # Find longest area_code for the country: + longest_area_code = country.area_codes.order( "LENGTH(area_code) DESC" ).first + + # Find a matching area_code: + if longest_area_code + longest_area_code.area_code.length.downto(1) do |area_code_length| + area_code = country.area_codes.where( :area_code => remainder[ 0, area_code_length ] ).first + if area_code + parts[:area_code] = area_code.area_code + break + end + end + + return nil if ! parts[:area_code] # No matching area_code for the country. + + remainder = remainder.gsub( /^#{parts[:area_code]}/, '' ) + #remainder = number[ parts[:area_code].length, 999 ] # e.g. "200000" + end + parts[:subscriber_number] = remainder + end + + parts # return value + end + + def parse_and_split_number! + if self.phone_numberable_type == 'PhoneNumberRange' && self.phone_numberable.name == INTERNAL_EXTENSIONS + # The parent is the PhoneNumberRange INTERNAL_EXTENSIONS. Therefor it must be an extensions. + # + self.country_code = nil + self.area_code = nil + self.subscriber_number = nil + self.central_office_code = nil + self.extension = self.number.to_s.strip + else + if self.tenant && + self.tenant.phone_number_ranges.exists?(:name => INTERNAL_EXTENSIONS) && + self.tenant.phone_number_ranges.where(:name => INTERNAL_EXTENSIONS).first.phone_numbers.exists?(:number => self.number) + self.country_code = nil + self.area_code = nil + self.subscriber_number = nil + self.central_office_code = nil + self.extension = self.number.to_s.strip + else + parsed_number = PhoneNumber.parse( self.number ) + if parsed_number + self.country_code = parsed_number[:country_code] + self.area_code = parsed_number[:area_code] + self.subscriber_number = parsed_number[:subscriber_number] + self.extension = parsed_number[:extension] + self.central_office_code = parsed_number[:central_office_code] + + self.number = self.to_s.gsub( /[^\+0-9]/, '' ) + end + end + end + end + + # Find the (grand-)parent tenant of this phone number: + # + def tenant + #OPTIMIZE Add a tenant_id to SipAccount + case self.phone_numberable + when SipAccount + self.phone_numberable.tenant + when Conference + case self.phone_numberable.conferenceable + when Tenant + self.phone_numberable.conferenceable + when User + self.phone_numberable.conferenceable.current_tenant #OPTIMIZE + when UserGroup + self.phone_numberable.conferenceable.tenant + end + end + end + + def move_up? + return self.position.to_i > PhoneNumber.where(:phone_numberable_id => self.phone_numberable_id, :phone_numberable_type => self.phone_numberable_type ).order(:position).first.position.to_i + end + + def move_down? + return self.position.to_i < PhoneNumber.where(:phone_numberable_id => self.phone_numberable_id, :phone_numberable_type => self.phone_numberable_type ).order(:position).last.position.to_i + end + + private + + def validate_number + if ! PhoneNumber.parse( self.number ) + errors.add( :number, "is invalid." ) + end + end + + def check_if_number_is_available + if self.phone_numberable_type != 'PhoneBookEntry' && self.tenant + + phone_number_ranges = self.tenant.phone_number_ranges.where( + :name => [INTERNAL_EXTENSIONS, DIRECT_INWARD_DIALING_NUMBERS] + ) + if !phone_number_ranges.empty? + if !PhoneNumber.where(:phone_numberable_type => 'PhoneNumberRange'). + where(:phone_numberable_id => phone_number_ranges). + exists?(:number => self.number) + errors.add(:number, "isn't defined as an extenation or DID for the tenant '#{self.tenant}'. #{phone_number_ranges.inspect}") + end + end + end + end + + def validate_inbound_uniqueness + if NUMBER_TYPES_INBOUND.include?(self.phone_numberable_type) + numbering_scope = PhoneNumber.where(:state => 'active', :number => self.number, :phone_numberable_type => NUMBER_TYPES_INBOUND) + if numbering_scope.where(:id => self.id).count == 0 && numbering_scope.count > 0 + errors.add(:number, 'not unique') + end + end + end + + def save_value_of_to_s + self.value_of_to_s = self.to_s + end + + def copy_existing_call_forwards_if_necessary + if self.phone_numberable.class == SipAccount && self.phone_numberable.callforward_rules_act_per_sip_account == true + sip_account = SipAccount.find(self.phone_numberable) + if sip_account.phone_numbers.where('id != ?', self.id).count > 0 + if sip_account.phone_numbers.where('id != ?', self.id).order(:created_at).first.call_forwards.count > 0 + sip_account.phone_numbers.where('id != ?', self.id).first.call_forwards.each do |call_forward| + call_forward.set_this_callforward_rule_to_all_phone_numbers_of_the_parent_sip_account + end + end + end + end + end + +end diff --git a/app/models/phone_number_range.rb b/app/models/phone_number_range.rb new file mode 100644 index 0000000..2fdd9b6 --- /dev/null +++ b/app/models/phone_number_range.rb @@ -0,0 +1,16 @@ +class PhoneNumberRange < ActiveRecord::Base + attr_accessible :name, :description + + has_many :phone_numbers, :as => :phone_numberable, :dependent => :destroy + belongs_to :phone_number_rangeable, :polymorphic => true + + validates_presence_of :name + validates_uniqueness_of :name, :scope => [:phone_number_rangeable_id, :phone_number_rangeable_type] + validates_inclusion_of :name, :in => [INTERNAL_EXTENSIONS, DIRECT_INWARD_DIALING_NUMBERS, SERVICE_NUMBERS] + validates_presence_of :phone_number_rangeable_id + validates_presence_of :phone_number_rangeable + + def to_s + name + end +end diff --git a/app/models/phone_sip_account.rb b/app/models/phone_sip_account.rb new file mode 100644 index 0000000..449ba39 --- /dev/null +++ b/app/models/phone_sip_account.rb @@ -0,0 +1,17 @@ +class PhoneSipAccount < ActiveRecord::Base + attr_accessible :sip_account_id + + belongs_to :phone + belongs_to :sip_account + + validates_presence_of :phone + validates_presence_of :sip_account + + validates_uniqueness_of :sip_account_id, :scope => :phone_id + + acts_as_list :scope => :phone + + def to_s + "Position #{self.position}" + end +end diff --git a/app/models/remote_gs_node/gs_cluster_sync_log_entry.rb b/app/models/remote_gs_node/gs_cluster_sync_log_entry.rb new file mode 100644 index 0000000..843494e --- /dev/null +++ b/app/models/remote_gs_node/gs_cluster_sync_log_entry.rb @@ -0,0 +1,9 @@ +# Find docu about ActiveResource at +# http://ofps.oreilly.com/titles/9780596521424/activeresource_id59243.html +# test = RemoteGSNode::GcLogEntry.first.attributes.delete_if{|key, value| ['id','updated_at','created_at'].include?(key) }) + +module RemoteGsNode + class GsClusterSyncLogEntry < ActiveResource::Base + self.site = 'http://0.0.0.0:3000' + end +end \ No newline at end of file diff --git a/app/models/ringtone.rb b/app/models/ringtone.rb new file mode 100644 index 0000000..36053c0 --- /dev/null +++ b/app/models/ringtone.rb @@ -0,0 +1,15 @@ +class Ringtone < ActiveRecord::Base + attr_accessible :audio, :bellcore_id + + mount_uploader :audio, AudioUploader + validates_presence_of :audio, :if => Proc.new{ |ringtone| ringtone.bellcore_id.blank? } + validates_presence_of :ringtoneable_type + validates_presence_of :ringtoneable_id + validates_presence_of :ringtoneable + + belongs_to :ringtoneable, :polymorphic => true + + def to_s + self.bellcore_id.to_s + end +end diff --git a/app/models/sip_account.rb b/app/models/sip_account.rb new file mode 100644 index 0000000..8459265 --- /dev/null +++ b/app/models/sip_account.rb @@ -0,0 +1,221 @@ +# encoding: UTF-8 + +class SipAccount < ActiveRecord::Base + include ActionView::Helpers::TextHelper + + attr_accessible :auth_name, :caller_name, :password, :voicemail_pin, + :tenant_id, :call_waiting, :clir, :clip_no_screening, + :clip, :description, :callforward_rules_act_per_sip_account, + :hotdeskable, :gs_node_id + + # Associations: + # + belongs_to :sip_accountable, :polymorphic => true + + has_many :phone_sip_accounts, :uniq => true + has_many :phones, :through => :phone_sip_accounts + + has_many :phone_numbers, :as => :phone_numberable, :dependent => :destroy + has_many :call_forwards, :through => :phone_numbers + + belongs_to :tenant + belongs_to :sip_domain + + has_many :softkeys, :dependent => :destroy + + has_many :voicemail_messages, :foreign_key => 'username', :primary_key => 'auth_name' + + has_many :call_histories, :as => :call_historyable, :dependent => :destroy + + has_one :voicemail_setting, :class_name => "VoicemailSetting", :primary_key => 'auth_name', :foreign_key => 'username', :dependent => :destroy + + belongs_to :gs_node + + # Delegations: + # + delegate :host, :to => :sip_domain, :allow_nil => true + delegate :realm, :to => :sip_domain, :allow_nil => true + + # Validations: + # + validates_presence_of :caller_name + validates_presence_of :sip_accountable + validates_presence_of :tenant + validates_presence_of :sip_domain + + validate_sip_password :password + + validates_format_of :voicemail_pin, :with => /[0-9]+/, + :allow_nil => true, :allow_blank => true + + validates_uniqueness_of :auth_name, :scope => :sip_domain_id + + # Before and after hooks: + # + before_save :save_value_of_to_s + after_save :create_voicemail_setting, :if => :'voicemail_setting == nil' + before_validation :find_and_set_tenant_id + before_validation :set_sip_domain_id + before_validation :convert_umlauts_in_caller_name + before_destroy :remove_sip_accounts_or_logout_phones + + # Sync other nodes when this is a cluster. + # + validates_presence_of :uuid + validates_uniqueness_of :uuid + + after_create { self.create_on_other_gs_nodes('sip_accountable', self.sip_accountable.try(:uuid)) } + after_destroy :destroy_on_other_gs_nodes + after_update { self.update_on_other_gs_nodes('sip_accountable', self.sip_accountable.try(:uuid)) } + + after_update :log_out_phone_if_not_local + + def to_s + truncate((self.caller_name || "SipAccount ID #{self.id}"), :length => TO_S_MAX_CALLER_NAME_LENGTH) + " (#{truncate(self.auth_name, :length => TO_S_MAX_LENGTH_OF_AUTH_NAME)}@...#{self.host.split(/\./)[2,3].to_a.join('.') if self.host })" + end + + def call_forwarding_toggle( call_forwarding_service, to_voicemail = nil ) + if ! self.phone_numbers.first + errors.add(:base, "You must provide at least one phone number") + end + + service_id = CallForwardCase.where(:value => call_forwarding_service).first.id + + call_forwarding_master = self.phone_numbers.first.call_forwards.where(:call_forward_case_id => service_id).order(:active).all(:conditions => 'source IS NULL OR source = ""').first + if ! call_forwarding_master + errors.add(:base, "No call forwarding entries found that could be toggled") + return false + end + + if call_forwarding_master.active + call_forwarding_master.active = false + else + if call_forwarding_service = 'assistant' && call_forwarding_master.call_forwardable_type == 'HuntGroup' && call_forwarding_master.call_forwardable + if call_forwarding_master.call_forwardable.hunt_group_members.where(:active => true).count > 0 + call_forwarding_master.active = true + else + call_forwarding_master.active = false + end + end + end + + self.phone_numbers.each do |phone_number| + call_forwarding = phone_number.call_forwards.where(:call_forward_case_id => service_id).order(:active).all(:conditions => 'source IS NULL OR source = ""').first + if ! call_forwarding + call_forwarding = CallForward.new() + call_forwarding.phone_number_id = phone_number.id + end + + if to_voicemail == nil + to_voicemail = call_forwarding_master.to_voicemail + end + + call_forwarding.call_forward_case_id = call_forwarding_master.call_forward_case_id + call_forwarding.timeout = call_forwarding_master.timeout + call_forwarding.destination = call_forwarding_master.destination + call_forwarding.source = call_forwarding_master.source + call_forwarding.depth = call_forwarding_master.depth + call_forwarding.active = call_forwarding_master.active + call_forwarding.to_voicemail = to_voicemail + + if ! call_forwarding.save + call_forwarding.errors.messages.each_with_index do |(error_key, error_message), index| + errors.add(error_key, "number: #{phone_number}: #{error_message}") + end + end + end + + if errors.empty? + return call_forwarding_master + end + + return false + end + + def registration + return FreeswitchRegistration.where(:reg_user => self.auth_name).first + end + + def call( phone_number ) + require 'freeswitch_event' + return FreeswitchAPI.execute( + 'originate', + "{origination_uuid=#{UUID.new.generate},origination_caller_id_number='#{phone_number}',origination_caller_id_name='Call'}user/#{self.auth_name} #{phone_number}", + true + ); + end + + + private + + def save_value_of_to_s + self.value_of_to_s = self.to_s + end + + def find_and_set_tenant_id + if self.new_record? and self.tenant_id != nil + return + else + tenant = case self.sip_accountable_type + when 'Tenant' ; sip_accountable + when 'UserGroup' ; sip_accountable.tenant + when 'User' ; sip_accountable.try(:current_tenant) || sip_accountable.try(:tenants).try(:last) + else nil + end + self.tenant_id = tenant.id if tenant != nil + end + end + + def set_sip_domain_id + self.sip_domain_id = self.tenant.try(:sip_domain_id) + end + + def convert_umlauts_in_caller_name + if !self.caller_name.blank? + self.caller_name = self.caller_name.sub(/ä/,'ae'). + sub(/Ä/,'Ae'). + sub(/ü/,'ue'). + sub(/Ü/,'Ue'). + sub(/ö/,'oe'). + sub(/Ö/,'Oe'). + sub(/ß/,'ss') + + self.caller_name = self.caller_name.gsub(/[^a-zA-Z0-9\-\,\:\. ]/,'_') + end + end + + # Make sure that a tenant phone goes back to the tenant and doesn't + # get deleted with this user. + # + def remove_sip_accounts_or_logout_phones + self.phones.each do |phone| + if phone.sip_accounts.where(:sip_accountable_type => 'Tenant').count > 0 + phone.user_logout + else + PhoneSipAccount.delete_all(:sip_account_id => self.id) + end + end + self.reload + end + + # log out phone if sip_account is not on this node + def log_out_phone_if_not_local + if self.gs_node_id && ! GsNode.where(:ip_address => HOMEBASE_IP_ADDRESS, :id => self.gs_node_id).first + self.phones.each do |phone| + phone.user_logout; + end + end + end + + def create_voicemail_setting + voicemail_setting = VoicemailSetting.new() + voicemail_setting.username = self.auth_name + voicemail_setting.domain = self.sip_domain.try(:host) + voicemail_setting.password = self.voicemail_pin + voicemail_setting.notify = true + voicemail_setting.attachment = true + voicemail_setting.mark_read = true + voicemail_setting.purge = false + voicemail_setting.save + end +end diff --git a/app/models/sip_domain.rb b/app/models/sip_domain.rb new file mode 100644 index 0000000..252fe4a --- /dev/null +++ b/app/models/sip_domain.rb @@ -0,0 +1,16 @@ +class SipDomain < ActiveRecord::Base + attr_accessible :host, :realm + + has_many :tenants, :dependent => :restrict + has_many :sip_accounts, :dependent => :restrict + + validates_presence_of :host + validates_uniqueness_of :host, :case_sensitive => false + + validates_presence_of :realm + validates_uniqueness_of :realm + + def to_s + self.host + end +end diff --git a/app/models/softkey.rb b/app/models/softkey.rb new file mode 100644 index 0000000..a709036 --- /dev/null +++ b/app/models/softkey.rb @@ -0,0 +1,100 @@ +class Softkey < ActiveRecord::Base + attr_accessible :softkey_function_id, :number, :label, :call_forward_id, :uuid + + belongs_to :sip_account + belongs_to :softkey_function + belongs_to :call_forward + + # Any CallForward BLF must have a valid softkey_call_forward_id. + # + validates_presence_of :call_forward_id, :if => Proc.new{ |softkey| self.softkey_function_id != nil && + self.softkey_function_id == SoftkeyFunction.find_by_name('call_forwarding').try(:id) } + + # These functions need a number to act. + # + validates_presence_of :number, :if => Proc.new{ |softkey| self.softkey_function_id != nil && + ['blf','speed_dial','dtmf','conference'].include?(softkey.softkey_function.name) } + + validates_presence_of :uuid + validates_uniqueness_of :uuid + + acts_as_list :scope => :sip_account + + before_validation :clean_up_and_leave_only_values_which_make_sense_for_the_current_softkey_function_id + after_validation :save_function_name_in_function, :if => Proc.new{ |softkey| self.call_forward_id.blank? } + after_save :resync_phone + after_destroy :resync_phone + + def possible_blf_call_forwards + if self.sip_account.phone_numbers.count == 0 + nil + else + if self.sip_account.callforward_rules_act_per_sip_account == true + # We pick one phone_number and display the rules of it. + # + phone_number = self.sip_account.phone_numbers.order(:number).first + call_forwards = self.sip_account.call_forwards.where(:phone_number_id => phone_number.id) + else + call_forwards = self.sip_account.call_forwards + end + + phone_numbers_ids = self.sip_account.phone_number_ids + phone_numbers = PhoneNumber.where(:id => phone_numbers_ids).pluck(:number) + + hunt_group_ids = PhoneNumber.where(:phone_numberable_type => 'HuntGroupMember', :number => phone_numbers). + map{ |phone_number| phone_number.phone_numberable.hunt_group.id }. + uniq + + call_forwards + CallForward.where(:call_forwardable_type => 'HuntGroup', :call_forwardable_id => hunt_group_ids). + where('phone_number_id NOT IN (?)', phone_numbers_ids) + end + end + + def to_s + if (['call_forwarding'].include?(self.softkey_function.name)) + "#{self.call_forward}" + else + if ['log_out', 'log_in'].include?(self.softkey_function.name) + I18n.t("softkeys.functions.#{self.softkey_function.name}") + else + "#{self.softkey_function.name} : #{self.number.to_s}" + end + end + end + + def resync_phone + phone_sip_account = PhoneSipAccount.find_by_sip_account_id(self.sip_account_id) + if phone_sip_account && phone_sip_account.phone + phone_sip_account.phone.resync() + end + end + + def move_up? + return self.position.to_i > Softkey.where(:sip_account_id => self.sip_account_id ).order(:position).first.position.to_i + end + + def move_down? + return self.position.to_i < Softkey.where(:sip_account_id => self.sip_account_id ).order(:position).last.position.to_i + end + + private + + def save_function_name_in_function + self.function = self.softkey_function.name + end + + # Make sure that no number is set when there is no need for one. + # And make sure that there is no CallForward connected when not needed. + # + def clean_up_and_leave_only_values_which_make_sense_for_the_current_softkey_function_id + if self.softkey_function_id != nil + if ['blf','speed_dial','dtmf','conference'].include?(self.softkey_function.name) + self.call_forward_id = nil + end + if ['call_forwarding'].include?(self.softkey_function.name) + self.number = nil + end + end + end + +end diff --git a/app/models/softkey_function.rb b/app/models/softkey_function.rb new file mode 100644 index 0000000..976827d --- /dev/null +++ b/app/models/softkey_function.rb @@ -0,0 +1,13 @@ +class SoftkeyFunction < ActiveRecord::Base + validates_presence_of :name + + validates_uniqueness_of :name + + acts_as_list + + default_scope order(:position) + + def to_s + self.name + end +end diff --git a/app/models/system_message.rb b/app/models/system_message.rb new file mode 100644 index 0000000..0d9e862 --- /dev/null +++ b/app/models/system_message.rb @@ -0,0 +1,7 @@ +class SystemMessage < ActiveRecord::Base + attr_accessible :content + + belongs_to :user + + validates_presence_of :content +end diff --git a/app/models/tenant.rb b/app/models/tenant.rb new file mode 100644 index 0000000..6f98603 --- /dev/null +++ b/app/models/tenant.rb @@ -0,0 +1,243 @@ +# encoding: UTF-8 + +class Tenant < ActiveRecord::Base + attr_accessible :name, :description, :sip_domain_id, :country_id, :language_id, :from_field_pin_change_email, :from_field_voicemail_email + + if STRICT_INTERNAL_EXTENSION_HANDLING == true + attr_accessible :internal_extension_ranges + end + + if STRICT_DID_HANDLING == true + attr_accessible :did_list + end + + # Associations: + # + has_many :tenant_memberships, :dependent => :destroy + has_many :users, :through => :tenant_memberships, :validate => true + + has_many :user_groups, :dependent => :destroy + + has_many :phone_books, :as => :phone_bookable, :dependent => :destroy + has_many :phone_book_entries, :through => :phone_books + + has_many :phone_number_ranges, :as => :phone_number_rangeable, :dependent => :destroy + + has_many :phones, :as => :phoneable, :dependent => :destroy + has_many :users_phones, :through => :users, :source => :phones, :readonly => true + + has_many :callthroughs, :dependent => :destroy + + has_many :fax_accounts, :dependent => :destroy # A tenant can't have a FaxAccount by itself! + + belongs_to :country + belongs_to :language + + belongs_to :sip_domain + + has_many :sip_accounts, :as => :sip_accountable, :dependent => :destroy + has_many :users_sip_accounts, :through => :users, :source => :sip_accounts, :readonly => true + + has_many :conferences, :as => :conferenceable, :dependent => :destroy + + has_many :hunt_groups, :dependent => :destroy + has_many :hunt_group_members, :through => :hunt_groups + + has_many :automatic_call_distributors, :as => :automatic_call_distributorable, :dependent => :destroy + has_many :acd_agents, :through => :automatic_call_distributors + + # Phone numbers of the tenant. + # + has_many :phone_number_ranges_phone_numbers, :through => :phone_number_ranges, :source => :phone_numbers, :readonly => true + has_many :phone_numbers, :through => :sip_accounts + has_many :conferences_phone_numbers, :through => :conferences, :source => :phone_numbers, :readonly => true + has_many :callthroughs_phone_numbers, :through => :conferences, :source => :phone_numbers, :readonly => true + has_many :huntgroups_phone_numbers, :through => :conferences, :source => :phone_numbers, :readonly => true + has_many :fax_accounts_phone_numbers, :through => :fax_accounts, :source => :phone_numbers, :readonly => true + + # Phone numbers of users of the tenant. + # + has_many :users_phone_numbers, :through => :users, :source => :phone_numbers, :readonly => true + has_many :user_groups_phone_numbers, :through => :users, :source => :phone_numbers, :readonly => true + has_many :users_conferences, :through => :users, :source => :conferences, :readonly => true + has_many :users_conferences_phone_numbers, :through => :users_conferences, :source => :phone_numbers, :readonly => true + has_many :users_fax_accounts, :through => :users, :source => :fax_accounts, :readonly => true + has_many :users_fax_accounts_phone_numbers, :through => :users_fax_accounts, :source => :phone_numbers, :readonly => true + + # Validations: + # + validates_presence_of :name, :state, :country, :language + validates_length_of :name, :within => 1..255 + validates_uniqueness_of :name + + validates_length_of :name, :within => 1..100 + + # Before and after hooks: + # + after_create :create_a_default_phone_book + + # State machine: + default_scope where(:state => 'active') + state_machine :initial => :active do + + event :deactivate do + transition [:active] => :deactivated + end + + event :activate do + transition [:deactivated] => :active + end + end + + def to_s + name + end + + if STRICT_INTERNAL_EXTENSION_HANDLING == true + def array_of_internal_extension_numbers + ranges = self.internal_extension_ranges.gsub(/[^0-9\-,]/,'').gsub(/[\-]+/,'-').gsub(/[,]+/,',').split(/,/) + output = [] + ranges.each do |range| + mini_range = range.split(/-/).map{|x| x.to_i}.sort + if mini_range.size == 1 + output << mini_range[0] + else + output = output + (mini_range[0]..mini_range[1]).to_a + end + output = output.try(:flatten) + end + output.try(:sort).try(:uniq).map{|number| number.to_s } + end + + # Generate the internal_extensions + # + def generate_internal_extensions + internal_extensions = self.phone_number_ranges.find_or_create_by_name(INTERNAL_EXTENSIONS, :description => 'A list of all available internal extensions.') + + phone_number_list = Array.new + + if self.array_of_internal_extension_numbers.size > 0 + if self.country.phone_number_ranges.first.try(:phone_numbers) == nil + phone_number_list = self.array_of_internal_extension_numbers + elsif + # Don't create extensions like 911, 110 or 112 (at least by default) + # + phone_number_list = (self.array_of_internal_extension_numbers - self.country.phone_number_ranges.where(:name => SERVICE_NUMBERS).first.phone_numbers.map{|entry| entry.number}) + end + end + + phone_number_list.each do |number| + internal_extensions.phone_numbers.find_or_create_by_name_and_number('Extension', number) + end + end + + end + + if STRICT_DID_HANDLING == true + def array_of_dids_generated_from_did_list + numbers = self.did_list.downcase.gsub(/[^0-9,x\+]/,'').gsub(/[,]+/,',').split(/,/) + array_of_all_external_numbers = [] + numbers.each do |number| + if number.include?('x') + self.array_of_internal_extension_numbers.each do |internal_extension| + array_of_all_external_numbers << number.gsub(/x/, "-#{internal_extension.to_s}") + end + else + array_of_all_external_numbers << number + end + end + array_of_all_external_numbers.try(:sort).try(:uniq).map{|number| number.to_s } + end + + # Generate the external numbers (DIDs) + # + def generate_dids + dids = self.phone_number_ranges.find_or_create_by_name(DIRECT_INWARD_DIALING_NUMBERS, :description => 'A list of all available DIDs.') + self.array_of_dids_generated_from_did_list.each do |number| + dids.phone_numbers.find_or_create_by_name_and_number('DID', number) + end + end + + end + + + # All phone_numbers which can be used + # + def internal_extensions_and_dids + @internal_extensions_and_dids ||= self.phone_number_ranges_phone_numbers. + where(:phone_numberable_type => 'PhoneNumberRange'). + where(:phone_numberable_id => self.phone_number_ranges. + where(:name => [INTERNAL_EXTENSIONS, DIRECT_INWARD_DIALING_NUMBERS]). + map{|pnr| pnr.id }) + end + + def array_of_internal_extensions + @array_of_internal_extensions ||= self.phone_number_ranges_phone_numbers. + where(:phone_numberable_type => 'PhoneNumberRange'). + where(:phone_numberable_id => self.phone_number_ranges. + where(:name => INTERNAL_EXTENSIONS). + map{|pnr| pnr.id }). + map{|phone_number| phone_number.number }. + sort.uniq + end + + def array_of_dids + @array_of_dids ||= self.phone_number_ranges_phone_numbers. + where(:phone_numberable_type => 'PhoneNumberRange'). + where(:phone_numberable_id => self.phone_number_ranges.where(:name => DIRECT_INWARD_DIALING_NUMBERS).map{|pnr| pnr.id }). + map{|phone_number| phone_number.to_s }. + sort.uniq + end + + def array_of_assigned_phone_numbers + (self.phone_numbers + self.conferences_phone_numbers + + self.callthroughs_phone_numbers + self.huntgroups_phone_numbers + + self.fax_accounts_phone_numbers + self.users_phone_numbers + + self.user_groups_phone_numbers + self.users_conferences_phone_numbers + + self.users_fax_accounts_phone_numbers). + map{|phone_number| phone_number.number }. + sort.uniq + end + + def array_of_available_internal_extensions + (self.array_of_internal_extensions - self.array_of_assigned_phone_numbers).sort.uniq + end + + def array_of_available_dids + (self.array_of_dids - self.array_of_assigned_phone_numbers).sort.uniq + end + + def array_of_available_internal_extensions_and_dids + self.array_of_available_internal_extensions + self.array_of_available_dids + end + + private + + # Create a public phone book for this tenant + def create_a_default_phone_book + if self.name != SUPER_TENANT_NAME + general_phone_book = self.phone_books.find_or_create_by_name_and_description( + I18n.t('phone_books.general_phone_book.name'), + I18n.t('phone_books.general_phone_book.description', :resource => self.to_s) + ) + amooma = general_phone_book.phone_book_entries.create( + :organization => 'AMOOMA GmbH', + :is_organization => true, + :description => "Hersteller von Gemeinschaft. Rufen Sie uns an, falls Sie kommerziellen Support oder Consulting für Gemeinschaft benötigen.", + :homepage_organization => 'http://www.amooma.de', + :twitter_account => 'amooma_de', + :facebook_account => 'https://www.facebook.com/AMOOMA.GmbH', + ) + amooma.phone_numbers.create( + :name => 'Office', + :number => '+492622706480' + ) + amooma.addresses.create( + :street => 'Bachstr. 124', + :zip_code => '56566', + :city => 'Neuwied', + :country_id => Country.where(:country_code => 49).first.try(:id), + ) + end + end +end diff --git a/app/models/tenant_membership.rb b/app/models/tenant_membership.rb new file mode 100644 index 0000000..122f702 --- /dev/null +++ b/app/models/tenant_membership.rb @@ -0,0 +1,25 @@ +class TenantMembership < ActiveRecord::Base + belongs_to :tenant + belongs_to :user + + validates_presence_of :tenant + validates_presence_of :user + + after_create :set_current_tenant_if_necessary + + # State Machine stuff + default_scope where(:state => 'active') + state_machine :initial => :active do + end + + private + # The first TenantMembership becomes the current_tenant by default. + # + def set_current_tenant_if_necessary + if !self.user.current_tenant + self.user.current_tenant = self.tenant + self.user.save + end + end + +end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..2d0256f --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,208 @@ +require 'digest/sha2' + +class User < ActiveRecord::Base + after_create :create_a_default_phone_book, :if => :'is_native != false' + + # Sync other nodes when this is a cluster. + # + after_create :create_on_other_gs_nodes + after_destroy :destroy_on_other_gs_nodes + after_update :update_on_other_gs_nodes + + attr_accessible :user_name, :email, :password, :password_confirmation, + :first_name, :middle_name, :last_name, :male, + :image, :current_tenant_id, :language_id, + :new_pin, :new_pin_confirmation, :send_voicemail_as_email_attachment, + :importer_checksum, :gs_node_id + + attr_accessor :new_pin, :new_pin_confirmation + + before_validation { + # If the PIN and PIN confirmation are left blank in the GUI + # then the user/admin does not want to change the PIN. + if self.new_pin.blank? && self.new_pin_confirmation.blank? + self.new_pin = nil + self.new_pin_confirmation = nil + end + } + + validates_length_of [:new_pin, :new_pin_confirmation], + :minimum => MINIMUM_PIN_LENGTH, :maximum => MAXIMUM_PIN_LENGTH, + :allow_blank => true, :allow_nil => true + validates_format_of [:new_pin, :new_pin_confirmation], + :with => /^[0-9]+$/, + :allow_blank => true, :allow_nil => true, + :message => "must be numeric." + + validates_confirmation_of :new_pin, :if => :'pin_changed?' + before_save :hash_new_pin, :if => :'pin_changed?' + + has_secure_password + + validates_presence_of :password, :password_confirmation, :on => :create, :if => :'password_digest.blank?' + validates_presence_of :email + validates_presence_of :last_name + validates_presence_of :first_name + validates_presence_of :user_name + + validates_uniqueness_of :user_name, :case_sensitive => false + validates_uniqueness_of :email, :allow_nil => true, :case_sensitive => false + + validates_length_of :user_name, :within => 0..50 + + validates_presence_of :uuid + validates_uniqueness_of :uuid + + # Associations: + # + has_many :tenant_memberships, :dependent => :destroy + has_many :tenants, :through => :tenant_memberships + + has_many :user_group_memberships, :dependent => :destroy, :uniq => true + has_many :user_groups, :through => :user_group_memberships + + has_many :phone_books, :as => :phone_bookable, :dependent => :destroy + has_many :phone_book_entries, :through => :phone_books + + has_many :phones, :as => :phoneable + has_many :sip_accounts, :as => :sip_accountable, :dependent => :destroy + has_many :phone_numbers, :through => :sip_accounts + + has_many :conferences, :as => :conferenceable, :dependent => :destroy + + has_many :fax_accounts, :as => :fax_accountable, :dependent => :destroy + + has_many :system_messages, :dependent => :destroy + + has_many :auto_destroy_access_authorization_phone_numbers, :class_name => 'PhoneNumber', :foreign_key => 'access_authorization_user_id', :dependent => :destroy + + belongs_to :current_tenant, :class_name => 'Tenant' + validates_presence_of :current_tenant, :if => Proc.new{ |user| user.current_tenant_id } + + belongs_to :language + validates_presence_of :language_id + validates_presence_of :language + + validate :current_tenant_is_included_in_tenants, :if => Proc.new{ |user| user.current_tenant_id } + + belongs_to :gs_node + + # Avatar like photo + mount_uploader :image, ImageUploader + + before_save :format_email_and_user_name + + before_destroy :destroy_or_logout_phones + + def destroy + clean_whitelist_entries + super + end + + def pin_changed? + ! @new_pin.blank? + end + + def sip_domain + if self.current_tenant + return self.current_tenant.sip_domain + end + return nil + end + + def to_s + max_first_name_length = 10 + max_last_name_length = 20 + if self.first_name.blank? + self.last_name.strip + else + "#{self.first_name.strip} #{self.last_name.strip}" + end + end + + def self.find_user_by_phone_number( number, tenant ) + tenant = Tenant.where( :id => tenant.id ).first + if tenant + if tenant.sip_domain + user = tenant.sip_domain.sip_accounts. + joins(:phone_numbers). + where(:phone_numbers => { :number => number }). + first. + try(:sip_accountable) + if user.class.name == 'User' + return user + end + end + end + return nil + end + + def authenticate_by_pin?( entered_pin ) + self.pin_hash == Digest::SHA2.hexdigest( "#{self.pin_salt}#{entered_pin}" ) + end + + + private + + def hash_new_pin + if @new_pin \ + && @new_pin_confirmation \ + && @new_pin_confirmation == @new_pin + self.pin_salt = SecureRandom.base64(8) + self.pin_hash = Digest::SHA2.hexdigest(self.pin_salt + @new_pin) + end + end + + def format_email_and_user_name + self.email = self.email.downcase.strip if !self.email.blank? + self.user_name = self.user_name.downcase.strip if !self.user_name.blank? + end + + # Create a personal phone book for this user: + def create_a_default_phone_book + private_phone_book = self.phone_books.find_or_create_by_name_and_description( + I18n.t('phone_books.private_phone_book.name', :resource => self.to_s), + I18n.t('phone_books.private_phone_book.description') + ) + end + + # Check if a current_tenant_id is possible tenant_membership wise. + def current_tenant_is_included_in_tenants + if !self.tenants.include?(Tenant.find(self.current_tenant_id)) + errors.add(:current_tenant_id, "is not possible (no TenantMembership)") + end + end + + # Make sure that there are no whitelist entries with phone_numbers of + # a just destroyed user. + # + def clean_whitelist_entries + phone_numbers = PhoneNumber.where( :phone_numberable_type => 'Whitelist'). + where( :number => self.phone_numbers.map{ |x| x.number } ) + phone_numbers.each do |phone_number| + if phone_number.phone_numberable.whitelistable.class == Callthrough + whitelist = Whitelist.find(phone_number.phone_numberable) + phone_number.destroy + if whitelist.phone_numbers.count == 0 + # Very lickly that this Whitelist doesn't make sense any more. + # + whitelist.destroy + end + end + end + end + + # Make sure that a tenant phone goes back to the tenant and doesn't + # get deleted with this user. + # + def destroy_or_logout_phones + self.phones.each do |phone| + if phone.sip_accounts.where(:sip_accountable_type => 'Tenant').count > 0 + phone.user_logout + else + phone.destroy + end + end + end + +end diff --git a/app/models/user_group.rb b/app/models/user_group.rb new file mode 100644 index 0000000..44f2fd8 --- /dev/null +++ b/app/models/user_group.rb @@ -0,0 +1,33 @@ +class UserGroup < ActiveRecord::Base + attr_accessible :name, :description + + belongs_to :tenant + + validates_presence_of :name + validates_uniqueness_of :name, :scope => :tenant_id + + validates_presence_of :tenant + + validates_length_of :name, :within => 1..50 + + has_many :user_group_memberships, :dependent => :destroy, :uniq => true + has_many :users, :through => :user_group_memberships + + has_many :gui_function_memberships, :dependent => :destroy + has_many :gui_functions, :through => :gui_function_memberships + + has_many :phone_books, :as => :phone_bookable, :dependent => :destroy + has_many :phone_book_entries, :through => :phone_books + + has_many :sip_accounts, :as => :sip_accountable, :dependent => :destroy + + has_many :conferences, :as => :conferenceable, :dependent => :destroy + + has_many :fax_accounts, :as => :fax_accountable, :dependent => :destroy + + acts_as_list :scope => :tenant_id + + def to_s + name + end +end diff --git a/app/models/user_group_membership.rb b/app/models/user_group_membership.rb new file mode 100644 index 0000000..18a8d48 --- /dev/null +++ b/app/models/user_group_membership.rb @@ -0,0 +1,26 @@ +class UserGroupMembership < ActiveRecord::Base + belongs_to :user + belongs_to :user_group + + validates_uniqueness_of :user_id, :scope => :user_group_id + validates_presence_of :user + validates_presence_of :user_group + + validate :user_belongs_to_the_tenant_of_the_user_group + + # State Machine stuff + default_scope where(:state => 'active') + state_machine :initial => :active do + end + + def to_s + "#{self.user} / #{self.user_group}" + end + + private + def user_belongs_to_the_tenant_of_the_user_group + if !self.user_group.tenant.users.include?(self.user) + errors.add(:user_id, "not a member of the tenant which this group belongs to") + end + end +end diff --git a/app/models/voicemail_message.rb b/app/models/voicemail_message.rb new file mode 100644 index 0000000..91ba457 --- /dev/null +++ b/app/models/voicemail_message.rb @@ -0,0 +1,52 @@ +class VoicemailMessage < ActiveRecord::Base + self.table_name = 'voicemail_msgs' + self.primary_key = 'uuid' + +# belongs_to :sip_account, :foreign_key => 'username', :primary_key => 'auth_name', :readonly => true + # Prevent objects from being destroyed + def before_destroy + raise ActiveRecord::ReadOnlyRecord + end + + # Prevent objects from being deleted + def self.delete_all + raise ActiveRecord::ReadOnlyRecord + end + + # Delete Message on FreeSWITCH over EventAPI + def delete + require 'freeswitch_event' + result = FreeswitchAPI.execute('vm_delete', "#{self.username}@#{self.domain} #{self.uuid}"); + end + + # Alias for delete + def destroy + self.delete + end + + # Mark Message read + def mark_read(mark_read_or_unread = true) + read_status = mark_read_or_unread ? 'read' : 'unread' + require 'freeswitch_event' + result = FreeswitchAPI.execute('vm_read', "#{self.username}@#{self.domain} #{read_status} #{self.uuid}"); + end + + def format_date(epoch, date_format = '%m/%d/%Y %H:%M', date_today_format = '%H:%M') + if epoch && epoch > 0 + time = Time.at(epoch) + if time.strftime('%Y%m%d') == Time.now.strftime('%Y%m%d') + return time.in_time_zone.strftime(date_today_format) + end + return time.in_time_zone.strftime(date_format) + end + end + + def display_duration + if self.message_len.to_i > 0 + minutes = (self.message_len / 1.minutes).to_i + seconds = self.message_len - minutes.minutes.seconds + return '%i:%02i' % [minutes, seconds] + end + end + +end diff --git a/app/models/voicemail_setting.rb b/app/models/voicemail_setting.rb new file mode 100644 index 0000000..a8bb304 --- /dev/null +++ b/app/models/voicemail_setting.rb @@ -0,0 +1,12 @@ +class VoicemailSetting < ActiveRecord::Base + self.table_name = 'voicemail_prefs' + self.primary_key = 'username' + + attr_accessible :username, :domain, :name_path, :greeting_path, :password, :notify, :attachment, :mark_read, :purge, :sip_account + + has_one :sip_account, :foreign_key => 'auth_name' + + validates_presence_of :username + validates_presence_of :domain + validates :username, :uniqueness => {:scope => :domain} +end diff --git a/app/models/whitelist.rb b/app/models/whitelist.rb new file mode 100644 index 0000000..8303728 --- /dev/null +++ b/app/models/whitelist.rb @@ -0,0 +1,23 @@ +class Whitelist < ActiveRecord::Base + attr_accessible :name, :phone_numbers_attributes, :uuid + + belongs_to :whitelistable, :polymorphic => true + + # These are the phone_numbers for this whitelist. + # + has_many :phone_numbers, :as => :phone_numberable, :dependent => :destroy + + accepts_nested_attributes_for :phone_numbers, + :reject_if => lambda { |phone_number| phone_number[:number].blank? }, + :allow_destroy => true + + acts_as_list :scope => [ :whitelistable_type, :whitelistable_id ] + + validates_presence_of :uuid + validates_uniqueness_of :uuid + + def to_s + self.name || I18n.t('whitelists.name') + ' ID ' + self.id.to_s + end + +end diff --git a/app/uploaders/audio_uploader.rb b/app/uploaders/audio_uploader.rb new file mode 100644 index 0000000..2ddbeac --- /dev/null +++ b/app/uploaders/audio_uploader.rb @@ -0,0 +1,49 @@ +# encoding: utf-8 + +class AudioUploader < CarrierWave::Uploader::Base + + # Include RMagick or ImageScience support: + # include CarrierWave::RMagick + # include CarrierWave::MiniMagick + # include CarrierWave::ImageScience + + # Choose what kind of storage to use for this uploader: + storage :file + # storage :fog + + # Override the directory where uploaded files will be stored. + # This is a sensible default for uploaders that are meant to be mounted: + def store_dir + "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" + end + + # Provide a default URL as a default if there hasn't been a file uploaded: + # def default_url + # "/images/fallback/" + [version_name, "default.png"].compact.join('_') + # end + + # Process files as they are uploaded: + # process :scale => [200, 300] + # + # def scale(width, height) + # # do something + # end + + # Create different versions of your uploaded files: + # version :thumb do + # process :scale => [50, 50] + # end + + # Add a white list of extensions which are allowed to be uploaded. + # For images you might use something like this: + # def extension_white_list + # %w(jpg jpeg gif png) + # end + + # Override the filename of the uploaded files: + # Avoid using model.id or version_name here, see uploader/store.rb for details. + # def filename + # "something.jpg" if original_filename + # end + +end diff --git a/app/uploaders/document_uploader.rb b/app/uploaders/document_uploader.rb new file mode 100644 index 0000000..05d70ca --- /dev/null +++ b/app/uploaders/document_uploader.rb @@ -0,0 +1,49 @@ +# encoding: utf-8 + +class DocumentUploader < CarrierWave::Uploader::Base + + # Include RMagick or ImageScience support: + # include CarrierWave::RMagick + include CarrierWave::MiniMagick + # include CarrierWave::ImageScience + + # Choose what kind of storage to use for this uploader: + storage :file + # storage :fog + + # Override the directory where uploaded files will be stored. + # This is a sensible default for uploaders that are meant to be mounted: + def store_dir + "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" + end + + # Provide a default URL as a default if there hasn't been a file uploaded: + # def default_url + # "/images/fallback/" + [version_name, "default.png"].compact.join('_') + # end + + # Process files as they are uploaded: + # process :scale => [200, 300] + # + # def scale(width, height) + # # do something + # end + + # Create different versions of your uploaded files: + # version :thumb do + # process :scale => [50, 50] + # end + + # Add a white list of extensions which are allowed to be uploaded. + # For images you might use something like this: + def extension_white_list + %w(pdf) + end + + # Override the filename of the uploaded files: + # Avoid using model.id or version_name here, see uploader/store.rb for details. + # def filename + # "something.jpg" if original_filename + # end + +end diff --git a/app/uploaders/image_uploader.rb b/app/uploaders/image_uploader.rb new file mode 100644 index 0000000..114ccc6 --- /dev/null +++ b/app/uploaders/image_uploader.rb @@ -0,0 +1,63 @@ +# encoding: utf-8 + +class ImageUploader < CarrierWave::Uploader::Base + + # Include RMagick or ImageScience support: + # include CarrierWave::RMagick + include CarrierWave::MiniMagick + # include CarrierWave::ImageScience + + # Choose what kind of storage to use for this uploader: + storage :file + # storage :fog + + # Override the directory where uploaded files will be stored. + # This is a sensible default for uploaders that are meant to be mounted: + def store_dir + "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" + end + + # Provide a default URL as a default if there hasn't been a file uploaded: + def default_url + "/images/fallback/" + [version_name, "default.jpg"].compact.join('_') + end + + # Process files as they are uploaded: + # process :scale => [200, 300] + # + # def scale(width, height) + # # do something + # end + + # Create different versions of your uploaded files: + version :mini do + process :resize_to_fill => [32, 32] + end + + version :small do + process :resize_to_fill => [72, 72] + end + + version :profile do + process :resize_to_fill => [200, 200] + end + + version :snom_caller_picture do + process :resize_to_fill => [100, 135] + end + + # Add a white list of extensions which are allowed to be uploaded. + # For images you might use something like this: + def extension_white_list + %w(jpg jpeg gif png) + end + + # Override the filename of the uploaded files: + # Avoid using model.id or version_name here, see uploader/store.rb for details. + # def filename + # "something.jpg" if original_filename + # end + + # TODO Secure filename + +end diff --git a/app/uploaders/thumbnail_uploader.rb b/app/uploaders/thumbnail_uploader.rb new file mode 100644 index 0000000..a401a91 --- /dev/null +++ b/app/uploaders/thumbnail_uploader.rb @@ -0,0 +1,62 @@ +# encoding: utf-8 + +class ThumbnailUploader < CarrierWave::Uploader::Base + + # Include RMagick or ImageScience support: + # include CarrierWave::RMagick + include CarrierWave::MiniMagick + # include CarrierWave::ImageScience + + # Choose what kind of storage to use for this uploader: + storage :file + # storage :fog + + # Override the directory where uploaded files will be stored. + # This is a sensible default for uploaders that are meant to be mounted: + def store_dir + "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" + end + + # Provide a default URL as a default if there hasn't been a file uploaded: + # def default_url + # "/images/fallback/" + [version_name, "default.png"].compact.join('_') + # end + + # Process files as they are uploaded: + # process :scale => [200, 300] + # + # def scale(width, height) + # # do something + # end + + # Create different versions of your uploaded files: + version :mini do + process :resize_to_limit => [75, 75] + end + + version :thumb do + process :resize_to_limit => [150, 150] + end + + version :medium do + process :resize_to_limit => [400, 400] + end + + version :big do + process :resize_to_limit => [800, 800] + end + + + # Add a white list of extensions which are allowed to be uploaded. + # For images you might use something like this: + def extension_white_list + %w(png) + end + + # Override the filename of the uploaded files: + # Avoid using model.id or version_name here, see uploader/store.rb for details. + # def filename + # "something.jpg" if original_filename + # end + +end diff --git a/app/uploaders/tiff_uploader.rb b/app/uploaders/tiff_uploader.rb new file mode 100644 index 0000000..d482aed --- /dev/null +++ b/app/uploaders/tiff_uploader.rb @@ -0,0 +1,49 @@ +# encoding: utf-8 + +class TiffUploader < CarrierWave::Uploader::Base + + # Include RMagick or ImageScience support: + # include CarrierWave::RMagick + # include CarrierWave::MiniMagick + # include CarrierWave::ImageScience + + # Choose what kind of storage to use for this uploader: + storage :file + # storage :fog + + # Override the directory where uploaded files will be stored. + # This is a sensible default for uploaders that are meant to be mounted: + def store_dir + "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" + end + + # Provide a default URL as a default if there hasn't been a file uploaded: + # def default_url + # "/images/fallback/" + [version_name, "default.png"].compact.join('_') + # end + + # Process files as they are uploaded: + # process :scale => [200, 300] + # + # def scale(width, height) + # # do something + # end + + # Create different versions of your uploaded files: + # version :thumb do + # process :scale => [50, 50] + # end + + # Add a white list of extensions which are allowed to be uploaded. + # For images you might use something like this: + # def extension_white_list + # %w(jpg jpeg gif png) + # end + + # Override the filename of the uploaded files: + # Avoid using model.id or version_name here, see uploader/store.rb for details. + # def filename + # "something.jpg" if original_filename + # end + +end diff --git a/app/views/access_authorizations/_form.html.haml b/app/views/access_authorizations/_form.html.haml new file mode 100644 index 0000000..fa417d9 --- /dev/null +++ b/app/views/access_authorizations/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([@parent, @access_authorization]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('access_authorizations.form.submit') \ No newline at end of file diff --git a/app/views/access_authorizations/_form_core.html.haml b/app/views/access_authorizations/_form_core.html.haml new file mode 100644 index 0000000..10530d7 --- /dev/null +++ b/app/views/access_authorizations/_form_core.html.haml @@ -0,0 +1,11 @@ +.inputs + = f.input :name, :label => t('access_authorizations.form.name.label'), :hint => conditional_hint('access_authorizations.form.name.hint') + = f.input :login, :label => t('access_authorizations.form.login.label'), :hint => conditional_hint('access_authorizations.form.login.hint') + = f.input :pin, :label => t('access_authorizations.form.pin.label'), :hint => conditional_hint('access_authorizations.form.pin.hint') + - if SipAccount.count < 50 + = f.association :sip_account, :label => t('callthroughs.form.sip_account.label'), :hint => conditional_hint('callthroughs.form.sip_account.hint') + - else + = f.input :sip_account_id, :label => t('callthroughs.form.sip_account_id.label'), :hint => conditional_hint('callthroughs.form.sip_account_id.hint') + + = f.simple_fields_for :phone_numbers do |phone_number| + = render "phone_numbers/form_core", :f => phone_number \ No newline at end of file diff --git a/app/views/access_authorizations/_index_core.html.haml b/app/views/access_authorizations/_index_core.html.haml new file mode 100644 index 0000000..083b16b --- /dev/null +++ b/app/views/access_authorizations/_index_core.html.haml @@ -0,0 +1,21 @@ +%table + %tr + %th= t('access_authorizations.index.name') + %th= t('access_authorizations.index.login') + %th= t('access_authorizations.index.pin') + %th= t('callthroughs.index.phone_numbers') + + - reset_cycle + - for access_authorization in access_authorizations + - show_path_method = method( :"#{access_authorization.access_authorizationable.class.name.underscore}_access_authorization_path" ) + - edit_path_method = method( :"edit_#{access_authorization.access_authorizationable.class.name.underscore}_access_authorization_path" ) + %tr{:class => cycle('odd', 'even')} + %td= access_authorization.name + %td= access_authorization.login + %td= access_authorization.pin + %td + =render 'phone_numbers/listing', :phone_numbers => access_authorization.phone_numbers + - if access_authorization.phone_numbers.count > 0 + %br + = link_to t('phone_numbers.index.actions.create'), new_access_authorization_phone_number_path(access_authorization) + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => access_authorization.access_authorizationable, :child => access_authorization} \ No newline at end of file diff --git a/app/views/access_authorizations/edit.html.haml b/app/views/access_authorizations/edit.html.haml new file mode 100644 index 0000000..414f094 --- /dev/null +++ b/app/views/access_authorizations/edit.html.haml @@ -0,0 +1,3 @@ +- title t("access_authorizations.edit.page_title") + += render "form" diff --git a/app/views/access_authorizations/index.html.haml b/app/views/access_authorizations/index.html.haml new file mode 100644 index 0000000..05b27db --- /dev/null +++ b/app/views/access_authorizations/index.html.haml @@ -0,0 +1,6 @@ +- title t("access_authorizations.index.page_title") + +- if @access_authorizations.count > 0 + = render "index_core", :access_authorizations => @access_authorizations + += render :partial => 'shared/create_link', :locals => {:parent => @parent, :child_class => AccessAuthorization} \ No newline at end of file diff --git a/app/views/access_authorizations/new.html.haml b/app/views/access_authorizations/new.html.haml new file mode 100644 index 0000000..0bbf16c --- /dev/null +++ b/app/views/access_authorizations/new.html.haml @@ -0,0 +1,3 @@ +- title t("access_authorizations.new.page_title") + += render "form" diff --git a/app/views/access_authorizations/show.html.haml b/app/views/access_authorizations/show.html.haml new file mode 100644 index 0000000..17d1d9b --- /dev/null +++ b/app/views/access_authorizations/show.html.haml @@ -0,0 +1,22 @@ +- title t("access_authorizations.show.page_title") + +%p + %strong= t('access_authorizations.show.name') + ":" + = @access_authorization.name +%p + %strong= t('access_authorizations.show.login') + ":" + = @access_authorization.login +%p + %strong= t('access_authorizations.show.pin') + ":" + = @access_authorization.pin +%p + %strong= t('access_authorizations.show.sip_account_id') + ":" + = @access_authorization.sip_account || t('access_authorizations.none') + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @parent, :child => @access_authorization } + +%h2= t('callthroughs.form.phone_numbers.label') +- if @access_authorization.phone_numbers.count > 0 + = render 'phone_numbers/index_core', :phone_numbers => @access_authorization.phone_numbers + %br += render :partial => 'shared/create_link', :locals => {:parent => @access_authorization, :child_class => PhoneNumber} \ No newline at end of file diff --git a/app/views/acd_agents/_form.html.haml b/app/views/acd_agents/_form.html.haml new file mode 100644 index 0000000..3b78bac --- /dev/null +++ b/app/views/acd_agents/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([@automatic_call_distributor, @acd_agent]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('acd_agents.form.submit') \ No newline at end of file diff --git a/app/views/acd_agents/_form_core.html.haml b/app/views/acd_agents/_form_core.html.haml new file mode 100644 index 0000000..ab4657c --- /dev/null +++ b/app/views/acd_agents/_form_core.html.haml @@ -0,0 +1,7 @@ +.inputs + = f.input :name, :label => t('acd_agents.form.name.label'), :hint => conditional_hint('acd_agents.form.name.hint') + = f.input :status, :label => t('acd_agents.form.status.label'), :hint => conditional_hint('acd_agents.form.status.hint'), :include_blank => false, :collection => AcdAgent::STATUSES + = f.input :last_call, :label => t('acd_agents.form.last_call.label'), :hint => conditional_hint('acd_agents.form.last_call.hint') + = f.input :calls_answered, :label => t('acd_agents.form.calls_answered.label'), :hint => conditional_hint('acd_agents.form.calls_answered.hint') + = f.input :destination_type, :label => t('acd_agents.form.destination_type.label'), :hint => conditional_hint('acd_agents.form.destination_type.hint'), :include_blank => false, :collection => AcdAgent::DESTINATION_TYPES + = f.input :destination_id, :label => t('acd_agents.form.destination_id.label'), :hint => conditional_hint('acd_agents.form.destination_id.hint') diff --git a/app/views/acd_agents/_index_core.html.haml b/app/views/acd_agents/_index_core.html.haml new file mode 100644 index 0000000..7cb1aae --- /dev/null +++ b/app/views/acd_agents/_index_core.html.haml @@ -0,0 +1,18 @@ +%table + %tr + %th= t('acd_agents.index.name') + %th= t('acd_agents.index.status') + %th= t('acd_agents.index.last_call') + %th= t('acd_agents.index.calls_answered') + %th= t('acd_agents.index.destination') + + - reset_cycle + - for acd_agent in acd_agents + %tr{:class => cycle('odd', 'even')} + %td= acd_agent.name + %td= acd_agent.status + %td= acd_agent.last_call + %td= acd_agent.calls_answered + %td= acd_agent.destination + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => acd_agent.automatic_call_distributor, :child => acd_agent} + \ No newline at end of file diff --git a/app/views/acd_agents/_listing.html.haml b/app/views/acd_agents/_listing.html.haml new file mode 100644 index 0000000..0495ec2 --- /dev/null +++ b/app/views/acd_agents/_listing.html.haml @@ -0,0 +1,8 @@ +- amount_of_acd_agents = acd_agents.count +- if amount_of_acd_agents > 0 + - if amount_of_acd_agents < 30 + = acd_agents.map{|acd_agent| acd_agent}.join(', ') + - else + = acd_agents.limit(15).map{|acd_agent| acd_agent}.join(', ') + ', ' + = '[...]' + = acd_agents.offset(amount_of_acd_agents - 15).map{|acd_agent| acd_agent}.join(', ') \ No newline at end of file diff --git a/app/views/acd_agents/edit.html.haml b/app/views/acd_agents/edit.html.haml new file mode 100644 index 0000000..8ab14b8 --- /dev/null +++ b/app/views/acd_agents/edit.html.haml @@ -0,0 +1,3 @@ +- title t("acd_agents.edit.page_title") + += render "form" \ No newline at end of file diff --git a/app/views/acd_agents/index.html.haml b/app/views/acd_agents/index.html.haml new file mode 100644 index 0000000..d586dcf --- /dev/null +++ b/app/views/acd_agents/index.html.haml @@ -0,0 +1,6 @@ +- title t("acd_agents.index.page_title") + +- if @acd_agents && @acd_agents.count > 0 + = render "index_core", :acd_agents => @acd_agents + += render :partial => 'shared/create_link', :locals => {:parent => @automatic_call_distributor, :child_class => AcdAgent} diff --git a/app/views/acd_agents/new.html.haml b/app/views/acd_agents/new.html.haml new file mode 100644 index 0000000..546136b --- /dev/null +++ b/app/views/acd_agents/new.html.haml @@ -0,0 +1,3 @@ +- title t("acd_agents.new.page_title") + += render "form" \ No newline at end of file diff --git a/app/views/acd_agents/show.html.haml b/app/views/acd_agents/show.html.haml new file mode 100644 index 0000000..97881f6 --- /dev/null +++ b/app/views/acd_agents/show.html.haml @@ -0,0 +1,28 @@ +- title t("acd_agents.show.page_title") + +%p + %strong= t('acd_agents.show.uuid') + ":" + = @acd_agent.uuid +%p + %strong= t('acd_agents.show.name') + ":" + = @acd_agent.name +%p + %strong= t('acd_agents.show.status') + ":" + = @acd_agent.status +%p + %strong= t('acd_agents.show.automatic_call_distributor_id') + ":" + = @acd_agent.automatic_call_distributor_id +%p + %strong= t('acd_agents.show.last_call') + ":" + = @acd_agent.last_call +%p + %strong= t('acd_agents.show.calls_answered') + ":" + = @acd_agent.calls_answered +%p + %strong= t('acd_agents.show.destination_type') + ":" + = @acd_agent.destination_type +%p + %strong= t('acd_agents.show.destination_id') + ":" + = @acd_agent.destination_id + += render :partial => 'shared/show_edit_destroy_part', :locals => {:parent => @automatic_call_distributor, :child => @acd_agent } \ No newline at end of file diff --git a/app/views/acd_callers/_index_core.html.haml b/app/views/acd_callers/_index_core.html.haml new file mode 100644 index 0000000..958b3ff --- /dev/null +++ b/app/views/acd_callers/_index_core.html.haml @@ -0,0 +1,21 @@ +%table + %tr + %th= t('acd_callers.index.channel_uuid') + %th= t('acd_callers.index.automatic_call_distributor_id') + %th= t('acd_callers.index.status') + %th= t('acd_callers.index.enter_time') + %th= t('acd_callers.index.agent_answer_time') + %th= t('acd_callers.index.callback_number') + %th= t('acd_callers.index.callback_attempts') + + - reset_cycle + - for acd_caller in acd_callers + %tr{:class => cycle('odd', 'even')} + %td= acd_caller.channel_uuid + %td= acd_caller.automatic_call_distributor_id + %td= acd_caller.status + %td= acd_caller.enter_time + %td= acd_caller.agent_answer_time + %td= acd_caller.callback_number + %td= acd_caller.callback_attempts + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:child => acd_caller} \ No newline at end of file diff --git a/app/views/acd_callers/index.html.haml b/app/views/acd_callers/index.html.haml new file mode 100644 index 0000000..70439ed --- /dev/null +++ b/app/views/acd_callers/index.html.haml @@ -0,0 +1,6 @@ +- title t("acd_callers.index.page_title") + +- if @acd_callers && @acd_callers.count > 0 + = render "index_core", :acd_callers => @acd_callers + += render :partial => 'shared/create_link', :locals => {:child_class => AcdCaller} \ No newline at end of file diff --git a/app/views/acd_callers/show.html.haml b/app/views/acd_callers/show.html.haml new file mode 100644 index 0000000..0ce8345 --- /dev/null +++ b/app/views/acd_callers/show.html.haml @@ -0,0 +1,25 @@ +- title t("acd_callers.show.page_title") + +%p + %strong= t('acd_callers.show.channel_uuid') + ":" + = @acd_caller.channel_uuid +%p + %strong= t('acd_callers.show.automatic_call_distributor_id') + ":" + = @acd_caller.automatic_call_distributor_id +%p + %strong= t('acd_callers.show.status') + ":" + = @acd_caller.status +%p + %strong= t('acd_callers.show.enter_time') + ":" + = @acd_caller.enter_time +%p + %strong= t('acd_callers.show.agent_answer_time') + ":" + = @acd_caller.agent_answer_time +%p + %strong= t('acd_callers.show.callback_number') + ":" + = @acd_caller.callback_number +%p + %strong= t('acd_callers.show.callback_attempts') + ":" + = @acd_caller.callback_attempts + += render :partial => 'shared/show_edit_destroy_part', :locals => { :child => @acd_caller } \ No newline at end of file diff --git a/app/views/addresses/_form.html.haml b/app/views/addresses/_form.html.haml new file mode 100644 index 0000000..eff9930 --- /dev/null +++ b/app/views/addresses/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for(@address) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('addresses.form.submit') \ No newline at end of file diff --git a/app/views/addresses/_form_core.html.haml b/app/views/addresses/_form_core.html.haml new file mode 100644 index 0000000..f01ac1c --- /dev/null +++ b/app/views/addresses/_form_core.html.haml @@ -0,0 +1,9 @@ +.inputs + = f.input :phone_book_entry_id, :label => t('addresses.form.phone_book_entry_id.label'), :hint => conditional_hint('addresses.form.phone_book_entry_id.hint') + = f.input :line1, :label => t('addresses.form.line1.label'), :hint => conditional_hint('addresses.form.line1.hint') + = f.input :line2, :label => t('addresses.form.line2.label'), :hint => conditional_hint('addresses.form.line2.hint') + = f.input :street, :label => t('addresses.form.street.label'), :hint => conditional_hint('addresses.form.street.hint') + = f.input :zip_code, :label => t('addresses.form.zip_code.label'), :hint => conditional_hint('addresses.form.zip_code.hint') + = f.input :city, :label => t('addresses.form.city.label'), :hint => conditional_hint('addresses.form.city.hint') + = f.input :country_id, :label => t('addresses.form.country_id.label'), :hint => conditional_hint('addresses.form.country_id.hint') + = f.input :position, :label => t('addresses.form.position.label'), :hint => conditional_hint('addresses.form.position.hint') diff --git a/app/views/addresses/_index_core.html.haml b/app/views/addresses/_index_core.html.haml new file mode 100644 index 0000000..2050ded --- /dev/null +++ b/app/views/addresses/_index_core.html.haml @@ -0,0 +1,23 @@ +%table + %tr + %th= t('addresses.index.phone_book_entry_id') + %th= t('addresses.index.line1') + %th= t('addresses.index.line2') + %th= t('addresses.index.street') + %th= t('addresses.index.zip_code') + %th= t('addresses.index.city') + %th= t('addresses.index.country_id') + %th= t('addresses.index.position') + + - reset_cycle + - for address in addresses + %tr{:class => cycle('odd', 'even')} + %td= address.phone_book_entry_id + %td= address.line1 + %td= address.line2 + %td= address.street + %td= address.zip_code + %td= address.city + %td= address.country_id + %td= address.position + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => address.phone_book_entry, :child => address} \ No newline at end of file diff --git a/app/views/addresses/edit.html.haml b/app/views/addresses/edit.html.haml new file mode 100644 index 0000000..3d85ae6 --- /dev/null +++ b/app/views/addresses/edit.html.haml @@ -0,0 +1,9 @@ +- title t("addresses.edit.page_title") + += render "form" + +%p + - if can? :edit, @address + = link_to t('addresses.edit.actions.edit'), @address + | + = link_to t('addresses.edit.actions.view_all'), addresses_path diff --git a/app/views/addresses/index.html.haml b/app/views/addresses/index.html.haml new file mode 100644 index 0000000..ecebc65 --- /dev/null +++ b/app/views/addresses/index.html.haml @@ -0,0 +1,6 @@ +- title t("addresses.index.page_title") + +- if @addresses.count > 0 + = render "index_core", :addresses => @addresses + += render :partial => 'shared/create_link', :locals => {:child_class => Address} \ No newline at end of file diff --git a/app/views/addresses/new.html.haml b/app/views/addresses/new.html.haml new file mode 100644 index 0000000..280de55 --- /dev/null +++ b/app/views/addresses/new.html.haml @@ -0,0 +1,3 @@ +- title t("addresses.new.page_title") + += render "form" diff --git a/app/views/addresses/show.html.haml b/app/views/addresses/show.html.haml new file mode 100644 index 0000000..211d020 --- /dev/null +++ b/app/views/addresses/show.html.haml @@ -0,0 +1,28 @@ +- title t("addresses.show.page_title") + +%p + %strong= t('addresses.show.phone_book_entry_id') + ":" + = @address.phone_book_entry_id +%p + %strong= t('addresses.show.line1') + ":" + = @address.line1 +%p + %strong= t('addresses.show.line2') + ":" + = @address.line2 +%p + %strong= t('addresses.show.street') + ":" + = @address.street +%p + %strong= t('addresses.show.zip_code') + ":" + = @address.zip_code +%p + %strong= t('addresses.show.city') + ":" + = @address.city +%p + %strong= t('addresses.show.country_id') + ":" + = @address.country_id +%p + %strong= t('addresses.show.position') + ":" + = @address.position + += render :partial => 'shared/show_edit_destroy_part', :locals => { :child => @address } \ No newline at end of file diff --git a/app/views/api/rows/_form.html.erb b/app/views/api/rows/_form.html.erb new file mode 100644 index 0000000..465b105 --- /dev/null +++ b/app/views/api/rows/_form.html.erb @@ -0,0 +1,21 @@ +<%= simple_form_for(@row) do |f| %> + <%= f.error_notification %> + +
    + <%= f.input :user_name %> + <%= f.input :last_name %> + <%= f.input :middle_name %> + <%= f.input :first_name %> + <%= f.input :office_phone_number %> + <%= f.input :internal_extension %> + <%= f.input :mobile_phone_number %> + <%= f.input :fax_phone_number %> + <%= f.input :email %> + <%= f.input :pin %> + <%= f.input :photo_file_name %> +
    + +
    + <%= f.button :submit %> +
    +<% end %> diff --git a/app/views/api/rows/edit.html.erb b/app/views/api/rows/edit.html.erb new file mode 100644 index 0000000..bce5694 --- /dev/null +++ b/app/views/api/rows/edit.html.erb @@ -0,0 +1,3 @@ +

    Editing row

    + +<%= render 'form' %> \ No newline at end of file diff --git a/app/views/api/rows/index.html.erb b/app/views/api/rows/index.html.erb new file mode 100644 index 0000000..d65e059 --- /dev/null +++ b/app/views/api/rows/index.html.erb @@ -0,0 +1,29 @@ +

    Listing rows

    + + + + + + + + + + + + + + +<% @rows.each do |row| %> + '> + + + + + + + + + + +<% end %> +
    IDUser nameLast nameFirst nameInternal extensionOffice phone numberFax phone numberEmailPin
    <%= row.id %><%= link_to row.user_name, tenant_user_path(row.user.current_tenant, row.user) %><%= row.last_name %><%= row.first_name %><%= row.internal_extension %><%= row.office_phone_number %><%= row.fax_phone_number %><%= row.email %><%= row.pin %>
    \ No newline at end of file diff --git a/app/views/api/rows/new.html.erb b/app/views/api/rows/new.html.erb new file mode 100644 index 0000000..fccd964 --- /dev/null +++ b/app/views/api/rows/new.html.erb @@ -0,0 +1,3 @@ +

    New row

    + +<%= render 'form' %> \ No newline at end of file diff --git a/app/views/api/rows/show.html.erb b/app/views/api/rows/show.html.erb new file mode 100644 index 0000000..aad60b5 --- /dev/null +++ b/app/views/api/rows/show.html.erb @@ -0,0 +1,56 @@ +

    <%= notice %>

    + +

    + User name: + <%= @row.user_name %> +

    + +

    + Last name: + <%= @row.last_name %> +

    + +

    + Middle name: + <%= @row.middle_name %> +

    + +

    + First name: + <%= @row.first_name %> +

    + +

    + Office phone number: + <%= @row.office_phone_number %> +

    + +

    + Internal extension: + <%= @row.internal_extension %> +

    + +

    + Mobile phone number: + <%= @row.mobile_phone_number %> +

    + +

    + Fax phone number: + <%= @row.fax_phone_number %> +

    + +

    + Email: + <%= @row.email %> +

    + +

    + Pin: + <%= @row.pin %> +

    + +

    + Photo file name: + <%= @row.photo_file_name %> +

    \ No newline at end of file diff --git a/app/views/automatic_call_distributors/_form.html.haml b/app/views/automatic_call_distributors/_form.html.haml new file mode 100644 index 0000000..fcf133c --- /dev/null +++ b/app/views/automatic_call_distributors/_form.html.haml @@ -0,0 +1,8 @@ += simple_form_for([@parent, @automatic_call_distributor]) do |f| + = f.error_notification + + = render "form_core", :f => f, :join_on => @join_on, :leave_on => @leave_on, :strategies => @strategies + + + .actions + = f.button :submit, conditional_t('automatic_call_distributors.form.submit') \ No newline at end of file diff --git a/app/views/automatic_call_distributors/_form_core.html.haml b/app/views/automatic_call_distributors/_form_core.html.haml new file mode 100644 index 0000000..77a38a6 --- /dev/null +++ b/app/views/automatic_call_distributors/_form_core.html.haml @@ -0,0 +1,16 @@ +.inputs + = f.input :name, :label => t('automatic_call_distributors.form.name.label'), :hint => conditional_hint('automatic_call_distributors.form.name.hint') + = f.input :strategy, :label => t('automatic_call_distributors.form.strategy.label'), :hint => conditional_hint('automatic_call_distributors.form.strategy.hint'), :include_blank => false, :as => :select, :collection => strategies + = f.input :max_callers, :label => t('automatic_call_distributors.form.max_callers.label'), :hint => conditional_hint('automatic_call_distributors.form.max_callers.hint') + = f.input :agent_timeout, :label => t('automatic_call_distributors.form.agent_timeout.label'), :hint => conditional_hint('automatic_call_distributors.form.agent_timeout.hint') + = f.input :retry_timeout, :label => t('automatic_call_distributors.form.retry_timeout.label'), :hint => conditional_hint('automatic_call_distributors.form.retry_timeout.hint') + = f.input :join, :label => t('automatic_call_distributors.form.join.label'), :hint => conditional_hint('automatic_call_distributors.form.join.hint'), :include_blank => false, :as => :select, :collection => join_on + = f.input :leave, :label => t('automatic_call_distributors.form.leave.label'), :hint => conditional_hint('automatic_call_distributors.form.leave.hint'), :include_blank => false, :as => :select, :collection => leave_on + + = f.input :announce_position, :label => t('automatic_call_distributors.form.announce_position.label'), :hint => conditional_hint('automatic_call_distributors.announce_position.hint'), :collection => [[t('automatic_call_distributors.announce_position.on_change_only'), 0],[t('automatic_call_distributors.announce_position.never'), nil],[t('automatic_call_distributors.announce_position.every_x_seconds', :x_seconds => 30), 30],[t('automatic_call_distributors.announce_position.every_x_seconds', :x_seconds => 60), 60], [t('automatic_call_distributors.announce_position.every_x_seconds', :x_seconds => 120), 120], [t('automatic_call_distributors.announce_position.every_x_seconds', :x_seconds => 300), 300], [t('automatic_call_distributors.announce_position.every_x_seconds', :x_seconds => 600), 600]], :include_blank => false + + = f.input :announce_call_agents, :label => t('automatic_call_distributors.form.announce_call_agents.label'), :hint => conditional_hint('automatic_call_distributors.form.announce_call_agents.hint') + = f.input :greeting, :label => t('automatic_call_distributors.form.greeting.label'), :hint => conditional_hint('automatic_call_distributors.form.greeting.hint') + = f.input :goodbye, :label => t('automatic_call_distributors.form.goodbye.label'), :hint => conditional_hint('automatic_call_distributors.form.goodbye.hint') + = f.input :music, :label => t('automatic_call_distributors.form.music.label'), :hint => conditional_hint('automatic_call_distributors.form.music.hint') + \ No newline at end of file diff --git a/app/views/automatic_call_distributors/_index_core.html.haml b/app/views/automatic_call_distributors/_index_core.html.haml new file mode 100644 index 0000000..c31a648 --- /dev/null +++ b/app/views/automatic_call_distributors/_index_core.html.haml @@ -0,0 +1,39 @@ +%table + %tr + %th= t('automatic_call_distributors.index.name') + %th= t('automatic_call_distributors.index.strategy') + %th= t('automatic_call_distributors.index.max_callers') + %th= t('automatic_call_distributors.index.agent_timeout') + %th= t('automatic_call_distributors.index.retry_timeout') + %th= t('automatic_call_distributors.index.join') + %th= t('automatic_call_distributors.index.leave') + %th= t('automatic_call_distributors.index.phone_numbers') + %th= t('automatic_call_distributors.index.acd_agents') + + - reset_cycle + - for automatic_call_distributor in automatic_call_distributors + %tr{:class => cycle('odd', 'even')} + %td= automatic_call_distributor.name + %td= t("automatic_call_distributors.strategies.#{automatic_call_distributor.strategy}") + %td= automatic_call_distributor.max_callers + %td= automatic_call_distributor.agent_timeout + %td= automatic_call_distributor.retry_timeout + %td= t("automatic_call_distributors.join_on.#{automatic_call_distributor.join}") + %td= t("automatic_call_distributors.leave_on.#{automatic_call_distributor.leave}") + + %td + - if automatic_call_distributor.phone_numbers.count > 0 + = render 'phone_numbers/listing', :phone_numbers => automatic_call_distributor.phone_numbers + %br + = render :partial => 'shared/create_link', :locals => {:parent => automatic_call_distributor, :child_class => PhoneNumber, :short_link => true} + + %td + - if automatic_call_distributor.acd_agents.count > 3 + = link_to automatic_call_distributor.acd_agents.count, automatic_call_distributor_acd_agents_path(automatic_call_distributor) + %br + - elsif automatic_call_distributor.acd_agents.count > 0 + = render 'acd_agents/listing', :acd_agents => automatic_call_distributor.acd_agents + %br + = render :partial => 'shared/create_link', :locals => {:parent => automatic_call_distributor, :child_class => AcdAgent, :short_link => true} + + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => automatic_call_distributor.automatic_call_distributorable, :child => automatic_call_distributor} \ No newline at end of file diff --git a/app/views/automatic_call_distributors/edit.html.haml b/app/views/automatic_call_distributors/edit.html.haml new file mode 100644 index 0000000..28cba74 --- /dev/null +++ b/app/views/automatic_call_distributors/edit.html.haml @@ -0,0 +1,3 @@ +- title t("automatic_call_distributors.edit.page_title") + += render "form" \ No newline at end of file diff --git a/app/views/automatic_call_distributors/index.html.haml b/app/views/automatic_call_distributors/index.html.haml new file mode 100644 index 0000000..f3f8b2b --- /dev/null +++ b/app/views/automatic_call_distributors/index.html.haml @@ -0,0 +1,6 @@ +- title t("automatic_call_distributors.index.page_title") + +- if @automatic_call_distributors && @automatic_call_distributors.count > 0 + = render "index_core", :automatic_call_distributors => @automatic_call_distributors + += render :partial => 'shared/create_link', :locals => {:parent => @parent, :child_class => AutomaticCallDistributor} diff --git a/app/views/automatic_call_distributors/new.html.haml b/app/views/automatic_call_distributors/new.html.haml new file mode 100644 index 0000000..96a2d93 --- /dev/null +++ b/app/views/automatic_call_distributors/new.html.haml @@ -0,0 +1,3 @@ +- title t("automatic_call_distributors.new.page_title") + += render "form" \ No newline at end of file diff --git a/app/views/automatic_call_distributors/show.html.haml b/app/views/automatic_call_distributors/show.html.haml new file mode 100644 index 0000000..e5bf785 --- /dev/null +++ b/app/views/automatic_call_distributors/show.html.haml @@ -0,0 +1,59 @@ +- title t("automatic_call_distributors.show.page_title") + +%table + %tr + %th= t('automatic_call_distributors.show.uuid') + ":" + %td= @automatic_call_distributor.uuid + %tr + %th= t('automatic_call_distributors.show.name') + ":" + %td= @automatic_call_distributor.name + %tr + %th= t('automatic_call_distributors.show.strategy') + ":" + %td= t("automatic_call_distributors.strategies.#{@automatic_call_distributor.strategy}") + %tr + %th= t('automatic_call_distributors.show.max_callers') + ":" + %td= @automatic_call_distributor.max_callers + %tr + %th= t('automatic_call_distributors.show.agent_timeout') + ":" + %td= @automatic_call_distributor.agent_timeout + %tr + %th= t('automatic_call_distributors.show.retry_timeout') + ":" + %td= @automatic_call_distributor.retry_timeout + %tr + %th= t('automatic_call_distributors.show.join') + ":" + %td= t("automatic_call_distributors.join_on.#{@automatic_call_distributor.join}") + %tr + %th= t('automatic_call_distributors.show.leave') + ":" + %td= t("automatic_call_distributors.leave_on.#{@automatic_call_distributor.leave}") + + %tr + %th= t('automatic_call_distributors.show.announce_position') + ":" + %td= @automatic_call_distributor.announce_position + + %tr + %th= t('automatic_call_distributors.show.announce_call_agents') + ":" + %td= @automatic_call_distributor.announce_call_agents + + %tr + %th= t('automatic_call_distributors.show.greeting') + ":" + %td= @automatic_call_distributor.greeting + + %tr + %th= t('automatic_call_distributors.show.goodbye') + ":" + %td= @automatic_call_distributor.goodbye + + %tr + %th= t('automatic_call_distributors.show.music') + ":" + %td= @automatic_call_distributor.music + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @automatic_call_distributor.automatic_call_distributorable, :child => @automatic_call_distributor } + +- if can?( :index, @automatic_call_distributor.phone_numbers ) + %h3= t('automatic_call_distributors.index.phone_numbers') + = render 'phone_numbers/index_core', :phone_numbers => @automatic_call_distributor.phone_numbers + = render :partial => 'shared/create_link', :locals => {:parent => @automatic_call_distributor, :child_class => PhoneNumber, :short_link => true} + +- if can?( :index, @automatic_call_distributor.acd_agents ) + %h3= t('automatic_call_distributors.index.acd_agents') + = render 'acd_agents/index_core', :acd_agents => @automatic_call_distributor.acd_agents + = render :partial => 'shared/create_link', :locals => {:parent => @automatic_call_distributor, :child_class => AcdAgent, :short_link => true} diff --git a/app/views/call_forwards/_form.html.haml b/app/views/call_forwards/_form.html.haml new file mode 100644 index 0000000..7310af3 --- /dev/null +++ b/app/views/call_forwards/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([ @phone_number, @call_forward ]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('call_forwards.form.submit') \ No newline at end of file diff --git a/app/views/call_forwards/_form_core.html.haml b/app/views/call_forwards/_form_core.html.haml new file mode 100644 index 0000000..3dadb68 --- /dev/null +++ b/app/views/call_forwards/_form_core.html.haml @@ -0,0 +1,15 @@ +.inputs + = f.input :call_forward_case_id, :as => :select, :collection => @available_call_forward_cases.map {|x| [I18n.t("call_forward_cases.#{x.value}"), x.id] }, :label => t('call_forwards.form.call_forward_case_id.label'), :hint => conditional_hint('call_forwards.form.call_forward_case_id.hint'), :include_blank => false + = f.input :timeout, :label => t('call_forwards.form.timeout.label'), :hint => conditional_hint('call_forwards.form.timeout.hint') + + = f.input :call_forwarding_destination , :as => :select, :collection => @call_forwarding_destinations, :label => t('call_forwards.form.call_forwarding_destination.label'), :hint => conditional_hint('call_forwards.form.call_forwarding_destination.hint'), :include_blank => false + + = f.input :destination, :label => t('call_forwards.form.destination.label'), :hint => conditional_hint('call_forwards.form.destination.hint') + + + = f.input :source, :label => t('call_forwards.form.source.label'), :hint => conditional_hint('call_forwards.form.source.hint') + - if GuiFunction.display?('depth_field_in_call_forward_form', current_user) + = f.input :depth, :collection => 1..MAX_CALL_FORWARD_DEPTH, :label => t('call_forwards.form.depth.label'), :hint => conditional_hint('call_forwards.form.depth.hint') + - else + = f.hidden_field :depth + = f.input :active, :label => t('call_forwards.form.active.label'), :hint => conditional_hint('call_forwards.form.active.hint') diff --git a/app/views/call_forwards/_index_core.html.haml b/app/views/call_forwards/_index_core.html.haml new file mode 100644 index 0000000..7733855 --- /dev/null +++ b/app/views/call_forwards/_index_core.html.haml @@ -0,0 +1,31 @@ +%table + %tr + - if !@phone_number + %th= t('call_forwards.index.phone_number_id') + %th= t('call_forwards.index.call_forward_case_id') + %th= t('call_forwards.index.timeout') + %th= t('call_forwards.index.destination') + %th= t('call_forwards.index.source') + - if GuiFunction.display?('depth_field_value_in_index_table', current_user) + %th= t('call_forwards.index.depth') + %th= t('call_forwards.index.active') + + - reset_cycle + - for call_forward in call_forwards + %tr{:class => cycle('odd', 'even')} + - if !@phone_number + %td= call_forward.phone_number + %td= t("call_forward_cases.#{call_forward.call_forward_case.value}") + %td= call_forward.timeout + %td + = call_forward.destination + - if call_forward.call_forwardable_type + %br + = call_forward.call_forwardable_type + - if call_forward.call_forwardable + = ": #{call_forward.call_forwardable}" + %td= call_forward.source + - if GuiFunction.display?('depth_field_value_in_index_table', current_user) + %td= call_forward.depth + %td= call_forward.active + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => call_forward.phone_number, :child => call_forward} \ No newline at end of file diff --git a/app/views/call_forwards/edit.html.haml b/app/views/call_forwards/edit.html.haml new file mode 100644 index 0000000..5fa9dcd --- /dev/null +++ b/app/views/call_forwards/edit.html.haml @@ -0,0 +1,3 @@ +- title t("call_forwards.edit.page_title", :resource => " for phone number #{@phone_number}" ) + += render "form" \ No newline at end of file diff --git a/app/views/call_forwards/index.html.haml b/app/views/call_forwards/index.html.haml new file mode 100644 index 0000000..93d64f2 --- /dev/null +++ b/app/views/call_forwards/index.html.haml @@ -0,0 +1,6 @@ +- title t("call_forwards.index.page_title") + +- if @call_forwards.count > 0 + = render "index_core", :call_forwards => @call_forwards + += render :partial => 'shared/create_link', :locals => {:parent => @phone_number, :child_class => CallForward} \ No newline at end of file diff --git a/app/views/call_forwards/new.html.haml b/app/views/call_forwards/new.html.haml new file mode 100644 index 0000000..960a9e6 --- /dev/null +++ b/app/views/call_forwards/new.html.haml @@ -0,0 +1,3 @@ +- title t("call_forwards.new.page_title") + += render "form" diff --git a/app/views/call_forwards/show.html.haml b/app/views/call_forwards/show.html.haml new file mode 100644 index 0000000..6d1a0c6 --- /dev/null +++ b/app/views/call_forwards/show.html.haml @@ -0,0 +1,33 @@ +- title t("call_forwards.show.page_title") + +%p + %strong= t('call_forwards.show.phone_number_id') + ":" + = @call_forward.phone_number +%p + %strong= t('call_forwards.show.call_forward_case_id') + ":" + = t("call_forward_cases.#{@call_forward.call_forward_case.value}") +%p + %strong= t('call_forwards.show.timeout') + ":" + = @call_forward.timeout +%p + %strong= t('call_forwards.show.destination') + ":" + = @call_forward.destination +- if @call_forward.call_forwardable_type == 'HuntGroup' && @call_forward.call_forwardable.class == HuntGroup + %p + %strong= t('call_forwards.show.hunt_group') + ":" + = @call_forward.call_forwardable +- if @call_forward.call_forwardable_type == 'Voicemail' + %p + %strong= t('call_forwards.show.to_voicemail') + ":" + = 'active' +%p + %strong= t('call_forwards.show.source') + ":" + = @call_forward.source +%p + %strong= t('call_forwards.show.depth') + ":" + = @call_forward.depth +%p + %strong= t('call_forwards.show.active') + ":" + = @call_forward.active + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @phone_number, :child => @call_forward } \ No newline at end of file diff --git a/app/views/call_histories/_index_core.html.haml b/app/views/call_histories/_index_core.html.haml new file mode 100644 index 0000000..2d7658a --- /dev/null +++ b/app/views/call_histories/_index_core.html.haml @@ -0,0 +1,65 @@ += form_tag(destroy_multiple_sip_account_call_histories_path(@sip_account), :method => :delete, :id => 'call_history_form') do + %header.entries-nav= render :partial => "call_histories/navigation" + .content + %table + - reset_cycle + - for call_history in call_histories + - phone_number = call_history.display_number + - voicemail_message = call_history.voicemail_message + - if phone_number + - phone_book_entry = call_history.phone_book_entry_by_number(phone_number) + %tr.call-history-entry{:class => cycle('odd', 'even')} + %td.select_box= check_box_tag("selected_ids[]", call_history.id, false, :id => "select_item_#{call_history.id}", :class => 'select_item') + %td.thumbnail + - image = call_history.display_image(:small, phone_book_entry) + - if image + = image_tag(image, :itemprop => 'image') + %td.time + - if voicemail_message + .voicemail-message + %a{:href => sip_account_voicemail_messages_path(@sip_account, :anchor => "message_#{voicemail_message.id}")} + = image_tag('icons/gs_envelope_16x.png', :class => 'display') + = call_history.display_call_date(t("call_histories.index.date_format"), t("call_histories.index.date_today_format")) + - elsif call_history.entry_type == 'forwarded' + .call-forwarded= call_history.display_call_date(t("call_histories.index.date_format"), t("call_histories.index.date_today_format")) + - if call_history.callee_account_type.to_s.downcase == 'voicemail' + = t("call_histories.index.voicemail") + - else + = call_history.destination_number + - elsif call_history.entry_type == 'dialed' + .call-placed= call_history.display_call_date(t("call_histories.index.date_format"), t("call_histories.index.date_today_format")) + - elsif call_history.entry_type == 'received' + .call-received= call_history.display_call_date(t("call_histories.index.date_format"), t("call_histories.index.date_today_format")) + - elsif call_history.entry_type == 'missed' + .call-missed= call_history.display_call_date(t("call_histories.index.date_format"), t("call_histories.index.date_today_format")) + - else + .call-unknown + = t("call_histories.index.#{call_history.entry_type}") + = call_history.display_call_date(t("call_histories.index.date_format"), t("call_histories.index.date_today_format")) + - if call_history.forwarding_service && call_history.entry_type != 'forwarded' + = t("call_histories.index.forwarded_by") + = call_history.display_auth_account_name + %td.user + - display_name = call_history.display_name + - if display_name.blank? + - display_name = phone_book_entry.to_s + - if phone_book_entry + %a.name{:href => phone_book_phone_book_entry_path(phone_book_entry.phone_book, phone_book_entry), :itemprop => "name"}= display_name + - else + .name= display_name + .phone= phone_number + %td.status + - if call_history.display_duration + .duration= call_history.display_duration + - else + .disposition= t("call_histories.call_results.#{call_history.result}") + %td.actions + - if @sip_account.registration && can?(:call, call_history) + = link_to t('call_histories.index.actions.call'), call_sip_account_call_history_path(@sip_account, call_history), :method => :put + %td.actions + - if can? :destroy, call_history + = link_to t('call_histories.index.actions.destroy'), sip_account_call_history_path(@sip_account, call_history), :method => :delete + + %footer.entries-nav= render :partial => "call_histories/navigation" + = image_submit_tag('icons/cross-16x.png', :confirm => t("call_histories.index.actions.confirm_selected")) + = t("call_histories.index.actions.destroy_multiple") diff --git a/app/views/call_histories/_navigation.html.haml b/app/views/call_histories/_navigation.html.haml new file mode 100644 index 0000000..a1999d9 --- /dev/null +++ b/app/views/call_histories/_navigation.html.haml @@ -0,0 +1,11 @@ +%nav + %ol.abc + %li + %a{ :href => "?type=" }= t("call_histories.index.navigation.all", :calls => @calls_count) + %a{ :href => "?type=missed" }= t("call_histories.index.navigation.missed", :calls => @calls_missed_count) + %a{ :href => "?type=received" }= t("call_histories.index.navigation.received", :calls => @calls_received_count) + %a{ :href => "?type=dialed" }= t("call_histories.index.navigation.dialed", :calls => @calls_dialed_count) + %a{ :href => "?type=forwarded" }= t("call_histories.index.navigation.forwarded", :calls => @calls_forwarded_count) + +.pagination + = will_paginate @call_histories diff --git a/app/views/call_histories/index.html.haml b/app/views/call_histories/index.html.haml new file mode 100644 index 0000000..adf6838 --- /dev/null +++ b/app/views/call_histories/index.html.haml @@ -0,0 +1,6 @@ +- if @type + - title t("call_histories.index.page_title_#{@type}") +- else + - title t("call_histories.index.page_title") + += render "index_core", :call_histories => @call_histories diff --git a/app/views/calls/_index_core.html.haml b/app/views/calls/_index_core.html.haml new file mode 100644 index 0000000..ddd0650 --- /dev/null +++ b/app/views/calls/_index_core.html.haml @@ -0,0 +1,9 @@ +%table + %tr + %th= t('calls.index.uuid') + + - reset_cycle + - for call in @calls + %tr{:class => cycle('odd', 'even')} + %td + = call.uuid diff --git a/app/views/calls/index.html.haml b/app/views/calls/index.html.haml new file mode 100644 index 0000000..4ea60a6 --- /dev/null +++ b/app/views/calls/index.html.haml @@ -0,0 +1,6 @@ +- title t("calls.index.page_title") + +- if @calls.count > 0 + = render "index_core", :calls => @calls + += render :partial => 'shared/create_link', :locals => {:parent => @parent, :child_class => Call} \ No newline at end of file diff --git a/app/views/callthroughs/_form.html.haml b/app/views/callthroughs/_form.html.haml new file mode 100644 index 0000000..99f92d0 --- /dev/null +++ b/app/views/callthroughs/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([@tenant, @callthrough]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('callthroughs.form.submit') diff --git a/app/views/callthroughs/_form_core.html.haml b/app/views/callthroughs/_form_core.html.haml new file mode 100644 index 0000000..1f137d9 --- /dev/null +++ b/app/views/callthroughs/_form_core.html.haml @@ -0,0 +1,24 @@ +.inputs + = f.input :name, :label => t('callthroughs.form.name.label'), :hint => conditional_hint('callthroughs.form.name.hint') + + %h2= t('callthroughs.form.phone_numbers.label') + - if !t('callthroughs.form.phone_numbers.hint').blank? + %p= t('callthroughs.form.phone_numbers.hint') + = f.simple_fields_for :phone_numbers do |phone_number| + = render "phone_numbers/form_core", :f => phone_number + %p + + - if @callthrough && @callthrough.access_authorizations.size > 0 + %h2= t('callthroughs.form.access_authorizations.label') + - if !t('callthroughs.form.access_authorizations.hint').blank? + %p= t('callthroughs.form.access_authorizations.hint') + = f.simple_fields_for :access_authorizations do |access_authorization| + = render "access_authorizations/form_core", :f => access_authorization + + - if CALLTHROUGH_HAS_WHITELISTS == true + - if @callthrough && @callthrough.whitelists.size > 0 + %h2= t('callthroughs.form.whitelists.label') + - if !t('callthroughs.form.whitelists.hint').blank? + %p= t('callthroughs.form.whitelists.hint') + = f.simple_fields_for :whitelists do |whitelist| + = render "whitelists/form_core", :f => whitelist diff --git a/app/views/callthroughs/_index_core.html.haml b/app/views/callthroughs/_index_core.html.haml new file mode 100644 index 0000000..f1802d4 --- /dev/null +++ b/app/views/callthroughs/_index_core.html.haml @@ -0,0 +1,17 @@ +%table + %tr + %th= t('callthroughs.index.name') + %th= t('callthroughs.index.phone_numbers') + %th= t('callthroughs.index.access_authorized_phone_numbers') + - if CALLTHROUGH_HAS_WHITELISTS == true + %th= t('callthroughs.index.whitelist_phone_numbers') + + - reset_cycle + - for callthrough in callthroughs + %tr{:class => cycle('odd', 'even')} + %td= callthrough.name + %td=render 'phone_numbers/listing', :phone_numbers => callthrough.phone_numbers + %td=render 'phone_numbers/listing', :phone_numbers => callthrough.access_authorization_phone_numbers + - if CALLTHROUGH_HAS_WHITELISTS == true + %td=render 'phone_numbers/listing', :phone_numbers => callthrough.whitelisted_phone_numbers + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => callthrough.tenant, :child => callthrough} \ No newline at end of file diff --git a/app/views/callthroughs/edit.html.haml b/app/views/callthroughs/edit.html.haml new file mode 100644 index 0000000..44fe17e --- /dev/null +++ b/app/views/callthroughs/edit.html.haml @@ -0,0 +1,3 @@ +- title t("callthroughs.edit.page_title") + += render "form" \ No newline at end of file diff --git a/app/views/callthroughs/index.html.haml b/app/views/callthroughs/index.html.haml new file mode 100644 index 0000000..c595351 --- /dev/null +++ b/app/views/callthroughs/index.html.haml @@ -0,0 +1,6 @@ +- title t("callthroughs.index.page_title") + +- if @callthroughs.count > 0 + = render "index_core", :callthroughs => @callthroughs + += render :partial => 'shared/create_link', :locals => {:parent => @parent, :child_class => Callthrough} \ No newline at end of file diff --git a/app/views/callthroughs/new.html.haml b/app/views/callthroughs/new.html.haml new file mode 100644 index 0000000..ff47c1c --- /dev/null +++ b/app/views/callthroughs/new.html.haml @@ -0,0 +1,3 @@ +- title t("callthroughs.new.page_title") + += render "form" diff --git a/app/views/callthroughs/show.html.haml b/app/views/callthroughs/show.html.haml new file mode 100644 index 0000000..55bd6eb --- /dev/null +++ b/app/views/callthroughs/show.html.haml @@ -0,0 +1,27 @@ +- title t("callthroughs.show.page_title") + +%p + %strong= t('callthroughs.show.name') + ":" + = @callthrough.name + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @callthrough.tenant, :child => @callthrough } + + +%h2= t('callthroughs.form.phone_numbers.label') +- if @callthrough.phone_numbers.count > 0 + = render 'phone_numbers/index_core', :phone_numbers => @callthrough.phone_numbers + %br += render :partial => 'shared/create_link', :locals => {:parent => @callthrough, :child_class => PhoneNumber} + +%h2= t('callthroughs.form.access_authorizations.label') +- if @callthrough.access_authorizations.count > 0 + = render 'access_authorizations/index_core', :access_authorizations => @callthrough.access_authorizations + %br += render :partial => 'shared/create_link', :locals => {:parent => @callthrough, :child_class => AccessAuthorization} + +- if CALLTHROUGH_HAS_WHITELISTS == true + %h2= t('callthroughs.form.whitelists.label') + - if @callthrough.whitelisted_phone_numbers.count > 0 + = render 'whitelists/index_core', :whitelists => @callthrough.whitelists + %br + = render :partial => 'shared/create_link', :locals => {:parent => @callthrough, :child_class => Whitelist} \ No newline at end of file diff --git a/app/views/conference_invitees/_form.html.haml b/app/views/conference_invitees/_form.html.haml new file mode 100644 index 0000000..400580d --- /dev/null +++ b/app/views/conference_invitees/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([@conference, @conference_invitee]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('conference_invitees.form.submit') \ No newline at end of file diff --git a/app/views/conference_invitees/_form_core.html.haml b/app/views/conference_invitees/_form_core.html.haml new file mode 100644 index 0000000..3cac18d --- /dev/null +++ b/app/views/conference_invitees/_form_core.html.haml @@ -0,0 +1,7 @@ +.inputs + = f.simple_fields_for :phone_number, @phone_number do |p| + = p.input :number, :label => t('phone_numbers.form.number.label'), :hint => conditional_hint('phone_numbers.form.number.hint') + + = f.input :pin, :label => t('conference_invitees.form.pin.label'), :hint => conditional_hint('conference_invitees.form.pin.hint') + = f.input :speaker, :label => t('conference_invitees.form.speaker.label'), :hint => conditional_hint('conference_invitees.form.speaker.hint') + = f.input :moderator, :label => t('conference_invitees.form.moderator.label'), :hint => conditional_hint('conference_invitees.form.moderator.hint') diff --git a/app/views/conference_invitees/_index_core.html.haml b/app/views/conference_invitees/_index_core.html.haml new file mode 100644 index 0000000..f84af7d --- /dev/null +++ b/app/views/conference_invitees/_index_core.html.haml @@ -0,0 +1,17 @@ +%table + %tr + %th= t('conference_invitees.index.phone_book_entry_id') + %th= t('conference_invitees.index.phone_number') + %th= t('conference_invitees.index.pin') + %th= t('conference_invitees.index.speaker') + %th= t('conference_invitees.index.moderator') + + - reset_cycle + - for conference_invitee in conference_invitees + %tr{:class => cycle('odd', 'even')} + %td= conference_invitee.phone_book_entry || '-' + %td= conference_invitee.phone_number + %td= conference_invitee.pin + %td= conference_invitee.speaker + %td= conference_invitee.moderator + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => conference_invitee.conference, :child => conference_invitee} \ No newline at end of file diff --git a/app/views/conference_invitees/edit.html.haml b/app/views/conference_invitees/edit.html.haml new file mode 100644 index 0000000..ce90bbe --- /dev/null +++ b/app/views/conference_invitees/edit.html.haml @@ -0,0 +1,3 @@ +- title t("conference_invitees.edit.page_title") + += render "form" \ No newline at end of file diff --git a/app/views/conference_invitees/index.html.haml b/app/views/conference_invitees/index.html.haml new file mode 100644 index 0000000..2a0c26c --- /dev/null +++ b/app/views/conference_invitees/index.html.haml @@ -0,0 +1,6 @@ +- title t("conference_invitees.index.page_title") + +- if @conference_invitees.count > 0 + = render "index_core", :conference_invitees => @conference_invitees + += render :partial => 'shared/create_link', :locals => {:parent => @conference, :child_class => ConferenceInvitee} \ No newline at end of file diff --git a/app/views/conference_invitees/new.html.haml b/app/views/conference_invitees/new.html.haml new file mode 100644 index 0000000..780494e --- /dev/null +++ b/app/views/conference_invitees/new.html.haml @@ -0,0 +1,3 @@ +- title t("conference_invitees.new.page_title") + += render "form" diff --git a/app/views/conference_invitees/show.html.haml b/app/views/conference_invitees/show.html.haml new file mode 100644 index 0000000..57c5627 --- /dev/null +++ b/app/views/conference_invitees/show.html.haml @@ -0,0 +1,20 @@ +- title t("conference_invitees.show.page_title") + +%p + %strong= t('conference_invitees.show.conference_id') + ":" + = @conference_invitee.conference +- if @conference_invitee.phone_book_entry_id + %p + %strong= t('conference_invitees.show.phone_book_entry_id') + ":" + = @conference_invitee.phone_book_entry +%p + %strong= t('conference_invitees.show.pin') + ":" + = @conference_invitee.pin +%p + %strong= t('conference_invitees.show.speaker') + ":" + = @conference_invitee.speaker +%p + %strong= t('conference_invitees.show.moderator') + ":" + = @conference_invitee.moderator + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @conference_invitee.conference, :child => @conference_invitee } \ No newline at end of file diff --git a/app/views/conferences/_form.html.haml b/app/views/conferences/_form.html.haml new file mode 100644 index 0000000..4bee1a4 --- /dev/null +++ b/app/views/conferences/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([ @parent, @conference ]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('conferences.form.submit') \ No newline at end of file diff --git a/app/views/conferences/_form_core.html.haml b/app/views/conferences/_form_core.html.haml new file mode 100644 index 0000000..04754de --- /dev/null +++ b/app/views/conferences/_form_core.html.haml @@ -0,0 +1,11 @@ +.inputs + = f.input :name, :label => t('conferences.form.name.label'), :hint => conditional_hint('conferences.form.name.hint'), :autofocus => true + - if !f.object.start.nil? + = f.input :start, :label => t('conferences.form.start.label'), :hint => conditional_hint('conferences.form.start.hint'), :include_blank => true, :start_year => Time.now.year, :end_year => Time.now.year + 2 + = f.input :end, :label => t('conferences.form.end.label'), :hint => conditional_hint('conferences.form.end.hint'), :include_blank => true, :start_year => Time.now.year, :end_year => Time.now.year + 2 + = f.input :description, :label => t('conferences.form.description.label'), :hint => conditional_hint('conferences.form.description.hint') + = f.input :pin, :label => t('conferences.form.pin.label'), :hint => conditional_hint('conferences.form.pin.hint') + = f.input :max_members, :collection => 1..MAXIMUM_NUMBER_OF_PEOPLE_IN_A_CONFERENCE, :include_blank => false, :label => t('conferences.form.max_members.label'), :hint => conditional_hint('conferences.form.max_members.hint') + = f.input :open_for_anybody, :label => t('conferences.form.open_for_anybody.label'), :hint => conditional_hint('conferences.form.open_for_anybody.hint') + = f.input :announce_new_member_by_name, :label => t('conferences.form.announce_new_member_by_name.label'), :hint => conditional_hint('conferences.form.announce_new_member_by_name.hint') + = f.input :announce_left_member_by_name, :label => t('conferences.form.announce_left_member_by_name.label'), :hint => conditional_hint('conferences.form.announce_left_member_by_name.hint') \ No newline at end of file diff --git a/app/views/conferences/_index_core.html.haml b/app/views/conferences/_index_core.html.haml new file mode 100644 index 0000000..4073e83 --- /dev/null +++ b/app/views/conferences/_index_core.html.haml @@ -0,0 +1,53 @@ +%table + %tr + %th= t('conferences.index.name') + - if !conferences.respond_to?('where') || conferences.where(:start => nil).where(:end => nil).count != conferences.count + %th= t('conferences.index.start') + %th= t('conferences.index.end') + %th= t('conferences.index.phone_numbers') + - if !conferences.respond_to?('where') || conferences.where(:pin => '').count != conferences.count + %th= t('conferences.index.pin') + %th= t('conferences.index.max_members') + %th= t('conferences.index.number_of_invitees') + %th= t('conferences.index.flags') + + - reset_cycle + - for conference in conferences + - parent = conference.conferenceable + %tr{:class => cycle('odd', 'even')} + %td= conference.name + - if !conferences.respond_to?('where') || conferences.where(:start => nil).where(:end => nil).count != conferences.count + %td + - if conference.start + = l conference.start, :format => :long + - else + = '-' + %td + - if conference.end + = l conference.end, :format => :long + - else + = '-' + %td + - if conference.phone_numbers.count > 0 + = render 'phone_numbers/listing', :phone_numbers => conference.phone_numbers.order(:number) + %br + = render :partial => 'shared/create_link', :locals => {:parent => conference, :child_class => PhoneNumber, :short_link => true} + + - if !conferences.respond_to?('where') || conferences.where(:pin => '').count != conferences.count + %td + - if !conference.pin.blank? + = conference.pin + - else + = '-' + %td= conference.max_members + %td= conference.conference_invitees.count + %td + %ul + - if conference.open_for_anybody + %li= t('conferences.index.open_for_anybody') + - if conference.announce_new_member_by_name + %li= t('conferences.index.announce_new_member_by_name') + - if conference.announce_left_member_by_name + %li= t('conferences.index.announce_left_member_by_name') + + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => parent, :child => conference} \ No newline at end of file diff --git a/app/views/conferences/edit.html.haml b/app/views/conferences/edit.html.haml new file mode 100644 index 0000000..bc190e7 --- /dev/null +++ b/app/views/conferences/edit.html.haml @@ -0,0 +1,3 @@ +- title t("conferences.edit.page_title") + += render "form" diff --git a/app/views/conferences/index.html.haml b/app/views/conferences/index.html.haml new file mode 100644 index 0000000..0324acd --- /dev/null +++ b/app/views/conferences/index.html.haml @@ -0,0 +1,6 @@ +- title t("conferences.index.page_title") + +- if @conferences.count > 0 + = render "index_core", :conferences => @conferences + += render :partial => 'shared/create_link', :locals => {:parent => @parent, :child_class => Conference} \ No newline at end of file diff --git a/app/views/conferences/new.html.haml b/app/views/conferences/new.html.haml new file mode 100644 index 0000000..102f6a9 --- /dev/null +++ b/app/views/conferences/new.html.haml @@ -0,0 +1,3 @@ +- title t("conferences.new.page_title") + += render "form" diff --git a/app/views/conferences/show.html.haml b/app/views/conferences/show.html.haml new file mode 100644 index 0000000..10ebaed --- /dev/null +++ b/app/views/conferences/show.html.haml @@ -0,0 +1,43 @@ +- title t("conferences.show.page_title") + +%p + %strong= t('conferences.show.name') + ":" + = @conference.name +- if @conference.start + %p + %strong= t('conferences.show.start') + ":" + = @conference.start + %p + %strong= t('conferences.show.end') + ":" + = @conference.end +- if !@conference.description.blank? + %p + %strong= t('conferences.show.description') + ":" + = @conference.description +- if !@conference.pin.blank? + %p + %strong= t('conferences.show.pin') + ":" + = @conference.pin +%p + %strong= t('conferences.show.open_for_anybody') + ":" + = @conference.open_for_anybody +%p + %strong= t('conferences.show.announce_new_member_by_name') + ":" + = @conference.announce_new_member_by_name +%p + %strong= t('conferences.show.announce_left_member_by_name') + ":" + = @conference.announce_left_member_by_name + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @parent, :child => @conference } + +%h2= t('phone_numbers.index.page_title') +- if @phone_numbers.count > 0 + = render "phone_numbers/index_core", :phone_numbers => @phone_numbers + += render :partial => 'shared/create_link', :locals => {:parent => @conference, :child_class => PhoneNumber} + +%h2= t("conference_invitees.index.page_title") +- if @conference.conference_invitees.count > 0 + = render "conference_invitees/index_core", :conference_invitees => @conference.conference_invitees + += render :partial => 'shared/create_link', :locals => {:parent => @conference, :child_class => ConferenceInvitee} \ No newline at end of file diff --git a/app/views/config_polycom/_call_history.xml.haml b/app/views/config_polycom/_call_history.xml.haml new file mode 100644 index 0000000..7d23edd --- /dev/null +++ b/app/views/config_polycom/_call_history.xml.haml @@ -0,0 +1,18 @@ +!!! XML +%html + %head + %title= @phone_xml_object[:title] + %body + %table{ :border => 0 } + %tbody + - @phone_xml_object[:entries].each do |entry| + %tr + %td= entry[:date] + %td= entry[:text] + %td + %a{:href => entry[:url]}= entry[:number] + + %softkey{ :index => 1, :label => 'Home', :action => 'SoftKey:Home' } + %softkey{ :index => 2, :label => 'Refresh', :action => 'SoftKey:Refresh' } + %softkey{ :index => 4, :label => 'Exit', :action => 'SoftKey:Exit' } + %softkey{ :index => 3, :label => 'Back', :action => 'SoftKey:Back' } diff --git a/app/views/config_polycom/_call_history_menu.xml.haml b/app/views/config_polycom/_call_history_menu.xml.haml new file mode 100644 index 0000000..6e56f37 --- /dev/null +++ b/app/views/config_polycom/_call_history_menu.xml.haml @@ -0,0 +1,13 @@ +!!! XML +%html + %head + %title= @phone_xml_object[:title] + %body + - @phone_xml_object[:entries].each do |entry| + %br + %a{ :href => entry[:url]}= entry[:text] + + %softkey{ :index => 1, :label => 'Home', :action => 'SoftKey:Home' } + %softkey{ :index => 2, :label => 'Refresh', :action => 'SoftKey:Refresh' } + %softkey{ :index => 4, :label => 'Exit', :action => 'SoftKey:Exit' } + %softkey{ :index => 3, :label => 'Back', :action => 'SoftKey:Back' } diff --git a/app/views/config_polycom/_phone_book.xml.haml b/app/views/config_polycom/_phone_book.xml.haml new file mode 100644 index 0000000..1066695 --- /dev/null +++ b/app/views/config_polycom/_phone_book.xml.haml @@ -0,0 +1,18 @@ +!!! XML +%html + %head + %title= @phone_xml_object[:title] + %body + %table{ :border => 0 } + %tbody + - @phone_xml_object[:entries].each do |entry| + %tr + %td= entry[:text] + %td + = "#{entry[:type][0]}: " + %a{:href => entry[:url]}= entry[:number] + + %softkey{ :index => 1, :label => 'Home', :action => 'SoftKey:Home' } + %softkey{ :index => 2, :label => 'Refresh', :action => 'SoftKey:Refresh' } + %softkey{ :index => 4, :label => 'Exit', :action => 'SoftKey:Exit' } + %softkey{ :index => 3, :label => 'Back', :action => 'SoftKey:Back' } diff --git a/app/views/config_polycom/config_files.xml.builder b/app/views/config_polycom/config_files.xml.builder new file mode 100644 index 0000000..50819ff --- /dev/null +++ b/app/views/config_polycom/config_files.xml.builder @@ -0,0 +1,12 @@ +xml.instruct! + +xml.tag!('APPLICATION', + 'APP_FILE_PATH' => 'sip.ld', + 'CONFIG_FILES' => "settings-#{@mac_address}.cfg", + 'MISC_FILES' => '', + 'LOG_FILE_DIRECTORY' => '', + 'OVERRIDES_DIRECTORY' => '', + 'CONTACTS_DIRECTORY' => '', + 'LICENSE_DIRECTORY' => '', + 'USER_PROFILES_DIRECTORY' => '', + 'CALL_LISTS_DIRECTORY' => '') diff --git a/app/views/config_polycom/idle_screen.xml.haml b/app/views/config_polycom/idle_screen.xml.haml new file mode 100644 index 0000000..fa52c4f --- /dev/null +++ b/app/views/config_polycom/idle_screen.xml.haml @@ -0,0 +1,7 @@ +!!! XML +%html + %head + %title= @sip_account.caller_name + %body + - @sip_account.phone_numbers.each do |number| + %br= number.number diff --git a/app/views/config_polycom/settings.xml.erb b/app/views/config_polycom/settings.xml.erb new file mode 100644 index 0000000..ea9d325 --- /dev/null +++ b/app/views/config_polycom/settings.xml.erb @@ -0,0 +1,8 @@ + + + + <%= key %>="<%= value %>" + <% end %> + /> + diff --git a/app/views/config_polycom/settings_directory.xml.haml b/app/views/config_polycom/settings_directory.xml.haml new file mode 100644 index 0000000..107f991 --- /dev/null +++ b/app/views/config_polycom/settings_directory.xml.haml @@ -0,0 +1,16 @@ +!!! XML +%directory + %item_list + %item + %ln= 'Directory' + %ct= '!directory' + %sd= 38 + %item + %ln= 'Call History' + %ct= '!callhistory' + %sd= 39 + %item + %ln= 'Applications' + %ct= '!applications' + %sd= 40 + diff --git a/app/views/config_siemens/_menu_list.xml.haml b/app/views/config_siemens/_menu_list.xml.haml new file mode 100644 index 0000000..70bfc43 --- /dev/null +++ b/app/views/config_siemens/_menu_list.xml.haml @@ -0,0 +1,33 @@ +!!! XML +%IppPhone + %IppDisplay + %IppScreen{:ID => '1', :HiddenCount => (@phone_xml_object[:hidden] ? @phone_xml_object[:hidden].length : '0'), :CommandCount => (@phone_xml_object[:commands] ? @phone_xml_object[:commands].length : '0')} + - if @phone_xml_object[:make_call] + %IppAction{:Type => 'MAKECALL'} + %Number= @phone_xml_object[:make_call] + - if @phone_xml_object[:led] != nil + %IppAction{:Type => (@phone_xml_object[:led] ? 'TURNLEDON' : 'TURNLEDOFF')} + %IppKey{:Keypad => 'YES', :SendKeys => 'YES', :BufferKeys => 'NO', :BufferLength => '0', :TermKey => '', :UrlKey => 'key'} + - if @phone_xml_object[:entries] + %IppList{:Type => 'IMPLICIT', :Count => @phone_xml_object[:entries].length, :Columns => @phone_xml_object[:columns]} + - if @phone_xml_object[:title] + %Title= @phone_xml_object[:title] + %Url= @phone_xml_object[:url] + - @phone_xml_object[:entries].each_with_index do |entry, index| + %Option{:ID => index+1, :Selected => (entry[:selected] ? 'TRUE' : 'FALSE'), :Key => (entry[:key] ? entry[:key] : 'item'), :Value => entry[:value]} + - if entry[:image] + %Image= entry[:image] + %OptionText= entry[:text].to_s + - if entry[:text_center] + %OptionText= entry[:text_center].to_s + - if entry[:text_right] + %OptionText= entry[:text_right].to_s + - if @phone_xml_object[:hidden] + - @phone_xml_object[:hidden].each do |key, value| + %IppHidden{:Type => 'VALUE', :Key => key} + %Value= value + - if @phone_xml_object[:commands] + - @phone_xml_object[:commands].each_with_index do |command, index| + %IppCommand{:Type => command[:type], :DisplayOn => command[:display], :Priority => index, :Key => command[:key], :Value => command[:value], :DisplayOn => command[:display_on], :Select => command[:select], :Default => command[:default], :Auto => command[:auto]} + %Label= command[:label] + %Screen= "1" diff --git a/app/views/config_siemens/clean-up.xml.erb b/app/views/config_siemens/clean-up.xml.erb new file mode 100644 index 0000000..e1cbf93 --- /dev/null +++ b/app/views/config_siemens/clean-up.xml.erb @@ -0,0 +1,5 @@ + + + CleanUp + + \ No newline at end of file diff --git a/app/views/config_siemens/index.xml.erb b/app/views/config_siemens/index.xml.erb new file mode 100644 index 0000000..0c60b1f --- /dev/null +++ b/app/views/config_siemens/index.xml.erb @@ -0,0 +1,5 @@ + + + ReadAllItems + + \ No newline at end of file diff --git a/app/views/config_siemens/write.xml.erb b/app/views/config_siemens/write.xml.erb new file mode 100644 index 0000000..ee9e32e --- /dev/null +++ b/app/views/config_siemens/write.xml.erb @@ -0,0 +1,10 @@ + + + WriteItems + + <% @new_settings.each do |setting| %> + index="<%=setting[1]%>"<%end%>><%=setting[2]%> + <% end %> + + + \ No newline at end of file diff --git a/app/views/config_snom/_snom_phone_directory.xml.haml b/app/views/config_snom/_snom_phone_directory.xml.haml new file mode 100644 index 0000000..698f2e5 --- /dev/null +++ b/app/views/config_snom/_snom_phone_directory.xml.haml @@ -0,0 +1,19 @@ +!!! XML +%SnomIPPhoneDirectory{:speedselect => 'off'} + %Title= @phone_xml_object[:title] + %Prompt= @phone_xml_object[:prompt] + - @phone_xml_object[:entries].each do |entry| + %DirectoryEntry{:sel => entry[:selected].to_s} + %Name= entry[:text] + %Telephone= entry[:number] + + - if @phone_xml_object[:softkeys] + - @phone_xml_object[:softkeys].each do |softkey| + %SoftKeyItem + %Name= softkey[:name] + - if ! softkey[:label].blank? + %Label= softkey[:label] + - if ! softkey[:url].blank? + %URL= softkey[:url] + - if ! softkey[:softkey].blank? + %URL= softkey[:softkey] diff --git a/app/views/config_snom/_snom_phone_input.xml.haml b/app/views/config_snom/_snom_phone_input.xml.haml new file mode 100644 index 0000000..6038282 --- /dev/null +++ b/app/views/config_snom/_snom_phone_input.xml.haml @@ -0,0 +1,19 @@ +!!! XML +%SnomIPPhoneInput + %Title= @phone_xml_object[:title] + %Prompt= @phone_xml_object[:prompt] + %URL= @phone_xml_object[:url] + %InputItem + %DisplayName= @phone_xml_object[:display_name] + %QueryStringParam= @phone_xml_object[:query_string_param] + %DefaultValue= @phone_xml_object[:default_value] + %InputFlags= @phone_xml_object[:input_flags] + - if @phone_xml_object[:softkeys] + - @phone_xml_object[:softkeys].each do |softkey| + %SoftKeyItem + %Name= softkey[:name] + %Label= softkey[:label] + - if ! softkey[:url].blank? + %URL= softkey[:url] + - if ! softkey[:softkey].blank? + %URL= softkey[:softkey] diff --git a/app/views/config_snom/_snom_phone_menu.xml.haml b/app/views/config_snom/_snom_phone_menu.xml.haml new file mode 100644 index 0000000..de016c0 --- /dev/null +++ b/app/views/config_snom/_snom_phone_menu.xml.haml @@ -0,0 +1,17 @@ +!!! XML +%SnomIPPhoneMenu{:speedselect => 'off'} + %Title= @phone_xml_object[:title] + - @phone_xml_object[:entries].each do |entry| + %MenuItem{:sel => entry[:selected].to_s} + %Name= entry[:text] + %URL= entry[:url] + + - if @phone_xml_object[:softkeys] + - @phone_xml_object[:softkeys].each do |softkey| + %SoftKeyItem + %Name= softkey[:name] + %Label= softkey[:label] + - if ! softkey[:url].blank? + %URL= softkey[:url] + - if ! softkey[:softkey].blank? + %URL= softkey[:softkey] diff --git a/app/views/config_snom/_snom_phone_text.xml.haml b/app/views/config_snom/_snom_phone_text.xml.haml new file mode 100644 index 0000000..6c3773c --- /dev/null +++ b/app/views/config_snom/_snom_phone_text.xml.haml @@ -0,0 +1,16 @@ +!!! XML +%SnomIPPhoneText + %Title= @phone_xml_object[:title] + %Prompt= @phone_xml_object[:prompt] + %Text= @phone_xml_object[:text] + - if @phone_xml_object[:softkeys] + - @phone_xml_object[:softkeys].each do |softkey| + %SoftKeyItem + %Name= softkey[:name] + %Label= softkey[:label] + - if ! softkey[:url].blank? + %URL= softkey[:url] + - if ! softkey[:softkey].blank? + %URL= softkey[:softkey] + -if @phone_xml_object[:fetch_url] + %fetch{:mil => @phone_xml_object[:fetch_mil]}= @phone_xml_object[:fetch_url] diff --git a/app/views/config_snom/call_history.xml.haml b/app/views/config_snom/call_history.xml.haml new file mode 100644 index 0000000..00f9990 --- /dev/null +++ b/app/views/config_snom/call_history.xml.haml @@ -0,0 +1,2 @@ +!!! XML += render @phone_xml_object[:name] diff --git a/app/views/config_snom/idle_screen.xml.haml b/app/views/config_snom/idle_screen.xml.haml new file mode 100644 index 0000000..9476c44 --- /dev/null +++ b/app/views/config_snom/idle_screen.xml.haml @@ -0,0 +1,33 @@ +!!! XML +%screen_description + - if @phone_xml_object[:image] + %Image + %Data{:encoding => 'base64'}= @phone_xml_object[:image][:data] + %LocationX= @phone_xml_object[:image][:location_x] + %LocationY= @phone_xml_object[:image][:location_y] + %Invert= @phone_xml_object[:image][:invert] + - if @phone_xml_object[:clock] + %Clock + %LocationX= @phone_xml_object[:clock][:location_x] + %LocationY= @phone_xml_object[:clock][:location_y] + - if @phone_xml_object[:digital_clock] + %DigitalClock + %LocationX= @phone_xml_object[:digital_clock][:location_x] + %LocationY= @phone_xml_object[:digital_clock][:location_y] + - if @phone_xml_object[:date] + %Date + %LocationX= @phone_xml_object[:date][:location_x] + %LocationY= @phone_xml_object[:date][:location_y] + - if @phone_xml_object[:line] + %Line + %Account + %LocationX= @phone_xml_object[:line][:location_x] + %LocationY= @phone_xml_object[:line][:location_y] + - if @phone_xml_object[:status] + %Status + %LocationX= @phone_xml_object[:status][:location_x] + %LocationY= @phone_xml_object[:status][:location_y] + - if @phone_xml_object[:softkeys] + %Softkeys + %LocationX= @phone_xml_object[:softkeys][:location_x] + %LocationY= @phone_xml_object[:softkeys][:location_y] diff --git a/app/views/config_snom/log_in.xml.haml b/app/views/config_snom/log_in.xml.haml new file mode 100644 index 0000000..1f45d93 --- /dev/null +++ b/app/views/config_snom/log_in.xml.haml @@ -0,0 +1,3 @@ +!!! XML += render @phone_xml_object[:name] + diff --git a/app/views/config_snom/show.xml.haml b/app/views/config_snom/show.xml.haml new file mode 100644 index 0000000..d9953c5 --- /dev/null +++ b/app/views/config_snom/show.xml.haml @@ -0,0 +1,151 @@ +!!! XML +%settings + %phone-settings + %auto_reboot_on_setting_change{:perm => 'RW'}= 'off' + - if !@phone_settings[:setting_server].blank? + %setting_server{:perm => 'RW'}= @phone_settings[:setting_server] + %web_language{:perm => 'RW'}= 'English' + %language{:perm => 'RW'}= @phone_settings[:language] + %timezone{:perm => 'RW'}= 'GER+1' + %date_us_format{:perm => 'RW'}= 'off' + %time_24_format{:perm => 'RW'}= 'on' + %reset_settings{:perm => 'RW'}= '' + %update_policy{:perm => 'RW'}= 'settings_only' + %settings_refresh_timer{:perm => 'RW'}= '0' + %firmware_status{:perm => 'RW'}= '' + %webserver_type{:perm => 'R'}= 'http_https' + %http_scheme{:perm => 'RW'}= 'off' + %http_port{:perm => 'R'}= '80' + %https_port{:perm => 'R'}= '443' + %http_user{:perm => 'R'}= @phone_settings[:http_user] + %http_pass{:perm => 'R'}= @phone_settings[:http_pass] + %admin_mode_password{:perm => 'R'}= @phone_settings[:admin_mode_password] + %tone_scheme{:perm => 'RW'}= @phone_settings[:tone_scheme] + %keytones{:perm => 'RW'}= 'off' + %dtmf_speaker_phone{:perm => 'RW'}= 'off' + %disable_redirection_menu{:perm => 'R'}= 'on' + %retry_after_failed_register{:perm => 'RW'}= '70' + %encode_display_name{:perm => 'R'}= 'on' + %dtmf_payload_type{:perm => 'RW'}= '101' + %ignore_security_warning{:perm => 'R'}= 'on' + %call_completion{:perm => 'RW'}= 'on' + %block_url_dialing{:perm => 'RW'}= 'on' + %redirect_ringing{:perm => 'RW'}= 'on' + %goto_virtual_keys_state_on_activity{:perm => 'RW'}= 'off' + %goto_monitor_state_on_line_activity{:perm => 'RW'}= 'on' + %ringer_animation{:perm => 'RW'}= 'on' + %display_method{:perm => 'RW'}= 'display_name_number' + %callpickup_dialoginfo{:perm => 'RW'}= 'on' + %show_local_line{:perm => 'RW'}= 'off' + %mwi_notification{:perm => 'RW'}= 'silent' + %mwi_dialtone{:perm => 'RW'}= 'normal' + %prefer_saved_over_received_photo{:perm => 'RW'}= 'off' + %no_dnd{:perm => 'RW'}= 'on' + %logon_wizard{:perm => 'RW'}= 'off' + %disable_deflection{:perm => 'RW'}= 'off' + %csta_control{:perm => 'RW'}= 'on' + %save_latest_callrecords_to_flash{:perm => 'RW'}= 'off' + %use_proxy_number_guessing{:perm => 'RW'}= 'off' + %guess_number{:perm => 'RW'}= 'off' + %guess_start_length{:perm => 'RW'}= '3' + %ieee8021x_eap_md5_username{:perm => 'RW'}= PROVISIONING_IEEE8021X_EAP_USERNAME + %ieee8021x_eap_md5_password{:perm => 'RW'}= PROVISIONING_IEEE8021X_EAP_PASSWORD + + - 0.upto(9) do |ringer_idx| + %internal_ringer_text{:idx => ringer_idx, :perm => 'RW'}= "Ringer#{(ringer_idx+1)}" + %internal_ringer_file{:idx => ringer_idx, :perm => 'RW'}= "Ringer#{(ringer_idx+1)}" + + %internal_ringer_text{:idx => 10, :perm => 'RW'}= "Ringer0" + %internal_ringer_file{:idx => 10, :perm => 'RW'}= "Silent" + + %gui_fkey1{:perm => 'R'}= 'none' + %gui_fkey2{:perm => 'R'}= 'none' + %gui_fkey3{:perm => 'R'}= 'none' + %gui_fkey4{:perm => 'R'}= 'none' + + %dkey_menu{:perm => 'RW'}= @dkeys[:menu] + %dkey_retrieve{:perm => 'RW'}= @dkeys[:retrieve] + %dkey_conf{:perm => 'RW'}= @dkeys[:conf] + %dkey_redial{:perm => 'RW'}= @dkeys[:redial] + %dkey_directory{:perm => 'RW'}= @dkeys[:directory] + + %idle_ok_key_action{:perm => 'RW'}= @dkeys[:idle_ok] + %idle_cancel_key_action{:perm => 'RW'}= @dkeys[:idle_cancel] + %idle_up_key_action{:perm => 'RW'}= @dkeys[:idle_up] + %idle_down_key_action{:perm => 'RW'}= @dkeys[:idle_down] + %idle_left_key_action{:perm => 'RW'}= @dkeys[:idle_left] + %idle_right_key_action{:perm => 'RW'}= @dkeys[:idle_right] + + != "\ + + + +%html.no-js{ :lang => "en" } + ~#OPTIMIZE Make html lang attribute reflect the actual language. + + %header + %meta{ :charset => "utf-8" }/ + ~#OPTIMIZE "/" seems to be supposed to make an empty element tag, but it doesn't work. HAML bug? + %title + = content_for?(:title) ? yield(:title) : "Untitled" + %meta{ :name => "viewport", :content => "width=device-width, initial-scale=1.0" }/ + = stylesheet_link_tag "application" + = javascript_include_tag "application" + = csrf_meta_tag + = yield(:head) + + %body + #container + = render :partial => "shared/header" + = render :partial => "shared/system_message" + = render :partial => "shared/flash", :locals => { :flash => flash} + + #content{:role => 'main'} + .light + %header.main + .breadcrumbs= render_breadcrumbs :separator => ' » ' + - if show_title? + %h1= yield(:title) + = yield + + %footer#main + %ul + - if GuiFunction.display?('amooma_commercial_support_link_in_footer', current_user) + %li + %a{:href => "http://www.amooma.de"} Kommerzieller Support und Consulting + - if GuiFunction.display?('gemeinschaft_mailinglist_link_in_footer', current_user) + %li + %a{:href => "https://groups.google.com/group/gs5-users/"} Kostenlose Mailingliste + + .amooma-logo + %span brought to you by + %a{ :target => '_blank', :href => "http://www.amooma.de/" } Amooma + diff --git a/app/views/manufacturers/_form.html.haml b/app/views/manufacturers/_form.html.haml new file mode 100644 index 0000000..d89c603 --- /dev/null +++ b/app/views/manufacturers/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for(@manufacturer) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('manufacturers.form.submit') \ No newline at end of file diff --git a/app/views/manufacturers/_form_core.html.haml b/app/views/manufacturers/_form_core.html.haml new file mode 100644 index 0000000..84b85c9 --- /dev/null +++ b/app/views/manufacturers/_form_core.html.haml @@ -0,0 +1,4 @@ +.inputs + = f.input :name, :label => t('manufacturers.form.name.label'), :hint => conditional_hint('manufacturers.form.name.hint') + = f.input :ieee_name, :label => t('manufacturers.form.ieee_name.label'), :hint => conditional_hint('manufacturers.form.ieee_name.hint') + = f.input :homepage_url, :label => t('manufacturers.form.homepage_url.label'), :hint => conditional_hint('manufacturers.form.homepage_url.hint') diff --git a/app/views/manufacturers/_index_core.html.haml b/app/views/manufacturers/_index_core.html.haml new file mode 100644 index 0000000..8937909 --- /dev/null +++ b/app/views/manufacturers/_index_core.html.haml @@ -0,0 +1,18 @@ +%table + %tr + %th= t('manufacturers.index.name') + %th= t('manufacturers.index.ieee_name') + %th= t('manufacturers.index.homepage_url') + %th= t('manufacturers.index.phone_models') + + - reset_cycle + - for manufacturer in manufacturers + %tr{:class => cycle('odd', 'even')} + %td= manufacturer.name + %td= manufacturer.ieee_name + %td + - if manufacturer.homepage_url + =link_to manufacturer.homepage_url, manufacturer.homepage_url + %td + = manufacturer.phone_models.map{|x| x.to_s }.join(', ') + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:child => manufacturer} \ No newline at end of file diff --git a/app/views/manufacturers/edit.html.haml b/app/views/manufacturers/edit.html.haml new file mode 100644 index 0000000..61bcba0 --- /dev/null +++ b/app/views/manufacturers/edit.html.haml @@ -0,0 +1,3 @@ +- title t("manufacturers.edit.page_title") + += render "form" diff --git a/app/views/manufacturers/index.html.haml b/app/views/manufacturers/index.html.haml new file mode 100644 index 0000000..43fecc6 --- /dev/null +++ b/app/views/manufacturers/index.html.haml @@ -0,0 +1,5 @@ +- title t("manufacturers.index.page_title") + += render "index_core", :manufacturers => @manufacturers + += render :partial => 'shared/create_link', :locals => {:child_class => Manufacturer} \ No newline at end of file diff --git a/app/views/manufacturers/new.html.haml b/app/views/manufacturers/new.html.haml new file mode 100644 index 0000000..4fb9dbf --- /dev/null +++ b/app/views/manufacturers/new.html.haml @@ -0,0 +1,3 @@ +- title t("manufacturers.new.page_title") + += render "form" diff --git a/app/views/manufacturers/show.html.haml b/app/views/manufacturers/show.html.haml new file mode 100644 index 0000000..1b8383b --- /dev/null +++ b/app/views/manufacturers/show.html.haml @@ -0,0 +1,18 @@ +- title t("manufacturers.show.page_title") + +%p + %strong= t('manufacturers.show.name') + ":" + = @manufacturer.name +%p + %strong= t('manufacturers.show.ieee_name') + ":" + = @manufacturer.ieee_name +%p + %strong= t('manufacturers.show.homepage_url') + ":" + - if @manufacturer.homepage_url + =link_to @manufacturer.homepage_url, @manufacturer.homepage_url + += render :partial => 'shared/show_edit_destroy_part', :locals => { :child => @manufacturer } + +%h2=t("phone_models.index.page_title") + +=render 'phone_models/index_core', :phone_models => @manufacturer.phone_models \ No newline at end of file diff --git a/app/views/notifications/new_fax.text.erb b/app/views/notifications/new_fax.text.erb new file mode 100644 index 0000000..579cc18 --- /dev/null +++ b/app/views/notifications/new_fax.text.erb @@ -0,0 +1,8 @@ +Hello <%= @fax[:greeting] %>, + +You've just received a fax document on your Gemeinschaft account <%= @fax[:account_name] %>. + + Caller: <%= @fax[:from] %> +Remote Station: <%= @fax[:remote_station_id] %> + Local Station: <%= @fax[:local_station_id] %> +Receiving Time: <%= @fax[:date] %> diff --git a/app/views/notifications/new_password.text.erb b/app/views/notifications/new_password.text.erb new file mode 100644 index 0000000..a865960 --- /dev/null +++ b/app/views/notifications/new_password.text.erb @@ -0,0 +1,3 @@ +Hello <%= @message[:greeting] %>, + +Your password has been reset to: <%= @password %> diff --git a/app/views/notifications/new_pin.text.erb b/app/views/notifications/new_pin.text.erb new file mode 100644 index 0000000..11cf17b --- /dev/null +++ b/app/views/notifications/new_pin.text.erb @@ -0,0 +1,7 @@ +Hello <%= @pin[:greeting] %>, + +the PIN of one of your conference rooms has been changed. + +Conference: <%= @pin[:conference] %> + Numbers: <%= @pin[:phone_numbers] %> + New PIN: <%= @pin[:pin] %> diff --git a/app/views/notifications/new_voicemail.text.erb b/app/views/notifications/new_voicemail.text.erb new file mode 100644 index 0000000..adeabda --- /dev/null +++ b/app/views/notifications/new_voicemail.text.erb @@ -0,0 +1,9 @@ +Hello <%= @voicemail[:greeting] %>, + +You've just received a voicemail on your Gemeinschaft account <%= @voicemail[:destination] %>. + + From: <%= @voicemail[:from] %> + To: <%= @voicemail[:to] %> +Receiving Time: <%= @voicemail[:date] %> +Message length: <%= @voicemail[:duration] %> + File: <%= @voicemail[:file_name] %> diff --git a/app/views/page/conference.html.haml b/app/views/page/conference.html.haml new file mode 100644 index 0000000..061dfd1 --- /dev/null +++ b/app/views/page/conference.html.haml @@ -0,0 +1,80 @@ +- conf_call_topic = "The next big thing" +- title "Conference Call \u2013 Topic: #{conf_call_topic}" + + +%section.conference + + %section.panel.speakers.first + %header + %h3 Speakers + ~# Naming this class message, since when you add or chat you're sending + ~# a message to the server. + %form.message + %input{:placeholder => '# '} + .actors + - 2.times do + .actor + .info + - user = current_user #FIXME + - avatar_url = user.image_url(:mini) || 'stubs/user-36x.jpg' + = image_tag avatar_url.to_s, :class => 'display', :alt => "[ ]" + %span.name Fake Stefan + %span.status Joined at 03:00 + .voice-actions + %a.make.listener{ :href => '#', :title => "Make listener" } Make listener + %a.voice.unmuted{ :href => '#', :title => "Mute" } Mute + %a.remove{ :href => '#', :title => "Remove from conference" } Remove + + + %section.panel.listeners + %header + %h3 Listeners + ~# Naming this class message, since when you add or chat you're sending + ~# a message to the server. + %form.message + %input{:placeholder => '# '} + .actors + - 5.times do + .actor + .info + - user = current_user #FIXME + - avatar_url = user.image_url(:mini) || 'stubs/user-36x.jpg' + = image_tag avatar_url.to_s, :class => 'display', :alt => "[ ]" + %span.name Fake Stefan + %span.status Joined at 03:00 + .voice-actions + %a.make.speaker{ :href => '#', :title => "Make speaker" } Make speaker + %a.voice.unmuted{ :href => '#', :title => "Mute" } Mute + %a.remove{ :href => '#', :title => "Remove from conference" } Remove + + + %section.panel.log.last + %header + %h3 Log + ~# Naming this class message, since when you add or chat you're sending + ~# a message to the server. + %form.message + %input{:placeholder => 'Write a Message...'} + .messages + %div + %span.name Mario: + %span.content Sorry for the Delay! + %div.status + %span.name 03:11: + %span.content Fake Stefan is now a Speaker. + %div.status + %span.name 03:10: + %span.content Stefan Wintermeyer Left. + %div + %span.name Stefan: + %span.content Hello World. + %div.status + %span.name 03:00: + %span.content Stefan Wintermeyer Joined. + %div + %span.name Herpiti Derp: + %span.content Cool Conference Room! + %div + %span.name Pamela: + %span.content I'm here to sing along. + diff --git a/app/views/page/index.de.html.haml b/app/views/page/index.de.html.haml new file mode 100644 index 0000000..2928319 --- /dev/null +++ b/app/views/page/index.de.html.haml @@ -0,0 +1,16 @@ +- title "Gemeinschaft #{GEMEINSCHAFT_VERSION}" + +%div + %h3 Aktueller Mandant + - if current_user && current_user.current_tenant + %strong= current_user.current_tenant + - else + %strong= "(none)" + +%div + %h3 Aktuelle Gruppenzugehörigkeiten + %ul + - (current_user.try(:user_groups) || []).each do |group| + %li + %strong= "#{group.name}" + = "(aus Mandant: %s)" % group.tenant diff --git a/app/views/page/index.html.haml b/app/views/page/index.html.haml new file mode 100644 index 0000000..9621395 --- /dev/null +++ b/app/views/page/index.html.haml @@ -0,0 +1,16 @@ +- title "Gemeinschaft #{GEMEINSCHAFT_VERSION}" + +%div + %h3 Current tenant + - if current_user && current_user.current_tenant + %strong= current_user.current_tenant + - else + %strong= "(none)" + +%div + %h3 Current user groups + %ul + - (current_user.try(:user_groups) || []).each do |group| + %li + %strong= "#{group.name}" + = "(from tenant: %s)" % group.tenant diff --git a/app/views/phone_book_entries/_form.html.haml b/app/views/phone_book_entries/_form.html.haml new file mode 100644 index 0000000..c73d10a --- /dev/null +++ b/app/views/phone_book_entries/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([@phone_book, @phone_book_entry]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('phone_book_entries.form.submit') \ No newline at end of file diff --git a/app/views/phone_book_entries/_form_core.html.haml b/app/views/phone_book_entries/_form_core.html.haml new file mode 100644 index 0000000..c05139e --- /dev/null +++ b/app/views/phone_book_entries/_form_core.html.haml @@ -0,0 +1,27 @@ +.inputs + = f.input :is_male, :collection => [[true, t('phone_book_entries.form.gender.male')], [false, t('phone_book_entries.form.gender.female')]], :label_method => :last, :value_method => :first, :label => t('phone_book_entries.form.male.label'), :hint => conditional_hint('phone_book_entries.form.gender.hint'), :label => t('phone_book_entries.form.gender.label'), :as => :radio + = f.input :first_name, :label => t('phone_book_entries.form.first_name.label'), :hint => conditional_hint('phone_book_entries.form.first_name.hint') + = f.input :middle_name, :label => t('phone_book_entries.form.middle_name.label'), :hint => conditional_hint('phone_book_entries.form.middle_name.hint') + = f.input :last_name, :label => t('phone_book_entries.form.last_name.label'), :hint => conditional_hint('phone_book_entries.form.last_name.hint') + = f.input :birth_name, :label => t('phone_book_entries.form.birth_name.label'), :hint => conditional_hint('phone_book_entries.form.birth_name.hint') + = f.input :title, :label => t('phone_book_entries.form.title.label'), :hint => conditional_hint('phone_book_entries.form.title.hint') + = f.input :nickname, :label => t('phone_book_entries.form.nickname.label'), :hint => conditional_hint('phone_book_entries.form.nickname.hint') + = f.input :organization, :label => t('phone_book_entries.form.organization.label'), :hint => conditional_hint('phone_book_entries.form.organization.hint') + / = f.input :is_organization, :label => t('phone_book_entries.form.is_organization.label'), :hint => conditional_hint('phone_book_entries.form.is_organization.hint') + = f.input :department, :label => t('phone_book_entries.form.department.label'), :hint => conditional_hint('phone_book_entries.form.department.hint') + = f.input :job_title, :label => t('phone_book_entries.form.job_title.label'), :hint => conditional_hint('phone_book_entries.form.job_title.hint') + + = f.input :birthday, :label => t('phone_book_entries.form.birthday.label'), :hint => conditional_hint('phone_book_entries.form.birthday.hint'), :start_year => Date.today.year - 100, :end_year => Date.today.year - 0, :order => [:day, :month, :year], :include_blank => true + + = f.input :description, :label => t('phone_book_entries.form.description.label'), :hint => conditional_hint('phone_book_entries.form.description.hint') + + = f.input :image, { :as => :file, :label => t('phone_book_entries.form.image.label'), :hint => conditional_hint('phone_book_entries.form.image.hint') } + + = f.input :homepage_organization, :label => t('phone_book_entries.form.homepage_organization.label'), :hint => conditional_hint('phone_book_entries.form.homepage_organization.hint') + = f.input :homepage_personal, :label => t('phone_book_entries.form.homepage_personal.label'), :hint => conditional_hint('phone_book_entries.form.homepage_personal.hint') + / = f.input :twitter_account, :label => t('phone_book_entries.form.twitter_account.label'), :hint => conditional_hint('phone_book_entries.form.twitter_account.hint') + / = f.input :facebook_account, :label => t('phone_book_entries.form.facebook_account.label'), :hint => conditional_hint('phone_book_entries.form.facebook_account.hint') + / = f.input :google_plus_account, :label => t('phone_book_entries.form.google_plus_account.label'), :hint => conditional_hint('phone_book_entries.form.google_plus_account.hint') + / = f.input :xing_account, :label => t('phone_book_entries.form.xing_account.label'), :hint => conditional_hint('phone_book_entries.form.xing_account.hint') + / = f.input :linkedin_account, :label => t('phone_book_entries.form.linkedin_account.label'), :hint => conditional_hint('phone_book_entries.form.linkedin_account.hint') + diff --git a/app/views/phone_book_entries/_index_core.de.html.haml b/app/views/phone_book_entries/_index_core.de.html.haml new file mode 100644 index 0000000..01be65f --- /dev/null +++ b/app/views/phone_book_entries/_index_core.de.html.haml @@ -0,0 +1,36 @@ +~# To Look for the other fields, please look into Git History. +%section.phone-book-entries + %header.entries-nav= render :partial => "phone_book_entries/navigation" + .content + - reset_cycle + %table + - for entry in phone_book_entries + ~# Dear IE7, + ~# Because of you we have to do this with a table. + ~# With Love, + ~# Mario. + %tr.phone-book-entry{:class => cycle('odd', 'even'), :"itemscope itemtype" => "http://schema.org/Person"} + %td.thumbnail + = image_tag(entry.image_url(:small).to_s, :itemprop => 'image') + %td.user + - if entry.is_organization == true + %a.name{:href=> phone_book_phone_book_entry_path(entry.phone_book, entry), :itemprop => "name"}= entry + - else + %a.name{:href=> phone_book_phone_book_entry_path(entry.phone_book, entry), :itemprop => "name"}= entry + %a.company{:href=> phone_book_phone_book_entry_path(entry.phone_book, entry), :itemprop => 'memberOf'}= entry.organization + %td.contact + - if @found_phone_numbers and @found_phone_numbers.where(:phone_numberable_id => entry.id) + %a.phone{:href=> phone_book_phone_book_entry_path(entry.phone_book, entry), :itemprop => 'telephone'}= @found_phone_numbers.where(:phone_numberable_id => entry.id).first + - elsif entry.phone_numbers.first + %a.phone{:href=> phone_book_phone_book_entry_path(entry.phone_book, entry), :itemprop => 'telephone'}= entry.phone_numbers.first + - if entry.phone_numbers.count > 1 + %a.more{:href => phone_book_phone_book_entry_path(entry.phone_book, entry)}= t('phone_book_entries.index.more_numbers', :numbers => (entry.phone_numbers.count-1)) + %td.extra + - if !entry.description.blank? + %strong Beschreibung: + %div= entry.description + - if can? :edit, entry + %td= link_to t('phone_book_entries.index.actions.edit'), edit_phone_book_phone_book_entry_path( entry.phone_book, entry ) + - if can? :destroy, entry + %td= link_to t('phone_book_entries.index.actions.destroy'), [entry.phone_book, entry], :confirm => t('phone_book_entries.index.actions.confirm'), :method => :delete + %footer.entries-nav= render :partial => "phone_book_entries/navigation" diff --git a/app/views/phone_book_entries/_index_core.html.haml b/app/views/phone_book_entries/_index_core.html.haml new file mode 100644 index 0000000..d9cfe10 --- /dev/null +++ b/app/views/phone_book_entries/_index_core.html.haml @@ -0,0 +1,36 @@ +~# To Look for the other fields, please look into Git History. +%section.phone-book-entries + %header.entries-nav= render :partial => "phone_book_entries/navigation" + .content + - reset_cycle + %table + - for entry in phone_book_entries + ~# Dear IE7, + ~# Because of you we have to do this with a table. + ~# With Love, + ~# Mario. + %tr.phone-book-entry{:class => cycle('odd', 'even'), :"itemscope itemtype" => "http://schema.org/Person"} + %td.thumbnail + = image_tag(entry.image_url(:small).to_s, :itemprop => 'image') + %td.user + - if entry.is_organization == true + %a.name{:href=> phone_book_phone_book_entry_path(entry.phone_book, entry), :itemprop => "name"}= entry + - else + %a.name{:href=> phone_book_phone_book_entry_path(entry.phone_book, entry), :itemprop => "name"}= entry + %a.company{:href=> phone_book_phone_book_entry_path(entry.phone_book, entry), :itemprop => 'memberOf'}= entry.organization + %td.contact + - if @found_phone_numbers and @found_phone_numbers.where(:phone_numberable_id => entry.id) + %a.phone{:href=> phone_book_phone_book_entry_path(entry.phone_book, entry), :itemprop => 'telephone'}= @found_phone_numbers.where(:phone_numberable_id => entry.id).first + - elsif entry.phone_numbers.first + %a.phone{:href=> phone_book_phone_book_entry_path(entry.phone_book, entry), :itemprop => 'telephone'}= entry.phone_numbers.first + - if entry.phone_numbers.count > 1 + %a.more{:href => phone_book_phone_book_entry_path(entry.phone_book, entry)}= t('phone_book_entries.index.more_numbers', :numbers => (entry.phone_numbers.count-1)) + %td.extra + - if !entry.description.blank? + %strong Description: + %div= entry.description + - if can? :edit, entry + %td= link_to t('phone_book_entries.index.actions.edit'), edit_phone_book_phone_book_entry_path( entry.phone_book, entry ) + - if can? :destroy, entry + %td= link_to t('phone_book_entries.index.actions.destroy'), [entry.phone_book, entry], :confirm => t('phone_book_entries.index.actions.confirm'), :method => :delete + %footer.entries-nav= render :partial => "phone_book_entries/navigation" diff --git a/app/views/phone_book_entries/_navigation.html.haml b/app/views/phone_book_entries/_navigation.html.haml new file mode 100644 index 0000000..dd1e8a7 --- /dev/null +++ b/app/views/phone_book_entries/_navigation.html.haml @@ -0,0 +1,8 @@ +%nav + %ol.abc + - %w{# A B C D E F G H I J K L M N O P Q R S T U V W X Y Z}.each do |char| + %li + %a{ :href => "?name=#{char}" }= char + +.pagination + = will_paginate @phone_book_entries diff --git a/app/views/phone_book_entries/edit.html.haml b/app/views/phone_book_entries/edit.html.haml new file mode 100644 index 0000000..d4fad4d --- /dev/null +++ b/app/views/phone_book_entries/edit.html.haml @@ -0,0 +1,9 @@ +- title t("phone_book_entries.edit.page_title") + += render "form" + +%p + - if can? :edit, @phone_book_entry + = link_to t('phone_book_entries.edit.actions.edit'), @phone_book_entry + | + = link_to t('phone_book_entries.edit.actions.view_all'), phone_book_entries_path diff --git a/app/views/phone_book_entries/index.html.haml b/app/views/phone_book_entries/index.html.haml new file mode 100644 index 0000000..6a17eb9 --- /dev/null +++ b/app/views/phone_book_entries/index.html.haml @@ -0,0 +1,19 @@ +- title t("phone_book_entries.index.page_title") + +- if @phone_books + %p + = t('phone_book_entries.index.available_phone_books') + - @phone_books.each do |phone_book| + = link_to phone_book, phone_book + - if can?(:create, PhoneBookEntry, :phone_book_id => phone_book.id) + ( + = link_to "#{t('phone_book_entries.index.create_new_phone_book_entry')}", new_phone_book_phone_book_entry_path(phone_book) + ) + - if phone_book != @phone_books.last + \, + +- if @phone_book_entries.count > 0 + = render "index_core", :phone_book_entries => @phone_book_entries + +- if @phone_book + = render :partial => 'shared/create_link', :locals => {:parent => @phone_book, :child_class => PhoneBookEntry} \ No newline at end of file diff --git a/app/views/phone_book_entries/new.html.haml b/app/views/phone_book_entries/new.html.haml new file mode 100644 index 0000000..d72d1a4 --- /dev/null +++ b/app/views/phone_book_entries/new.html.haml @@ -0,0 +1,3 @@ +- title t("phone_book_entries.new.page_title") + += render "form" diff --git a/app/views/phone_book_entries/show.html.haml b/app/views/phone_book_entries/show.html.haml new file mode 100644 index 0000000..b6e8c6e --- /dev/null +++ b/app/views/phone_book_entries/show.html.haml @@ -0,0 +1,146 @@ +- title nil + +%section.phone-book-entry + .content + %header + %h1.username + %a= @phone_book_entry + - if !@phone_book_entry.organization.blank? + .work + %a= @phone_book_entry.organization + - if !@phone_book_entry.department.blank? + \/ + = @phone_book_entry.department + - if !@phone_book_entry.job_title.blank? + \/ + = @phone_book_entry.job_title + .personal + - if !@phone_book_entry.nickname.blank? + %span.nickname + a.k.a + %strong= @phone_book_entry.nickname + - if @phone_book_entry.birthday + %span.birthday + = l(@phone_book_entry.birthday) + .tags + %a= l @phone_book_entry.created_at.utc.getlocal, :format => :short + , + %a= l @phone_book_entry.updated_at.utc.getlocal, :format => :short + %section.activity + - if @user_log + %h2 User Log + - @user_log.each do |log_entry| + - if log_entry[:type] == 'voicemail' + .entry.voice-message + %span.motive + = log_entry[:text] + %span.timestamp + = log_entry[:timestamp] + - if log_entry[:type] == 'fax_document' + .entry.fax + %span.motive + = log_entry[:text] + %span.timestamp + = log_entry[:timestamp] + - if log_entry[:type] == 'call_placed' + .entry.phone + %span.motive + log_entry[:text] + %span.timestamp + = log_entry[:timestamp] + - elsif log_entry[:type] == 'call_received' + .entry.phone + %span.motive + = log_entry[:text] + %span.timestamp + = log_entry[:timestamp] + - elsif log_entry[:type] == 'call_missed' + .entry.phone-down + %span.motive + = log_entry[:text] + %span.timestamp + = log_entry[:timestamp] + + .sidebar + = image_tag @phone_book_entry.image_url(:profile).to_s, :class => 'display' + %p.description + = @phone_book_entry.description + .widget.phones + - @phone_book_entry.phone_numbers.each do |phone_number| + - case phone_number.name + - when /fax/ + .fax + %a= phone_number + %span= phone_number.name + - when /home/ + .home + %a= phone_number + %span= phone_number.name + - when /mobile/ + .cellphone + %a= phone_number + %span= phone_number.name + - when /office/ + .office + %a= phone_number + %span= phone_number.name + - else + .phone + %a= phone_number + %span= phone_number.name + = link_to t('phone_book_entries.show.manage_phone_numbers'), phone_book_entry_phone_numbers_path(@phone_book_entry) + + .widget.adresses + - @phone_book_entry.addresses.each do |address| + .home + %strong + - if !address.line1.blank? + = address.line1 + %br + - if !address.line2.blank? + = address.line1 + %br + - if !address.street.blank? + = address.street + %br + - if !address.city.blank? + = "#{address.city} #{address.zip_code}" + %br + - if !address.country.blank? + = address.country.to_s + %br + / %span Home + / .office + .widget.social + - if !@phone_book_entry.homepage_organization.blank? + .home + %a= @phone_book_entry.homepage_organization + %span www + - if !@phone_book_entry.homepage_personal.blank? + .home + %a= @phone_book_entry.homepage_personal + %span www + - if !@phone_book_entry.twitter_account.blank? + .twitter + %a= @phone_book_entry.twitter_account + %span Twitter + - if !@phone_book_entry.google_plus_account.blank? + .google_plus + %a= @phone_book_entry.google_plus_account + %span Google+ + - if !@phone_book_entry.facebook_account.blank? + .facebook + %a= @phone_book_entry.facebook_account + %span Facebook + - if !@phone_book_entry.xing_account.blank? + .xing + %a= @phone_book_entry.xing_account + %span Xing + - if !@phone_book_entry.linkedin_account.blank? + .linkedin + %a= @phone_book_entry.linkedin_account + %span LinkedIn + - if !@phone_book_entry.mobileme_account.blank? + .mobileme + %a= @phone_book_entry.mobileme_account + %span MobileMe diff --git a/app/views/phone_book_entries/show.html.haml.examlple b/app/views/phone_book_entries/show.html.haml.examlple new file mode 100644 index 0000000..176ad04 --- /dev/null +++ b/app/views/phone_book_entries/show.html.haml.examlple @@ -0,0 +1,194 @@ +- title nil + +%section.phone-book-entry + .content + %header + %h1.username + %a= @phone_book_entry + - if !@phone_book_entry.organization.blank? + .work + %a= @phone_book_entry.organization + - if !@phone_book_entry.department.blank? + \/ + = @phone_book_entry.department + - if !@phone_book_entry.job_title.blank? + \/ + = @phone_book_entry.job_title + .personal + - if !@phone_book_entry.nickname.blank? + %span.nickname + a.k.a + %strong= @phone_book_entry.nickname + - if @phone_book_entry.birthday + %span.birthday + = l(@phone_book_entry.birthday) + .tags + %a Developer + , + %a Worked With + , + %a Friend + %section.activity + %h2 User Log + = form_tag '/entry-whatever' do + %textarea{ :placeholder => "Leave a comment ..." } + .comment + = image_tag @phone_book_entry.image_url(:mini).to_s, :class => 'display' + .info + %span.commenter Random User + %span.time at 10:00 of Today + .body + I'm really tired and I still have to pack part of my baggage... + - 3.times do + .entry.voice-message + %span.motive + Stefan Wintermeyer left you a voice message 4 minutes ago. + %span.timestamp + 10:30 03/11/2011 + .entry.phone + %span.motive + Called Stefan Wintermeyer at + %a Work + with a duration of 5 minutes. + %span.timestamp + 10:30 03/11/2011 + .comment + = image_tag @phone_book_entry.image_url(:mini).to_s, :class => 'display' + .info + %span.commenter Random User + %span.time at 10:00 of Today + .body + I'm really tired and I still have to pack part of my baggage... + .entry.fax + %span.motive + Stefan Wintermeyer sent you a fax with 3 pages. + %span.timestamp + 10:30 03/11/2011 + + .entry.phone-down + %span.motive + Missed call from Stephan Wintermeyer. + %span.timestamp + 10:30 03/11/2011 + + .sidebar + = image_tag @phone_book_entry.image_url(:profile).to_s, :class => 'display' + %p.description + = @phone_book_entry.description + .widget.phones + - @phone_book_entry.phone_numbers.each do |phone_number| + - case phone_number.name + - when /fax/ + .fax + %a= phone_number + %span= phone_number.name + - when /home/ + .home + %a= phone_number + %span= phone_number.name + - when /mobile/ + .cellphone + %a= phone_number + %span= phone_number.name + - when /office/ + .office + %a= phone_number + %span= phone_number.name + - else + .phone + %a= phone_number + %span= phone_number.name + = link_to t('phone_book_entries.show.manage_phone_numbers'), phone_book_entry_phone_numbers_path(@phone_book_entry) + + .widget.adresses + - @phone_book_entry.addresses.each do |address| + .home + %strong + - if !address.line1.blank? + = address.line1 + %br + - if !address.line2.blank? + = address.line1 + %br + - if !address.street.blank? + = address.street + %br + - if !address.city.blank? + = "#{address.city} #{address.zip_code}" + %br + - if !address.country.blank? + = address.country.to_s + %br + / %span Home + / .office + .widget.social + - if !@phone_book_entry.homepage_organization.blank? + .home + %a= @phone_book_entry.homepage_organization + %span www + - if !@phone_book_entry.homepage_personal.blank? + .home + %a= @phone_book_entry.homepage_personal + %span www + - if !@phone_book_entry.twitter_account.blank? + .twitter + %a= @phone_book_entry.twitter_account + %span Twitter + - if !@phone_book_entry.google_plus_account.blank? + .google_plus + %a= @phone_book_entry.google_plus_account + %span Google+ + - if !@phone_book_entry.facebook_account.blank? + .facebook + %a= @phone_book_entry.facebook_account + %span Facebook + - if !@phone_book_entry.xing_account.blank? + .xing + %a= @phone_book_entry.xing_account + %span Xing + - if !@phone_book_entry.linkedin_account.blank? + .linkedin + %a= @phone_book_entry.linkedin_account + %span LinkedIn + - if !@phone_book_entry.mobileme_account.blank? + .mobileme + %a= @phone_book_entry.mobileme_account + %span MobileMe + +/ = debug @phone_book_entry.attributes + + +/ %p +/ %strong= t('phone_book_entries.show.first_name') + ":" +/ = @phone_book_entry.first_name +/ %p +/ %strong= t('phone_book_entries.show.middle_name') + ":" +/ = @phone_book_entry.middle_name +/ %p +/ %strong= t('phone_book_entries.show.last_name') + ":" +/ = @phone_book_entry.last_name +/ %p +/ %strong= t('phone_book_entries.show.title') + ":" +/ = @phone_book_entry.title +/ %p +/ %strong= t('phone_book_entries.show.nickname') + ":" +/ = @phone_book_entry.nickname +/ %p +/ %strong= t('phone_book_entries.show.organization') + ":" +/ = @phone_book_entry.organization +/ %p +/ %strong= t('phone_book_entries.show.department') + ":" +/ = @phone_book_entry.department +/ %p +/ %strong= t('phone_book_entries.show.job_title') + ":" +/ = @phone_book_entry.job_title +/ +/ %p +/ = link_to t('phone_book_entries.show.actions.edit'), edit_phone_book_phone_book_entry_path( @phone_book_entry.phone_book, @phone_book_entry ) +/ | +/ - if can? :destroy, @phone_book_entry +/ = link_to t('phone_book_entries.show.actions.destroy'), phone_book_phone_book_entry_path( @phone_book_entry.phone_book, @phone_book_entry ), :confirm => t('phone_book_entries.show.actions.confirm'), :method => :delete +/ +/ - if @phone_book_entry.phone_numbers.count > 0 +/ = render "phone_numbers/index_core", :phone_numbers => @phone_book_entry.phone_numbers +/ diff --git a/app/views/phone_books/_form.html.haml b/app/views/phone_books/_form.html.haml new file mode 100644 index 0000000..245426b --- /dev/null +++ b/app/views/phone_books/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([ @parent, @phone_book ]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('phone_books.form.submit') \ No newline at end of file diff --git a/app/views/phone_books/_form_core.html.haml b/app/views/phone_books/_form_core.html.haml new file mode 100644 index 0000000..0e36c4d --- /dev/null +++ b/app/views/phone_books/_form_core.html.haml @@ -0,0 +1,3 @@ +.inputs + = f.input :name, :label => t('phone_books.form.name.label'), :hint => conditional_hint('phone_books.form.name.hint'), :autofocus => true + = f.input :description, :label => t('phone_books.form.description.label'), :hint => conditional_hint('phone_books.form.description.hint') diff --git a/app/views/phone_books/_index_core.html.haml b/app/views/phone_books/_index_core.html.haml new file mode 100644 index 0000000..5f50675 --- /dev/null +++ b/app/views/phone_books/_index_core.html.haml @@ -0,0 +1,16 @@ +%table + %tr + %th= t('phone_books.index.name') + %th= t('phone_books.index.description') + %th= t('phone_books.index.count') + + - reset_cycle + - for phone_book in phone_books + %tr{:class => cycle('odd', 'even')} + %td= phone_book.name + %td= phone_book.description + %td + = number_with_delimiter( phone_book.phone_book_entries.count ) + = render :partial => 'shared/create_link', :locals => {:parent => phone_book, :child_class => PhoneBookEntry, :short_link => true} + + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => phone_book.phone_bookable, :child => phone_book} \ No newline at end of file diff --git a/app/views/phone_books/edit.html.haml b/app/views/phone_books/edit.html.haml new file mode 100644 index 0000000..36c945b --- /dev/null +++ b/app/views/phone_books/edit.html.haml @@ -0,0 +1,3 @@ +- title t("phone_books.edit.page_title", :resource => @phone_book) + += render "form" diff --git a/app/views/phone_books/index.html.haml b/app/views/phone_books/index.html.haml new file mode 100644 index 0000000..52b4e9b --- /dev/null +++ b/app/views/phone_books/index.html.haml @@ -0,0 +1,6 @@ +- title t("phone_books.index.page_title") + +- if @phone_books.count > 0 + = render "index_core", :phone_books => @phone_books + += render :partial => 'shared/create_link', :locals => {:parent => @parent, :child_class => PhoneBook} \ No newline at end of file diff --git a/app/views/phone_books/new.html.haml b/app/views/phone_books/new.html.haml new file mode 100644 index 0000000..e96ce1e --- /dev/null +++ b/app/views/phone_books/new.html.haml @@ -0,0 +1,3 @@ +- title t("phone_books.new.page_title") + += render "form" \ No newline at end of file diff --git a/app/views/phone_books/show.html.haml b/app/views/phone_books/show.html.haml new file mode 100644 index 0000000..047b15e --- /dev/null +++ b/app/views/phone_books/show.html.haml @@ -0,0 +1,13 @@ +- title @phone_book +- if ! @phone_book.description.blank? + %p + %strong= t('phone_books.show.description') + ":" + = @phone_book.description + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @phone_book.phone_bookable, :child => @phone_book } + +%h2= t("phone_book_entries.index.page_title") +- if @phone_book_entries.count > 0 + = render "phone_book_entries/index_core", :phone_book_entries => @phone_book_entries + += render :partial => 'shared/create_link', :locals => {:parent => @phone_book, :child_class => PhoneBookEntry} \ No newline at end of file diff --git a/app/views/phone_models/_form.html.haml b/app/views/phone_models/_form.html.haml new file mode 100644 index 0000000..45c176f --- /dev/null +++ b/app/views/phone_models/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([ @manufacturer, @phone_model ]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('phone_models.form.submit') \ No newline at end of file diff --git a/app/views/phone_models/_form_core.html.haml b/app/views/phone_models/_form_core.html.haml new file mode 100644 index 0000000..b406d6e --- /dev/null +++ b/app/views/phone_models/_form_core.html.haml @@ -0,0 +1,4 @@ +.inputs + = f.input :name, :label => t('phone_models.form.name.label'), :hint => conditional_hint('phone_models.form.name.hint') + = f.input :product_manual_homepage_url, :label => t('phone_models.form.product_manual_homepage_url.label'), :hint => conditional_hint('phone_models.form.product_manual_homepage_url.hint') + = f.input :product_homepage_url, :label => t('phone_models.form.product_homepage_url.label'), :hint => conditional_hint('phone_models.form.product_homepage_url.hint') diff --git a/app/views/phone_models/_index_core.html.haml b/app/views/phone_models/_index_core.html.haml new file mode 100644 index 0000000..b07eb68 --- /dev/null +++ b/app/views/phone_models/_index_core.html.haml @@ -0,0 +1,19 @@ +%table + %tr + %th= t('phone_models.index.name') + %th= t('phone_models.index.product_manual_homepage_url') + %th= t('phone_models.index.product_homepage_url') + %th= t('phone_models.index.number_of_phones') + + - reset_cycle + - for phone_model in phone_models + %tr{:class => cycle('odd', 'even')} + %td= phone_model.name + %td + - if phone_model.product_manual_homepage_url + =link_to truncate(phone_model.product_manual_homepage_url, :length => 40), phone_model.product_manual_homepage_url + %td + - if phone_model.product_homepage_url + =link_to truncate(phone_model.product_homepage_url, :length => 40), phone_model.product_homepage_url + %td= phone_model.phones.count + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:child => phone_model, :parent => phone_model.manufacturer} \ No newline at end of file diff --git a/app/views/phone_models/edit.html.haml b/app/views/phone_models/edit.html.haml new file mode 100644 index 0000000..bf31ffc --- /dev/null +++ b/app/views/phone_models/edit.html.haml @@ -0,0 +1,3 @@ +- title t("phone_models.edit.page_title") + += render "form" diff --git a/app/views/phone_models/index.html.haml b/app/views/phone_models/index.html.haml new file mode 100644 index 0000000..90aa4ce --- /dev/null +++ b/app/views/phone_models/index.html.haml @@ -0,0 +1,6 @@ +- title t("phone_models.index.page_title") + +- if @phone_models.count > 0 + = render "index_core", :phone_models => @phone_models + += render :partial => 'shared/create_link', :locals => {:parent => @manufacturer, :child_class => PhoneModel} \ No newline at end of file diff --git a/app/views/phone_models/new.html.haml b/app/views/phone_models/new.html.haml new file mode 100644 index 0000000..9e900d4 --- /dev/null +++ b/app/views/phone_models/new.html.haml @@ -0,0 +1,3 @@ +- title t("phone_models.new.page_title") + += render "form" diff --git a/app/views/phone_models/show.html.haml b/app/views/phone_models/show.html.haml new file mode 100644 index 0000000..06fae4b --- /dev/null +++ b/app/views/phone_models/show.html.haml @@ -0,0 +1,18 @@ +- title t("phone_models.show.page_title") + +%p + %strong= t('phone_models.show.name') + ":" + = @phone_model.name +%p + %strong= t('phone_models.show.manufacturer_id') + ":" + = @phone_model.manufacturer +%p + %strong= t('phone_models.show.product_manual_homepage_url') + ":" + - if @phone_model.product_manual_homepage_url + =link_to @phone_model.product_manual_homepage_url, @phone_model.product_manual_homepage_url +%p + %strong= t('phone_models.show.product_homepage_url') + ":" + - if @phone_model.product_homepage_url + =link_to @phone_model.product_homepage_url, @phone_model.product_homepage_url + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @manufacturer, :child => @phone_model } \ No newline at end of file diff --git a/app/views/phone_number_ranges/_form.html.haml b/app/views/phone_number_ranges/_form.html.haml new file mode 100644 index 0000000..a86d45b --- /dev/null +++ b/app/views/phone_number_ranges/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([ @phone_number_range.phone_number_rangeable, @phone_number_range ]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('phone_number_ranges.form.submit') \ No newline at end of file diff --git a/app/views/phone_number_ranges/_form_core.html.haml b/app/views/phone_number_ranges/_form_core.html.haml new file mode 100644 index 0000000..f553f08 --- /dev/null +++ b/app/views/phone_number_ranges/_form_core.html.haml @@ -0,0 +1,3 @@ +.inputs + = f.input :name, :label => t('phone_number_ranges.form.name.label'), :hint => conditional_hint('phone_number_ranges.form.name.hint') + = f.input :description, :label => t('phone_number_ranges.form.description.label'), :hint => conditional_hint('phone_number_ranges.form.description.hint') diff --git a/app/views/phone_number_ranges/_index_core.html.haml b/app/views/phone_number_ranges/_index_core.html.haml new file mode 100644 index 0000000..24ea96d --- /dev/null +++ b/app/views/phone_number_ranges/_index_core.html.haml @@ -0,0 +1,21 @@ +%table + %tr + %th= t('phone_number_ranges.index.name') + %th= t('phone_number_ranges.index.description') + %th= t('phone_number_ranges.index.numbers') + %th= t('phone_number_ranges.index.amount') + + - reset_cycle + - for phone_number_range in phone_number_ranges + %tr{:class => cycle('odd', 'even')} + %td= t("phone_number_ranges.ranges.#{phone_number_range}.label") + %td= t("phone_number_ranges.ranges.#{phone_number_range}.description") + %td + - if phone_number_range.phone_numbers.count > 0 + = render 'phone_numbers/listing', :phone_numbers => phone_number_range.phone_numbers.order(:number) + %br + = render :partial => 'shared/create_link', :locals => {:parent => phone_number_range, :child_class => PhoneNumber, :short_link => true} + + %td= phone_number_range.phone_numbers.count + - if phone_number_range.phone_number_rangeable.class != Country + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => phone_number_range.phone_number_rangeable, :child => phone_number_range} \ No newline at end of file diff --git a/app/views/phone_number_ranges/edit.html.haml b/app/views/phone_number_ranges/edit.html.haml new file mode 100644 index 0000000..fbf6d12 --- /dev/null +++ b/app/views/phone_number_ranges/edit.html.haml @@ -0,0 +1,3 @@ +- title t("phone_number_ranges.edit.page_title", :resource => @phone_number_range) + += render "form" diff --git a/app/views/phone_number_ranges/index.html.haml b/app/views/phone_number_ranges/index.html.haml new file mode 100644 index 0000000..56cf137 --- /dev/null +++ b/app/views/phone_number_ranges/index.html.haml @@ -0,0 +1,6 @@ +- title t("phone_number_ranges.index.page_title") + +- if @phone_number_ranges.count > 0 + = render "index_core", :phone_number_ranges => @phone_number_ranges + += render :partial => 'shared/create_link', :locals => {:child_class => PhoneNumberRange} \ No newline at end of file diff --git a/app/views/phone_number_ranges/new.html.haml b/app/views/phone_number_ranges/new.html.haml new file mode 100644 index 0000000..d26b34d --- /dev/null +++ b/app/views/phone_number_ranges/new.html.haml @@ -0,0 +1,3 @@ +- title t("phone_number_ranges.new.page_title") + += render "form" diff --git a/app/views/phone_number_ranges/show.html.haml b/app/views/phone_number_ranges/show.html.haml new file mode 100644 index 0000000..64df556 --- /dev/null +++ b/app/views/phone_number_ranges/show.html.haml @@ -0,0 +1,18 @@ +- title t("phone_number_ranges.show.page_title") + +%p + %strong= t('phone_number_ranges.show.name') + ":" + = t("phone_number_ranges.ranges.#{@phone_number_range}.label") +%p + %strong= t('phone_number_ranges.show.description') + ":" + = @phone_number_range.description + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @phone_number_range.phone_number_rangeable, :child => @phone_number_range } + +%h2= t("phone_number_ranges.show.phone_numbers") + +- if @phone_number_range.try(:phone_numbers).try(:count).to_i > 0 + = render "phone_numbers/index_core", :phone_numbers => @phone_number_range.phone_numbers.order(:number) + +%p + = render :partial => 'shared/create_link', :locals => {:parent => @phone_number_range, :child_class => PhoneNumber} \ No newline at end of file diff --git a/app/views/phone_numbers/_form.html.haml b/app/views/phone_numbers/_form.html.haml new file mode 100644 index 0000000..2812e21 --- /dev/null +++ b/app/views/phone_numbers/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([ @parent, @phone_number ]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('phone_numbers.form.submit') diff --git a/app/views/phone_numbers/_form_core.html.haml b/app/views/phone_numbers/_form_core.html.haml new file mode 100644 index 0000000..add3039 --- /dev/null +++ b/app/views/phone_numbers/_form_core.html.haml @@ -0,0 +1,10 @@ +.inputs + + - if @phone_book_entry + = f.input :name, :collection => ['Office', 'Home', 'Mobile', 'Fax'], :include_blank => false, :label => t('phone_numbers.form.name.label'), :hint => conditional_hint('phone_numbers.form.name.hint') + = f.input :number, :label => t('phone_numbers.form.number.label'), :hint => conditional_hint('phone_numbers.form.number.hint') + - else + - if @callthrough || @hunt_group_member || @access_authorization || @current_user.current_tenant.array_of_available_internal_extensions_and_dids.count == 0 || @current_user.current_tenant.array_of_available_internal_extensions_and_dids.count > 250 + = f.input :number, :label => t('phone_numbers.form.number.label'), :hint => conditional_hint('phone_numbers.form.number.hint') + - else + = f.input :number, :collection => @current_user.current_tenant.array_of_available_internal_extensions_and_dids, :label => t('phone_numbers.form.number.label'), :hint => conditional_hint('phone_numbers.form.number.hint'), :include_blank => false diff --git a/app/views/phone_numbers/_index_core.html.haml b/app/views/phone_numbers/_index_core.html.haml new file mode 100644 index 0000000..06b27c8 --- /dev/null +++ b/app/views/phone_numbers/_index_core.html.haml @@ -0,0 +1,13 @@ +%table + %tr + - if phone_numbers.count > 1 && phone_numbers.first.phone_numberable_type == 'PhoneBookEntry' + %th= t('phone_numbers.index.name') + %th= t('phone_numbers.index.number') + + - reset_cycle + - for phone_number in phone_numbers.order(:position) + %tr{:class => cycle('odd', 'even')} + - if phone_number.phone_numberable_type == 'PhoneBookEntry' + %td= phone_number.name + %td= phone_number + = render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => phone_number.phone_numberable, :child => phone_number} diff --git a/app/views/phone_numbers/_listing.html.haml b/app/views/phone_numbers/_listing.html.haml new file mode 100644 index 0000000..ca002c5 --- /dev/null +++ b/app/views/phone_numbers/_listing.html.haml @@ -0,0 +1,8 @@ +- amount_of_phone_numbers = phone_numbers.count +- if amount_of_phone_numbers > 0 + - if amount_of_phone_numbers < 110 + = phone_numbers.map{|number| number}.join(', ') + - else + = phone_numbers.limit(30).map{|number| number}.join(', ') + ', ' + = '[...]' + = phone_numbers.offset(amount_of_phone_numbers - 30).map{|number| number}.join(', ') \ No newline at end of file diff --git a/app/views/phone_numbers/edit.html.haml b/app/views/phone_numbers/edit.html.haml new file mode 100644 index 0000000..d238d3d --- /dev/null +++ b/app/views/phone_numbers/edit.html.haml @@ -0,0 +1,3 @@ +- title t("phone_numbers.edit.page_title", :resource => "" ) + += render "form" \ No newline at end of file diff --git a/app/views/phone_numbers/index.html.haml b/app/views/phone_numbers/index.html.haml new file mode 100644 index 0000000..2161739 --- /dev/null +++ b/app/views/phone_numbers/index.html.haml @@ -0,0 +1,6 @@ +- title @parent + +- if @phone_numbers.count > 0 + = render "index_core", :phone_numbers => @phone_numbers + += render :partial => 'shared/create_link', :locals => {:parent => @parent, :child_class => PhoneNumber} \ No newline at end of file diff --git a/app/views/phone_numbers/new.html.haml b/app/views/phone_numbers/new.html.haml new file mode 100644 index 0000000..e91f4f4 --- /dev/null +++ b/app/views/phone_numbers/new.html.haml @@ -0,0 +1,3 @@ +- title t("phone_numbers.new.page_title") + += render "form" diff --git a/app/views/phone_numbers/show.html.haml b/app/views/phone_numbers/show.html.haml new file mode 100644 index 0000000..30c48bc --- /dev/null +++ b/app/views/phone_numbers/show.html.haml @@ -0,0 +1,27 @@ +- title t("phone_numbers.show.page_title") + +- if @phone_number.phone_numberable.class == PhoneBookEntry + %p + %strong= t('phone_numbers.show.name') + ":" + = @phone_number.name + +%p + %strong= t('phone_numbers.show.number') + ":" + = @phone_number.to_s + +- if @ringtoneable_classes.has_key?(@phone_number.phone_numberable.class.to_s) + %p + %strong= t('ringtones.name') + ':' + - if @phone_number.ringtones.count > 0 + = link_to @phone_number.ringtones.first, phone_number_ringtone_path(@phone_number, @phone_number.ringtones.first) + - else + = link_to t('ringtones.set_a_ringtone'), new_phone_number_ringtone_path(@phone_number) + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @phone_number.phone_numberable, :child => @phone_number } + +- if @forwardable_classes.has_key?(@phone_number.phone_numberable.class.to_s) + %h3= t("call_forwards.index.page_title") + - if @phone_number.call_forwards.length > 0 + = render "call_forwards/index_core", :call_forwards => @phone_number.call_forwards + + = render :partial => 'shared/create_link', :locals => {:parent => @phone_number, :child_class => CallForward} \ No newline at end of file diff --git a/app/views/phone_sip_accounts/_form.html.haml b/app/views/phone_sip_accounts/_form.html.haml new file mode 100644 index 0000000..c2558b8 --- /dev/null +++ b/app/views/phone_sip_accounts/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([@phone, @phone_sip_account]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('phone_sip_accounts.form.submit') \ No newline at end of file diff --git a/app/views/phone_sip_accounts/_form_core.html.haml b/app/views/phone_sip_accounts/_form_core.html.haml new file mode 100644 index 0000000..81f1121 --- /dev/null +++ b/app/views/phone_sip_accounts/_form_core.html.haml @@ -0,0 +1,2 @@ +.inputs + = f.association :sip_account, :collection => @available_sip_accounts, :label => t('phone_sip_accounts.form.sip_account_id.label'), :hint => conditional_hint('phone_sip_accounts.form.sip_account_id.hint'), :include_blank => false diff --git a/app/views/phone_sip_accounts/_index_core.html.haml b/app/views/phone_sip_accounts/_index_core.html.haml new file mode 100644 index 0000000..89afb2b --- /dev/null +++ b/app/views/phone_sip_accounts/_index_core.html.haml @@ -0,0 +1,13 @@ +%table + %tr + %th= t('phone_sip_accounts.index.phone_id') + %th= t('phone_sip_accounts.index.sip_account_id') + %th= t('phone_sip_accounts.index.position') + + - reset_cycle + - for phone_sip_account in phone_sip_accounts + %tr{:class => cycle('odd', 'even')} + %td= phone_sip_account.phone + %td= phone_sip_account.sip_account + %td= phone_sip_account.position + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => phone_sip_account.phone, :child => phone_sip_account} \ No newline at end of file diff --git a/app/views/phone_sip_accounts/index.html.haml b/app/views/phone_sip_accounts/index.html.haml new file mode 100644 index 0000000..a9e3f85 --- /dev/null +++ b/app/views/phone_sip_accounts/index.html.haml @@ -0,0 +1,6 @@ +- title t("phone_sip_accounts.index.page_title") + +- if @phone_sip_accounts.count > 0 + =render "index_core", :phone_sip_accounts => @phone_sip_accounts + += render :partial => 'shared/create_link', :locals => {:parent => @phone, :child_class => PhoneSipAccount} \ No newline at end of file diff --git a/app/views/phone_sip_accounts/new.html.haml b/app/views/phone_sip_accounts/new.html.haml new file mode 100644 index 0000000..bfe40b8 --- /dev/null +++ b/app/views/phone_sip_accounts/new.html.haml @@ -0,0 +1,3 @@ +- title t("phone_sip_accounts.new.page_title") + += render "form" diff --git a/app/views/phone_sip_accounts/show.html.haml b/app/views/phone_sip_accounts/show.html.haml new file mode 100644 index 0000000..0dd5a9b --- /dev/null +++ b/app/views/phone_sip_accounts/show.html.haml @@ -0,0 +1,13 @@ +- title t("phone_sip_accounts.show.page_title") + +%p + %strong= t('phone_sip_accounts.show.phone_id') + ":" + = @phone_sip_account.phone +%p + %strong= t('phone_sip_accounts.show.sip_account_id') + ":" + = @phone_sip_account.sip_account +%p + %strong= t('phone_sip_accounts.show.position') + ":" + = @phone_sip_account.position + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @phone, :child => @phone_sip_account } \ No newline at end of file diff --git a/app/views/phones/_form.html.haml b/app/views/phones/_form.html.haml new file mode 100644 index 0000000..9bfa226 --- /dev/null +++ b/app/views/phones/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([ @phoneable, @phone ]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('phones.form.submit') \ No newline at end of file diff --git a/app/views/phones/_form_core.html.haml b/app/views/phones/_form_core.html.haml new file mode 100644 index 0000000..51ceff5 --- /dev/null +++ b/app/views/phones/_form_core.html.haml @@ -0,0 +1,8 @@ +.inputs + = f.input :mac_address, :label => t('phones.form.mac_address.label'), :hint => conditional_hint('phones.form.mac_address.hint') + = f.association :phone_model, :label => t('phones.form.phone_model_id.label'), :hint => conditional_hint('phones.form.phone_model_id.hint') + = f.input :hot_deskable, :label => t('phones.form.hot_deskable.label'), :hint => conditional_hint('phones.form.hot_deskable.hint') + - if defined? NIGHTLY_REBOOT_OF_PHONES && NIGHTLY_REBOOT_OF_PHONES == true + = f.input :nightly_reboot, :label => t('phones.form.nightly_reboot.label'), :hint => conditional_hint('phones.form.nightly_reboot.hint') + - if defined? PROVISIONING_KEY_LENGTH && PROVISIONING_KEY_LENGTH > 0 + = f.input :provisioning_key_active, :label => t('phones.form.provisioning_key_active.label'), :hint => conditional_hint('phones.form.provisioning_key_active.hint') diff --git a/app/views/phones/_index_core.html.haml b/app/views/phones/_index_core.html.haml new file mode 100644 index 0000000..c442d7f --- /dev/null +++ b/app/views/phones/_index_core.html.haml @@ -0,0 +1,15 @@ +%table + %tr + %th= t('phones.index.mac_address') + %th= t('phones.index.phone_model_id') + %th= t('phones.index.hot_deskable') + %th= t('phones.index.ip_address') + + - reset_cycle + - for phone in phones + %tr{:class => cycle('odd', 'even')} + %td= phone.pretty_mac_address + %td= phone.phone_model + %td= phone.hot_deskable + %td= phone.ip_address + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => phone.phoneable, :child => phone} \ No newline at end of file diff --git a/app/views/phones/edit.html.haml b/app/views/phones/edit.html.haml new file mode 100644 index 0000000..cdbacac --- /dev/null +++ b/app/views/phones/edit.html.haml @@ -0,0 +1,3 @@ +- title t("phones.edit.page_title", :resource => @phone.mac_address) + += render "form" diff --git a/app/views/phones/index.html.haml b/app/views/phones/index.html.haml new file mode 100644 index 0000000..785adf9 --- /dev/null +++ b/app/views/phones/index.html.haml @@ -0,0 +1,6 @@ +- title t("phones.index.page_title") + +- if @phones.count > 0 + = render "index_core", :phones => @phones + += render :partial => 'shared/create_link', :locals => {:parent => @parent, :child_class => Phone} \ No newline at end of file diff --git a/app/views/phones/new.html.haml b/app/views/phones/new.html.haml new file mode 100644 index 0000000..61923cc --- /dev/null +++ b/app/views/phones/new.html.haml @@ -0,0 +1,3 @@ +- title t("phones.new.page_title") + += render "form" diff --git a/app/views/phones/show.html.haml b/app/views/phones/show.html.haml new file mode 100644 index 0000000..2664ffa --- /dev/null +++ b/app/views/phones/show.html.haml @@ -0,0 +1,31 @@ +- title t("phones.show.page_title") + +%p + %strong= t('phones.show.mac_address') + ":" + = @phone.pretty_mac_address +%p + %strong= t('phones.show.phone_model_id') + ":" + = @phone.phone_model +%p + %strong= t('phones.show.hot_deskable') + ":" + = @phone.hot_deskable +- if defined? NIGHTLY_REBOOT_OF_PHONES && NIGHTLY_REBOOT_OF_PHONES == true + %p + %strong= t('phones.show.nightly_reboot') + ":" + = @phone.nightly_reboot + +- if defined? PROVISIONING_KEY_LENGTH && PROVISIONING_KEY_LENGTH > 0 + %p + %strong= t('phones.show.provisioning_key_active') + ":" + = @phone.provisioning_key_active +%p + %strong= t('phones.show.ip_address') + ":" + = @phone.ip_address + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @phone.phoneable, :child => @phone } + +%h2= t("phones.sip_accounts.title") +- if @phone.phone_sip_accounts.count > 0 + = render "phone_sip_accounts/index_core", :phone_sip_accounts => @phone.phone_sip_accounts + += render :partial => 'shared/create_link', :locals => {:parent => @phone, :child_class => PhoneSipAccount} diff --git a/app/views/ringtones/_form.html.haml b/app/views/ringtones/_form.html.haml new file mode 100644 index 0000000..7dbfcb0 --- /dev/null +++ b/app/views/ringtones/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([@parent,@ringtone]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('ringtones.form.submit') \ No newline at end of file diff --git a/app/views/ringtones/_form_core.html.haml b/app/views/ringtones/_form_core.html.haml new file mode 100644 index 0000000..e44c950 --- /dev/null +++ b/app/views/ringtones/_form_core.html.haml @@ -0,0 +1,3 @@ +.inputs + / = f.input :audio, :label => t('ringtones.form.audio.label'), :hint => conditional_hint('ringtones.form.audio.hint') + = f.input :bellcore_id, :collection => 0..10, :label => t('ringtones.form.bellcore_id.label'), :hint => conditional_hint('ringtones.form.bellcore_id.hint'), :include_blank => true diff --git a/app/views/ringtones/_index_core.html.haml b/app/views/ringtones/_index_core.html.haml new file mode 100644 index 0000000..c39357a --- /dev/null +++ b/app/views/ringtones/_index_core.html.haml @@ -0,0 +1,11 @@ +%table + %tr + %th= t('ringtones.index.audio') + %th= t('ringtones.index.bellcore_id') + + - reset_cycle + - for ringtone in ringtones + %tr{:class => cycle('odd', 'even')} + %td= ringtone.audio + %td= ringtone.bellcore_id + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => ringtone.ringtoneable, :child => ringtone} \ No newline at end of file diff --git a/app/views/ringtones/edit.html.haml b/app/views/ringtones/edit.html.haml new file mode 100644 index 0000000..6779190 --- /dev/null +++ b/app/views/ringtones/edit.html.haml @@ -0,0 +1,3 @@ +- title t("ringtones.edit.page_title") + += render "form" diff --git a/app/views/ringtones/index.html.haml b/app/views/ringtones/index.html.haml new file mode 100644 index 0000000..4da75fa --- /dev/null +++ b/app/views/ringtones/index.html.haml @@ -0,0 +1,6 @@ +- title t("ringtones.index.page_title") + +- if @ringtones.count > 0 + = render "index_core", :ringtones => @ringtones + += render :partial => 'shared/create_link', :locals => {:parent => @parent, :child_class => Ringtone} \ No newline at end of file diff --git a/app/views/ringtones/new.html.haml b/app/views/ringtones/new.html.haml new file mode 100644 index 0000000..025f440 --- /dev/null +++ b/app/views/ringtones/new.html.haml @@ -0,0 +1,3 @@ +- title t("ringtones.new.page_title") + += render "form" diff --git a/app/views/ringtones/show.html.haml b/app/views/ringtones/show.html.haml new file mode 100644 index 0000000..408b808 --- /dev/null +++ b/app/views/ringtones/show.html.haml @@ -0,0 +1,12 @@ +- title t("ringtones.show.page_title") + +- if 1 == 2 + %p + %strong= t('ringtones.show.audio') + ":" + = @ringtone.audio + +%p + %strong= t('ringtones.show.bellcore_id') + ":" + = @ringtone.bellcore_id + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @ringtone.ringtoneable, :child => @ringtone } \ No newline at end of file diff --git a/app/views/sessions/new.html.haml b/app/views/sessions/new.html.haml new file mode 100644 index 0000000..8ad77b1 --- /dev/null +++ b/app/views/sessions/new.html.haml @@ -0,0 +1,8 @@ +- title t("sessions.new.page_title") + += simple_form_for :sessions, :url => sessions_path do |t| + = t.input :login_data, :label => t('sessions.form.email'), :autofocus => true + = t.input :password, :label => t('sessions.form.password'), :required => false + = t.input :reset_password, :label => t('sessions.form.reset_password'), :as => :boolean + .actions + = t.button :submit, :value => 'Login' diff --git a/app/views/shared/_create_link.html.haml b/app/views/shared/_create_link.html.haml new file mode 100644 index 0000000..103c82b --- /dev/null +++ b/app/views/shared/_create_link.html.haml @@ -0,0 +1,11 @@ +- if !(defined? parent).nil? && !(defined? child_class).nil? + - if can? :create, parent.send(child_class.name.underscore.pluralize).build + %p + - if t("#{child_class.name.underscore.pluralize}.index.actions.create_for").include?('translation missing') || (!(defined? short_link).nil? && short_link == true) + = link_to t("#{child_class.name.underscore.pluralize}.index.actions.create"), method( :"new_#{parent.class.name.underscore}_#{child_class.name.underscore}_path" ).(parent) + - else + = link_to t("#{child_class.name.underscore.pluralize}.index.actions.create_for", :resource => parent.to_s), method( :"new_#{parent.class.name.underscore}_#{child_class.name.underscore}_path" ).(parent) +- elsif !(defined? child_class).nil? + - if can? :create, child_class + %p + = link_to t("#{child_class.name.underscore.pluralize}.index.actions.create"), method( :"new_#{child_class.name.underscore}_path" ).() \ No newline at end of file diff --git a/app/views/shared/_flash.html.haml b/app/views/shared/_flash.html.haml new file mode 100644 index 0000000..320fd15 --- /dev/null +++ b/app/views/shared/_flash.html.haml @@ -0,0 +1,19 @@ +- flash.each do |type, msg| + .flash{:class => type} + .light + .sign= resolve_flash_sign(type) + .message= msg + + +-# These are the available types: +-# +-# .flash.notice +-# .light +-# .sign i +-# .message Lorem ipsum dolor sit amet, consectetur adipisicing eli.w +-# +-# .flash.warning +-# .light +-# .sign ! +-# .message Lorem ipsum dolor sit amet, consectetur adipisicing eli.w + diff --git a/app/views/shared/_header.de.html.haml b/app/views/shared/_header.de.html.haml new file mode 100644 index 0000000..c6205ae --- /dev/null +++ b/app/views/shared/_header.de.html.haml @@ -0,0 +1,41 @@ +%header#main + .light + %h1.gemeinschaft-logo + - if @current_user && @current_user.current_tenant + = link_to "Gemeinschaft", tenant_path(@current_user.current_tenant) + - else + = link_to "Gemeinschaft", root_url + + - if current_user + = form_tag '/search' do + %div.search-box + - if GuiFunction.display?('search_field_in_top_navigation_bar', current_user) + %input.text{:value => 'Suchen ...', :name => 'q'} + %input{:type => 'submit', :value => ''} + + / Adjustable Navigation. + - if current_user + - if navigation_items.size > 0 + - navigation_items.each do |item| + - if GuiFunction.display?('navigation_items_in_top_navigation_bar', current_user) + %span + = link_to item[:title], item[:url] + + - if current_user + .user-context + %a.user{:href => tenant_user_path(current_user.current_tenant.id, current_user.id)} + - if GuiFunction.display?('user_avatar_in_top_navigation_bar', current_user) + - if current_user.image? && current_user.image_url(:mini) + = image_tag current_user.image_url(:mini).to_s, :class => 'display' + - else + - if current_user.male? + = image_tag 'icons/user-male-16x.png', :class => 'display logged-out' + - else + = image_tag 'icons/user-female-16x.png', :class => 'display logged-out' + = current_user + = link_to( "[x]", log_out_path, :class => 'logout', :title => "Abmelden" ) # Temporary way of logging out. + - else + .user-context + = link_to "Registrieren", sign_up_path + oder + = link_to "Anmelden", log_in_path diff --git a/app/views/shared/_header.html.haml b/app/views/shared/_header.html.haml new file mode 100644 index 0000000..377d8e0 --- /dev/null +++ b/app/views/shared/_header.html.haml @@ -0,0 +1,41 @@ +%header#main + .light + %h1.gemeinschaft-logo + - if @current_user && @current_user.current_tenant + = link_to "Gemeinschaft", tenant_path(@current_user.current_tenant) + - else + = link_to "Gemeinschaft", root_url + + - if current_user + = form_tag '/search' do + %div.search-box + - if GuiFunction.display?('search_field_in_top_navigation_bar', current_user) + %input.text{:value => 'Search ...', :name => 'q'} + %input{:type => 'submit', :value => ''} + + / Adjustable Navigation. + - if current_user + - if navigation_items.size > 0 + - navigation_items.each do |item| + - if GuiFunction.display?('navigation_items_in_top_navigation_bar', current_user) + %span + = link_to item[:title], item[:url] + + - if current_user + .user-context + %a.user{:href => tenant_user_path(current_user.current_tenant.id, current_user.id)} + - if GuiFunction.display?('user_avatar_in_top_navigation_bar', current_user) + - if current_user.image? && current_user.image_url(:mini) + = image_tag current_user.image_url(:mini).to_s, :class => 'display' + - else + - if current_user.male? + = image_tag 'icons/user-male-16x.png', :class => 'display logged-out' + - else + = image_tag 'icons/user-female-16x.png', :class => 'display logged-out' + = current_user + = link_to( "[x]", log_out_path, :class => 'logout', :title => "Log out" ) # Temporary way of logging out. + - else + .user-context + = link_to "Sign up", sign_up_path + or + = link_to "Log in", log_in_path diff --git a/app/views/shared/_index_view_edit_destroy_part.html.haml b/app/views/shared/_index_view_edit_destroy_part.html.haml new file mode 100644 index 0000000..06ec904 --- /dev/null +++ b/app/views/shared/_index_view_edit_destroy_part.html.haml @@ -0,0 +1,29 @@ +- style = 'width:35px' + +- if !(defined? parent).nil? && !(defined? child).nil? + %td{ :style => style } + - if can? :show, child + = link_to t("#{child.class.name.underscore.pluralize}.index.actions.show"), method( :"#{parent.class.name.underscore}_#{child.class.name.underscore}_path" ).(parent, child) + %td{ :style => style } + - if can? :edit, child + = link_to t("#{child.class.name.underscore.pluralize}.index.actions.edit"), method( :"edit_#{parent.class.name.underscore}_#{child.class.name.underscore}_path" ).(parent, child) + %td{ :style => style } + - if can? :destroy, child + = link_to t("#{child.class.name.underscore.pluralize}.index.actions.destroy"), method( :"#{parent.class.name.underscore}_#{child.class.name.underscore}_path" ).(parent, child), :method => :delete + - if child.respond_to?(:move_up?) or child and child.respond_to?(:move_down?) + %td{ :style => style } + - if can? :move_down, child and child.respond_to?(:move_down?) and child.move_down? + = link_to '⇩'.html_safe, method( :"move_lower_#{parent.class.name.underscore}_#{child.class.name.underscore}_path" ).(parent, child), :method => :put + - if can? :move_up, child and child.respond_to?(:move_up?) and child.move_up? + = link_to '⇧'.html_safe, method( :"move_higher_#{parent.class.name.underscore}_#{child.class.name.underscore}_path" ).(parent, child), :method => :put + +- elsif !(defined? child).nil? + %td{ :style => style } + - if can? :show, child + = link_to t("#{child.class.name.underscore.pluralize}.index.actions.show"), method( :"#{child.class.name.underscore}_path" ).(child) + %td{ :style => style } + - if can? :edit, child + = link_to t("#{child.class.name.underscore.pluralize}.index.actions.edit"), method( :"edit_#{child.class.name.underscore}_path" ).(child) + %td{ :style => style } + - if can? :destroy, child + = link_to t("#{child.class.name.underscore.pluralize}.index.actions.destroy"), method( :"#{child.class.name.underscore}_path" ).(child), :method => :delete \ No newline at end of file diff --git a/app/views/shared/_show_edit_destroy_part.html.haml b/app/views/shared/_show_edit_destroy_part.html.haml new file mode 100644 index 0000000..aff18d1 --- /dev/null +++ b/app/views/shared/_show_edit_destroy_part.html.haml @@ -0,0 +1,16 @@ +%p + - if !(defined? parent).nil? && !(defined? child).nil? + - if can? :edit, child + = link_to t("#{child.class.name.underscore.pluralize}.show.actions.edit"), method( :"edit_#{parent.class.name.underscore}_#{child.class.name.underscore}_path" ).(parent, child) + - if can? :destroy, child + - if can? :edit, child + | + = link_to t("#{child.class.name.underscore.pluralize}.show.actions.destroy"), method( :"#{parent.class.name.underscore}_#{child.class.name.underscore}_path" ).(parent, child), :method => :delete + + - elsif !(defined? child).nil? + - if can? :edit, child + = link_to t("#{child.class.name.underscore.pluralize}.show.actions.edit"), method( :"edit_#{child.class.name.underscore}_path" ).(child) + - if can? :destroy, child + - if can? :edit, child + | + = link_to t("#{child.class.name.underscore.pluralize}.show.actions.destroy"), method( :"#{child.class.name.underscore}_path" ).(child), :method => :delete \ No newline at end of file diff --git a/app/views/shared/_system_message.html.haml b/app/views/shared/_system_message.html.haml new file mode 100644 index 0000000..4aabb9c --- /dev/null +++ b/app/views/shared/_system_message.html.haml @@ -0,0 +1,10 @@ +- if current_user + .flash.notice#system_message_display + .light + .sign i + .message#system_message This is the place to display incoming calls and other stuff. + + = subscribe_to "/users/#{current_user.id}/system_messages" + + :javascript + $('#system_message_display').hide() \ No newline at end of file diff --git a/app/views/sip_accounts/_form.html.haml b/app/views/sip_accounts/_form.html.haml new file mode 100644 index 0000000..f209bf4 --- /dev/null +++ b/app/views/sip_accounts/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([ @parent, @sip_account ]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('sip_accounts.form.submit') \ No newline at end of file diff --git a/app/views/sip_accounts/_form_core.html.haml b/app/views/sip_accounts/_form_core.html.haml new file mode 100644 index 0000000..dbd27fe --- /dev/null +++ b/app/views/sip_accounts/_form_core.html.haml @@ -0,0 +1,12 @@ +.inputs + = f.input :auth_name, :as => :string, :label => t('sip_accounts.form.auth_name.label'), :hint => conditional_hint('sip_accounts.form.auth_name.hint') + = f.input :password, :as => :string, :label => t('sip_accounts.form.password.label'), :hint => conditional_hint('sip_accounts.form.password.hint') + = f.input :caller_name, :as => :string, :label => t('sip_accounts.form.caller_name.label'), :hint => conditional_hint('sip_accounts.form.caller_name.hint') + = f.input :voicemail_pin, :as => :string, :label => t('sip_accounts.form.voicemail_pin.label'), :hint => conditional_hint('sip_accounts.form.voicemail_pin.hint') + = f.input :call_waiting, :label => t('sip_accounts.form.call_waiting.label'), :hint => conditional_hint('sip_accounts.form.call_waiting.hint') + = f.input :clir, :label => t('sip_accounts.form.clir.label'), :hint => conditional_hint('sip_accounts.form.clir.hint') + = f.input :clip, :label => t('sip_accounts.form.clip.label'), :hint => conditional_hint('sip_accounts.form.clip.hint') + = f.input :hotdeskable, :label => t('sip_accounts.form.hotdeskable.label'), :hint => conditional_hint('sip_accounts.form.hotdeskable.hint') + = f.input :clip_no_screening, :label => t('sip_accounts.form.clip_no_screening.label'), :hint => conditional_hint('sip_accounts.form.clip_no_screening.hint') + - if CallForward.where(:phone_number_id => @sip_account.phone_number_ids).count == 0 || @sip_account.callforward_rules_act_per_sip_account == true + = f.input :callforward_rules_act_per_sip_account, :label => t('sip_accounts.form.callforward_rules_act_per_sip_account.label'), :hint => conditional_hint('sip_accounts.form.callforward_rules_act_per_sip_account.hint') diff --git a/app/views/sip_accounts/_index_core.html.haml b/app/views/sip_accounts/_index_core.html.haml new file mode 100644 index 0000000..7f8dcd2 --- /dev/null +++ b/app/views/sip_accounts/_index_core.html.haml @@ -0,0 +1,28 @@ +%table + %tr + %th= t('sip_accounts.index.online') + %th= t('sip_accounts.index.caller_name') + %th= t('sip_accounts.index.phone_numbers') + %th= t('phones.name') + + - reset_cycle + - for sip_account in sip_accounts + %tr{:class => cycle('odd', 'even')} + %td + - if sip_account.registration + %img{:src => '/assets/icons/phone-down-green-32x.png'} + - else + %img{:src => '/assets/icons/phone-down-grey-32x.png'} + %td + = sip_account.caller_name + - phone_numbers = sip_account.phone_numbers + %td + - if sip_account.phone_numbers.count > 0 + = render 'phone_numbers/listing', :phone_numbers => sip_account.phone_numbers.order(:number) + %br + = render :partial => 'shared/create_link', :locals => {:parent => sip_account, :child_class => PhoneNumber, :short_link => true} + + %td + - sip_account.phones.each do |phone| + = link_to phone.to_s, method( :"#{phone.phoneable_type.underscore}_phone_path" ).( phone.phoneable_id, phone ) + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => sip_account.sip_accountable, :child => sip_account} \ No newline at end of file diff --git a/app/views/sip_accounts/edit.html.haml b/app/views/sip_accounts/edit.html.haml new file mode 100644 index 0000000..c070ff7 --- /dev/null +++ b/app/views/sip_accounts/edit.html.haml @@ -0,0 +1,3 @@ +- title t("sip_accounts.edit.page_title") + += render "form" diff --git a/app/views/sip_accounts/index.html.haml b/app/views/sip_accounts/index.html.haml new file mode 100644 index 0000000..1131770 --- /dev/null +++ b/app/views/sip_accounts/index.html.haml @@ -0,0 +1,6 @@ +- title t("sip_accounts.index.page_title") + +- if @sip_accounts.count > 0 + = render "index_core", :sip_accounts => @sip_accounts + += render :partial => 'shared/create_link', :locals => {:parent => @parent, :child_class => SipAccount} \ No newline at end of file diff --git a/app/views/sip_accounts/new.html.haml b/app/views/sip_accounts/new.html.haml new file mode 100644 index 0000000..9d44680 --- /dev/null +++ b/app/views/sip_accounts/new.html.haml @@ -0,0 +1,3 @@ +- title t("sip_accounts.new.page_title") + += render "form" diff --git a/app/views/sip_accounts/show.html.haml b/app/views/sip_accounts/show.html.haml new file mode 100644 index 0000000..c6344cd --- /dev/null +++ b/app/views/sip_accounts/show.html.haml @@ -0,0 +1,50 @@ +- title t("sip_accounts.show.page_title") + +%p + %strong= t('sip_accounts.show.auth_name') + ":" + = @sip_account.auth_name +%p + %strong= t('sip_accounts.show.caller_name') + ":" + = @sip_account.caller_name +%p + %strong= t('sip_accounts.show.password') + ":" + = @sip_account.password +%p + %strong= t('sip_accounts.show.call_waiting') + ":" + = @sip_account.call_waiting +%p + %strong= t('sip_accounts.show.clir') + ":" + = @sip_account.clir +%p + %strong= t('sip_accounts.show.clip_no_screening') + ":" + = @sip_account.clip_no_screening +%p + %strong= t('sip_accounts.show.hotdeskable') + ":" + = @sip_account.hotdeskable +%p + %strong= t('sip_accounts.show.callforward_rules_act_per_sip_account') + ":" + = @sip_account.callforward_rules_act_per_sip_account +- if @sip_account.registration.try(:network_ip) && @sip_account.registration.try(:network_port) + %p + %strong= t('sip_accounts.show.registration') + ":" + = "#{@sip_account.registration.network_ip}:#{@sip_account.registration.network_port}" +- if @sip_account.registration.try(:expires) + %p + %strong= t('sip_accounts.show.expires') + ":" + = "#{@sip_account.registration.try(:expires) - Time.now.to_i} s" + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @sip_account.sip_accountable, :child => @sip_account } + +- if @sip_account.phone_numbers.count > 0 || can?(:create, @sip_account.phone_numbers.build) + %h2= t('phone_numbers.index.page_title') + - if @sip_account.phone_numbers.count > 0 + = render "phone_numbers/index_core", :phone_numbers => @sip_account.phone_numbers + %br + = render :partial => 'shared/create_link', :locals => { :parent => @sip_account, :child_class => PhoneNumber } + +- if @sip_account.softkeys.count > 0 || can?(:create, @sip_account.softkeys.build) + %h2= t("softkeys.index.page_title") + - if @sip_account.softkeys.count > 0 + = render "softkeys/index_core", :softkeys => @sip_account.softkeys + %br + = render :partial => 'shared/create_link', :locals => { :parent => @sip_account, :child_class => Softkey } \ No newline at end of file diff --git a/app/views/sip_domains/_form.html.haml b/app/views/sip_domains/_form.html.haml new file mode 100644 index 0000000..2d662af --- /dev/null +++ b/app/views/sip_domains/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for(@sip_domain) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('sip_domains.form.submit') \ No newline at end of file diff --git a/app/views/sip_domains/_form_core.html.haml b/app/views/sip_domains/_form_core.html.haml new file mode 100644 index 0000000..a7f024f --- /dev/null +++ b/app/views/sip_domains/_form_core.html.haml @@ -0,0 +1,3 @@ +.inputs + = f.input :host, :label => t('sip_domains.form.host.label'), :hint => conditional_hint('sip_domains.form.host.hint') + = f.input :realm, :label => t('sip_domains.form.realm.label'), :hint => conditional_hint('sip_domains.form.realm.hint') diff --git a/app/views/sip_domains/_index_core.html.haml b/app/views/sip_domains/_index_core.html.haml new file mode 100644 index 0000000..37374f2 --- /dev/null +++ b/app/views/sip_domains/_index_core.html.haml @@ -0,0 +1,11 @@ +%table + %tr + %th= t('sip_domains.index.host') + %th= t('sip_domains.index.realm') + + - reset_cycle + - for sip_domain in sip_domains + %tr{:class => cycle('odd', 'even')} + %td= sip_domain.host + %td= sip_domain.realm + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:child => sip_domain} \ No newline at end of file diff --git a/app/views/sip_domains/edit.html.haml b/app/views/sip_domains/edit.html.haml new file mode 100644 index 0000000..dcf8d6b --- /dev/null +++ b/app/views/sip_domains/edit.html.haml @@ -0,0 +1,3 @@ +- title t("sip_domains.edit.page_title") + += render "form" diff --git a/app/views/sip_domains/index.html.haml b/app/views/sip_domains/index.html.haml new file mode 100644 index 0000000..6de7f42 --- /dev/null +++ b/app/views/sip_domains/index.html.haml @@ -0,0 +1,6 @@ +- title t("sip_domains.index.page_title") + +- if @sip_domains.count > 0 + = render "index_core", :sip_domains => @sip_domains + += render :partial => 'shared/create_link', :locals => {:child_class => SipDomain} \ No newline at end of file diff --git a/app/views/sip_domains/new.html.haml b/app/views/sip_domains/new.html.haml new file mode 100644 index 0000000..12ff340 --- /dev/null +++ b/app/views/sip_domains/new.html.haml @@ -0,0 +1,3 @@ +- title t("sip_domains.new.page_title") + += render "form" diff --git a/app/views/sip_domains/show.html.haml b/app/views/sip_domains/show.html.haml new file mode 100644 index 0000000..e136eaf --- /dev/null +++ b/app/views/sip_domains/show.html.haml @@ -0,0 +1,10 @@ +- title t("sip_domains.show.page_title") + +%p + %strong= t('sip_domains.show.host') + ":" + = @sip_domain.host +%p + %strong= t('sip_domains.show.realm') + ":" + = @sip_domain.realm + += render :partial => 'shared/show_edit_destroy_part', :locals => { :child => @sip_domain } \ No newline at end of file diff --git a/app/views/softkeys/_form.html.haml b/app/views/softkeys/_form.html.haml new file mode 100644 index 0000000..5b799b6 --- /dev/null +++ b/app/views/softkeys/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([@sip_account, @softkey]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('softkeys.form.submit') \ No newline at end of file diff --git a/app/views/softkeys/_form_core.html.haml b/app/views/softkeys/_form_core.html.haml new file mode 100644 index 0000000..b833aad --- /dev/null +++ b/app/views/softkeys/_form_core.html.haml @@ -0,0 +1,12 @@ +%script{:type => "text/javascript"} + :plain + call_forwarding_function_name = "#{I18n.t('softkeys.functions.call_forwarding')}" + hold_function_name = "#{I18n.t('softkeys.functions.hold')}" + deactivated_function_name = "#{I18n.t('softkeys.functions.deactivated')}" + +.inputs + = f.input :softkey_function_id, :as => :select, :collection => @softkey_functions.map {|x| [I18n.t("softkeys.functions.#{x}"), x.id] }, :label => t('softkeys.form.function.label'), :hint => conditional_hint('softkeys.form.function.hint'), :include_blank => false + - if @available_call_forwards && @available_call_forwards.count > 0 + = f.association :call_forward, :collection => @available_call_forwards, :label => t('softkeys.form.call_forward.label'), :hint => conditional_hint('softkeys.form.call_forward.hint'), :include_blank => false + = f.input :number, :label => t('softkeys.form.number.label'), :hint => conditional_hint('softkeys.form.number.hint') + = f.input :label, :label => t('softkeys.form.label.label'), :hint => conditional_hint('softkeys.form.label.hint') diff --git a/app/views/softkeys/_index_core.html.haml b/app/views/softkeys/_index_core.html.haml new file mode 100644 index 0000000..fd3dca8 --- /dev/null +++ b/app/views/softkeys/_index_core.html.haml @@ -0,0 +1,14 @@ +%table + %tr + %th= t('softkeys.index.function') + %th= t('softkeys.index.number') + %th= t('softkeys.index.label') + + - reset_cycle + - for softkey in softkeys.order(:position) + %tr{:class => cycle('odd', 'even')} + %td + =softkey.to_s + %td= softkey.number + %td= softkey.label + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => softkey.sip_account, :child => softkey} \ No newline at end of file diff --git a/app/views/softkeys/edit.html.haml b/app/views/softkeys/edit.html.haml new file mode 100644 index 0000000..54d53fc --- /dev/null +++ b/app/views/softkeys/edit.html.haml @@ -0,0 +1,3 @@ +- title t("softkeys.edit.page_title") + += render "form" \ No newline at end of file diff --git a/app/views/softkeys/index.html.haml b/app/views/softkeys/index.html.haml new file mode 100644 index 0000000..8bdc00e --- /dev/null +++ b/app/views/softkeys/index.html.haml @@ -0,0 +1,6 @@ +- title t("softkeys.index.page_title") + +- if @softkeys.count > 0 + = render "index_core", :softkeys => @softkeys + += render :partial => 'shared/create_link', :locals => {:parent => @sip_account, :child_class => Softkey} \ No newline at end of file diff --git a/app/views/softkeys/new.html.haml b/app/views/softkeys/new.html.haml new file mode 100644 index 0000000..593add6 --- /dev/null +++ b/app/views/softkeys/new.html.haml @@ -0,0 +1,3 @@ +- title t("softkeys.new.page_title") + += render "form" diff --git a/app/views/softkeys/show.html.haml b/app/views/softkeys/show.html.haml new file mode 100644 index 0000000..9ab4333 --- /dev/null +++ b/app/views/softkeys/show.html.haml @@ -0,0 +1,7 @@ +- title t("softkeys.show.page_title") + +%p + %strong= t('softkeys.show.function') + ":" + =@softkey.to_s + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @softkey.sip_account, :child => @softkey } \ No newline at end of file diff --git a/app/views/system_messages/_form.html.haml b/app/views/system_messages/_form.html.haml new file mode 100644 index 0000000..036ee00 --- /dev/null +++ b/app/views/system_messages/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([@user, @system_message]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('system_messages.form.submit') \ No newline at end of file diff --git a/app/views/system_messages/_form_core.html.haml b/app/views/system_messages/_form_core.html.haml new file mode 100644 index 0000000..a85db28 --- /dev/null +++ b/app/views/system_messages/_form_core.html.haml @@ -0,0 +1,2 @@ +.inputs + = f.input :content, :label => t('system_messages.form.content.label'), :hint => conditional_hint('system_messages.form.content.hint') diff --git a/app/views/system_messages/_index_core.html.haml b/app/views/system_messages/_index_core.html.haml new file mode 100644 index 0000000..157d964 --- /dev/null +++ b/app/views/system_messages/_index_core.html.haml @@ -0,0 +1,11 @@ +%table + %tr + %th= t('system_messages.index.created_at') + %th= t('system_messages.index.content') + + - reset_cycle + - for system_message in system_messages + %tr{:class => cycle('odd', 'even')} + %td= system_message.created_at + %td= system_message.content + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:child => system_message} \ No newline at end of file diff --git a/app/views/system_messages/index.html.haml b/app/views/system_messages/index.html.haml new file mode 100644 index 0000000..da77e18 --- /dev/null +++ b/app/views/system_messages/index.html.haml @@ -0,0 +1,3 @@ +- title t("system_messages.index.page_title") + += render "index_core", :system_messages => @system_messages \ No newline at end of file diff --git a/app/views/system_messages/new.html.haml b/app/views/system_messages/new.html.haml new file mode 100644 index 0000000..3afdb24 --- /dev/null +++ b/app/views/system_messages/new.html.haml @@ -0,0 +1,3 @@ +- title t("system_messages.new.page_title") + += render "form" diff --git a/app/views/system_messages/show.html.haml b/app/views/system_messages/show.html.haml new file mode 100644 index 0000000..694e4c1 --- /dev/null +++ b/app/views/system_messages/show.html.haml @@ -0,0 +1,8 @@ +- title t("system_messages.show.page_title") + +%p + %strong= t('system_messages.show.created_at') + ":" + = @system_message.created_at +%p + %strong= t('system_messages.show.content') + ":" + = @system_message.content diff --git a/app/views/tenants/_admin_area.de.html.haml b/app/views/tenants/_admin_area.de.html.haml new file mode 100644 index 0000000..b9b47d5 --- /dev/null +++ b/app/views/tenants/_admin_area.de.html.haml @@ -0,0 +1,118 @@ +%p + Sie sind Mitglied der + = link_to 'Admin Gruppe', tenant_user_group_path(@tenant, @tenant.user_groups.find_by_name('Admins')) + und haben deshalb besondere Rechte. Aber wie Peter Parker schon sagte: "With great power comes great responsibility." + +%p + Dieser Mandant hat + = link_to pluralize(@tenant.user_groups.count, 'user group'), tenant_user_groups_path(@tenant) + - if @tenant.user_groups.count < 5 + = "(#{@tenant.user_groups.order(:name).map{|group| group.to_s }.join(', ')})" + die in Summe + = link_to pluralize(@tenant.users.count, 'user'), tenant_users_path(@tenant) + verwalten. + Das System kann + = PhoneModel.count + verschiedene Telefonmodelle von den folgenden Herstellern verwalten: + - Manufacturer.all.each do |manufacturer| + - if manufacturer != Manufacturer.last && manufacturer != Manufacturer.limit(Manufacturer.count - 1).last + = succeed ', ' do + =link_to manufacturer, manufacturer_path(manufacturer) + - elsif manufacturer == Manufacturer.limit(Manufacturer.count - 1).last + = succeed ' und ' do + =link_to manufacturer, manufacturer_path(manufacturer) + - else + = succeed '.' do + =link_to manufacturer, manufacturer_path(manufacturer) + +%h3 SIP-Konten und Telefone + +%table + %tr{:class => 'even'} + %th + %th + = @tenant + %th + Alle Benutzer von + = "\"#{@tenant}\"" + %tr{:class => 'odd'} + %td + SIP-Konten + %td + = link_to @tenant.sip_accounts.count.to_s, tenant_sip_accounts_path(@tenant) + = render :partial => 'shared/create_link', :locals => {:parent => @tenant, :child_class => SipAccount} + %td= @tenant.users_sip_accounts.count.to_s + %tr{:class => 'even'} + %td + Telefone + %td + = link_to @tenant.phones.count.to_s, tenant_phones_path(@tenant) + = render :partial => 'shared/create_link', :locals => {:parent => @tenant, :child_class => Phone} + %td= @tenant.users_phones.count.to_s + +%h3 Allgemein + +%table + %tr{:class => 'even'} + %th + Funktion + %th + Anzahl + %th + %tr{:class => 'odd'} + %td + Callthrough + %td + = link_to @tenant.callthroughs.count.to_s, tenant_callthroughs_path(@tenant) + %td + = render :partial => 'shared/create_link', :locals => {:parent => @tenant, :child_class => Callthrough} + %tr{:class => 'even'} + %td + Konferenzen + %td + = link_to @tenant.conferences.count.to_s, tenant_conferences_path(@tenant) + %td + = render :partial => 'shared/create_link', :locals => {:parent => @tenant, :child_class => Conference} + %tr{:class => 'odd'} + %td + Rufgruppen + %td + = link_to @tenant.hunt_groups.count.to_s, tenant_hunt_groups_path(@tenant) + %td + = render :partial => 'shared/create_link', :locals => {:parent => @tenant, :child_class => HuntGroup} + %tr{:class => 'even'} + %td + Warteschleifen + %td + = link_to @tenant.automatic_call_distributors.count.to_s, tenant_automatic_call_distributors_path(@tenant) + %td + = render :partial => 'shared/create_link', :locals => {:parent => @tenant, :child_class => AutomaticCallDistributor} + %tr{:class => 'odd'} + %td + Oberflächen-Funktionen + %td + = link_to GuiFunction.count.to_s, gui_functions_path + %td + +-# Phone books +-# +- if GuiFunction.display?('show_phone_books_in_user_show_view', current_user) + - if can?( :index, PhoneBook ) + %h2=t("phone_books.index.page_title") + = render "phone_books/index_core", :phone_books => @tenant.phone_books + = render :partial => 'shared/create_link', :locals => {:parent => @tenant, :child_class => PhoneBook} + +- if STRICT_INTERNAL_EXTENSION_HANDLING == true + %h3= t('phone_number_ranges.index.page_title') + + - if @tenant.created_at > (Time.now - 15.minutes) && Delayed::Job.count > 0 && @tenant.phone_number_ranges.find_by_name(INTERNAL_EXTENSIONS).try(:phone_numbers).try(:count).to_i == 0 + Der Mandant + = "\"#{@tenant}\"" + wurde erst vor + = distance_of_time_in_words_to_now(@tenant.created_at) + erstellt. Es gibt immer noch nicht abgeschlossene + = pluralize(Delayed::Job.count, 'Hintergrundprozesse') + \. Bitte warten Sie noch ein paar Minuten und laden anschließend diese Seite erneut. + - else + =render 'phone_number_ranges/index_core', :phone_number_ranges => (@tenant.phone_number_ranges + @tenant.country.phone_number_ranges.where(:name => SERVICE_NUMBERS)) + =render :partial => 'shared/create_link', :locals => {:parent => @tenant, :child_class => PhoneNumberRange} diff --git a/app/views/tenants/_admin_area.html.haml b/app/views/tenants/_admin_area.html.haml new file mode 100644 index 0000000..d648143 --- /dev/null +++ b/app/views/tenants/_admin_area.html.haml @@ -0,0 +1,116 @@ +%p + You belong to the + = link_to 'admin group', tenant_user_group_path(@tenant, @tenant.user_groups.find_by_name('Admins')) + and therefore have super powers. But always remember Peter Parker's: "With great power comes great responsibility." + +%p + = succeed '.' do + This tenant has + = link_to pluralize(@tenant.user_groups.count, 'user group'), tenant_user_groups_path(@tenant) + - if @tenant.user_groups.count < 5 + = "(#{@tenant.user_groups.order(:name).map{|group| group.to_s }.join(', ')})" + which handle a total of + = link_to pluralize(@tenant.users.count, 'user'), tenant_users_path(@tenant) + This system can setup + = PhoneModel.count + different phone models from the manufacturers + - Manufacturer.all.each do |manufacturer| + - if manufacturer != Manufacturer.last && manufacturer != Manufacturer.limit(Manufacturer.count - 1).last + = succeed ', ' do + =link_to manufacturer, manufacturer_path(manufacturer) + - elsif manufacturer == Manufacturer.limit(Manufacturer.count - 1).last + = succeed ' and ' do + =link_to manufacturer, manufacturer_path(manufacturer) + - else + = succeed '.' do + =link_to manufacturer, manufacturer_path(manufacturer) + +%h3 SIP-Accounts and Phones + +%table + %tr{:class => 'even'} + %th + %th + = @tenant + %th + All users of + = "\"#{@tenant}\"" + %tr{:class => 'odd'} + %td + SIP accounts + %td + = link_to @tenant.sip_accounts.count.to_s, tenant_sip_accounts_path(@tenant) + = render :partial => 'shared/create_link', :locals => {:parent => @tenant, :child_class => SipAccount} + %td= @tenant.users_sip_accounts.count.to_s + %tr{:class => 'even'} + %td + Phones + %td + = link_to @tenant.phones.count.to_s, tenant_phones_path(@tenant) + = render :partial => 'shared/create_link', :locals => {:parent => @tenant, :child_class => Phone} + %td= @tenant.users_phones.count.to_s + +%h3 Misc + +%table + %tr{:class => 'even'} + %th + Feature + %th + Counter + %th + %tr{:class => 'odd'} + %td + Callthroughs + %td + = link_to @tenant.callthroughs.count.to_s, tenant_callthroughs_path(@tenant) + %td + = render :partial => 'shared/create_link', :locals => {:parent => @tenant, :child_class => Callthrough} + %tr{:class => 'even'} + %td + Conferences + %td + = link_to @tenant.conferences.count.to_s, tenant_conferences_path(@tenant) + %td + = render :partial => 'shared/create_link', :locals => {:parent => @tenant, :child_class => Conference} + %tr{:class => 'odd'} + %td + Hunt groups + %td + = link_to @tenant.hunt_groups.count.to_s, tenant_hunt_groups_path(@tenant) + %td + = render :partial => 'shared/create_link', :locals => {:parent => @tenant, :child_class => HuntGroup} + %tr{:class => 'even'} + %td + ACDs + %td + = link_to @tenant.automatic_call_distributors.count.to_s, tenant_automatic_call_distributors_path(@tenant) + %td + = render :partial => 'shared/create_link', :locals => {:parent => @tenant, :child_class => AutomaticCallDistributor} + %tr{:class => 'odd'} + %td + GUI functions + %td + = link_to GuiFunction.count.to_s, gui_functions_path + %td + +-# Phone books +-# +- if GuiFunction.display?('show_phone_books_in_user_show_view', current_user) + - if can?( :index, PhoneBook ) + %h2=t("phone_books.index.page_title") + = render "phone_books/index_core", :phone_books => @tenant.phone_books + = render :partial => 'shared/create_link', :locals => {:parent => @tenant, :child_class => PhoneBook} + +- if STRICT_INTERNAL_EXTENSION_HANDLING == true + %h3= t('phone_number_ranges.index.page_title') + + - if @tenant.created_at > (Time.now - 15.minutes) && Delayed::Job.count > 0 && @tenant.phone_number_ranges.find_by_name(INTERNAL_EXTENSIONS).try(:phone_numbers).try(:count).to_i == 0 + This tenant was created + = distance_of_time_in_words_to_now(@tenant.created_at) + ago. There are still + = pluralize(Delayed::Job.count, 'background job') + not finished. This can take a couple of minutes. Please reload this page later. + - else + =render 'phone_number_ranges/index_core', :phone_number_ranges => (@tenant.phone_number_ranges + @tenant.country.phone_number_ranges.where(:name => SERVICE_NUMBERS)) + =render :partial => 'shared/create_link', :locals => {:parent => @tenant, :child_class => PhoneNumberRange} diff --git a/app/views/tenants/_form.html.haml b/app/views/tenants/_form.html.haml new file mode 100644 index 0000000..2ca8a69 --- /dev/null +++ b/app/views/tenants/_form.html.haml @@ -0,0 +1,24 @@ += simple_form_for(@tenant) do |f| + = f.error_notification + + = render "form_core", :f => f + + = f.association :country, :label => t('tenants.form.country_id.label'), :hint => conditional_hint('tenants.form.country_id.hint'), :include_blank => false + = f.association :language, :label => t('tenants.form.language_id.label'), :hint => conditional_hint('tenants.form.language_id.hint'), :include_blank => false + + = f.association :sip_domain, :label => t('tenants.form.sip_domain.label'), :hint => conditional_hint('tenants.form.sip_domain.hint'), :include_blank => false + + = f.input :from_field_voicemail_email, :label => t('tenants.form.from_field_voicemail_email.label'), :hint => conditional_hint('tenants.form.from_field_voicemail_email.hint') + = f.input :from_field_pin_change_email, :label => t('tenants.form.from_field_pin_change_email.label'), :hint => conditional_hint('tenants.form.from_field_pin_change_email.hint') + + - if STRICT_INTERNAL_EXTENSION_HANDLING == true || STRICT_DID_HANDLING == true + %h2= t('tenants.form.phone_numbers') + %p= t('tenants.form.intro') + + - if STRICT_INTERNAL_EXTENSION_HANDLING == true + = f.input :internal_extension_ranges, :label => t('tenants.form.internal_extension_ranges.label'), :hint => conditional_hint('tenants.form.internal_extension_ranges.hint') + - if STRICT_DID_HANDLING == true + = f.input :did_list, :label => t('tenants.form.did_list.label'), :hint => conditional_hint('tenants.form.did_list.hint') + + .actions + = f.button :submit, conditional_t('tenants.form.submit') \ No newline at end of file diff --git a/app/views/tenants/_form_core.html.haml b/app/views/tenants/_form_core.html.haml new file mode 100644 index 0000000..4eb2ccc --- /dev/null +++ b/app/views/tenants/_form_core.html.haml @@ -0,0 +1,3 @@ +.inputs + = f.input :name, :label => t('tenants.form.name.label'), :hint => conditional_hint('tenants.form.name.hint') + = f.input :description, :label => t('tenants.form.description.label'), :hint => conditional_hint('tenants.form.description.hint') diff --git a/app/views/tenants/_index_core.html.haml b/app/views/tenants/_index_core.html.haml new file mode 100644 index 0000000..60afeee --- /dev/null +++ b/app/views/tenants/_index_core.html.haml @@ -0,0 +1,17 @@ +%table + %tr + %th= t('tenants.index.name') + %th= t('tenants.index.description') + + - reset_cycle + - for tenant in tenants + %tr{:class => cycle('odd', 'even')} + %td= tenant.name + %td= tenant.description + %td + - if current_user && current_user.current_tenant != tenant && current_user.tenants.include?(tenant) + = simple_form_for([current_user.current_tenant, current_user]) do |f| + = f.hidden_field :current_tenant_id, :value => tenant.id + .actions + = f.button :submit, conditional_t('tenants.switch_to_tenant') + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:child => tenant} \ No newline at end of file diff --git a/app/views/tenants/edit.html.haml b/app/views/tenants/edit.html.haml new file mode 100644 index 0000000..159f4fd --- /dev/null +++ b/app/views/tenants/edit.html.haml @@ -0,0 +1,3 @@ +- title t("tenants.edit.page_title", :resource => @tenant ) + += render "form" diff --git a/app/views/tenants/index.html.haml b/app/views/tenants/index.html.haml new file mode 100644 index 0000000..1783825 --- /dev/null +++ b/app/views/tenants/index.html.haml @@ -0,0 +1,6 @@ +- title t("tenants.index.page_title") + +- if @tenants.count > 0 + = render "index_core", :tenants => @tenants + += render :partial => 'shared/create_link', :locals => {:child_class => Tenant} \ No newline at end of file diff --git a/app/views/tenants/new.html.haml b/app/views/tenants/new.html.haml new file mode 100644 index 0000000..dca3809 --- /dev/null +++ b/app/views/tenants/new.html.haml @@ -0,0 +1,3 @@ +- title t("tenants.new.page_title") + += render "form" diff --git a/app/views/tenants/show.html.haml b/app/views/tenants/show.html.haml new file mode 100644 index 0000000..cb2b895 --- /dev/null +++ b/app/views/tenants/show.html.haml @@ -0,0 +1,14 @@ +- title t("tenants.show.page_title") + +%p + %strong= t('tenants.show.name') + ":" + = @tenant.name +- if !@tenant.description.blank? + %p + %strong= t('tenants.show.description') + ":" + = @tenant.description + += render :partial => 'shared/show_edit_destroy_part', :locals => { :child => @tenant } + +- if @tenant.user_groups.where(:name => 'Admins').count > 0 && @tenant.user_groups.where(:name => 'Admins').first.users.include?(current_user) + = render 'admin_area' \ No newline at end of file diff --git a/app/views/user_group_memberships/_form.html.haml b/app/views/user_group_memberships/_form.html.haml new file mode 100644 index 0000000..3c0fee1 --- /dev/null +++ b/app/views/user_group_memberships/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([@user_group, @user_group_membership]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('user_group_memberships.form.submit') \ No newline at end of file diff --git a/app/views/user_group_memberships/_form_core.html.haml b/app/views/user_group_memberships/_form_core.html.haml new file mode 100644 index 0000000..e77427f --- /dev/null +++ b/app/views/user_group_memberships/_form_core.html.haml @@ -0,0 +1,2 @@ +.inputs + = f.input :user_id, :label => t('hunt_groups.form.user.label'), :hint => conditional_hint('hunt_groups.form.user.hint'), :collection => @potential_users, :include_blank => false \ No newline at end of file diff --git a/app/views/user_group_memberships/_index_core.html.haml b/app/views/user_group_memberships/_index_core.html.haml new file mode 100644 index 0000000..3c3cebe --- /dev/null +++ b/app/views/user_group_memberships/_index_core.html.haml @@ -0,0 +1,13 @@ +%table + %tr + %th= t('user_group_memberships.index.tenant') + %th= t('user_group_memberships.index.user_group') + %th= t('user_group_memberships.index.user') + + - reset_cycle + - for user_group_membership in user_group_memberships + %tr{:class => cycle('odd', 'even')} + %td= user_group_membership.user_group.tenant + %td= user_group_membership.user_group + %td= user_group_membership.user + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => user_group_membership.user_group, :child => user_group_membership} \ No newline at end of file diff --git a/app/views/user_group_memberships/edit.html.haml b/app/views/user_group_memberships/edit.html.haml new file mode 100644 index 0000000..2080c87 --- /dev/null +++ b/app/views/user_group_memberships/edit.html.haml @@ -0,0 +1,3 @@ +- title t("user_group_memberships.edit.page_title", :resource => @user_group_membership) + += render "form" diff --git a/app/views/user_group_memberships/index.html.haml b/app/views/user_group_memberships/index.html.haml new file mode 100644 index 0000000..1d7927b --- /dev/null +++ b/app/views/user_group_memberships/index.html.haml @@ -0,0 +1,7 @@ +- title t("user_group_memberships.index.page_title") + +- if @user_group_memberships.count > 0 + = render "index_core", :user_group_memberships => @user_group_memberships + +- if @potential_users_count > 0 + = render :partial => 'shared/create_link', :locals => {:parent => @user_group, :child_class => UserGroupMembership} \ No newline at end of file diff --git a/app/views/user_group_memberships/new.html.haml b/app/views/user_group_memberships/new.html.haml new file mode 100644 index 0000000..9d59fdd --- /dev/null +++ b/app/views/user_group_memberships/new.html.haml @@ -0,0 +1,3 @@ +- title t("user_group_memberships.new.page_title") + += render "form" diff --git a/app/views/user_group_memberships/show.html.haml b/app/views/user_group_memberships/show.html.haml new file mode 100644 index 0000000..0e5cfab --- /dev/null +++ b/app/views/user_group_memberships/show.html.haml @@ -0,0 +1,7 @@ +- title t("user_group_memberships.show.page_title") + +%p + %strong= t('user_group_memberships.show.user') + ":" + = @user_group_membership.user + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @user_group, :child => @user_group_membership } \ No newline at end of file diff --git a/app/views/user_groups/_form.html.haml b/app/views/user_groups/_form.html.haml new file mode 100644 index 0000000..cbe3cc4 --- /dev/null +++ b/app/views/user_groups/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for(@user_group) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('user_groups.form.submit') \ No newline at end of file diff --git a/app/views/user_groups/_form_core.html.haml b/app/views/user_groups/_form_core.html.haml new file mode 100644 index 0000000..a45ba6f --- /dev/null +++ b/app/views/user_groups/_form_core.html.haml @@ -0,0 +1,3 @@ +.inputs + = f.input :name, :label => t('user_groups.form.name.label'), :hint => conditional_hint('user_groups.form.name.hint') + = f.input :description, :label => t('user_groups.form.description.label'), :hint => conditional_hint('user_groups.form.description.hint') diff --git a/app/views/user_groups/_index_core.html.haml b/app/views/user_groups/_index_core.html.haml new file mode 100644 index 0000000..d2b6e88 --- /dev/null +++ b/app/views/user_groups/_index_core.html.haml @@ -0,0 +1,24 @@ +%table + %tr + %th= t('user_groups.index.name') + %th= t('user_groups.index.description') + - if @user + %th= t('user_groups.index.tenant_id') + - else + %th= t('user_groups.index.members') + + - reset_cycle + - for user_group in user_groups + %tr{:class => cycle('odd', 'even')} + %td= user_group.name + %td= user_group.description + - if @user + %td= user_group.tenant + - else + %td + =render 'users/listing', :users => user_group.users + - if user_group.users.count > 1 + %br + = render :partial => 'shared/create_link', :locals => {:parent => user_group, :child_class => UserGroupMembership} + + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => user_group.tenant, :child => user_group} diff --git a/app/views/user_groups/edit.html.haml b/app/views/user_groups/edit.html.haml new file mode 100644 index 0000000..35514e0 --- /dev/null +++ b/app/views/user_groups/edit.html.haml @@ -0,0 +1,3 @@ +- title t("user_groups.edit.page_title", :resource => @user_group) + += render "form" diff --git a/app/views/user_groups/index.html.haml b/app/views/user_groups/index.html.haml new file mode 100644 index 0000000..545b838 --- /dev/null +++ b/app/views/user_groups/index.html.haml @@ -0,0 +1,6 @@ +- title t("user_groups.index.page_title") + +- if @user_groups.count > 0 + = render "index_core", :user_groups => @user_groups + += render :partial => 'shared/create_link', :locals => {:parent => @parent, :child_class => UserGroup} \ No newline at end of file diff --git a/app/views/user_groups/new.html.haml b/app/views/user_groups/new.html.haml new file mode 100644 index 0000000..dfef18e --- /dev/null +++ b/app/views/user_groups/new.html.haml @@ -0,0 +1,3 @@ +- title t("user_groups.new.page_title") + += render "form" diff --git a/app/views/user_groups/show.html.haml b/app/views/user_groups/show.html.haml new file mode 100644 index 0000000..00bdeb7 --- /dev/null +++ b/app/views/user_groups/show.html.haml @@ -0,0 +1,20 @@ +- title t("user_groups.show.page_title") + +%p + %strong= t('user_groups.show.name') + ":" + = @user_group.name +%p + %strong= t('user_groups.show.description') + ":" + = @user_group.description +%p + %strong= t('user_groups.show.tenant_id') + ":" + = @user_group.tenant + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @user_group.tenant, :child => @user_group } + +%h2=t("user_group_memberships.index.page_title") + +- if @user_group.user_group_memberships.count > 0 + = render "user_group_memberships/index_core", :user_group_memberships => @user_group.user_group_memberships + += render :partial => 'shared/create_link', :locals => {:parent => @user_group, :child_class => UserGroupMembership} \ No newline at end of file diff --git a/app/views/users/_form.html.haml b/app/views/users/_form.html.haml new file mode 100644 index 0000000..9a75677 --- /dev/null +++ b/app/views/users/_form.html.haml @@ -0,0 +1,16 @@ +- if @parent && @parent.class == Tenant + = simple_form_for([@parent, @user]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('users.form.submit') +- else + = simple_form_for(@user) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('users.form.submit') diff --git a/app/views/users/_form_core.html.haml b/app/views/users/_form_core.html.haml new file mode 100644 index 0000000..8e18d12 --- /dev/null +++ b/app/views/users/_form_core.html.haml @@ -0,0 +1,27 @@ +.inputs + - if GuiFunction.display?('name_data_fields_in_user_edit_form', current_user) + = f.input :male, :collection => [[true, t('users.form.gender.male')], [false, t('users.form.gender.female')]], :label_method => :last, :value_method => :first, :label => t('users.form.male.label'), :hint => conditional_hint('users.form.gender.hint'), :label => t('users.form.gender.label'), :as => :radio + = f.input :first_name, :label => t('users.form.first_name.label'), :hint => conditional_hint('users.form.first_name.hint'), :autofocus => true + = f.input :middle_name, :label => t('users.form.middle_name.label'), :hint => conditional_hint('users.form.middle_name.hint') + = f.input :last_name, :label => t('users.form.last_name.label'), :hint => conditional_hint('users.form.last_name.hint') + - if GuiFunction.display?('user_name_field_in_user_edit_form', current_user) + = f.input :user_name, :label => t('users.form.user_name.label'), :hint => conditional_hint('users.form.user_name.hint') + - if GuiFunction.display?('email_field_in_user_edit_form', current_user) + = f.input :email, :label => t('users.form.email.label'), :hint => conditional_hint('users.form.email.hint') + + - if GuiFunction.display?('password_fields_in_user_edit_form', current_user) + = f.input :password, :label => t('users.form.password.label'), :hint => conditional_hint('users.form.password.hint'), :as => :password + = f.input :password_confirmation, :label => t('users.form.password_confirmation.label'), :hint => conditional_hint('users.form.password_confirmation.hint'), :as => :password + + - if GuiFunction.display?('pin_fields_in_user_edit_form', current_user) + = f.input :new_pin, :label => t('users.form.new_pin.label'), :hint => conditional_hint('users.form.new_pin.hint'), :as => :password + = f.input :new_pin_confirmation, :label => t('users.form.new_pin_confirmation.label'), :hint => conditional_hint('users.form.new_pin_confirmation.hint'), :as => :password + + = f.input :image, { :as => :file, :label => t('users.form.image.label'), :hint => conditional_hint('users.form.image.hint') } + - if @user && @user.image? + %p + =link_to 'Destroy avatar', tenant_user_destroy_avatar_path(@tenant, @user) + + = f.input :language_id, :collection => Language.all, :label => t('users.form.language_id.label'), :hint => conditional_hint('users.form.language_id.hint'), :include_blank => false + + /= f.input :send_voicemail_as_email_attachment, :label => t('users.form.send_voicemail_as_email_attachment.label'), :hint => conditional_hint('users.form.send_voicemail_as_email_attachment.hint') diff --git a/app/views/users/_index_core.html.haml b/app/views/users/_index_core.html.haml new file mode 100644 index 0000000..51c15de --- /dev/null +++ b/app/views/users/_index_core.html.haml @@ -0,0 +1,18 @@ +%table + %tr + %th + %th= t('users.index.user_name') + %th= t('users.index.email') + %th= t('users.index.first_name') + %th= t('users.index.last_name') + + - reset_cycle + - for user in users + %tr{:class => cycle('odd', 'even')} + %td + = image_tag user.image_url(:mini).to_s if user.image_url(:mini) + %td= user.user_name + %td= user.email + %td= user.first_name + %td= user.last_name + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => @tenant, :child => user} \ No newline at end of file diff --git a/app/views/users/_listing.html.haml b/app/views/users/_listing.html.haml new file mode 100644 index 0000000..0a97ad1 --- /dev/null +++ b/app/views/users/_listing.html.haml @@ -0,0 +1,8 @@ +- amount_of_users = users.count +- if amount_of_users > 0 + - if amount_of_users < 30 + = users.map{|user| user}.join(', ') + - else + = users.limit(15).map{|user| user}.join(', ') + ', ' + = '[...]' + = users.offset(amount_of_users - 15).map{|user| user}.join(', ') \ No newline at end of file diff --git a/app/views/users/edit.html.haml b/app/views/users/edit.html.haml new file mode 100644 index 0000000..96272f5 --- /dev/null +++ b/app/views/users/edit.html.haml @@ -0,0 +1,3 @@ +- title t("users.edit.page_title", :resource => @user) + += render "form" diff --git a/app/views/users/index.html.haml b/app/views/users/index.html.haml new file mode 100644 index 0000000..892e035 --- /dev/null +++ b/app/views/users/index.html.haml @@ -0,0 +1,6 @@ +- title t("users.index.page_title") + +- if @users.count > 0 + = render "index_core", :users => @users + += render :partial => 'shared/create_link', :locals => {:parent => @tenant, :child_class => User} \ No newline at end of file diff --git a/app/views/users/new.html.haml b/app/views/users/new.html.haml new file mode 100644 index 0000000..a014611 --- /dev/null +++ b/app/views/users/new.html.haml @@ -0,0 +1,3 @@ +- title t("users.new.page_title") + += render "form" diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml new file mode 100644 index 0000000..7730447 --- /dev/null +++ b/app/views/users/show.html.haml @@ -0,0 +1,96 @@ +- title "User: #{@user}" + +#user-show + %aside + = image_tag @user.image_url(:small).to_s, class: 'display' if @user.image? && @user.image_url(:small) + %p + %strong= t('users.show.user_name') + ":" + = @user.user_name + %p + %strong= t('users.show.email') + ":" + = @user.email + + %p.controls + = render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @tenant, :child => @user } + + - @user.sip_accounts.each do |sip_account| + - phone_number = sip_account.phone_numbers.order(:number).last + - if phone_number && !phone_number.number.blank? && phone_number.number[0] != '+' + %p + %strong= sip_account.phone_numbers.order(:number).last.number + %p + =link_to t("call_histories.index.page_title"), sip_account_call_histories_path(sip_account) + %br + =link_to t("voicemail_messages.index.page_title"), sip_account_voicemail_messages_path(sip_account) + %br + =link_to t("call_forwards.index.page_title"), phone_number_call_forwards_path(phone_number) + %br + =link_to t("voicemail_settings.index.page_title"), sip_account_voicemail_settings_path(sip_account) + %br + =link_to t("softkeys.index.page_title"), sip_account_softkeys_path(sip_account) + %br + =link_to t("ringtones.show.page_title"), phone_number_ringtones_path(phone_number) + + - if @user.conferences.any? + %p + %strong= t("conferences.index.page_title") + - @user.conferences.each do |conference| + %p + =link_to conference, edit_user_conference_path(@user, conference) + + + %section + -# Phone books + -# + - if GuiFunction.display?('show_phone_books_in_user_show_view', current_user) + - if can?( :index, PhoneBook ) + %h2=t("phone_books.index.page_title") + = render "phone_books/index_core", :phone_books => @phone_books + = render :partial => 'shared/create_link', :locals => {:parent => @user, :child_class => PhoneBook} + + -# User groups (only if the current user can edit or destroy them) + -# + - if @user.user_groups.map{ |x| can?( :edit, x ) || can?( :destroy, x ) }.include?(true) + - if can?( :index, UserGroup ) + %h2=t("user_groups.index.page_title") + - if @user.user_groups.count > 0 + = render "user_groups/index_core", :user_groups => @user.user_groups.where(:tenant_id => @tenant.id).order(:name) + = render :partial => 'shared/create_link', :locals => {:parent => @tenant, :child_class => UserGroup} + + -# SIP accounts + -# + - if (can?( :index, SipAccount ) && @user.sip_accounts.count > 0 ) || can?( :create, SipAccount ) + %h2= t('sip_accounts.index.page_title') + - if can?( :index, SipAccount ) && @user.sip_accounts.count > 0 + = render "sip_accounts/index_core", :sip_accounts => @user.sip_accounts + = render :partial => 'shared/create_link', :locals => {:parent => @user, :child_class => SipAccount} + + -# Phones + -# + - if (can?( :index, Phone, :phoneable => @user ) && @user.phones.count > 0 ) || can?( :create, Phone, :phoneable => @user ) + %h2= t('phones.index.page_title') + - if can?( :index, Phone, :phoneable => @user ) && @user.phones.count > 0 + = render "phones/index_core", :phones => @user.phones + = render :partial => 'shared/create_link', :locals => {:parent => @user, :child_class => Phone} + + -# FaxAccount + -# + - if (can?( :index, FaxAccount ) && @user.fax_accounts.count > 0 ) || can?( :create, FaxAccount ) + %h2= t('fax_accounts.index.page_title') + - if can?( :index, FaxAccount ) && @user.fax_accounts.count > 0 + = render "fax_accounts/index_core", {:fax_accounts => @user.fax_accounts, :fax_accountable => @user} + = render :partial => 'shared/create_link', :locals => {:parent => @user, :child_class => FaxAccount} + + -# Conferences + -# + - if (can?( :index, Conference ) && @user.conferences.count > 0 ) || can?( :create, Conference ) + %h2= t('conferences.index.page_title') + - if can?( :index, Conference ) && @user.conferences.count > 0 + = render "conferences/index_core", :conferences => @user.conferences + = render :partial => 'shared/create_link', :locals => {:parent => @user, :child_class => Conference} + + -# Tenants + -# + - if can?( :index, Tenant ) && @user.tenants.count > 1 + %h2=t("tenants.index.page_title") + = render "tenants/index_core", :tenants => @user.tenants \ No newline at end of file diff --git a/app/views/voicemail_messages/_index_core.html.haml b/app/views/voicemail_messages/_index_core.html.haml new file mode 100644 index 0000000..b8e47af --- /dev/null +++ b/app/views/voicemail_messages/_index_core.html.haml @@ -0,0 +1,44 @@ += form_tag(destroy_multiple_sip_account_voicemail_messages_path(@sip_account), :method => :delete, :id => 'voicemail_message_form') do + %header.entries-nav= render :partial => "voicemail_messages/navigation" + .content + %table + - reset_cycle + - for voicemail_message in voicemail_messages + %tr.voicemail-messages-entry{:class => cycle('odd', 'even'), :id => "message_#{voicemail_message.uuid}"} + %td.select_box= check_box_tag("selected_uuids[]", voicemail_message.uuid, false, :uuid => "select_item_#{voicemail_message.uuid}", :class => 'select_item') + %td.time + .voicemail-received + = voicemail_message.format_date(voicemail_message.created_epoch, t("voicemail_messages.index.date_format"), t("voicemail_messages.index.date_today_format")) + + - read_date = voicemail_message.format_date(voicemail_message.read_epoch, t("voicemail_messages.index.date_format"), t("voicemail_messages.index.date_today_format")) + - if read_date + .voicemail-read + = read_date + %td.folder + = t("voicemail_messages.index.mailbox.#{voicemail_message.in_folder}") + %td.user + .name= voicemail_message.cid_name + .phone= voicemail_message.cid_number + %td.status + .duration= voicemail_message.display_duration + %td + - if ! voicemail_message.flags.blank? + = t("voicemail_messages.index.flags.#{voicemail_message.flags}") + %td.actions + - if can?(:show, voicemail_message) && File.readable?(voicemail_message.file_path) + = link_to t('voicemail_messages.index.actions.download'), sip_account_voicemail_message_path(@sip_account, voicemail_message, :format => :wav), :method => :get + %td.actions + - if @sip_account.registration && can?(:call, voicemail_message) + = link_to t('voicemail_messages.index.actions.call'), call_sip_account_voicemail_message_path(@sip_account, voicemail_message), :method => :put + %td.actions + - if can?(:edit, voicemail_message) && voicemail_message.read_epoch > 0 + = link_to t('voicemail_messages.index.actions.mark_unread'), mark_unread_sip_account_voicemail_message_path(@sip_account, voicemail_message), :method => :put + - else + = link_to t('voicemail_messages.index.actions.mark_read'), mark_read_sip_account_voicemail_message_path(@sip_account, voicemail_message), :method => :put + %td.actions + - if can? :destroy, voicemail_message + = link_to t('voicemail_messages.index.actions.destroy'), sip_account_voicemail_message_path(@sip_account, voicemail_message), :method => :delete + + %footer.entries-nav= render :partial => "voicemail_messages/navigation" + = image_submit_tag('icons/cross-16x.png', :confirm => t("voicemail_messages.index.actions.confirm_selected")) + = t("voicemail_messages.index.actions.destroy_multiple") diff --git a/app/views/voicemail_messages/_navigation.html.haml b/app/views/voicemail_messages/_navigation.html.haml new file mode 100644 index 0000000..2277bf2 --- /dev/null +++ b/app/views/voicemail_messages/_navigation.html.haml @@ -0,0 +1,9 @@ +%nav + %ol.abc + %li + %a{ :href => "?type=" }= t('voicemail_messages.index.navigation.all', :count => @messages_count) + %a{ :href => "?type=read" }= t('voicemail_messages.index.navigation.read', :count => @messages_read_count) + %a{ :href => "?type=unread" }= t('voicemail_messages.index.navigation.unread', :count => @messages_unread_count) + +.pagination + = will_paginate @voicemail_messages diff --git a/app/views/voicemail_messages/index.html.haml b/app/views/voicemail_messages/index.html.haml new file mode 100644 index 0000000..53f8090 --- /dev/null +++ b/app/views/voicemail_messages/index.html.haml @@ -0,0 +1,6 @@ +- if @type + - title t("voicemail_messages.index.page_title_#{@type}") +- else + - title t("voicemail_messages.index.page_title") + += render "index_core", :voicemail_messages => @voicemail_messages diff --git a/app/views/voicemail_settings/_form.html.haml b/app/views/voicemail_settings/_form.html.haml new file mode 100644 index 0000000..6d5f845 --- /dev/null +++ b/app/views/voicemail_settings/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([@sip_account,@voicemail_setting]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('voicemail_settings.form.submit') \ No newline at end of file diff --git a/app/views/voicemail_settings/_form_core.html.haml b/app/views/voicemail_settings/_form_core.html.haml new file mode 100644 index 0000000..08bdfc2 --- /dev/null +++ b/app/views/voicemail_settings/_form_core.html.haml @@ -0,0 +1,11 @@ +.inputs + + = f.input :greeting_path, :as => :select, :label => t('voicemail_settings.form.greeting.label'), :hint => conditional_hint('voicemail_settings.form.greeting.hint'), :collection => @greeting_files + = f.input :name_path, :as => :select, :label => t('voicemail_settings.form.name.label'), :hint => conditional_hint('voicemail_settings.form.name.hint'), :collection => @name_files + + = f.input :password, :label => t('voicemail_settings.form.pin.label'), :hint => conditional_hint('voicemail_settings.form.pin.hint') + + = f.input :notify, :as => :boolean, :label => t('voicemail_settings.form.notify.label'), :hint => conditional_hint('voicemail_settings.form.notify.hint') + = f.input :attachment, :as => :boolean, :label => t('voicemail_settings.form.attachment.label'), :hint => conditional_hint('voicemail_settings.form.attachment.hint') + = f.input :mark_read, :as => :boolean, :label => t('voicemail_settings.form.mark_read.label'), :hint => conditional_hint('voicemail_settings.form.mark_read.hint') + = f.input :purge, :as => :boolean, :label => t('voicemail_settings.form.purge.label'), :hint => conditional_hint('voicemail_settings.form.purge.hint') diff --git a/app/views/voicemail_settings/edit.html.haml b/app/views/voicemail_settings/edit.html.haml new file mode 100644 index 0000000..6bd7031 --- /dev/null +++ b/app/views/voicemail_settings/edit.html.haml @@ -0,0 +1,3 @@ +- title t("voicemail_settings.edit.page_title") + += render "form" diff --git a/app/views/voicemail_settings/show.html.haml b/app/views/voicemail_settings/show.html.haml new file mode 100644 index 0000000..30e12d0 --- /dev/null +++ b/app/views/voicemail_settings/show.html.haml @@ -0,0 +1,26 @@ +- title t("voicemail_settings.show.page_title") + +%p + %strong= t('voicemail_settings.show.greeting_path') + ":" + = File.basename(@voicemail_setting.greeting_path.to_s) + +%p + %strong= t('voicemail_settings.show.name_path') + ":" + = File.basename(@voicemail_setting.name_path.to_s) + +%p + %strong= t('voicemail_settings.show.flags') + ":" + - if @voicemail_setting.notify + %br + = "- " + t('voicemail_settings.show.notify') + - if @voicemail_setting.attachment + %br + = "- " + t('voicemail_settings.show.attachment') + - if @voicemail_setting.mark_read + %br + = "- " + t('voicemail_settings.show.mark_read') + - if @voicemail_setting.purge + %br + = "- " + t('voicemail_settings.show.purge') + += link_to t('voicemail_settings.actions.edit'), edit_sip_account_voicemail_setting_path(@sip_account, @voicemail_setting) diff --git a/app/views/whitelists/_form.html.haml b/app/views/whitelists/_form.html.haml new file mode 100644 index 0000000..c7f787a --- /dev/null +++ b/app/views/whitelists/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([@parent, @whitelist]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('whitelists.form.submit') \ No newline at end of file diff --git a/app/views/whitelists/_form_core.html.haml b/app/views/whitelists/_form_core.html.haml new file mode 100644 index 0000000..38f1487 --- /dev/null +++ b/app/views/whitelists/_form_core.html.haml @@ -0,0 +1,8 @@ +.inputs + = f.input :name, :label => t('whitelists.form.name.label'), :hint => conditional_hint('whitelists.form.name.hint') + + %h3= t('whitelists.form.phone_numbers.label') + - if !t('whitelists.form.phone_numbers.hint').blank? + %p= t('whitelists.form.phone_numbers.hint') + = f.simple_fields_for :phone_numbers do |phone_number| + = render "phone_numbers/form_core", :f => phone_number diff --git a/app/views/whitelists/_index_core.html.haml b/app/views/whitelists/_index_core.html.haml new file mode 100644 index 0000000..b4c5b0c --- /dev/null +++ b/app/views/whitelists/_index_core.html.haml @@ -0,0 +1,15 @@ +%table + %tr + %th= t('whitelists.index.name') + %th= t('whitelists.index.phone_numbers') + + - reset_cycle + - for whitelist in whitelists + %tr{:class => cycle('odd', 'even')} + %td= whitelist.name || '-' + %td + = render 'phone_numbers/listing', :phone_numbers => whitelist.phone_numbers + %br + = render :partial => 'shared/create_link', :locals => {:parent => whitelist, :child_class => PhoneNumber, :short_link => true} + + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => whitelist.whitelistable, :child => whitelist} \ No newline at end of file diff --git a/app/views/whitelists/edit.html.haml b/app/views/whitelists/edit.html.haml new file mode 100644 index 0000000..9f8af90 --- /dev/null +++ b/app/views/whitelists/edit.html.haml @@ -0,0 +1,3 @@ +- title t("whitelists.edit.page_title") + += render "form" diff --git a/app/views/whitelists/index.html.haml b/app/views/whitelists/index.html.haml new file mode 100644 index 0000000..0873189 --- /dev/null +++ b/app/views/whitelists/index.html.haml @@ -0,0 +1,6 @@ +- title t("whitelists.index.page_title") + +- if @whitelists.count > 0 + = render "index_core", :whitelists => @whitelists + += render :partial => 'shared/create_link', :locals => {:parent => @parent, :child_class => Whitelist} \ No newline at end of file diff --git a/app/views/whitelists/new.html.haml b/app/views/whitelists/new.html.haml new file mode 100644 index 0000000..f1101ad --- /dev/null +++ b/app/views/whitelists/new.html.haml @@ -0,0 +1,3 @@ +- title t("whitelists.new.page_title") + += render "form" diff --git a/app/views/whitelists/show.html.haml b/app/views/whitelists/show.html.haml new file mode 100644 index 0000000..77652f9 --- /dev/null +++ b/app/views/whitelists/show.html.haml @@ -0,0 +1,7 @@ +- title t("whitelists.show.page_title") + +%p + %strong= t('whitelists.show.name') + ":" + = @whitelist.name + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @parent, :child => @whitelist } \ No newline at end of file diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..03f69d2 --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +# This file is used by Rack-based servers to start the application. + +require ::File.expand_path('../config/environment', __FILE__) +run Gemeinschaft42c::Application diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..d09cf24 --- /dev/null +++ b/config/application.rb @@ -0,0 +1,65 @@ +require File.expand_path('../boot', __FILE__) + +require 'rails/all' + +if defined?(Bundler) + # If you precompile assets before deploying to production, use this line + Bundler.require *Rails.groups(:assets => %w(development test)) + # If you want your assets lazily compiled in production, use this line + # Bundler.require(:default, :assets, Rails.env) +end + +module Gemeinschaft42c + class Application < Rails::Application + # Settings in config/environments/* take precedence over those specified here. + # Application configuration should go into files in config/initializers + # -- all .rb files in that directory are automatically loaded. + + # Custom directories with classes and modules you want to be autoloadable. + # config.autoload_paths += %W(#{config.root}/extras) + + # Only load the plugins named here, in the order given (default is alphabetical). + # :all can be used as a placeholder for all plugins not explicitly named. + # config.plugins = [ :exception_notification, :ssl_requirement, :all ] + + # --- rather use Apache + Passenger for SSL -----{ + #config.plugins = [ :exception_notification, :ssl_requirement, :all ] + + #config.middleware.insert_before ActionDispatch::Static, "Rack::SSL" + #config.middleware.insert_before ActionDispatch::Static, Rack::SSL, :exclude => proc { |env| env['HTTPS'] != 'on' } + #config.force_ssl = true + + #require 'rack/ssl' + #config.middleware.use Rack::SSL + # -----------------------------------------------} + + + # Activate observers that should always be running. + # config.active_record.observers = :cacher, :garbage_collector, :forum_observer + + # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. + # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. + # config.time_zone = 'Central Time (US & Canada)' + config.time_zone = 'Berlin' + config.active_record.default_timezone = :utc + + # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. + config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '*', '*', '*.{rb,yml}').to_s] + # config.i18n.default_locale = :de + + # Configure the default encoding used in templates for Ruby 1.9. + config.encoding = "utf-8" + + # Configure sensitive parameters which will be filtered from the log file. + config.filter_parameters += [:password, :password_confirmation, :pin, :voicemail_pin] + + # Enable the asset pipeline + config.assets.enabled = true + + # Version of your assets, change this if you want to expire all your assets + config.assets.version = '1.0' + + # Load the PhoneControllers + config.autoload_paths += %W(#{config.root}/lib/phone_controllers) + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..4489e58 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,6 @@ +require 'rubygems' + +# Set up gems listed in the Gemfile. +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) + +require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..4ea8d4a --- /dev/null +++ b/config/database.yml @@ -0,0 +1,22 @@ +development: + adapter: sqlite3 + database: db/development.sqlite3 + pool: 5 + timeout: 5000 + +production: + adapter: sqlite3 + database: db/development.sqlite3 + pool: 5 + timeout: 5000 + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. + +test: + adapter: sqlite3 + database: db/test<%= ENV['TEST_ENV_NUMBER'] %>.sqlite3 + pool: 5 + timeout: 5000 + diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..efe867e --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,5 @@ +# Load the rails application +require File.expand_path('../application', __FILE__) + +# Initialize the rails application +Gemeinschaft42c::Application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..bd34e4f --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,45 @@ +Gemeinschaft42c::Application.configure do + # Settings specified here will take precedence over those in config/application.rb + + # In the development environment your application's code is reloaded on + # every request. This slows down response time but is perfect for development + # since you don't have to restart the web server when you make code changes. + config.cache_classes = false + + # Log error messages when you accidentally call methods on nil. + config.whiny_nils = true + + # Show full error reports and disable caching + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Don't care if the mailer can't send + config.action_mailer.raise_delivery_errors = false + + # Print deprecation notices to the Rails logger + config.active_support.deprecation = :log + + # Only use best-standards-support built into browsers + config.action_dispatch.best_standards_support = :builtin + + # Raise exception on mass assignment protection for Active Record models + config.active_record.mass_assignment_sanitizer = :strict + + # Log the query plan for queries taking more than this (works + # with SQLite, MySQL, and PostgreSQL) + config.active_record.auto_explain_threshold_in_seconds = 0.5 + + # Do not compress assets + config.assets.compress = false + + # Expands the lines which load the assets + config.assets.debug = true + + # Enable Hirb: + extend Hirb::Console + Hirb::View.enable +end + + + + diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..4e5bdd8 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,65 @@ +Gemeinschaft42c::Application.configure do + # Settings specified here will take precedence over those in config/application.rb + + # Code is not reloaded between requests + config.cache_classes = true + + # Full error reports are disabled and caching is turned on + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Disable Rails's static asset server (Apache or nginx will already do this) + config.serve_static_assets = true + + # Compress JavaScripts and CSS + config.assets.compress = true + + # Don't fallback to assets pipeline if a precompiled asset is missed + config.assets.compile = false + + # Generate digests for assets URLs + config.assets.digest = true + + # Defaults to Rails.root.join("public/assets") + # config.assets.manifest = YOUR_PATH + + # Specifies the header that your server uses for sending files + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # See everything in the log (default is :info) + # config.log_level = :debug + + # Use a different logger for distributed setups + # config.logger = SyslogLogger.new + + # Use a different cache store in production + # config.cache_store = :mem_cache_store + + # Enable serving of images, stylesheets, and JavaScripts from an asset server + # config.action_controller.asset_host = "http://assets.example.com" + + # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) + # config.assets.precompile += %w( search.js ) + config.assets.initialize_on_precompile = false + + # Disable delivery errors, bad email addresses will be ignored + # config.action_mailer.raise_delivery_errors = false + + # Enable threaded mode + # config.threadsafe! + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation can not be found) + config.i18n.fallbacks = true + + # Send deprecation notices to registered listeners + config.active_support.deprecation = :notify + + # Enable Hirb: + extend Hirb::Console + Hirb::View.enable +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..f2d3a67 --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,37 @@ +Gemeinschaft42c::Application.configure do + # Settings specified here will take precedence over those in config/application.rb + + # The test environment is used exclusively to run your application's + # test suite. You never need to work with it otherwise. Remember that + # your test database is "scratch space" for the test suite and is wiped + # and recreated between test runs. Don't rely on the data there! + config.cache_classes = true + + # Configure static asset server for tests with Cache-Control for performance + config.serve_static_assets = true + config.static_cache_control = "public, max-age=3600" + + # Log error messages when you accidentally call methods on nil + config.whiny_nils = true + + # Show full error reports and disable caching + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Raise exceptions instead of rendering exception templates + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment + config.action_controller.allow_forgery_protection = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Raise exception on mass assignment protection for Active Record models + config.active_record.mass_assignment_sanitizer = :strict + + # Print deprecation notices to the stderr + config.active_support.deprecation = :stderr +end diff --git a/config/hirb.yml b/config/hirb.yml new file mode 100644 index 0000000..f011c9d --- /dev/null +++ b/config/hirb.yml @@ -0,0 +1,201 @@ +:output: + CallForwardCase: + :options: + :fields: + - id + - value + CallForward: + :options: + :fields: + - id + - phone_number + - call_forward_case + - timeout + - destination + - source + - depth + - active + PhoneNumberRange: + :options: + :fields: + - id + - name + - description + - phone_number_rangeable_type + - phone_number_rangeable + AreaCode: + :options: + :fields: + - id + - country + - name + - area_code + - central_office_code + Manufacturer: + :options: + :fields: + - id + - name + - homepage_url + - state + PhoneModel: + :options: + :fields: + - id + - name + - manufacturer + - state + Oui: + :options: + :fields: + - id + - manufacturer + - value + - state + User: + :options: + :fields: + - id + - user_name + - last_name + - email + - current_tenant_id + - current_tenant + Tenant: + :options: + :fields: + - id + - name + - state + - country + - sip_domain + SipDomain: + :options: + :fields: + - id + - host + - realm + PhoneBook: + :options: + :fields: + - id + - name + - phone_bookable_type + - phone_bookable_id + - phone_bookable + - state + PhoneBookEntry: + :options: + :fields: + - id + - phone_book_id + - phone_book + - first_name + - organization + PhoneNumber: + :options: + :fields: + - id + - name + - number + - phone_numberable_type + - phone_numberable_id + Phone: + :options: + :fields: + - id + - phone_model + - mac_address + - ip_address + - last_ip_address + - phoneable_type + - phoneable_id + - phoneable + SipAccount: + :options: + :fields: + - id + - sip_accountable_type + - sip_accountable + - auth_name + - caller_name + - voicemail_pin + TenantMembership: + :options: + :fields: + - id + - tenant + - user + - state + UserGroupMembership: + :options: + :fields: + - id + - user_group + - user + UserGroup: + :options: + :fields: + - id + - name + - tenant + - position + Country: + :options: + :fields: + - id + - name + - country_code + - international_call_prefix + - trunk_prefix + Conference: + :options: + :fields: + - id + - name + - start + - conferenceable_type + - conferenceable + ConferenceInvitee: + :options: + :fields: + - id + - conference + - phone_number + - phone_book_entry_id + - speaker + - moderator + - pin + FaxDocument: + :options: + :fields: + - id + - destination_phone_number + - document + Callthrough: + :options: + :fields: + - id + - tenant + - name + Language: + :options: + :fields: + - id + - name + - code + SoftkeyFunction: + :options: + :fields: + - id + - name + - position + Api::Row: + :options: + :fields: + - id + - last_name + - first_name + - user_name + - user + diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb new file mode 100644 index 0000000..59385cd --- /dev/null +++ b/config/initializers/backtrace_silencers.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. +# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } + +# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. +# Rails.backtrace_cleaner.remove_silencers! diff --git a/config/initializers/connectivity_check.rb b/config/initializers/connectivity_check.rb new file mode 100644 index 0000000..583f372 --- /dev/null +++ b/config/initializers/connectivity_check.rb @@ -0,0 +1,23 @@ +require 'socket' +require 'timeout' + +module Connectivity + + def self.port_open?( ip_addr, port ) + begin + Timeout::timeout(5) { + s = TCPSocket.new( ip_addr, port ) + s.close + return true + } + rescue Errno::ECONNREFUSED + rescue Errno::EHOSTUNREACH + rescue Errno::EADDRNOTAVAIL + rescue SocketError + rescue Timeout::Error + end + + return false + end + +end diff --git a/config/initializers/gemeinschaft_parameters.rb b/config/initializers/gemeinschaft_parameters.rb new file mode 100644 index 0000000..6e89abd --- /dev/null +++ b/config/initializers/gemeinschaft_parameters.rb @@ -0,0 +1,81 @@ +# Use this file to set generic parameters for Gemeinschaft + +GEMEINSCHAFT_VERSION = '5.0' +SUPER_TENANT_NAME = 'Super-Tenant' + +# System defaults +MINIMUM_PIN_LENGTH = 4 +MAXIMUM_PIN_LENGTH = 10 + +# GUI +GUI_REDIRECT_HTTPS = false + +# Phone numbers +# Only touch this if you know what you are doing! +STRICT_INTERNAL_EXTENSION_HANDLING = false +STRICT_DID_HANDLING = false + +# SIP defaults +DEFAULT_LENGTH_SIP_AUTH_NAME = 10 +DEFAULT_LENGTH_SIP_PASSWORD = 15 +CALL_WAITING = false +DEFAULT_CLIR_SETTING = false +DEFAULT_CLIP_SETTING = true + +TO_S_MAX_CALLER_NAME_LENGTH = 20 +TO_S_MAX_LENGTH_OF_AUTH_NAME = 8 + +# Pagination defaults +DEFAULT_PAGINATION_ENTRIES_PER_PAGE = 50 + +# Conference defaults +MAXIMUM_NUMBER_OF_PEOPLE_IN_A_CONFERENCE = 100 +DEFAULT_MAX_CONFERENCE_MEMBERS = 10 + +# Misc defaults +MAX_EXTENSION_LENGTH = 6 + +# Fax defaults +DEFAULT_NUMBER_OF_RETRIES = 3 +DAYS_TILL_AUTO_DELETE = 90 + +# Names of PhoneNumberRanges +INTERNAL_EXTENSIONS = 'internal_extensions' +SERVICE_NUMBERS = 'service_numbers' +DIRECT_INWARD_DIALING_NUMBERS = 'direct_inward_dialing_numbers' + +# Callthrough defaults +CALLTHROUGH_HAS_WHITELISTS = true + +# Hunt groups +HUNT_GROUP_STRATEGIES = ['ring_all', 'ring_recursively'] +VALID_SECONDS_BETWEEN_JUMPS_VALUES = (1 .. 60).to_a.map{|x| x * 2} + +# Callforward +DEFAULT_CALL_FORWARD_DEPTH = 1 +MAX_CALL_FORWARD_DEPTH = 40 +CALLFORWARD_DESTINATION_DEFAULT = '+49' +CALLFORWARD_RULES_ACT_PER_SIP_ACCOUNT_DEFAULT = true + +# Phone +PROVISIONING_AUTO_ADD_PHONE = true +PROVISIONING_AUTO_ADD_SIP_ACCOUNT = true +PROVISIONING_AUTO_TENANT_ID = 2 +PROVISIONING_AUTO_SIP_ACCOUNT_CALLER_PREFIX = 'Gemeinschaft ' +PROVISIONING_IEEE8021X_EAP_USERNAME = '' +PROVISIONING_IEEE8021X_EAP_PASSWORD = '' +NIGHTLY_REBOOT_OF_PHONES = true +SIEMENS_HISTORY_RELOAD_TIMES = {0..6 => 600, 7..20 => 40, 21..24 => 300} + +# API configuration +DEFAULT_API_TENANT_ID = 2 +REMOTE_IP_ADDRESS_WHITELIST = [] # e.g. ['10.0.0.1'] +IMPORT_CSV_FILE = '/var/tmp/ExampleVoipCsvExport.csv' +DOUBLE_CHECK_POSITIVE_USERS_CSV = '/var/tmp/ExampleDoubleCheckVoipCsvExport.csv' +IMPORT_CSV_ENCODING = 'UTF-8' +USER_NAME_PREFIX = 'dtc' +CALLTHROUGH_NAME_TO_BE_USED_FOR_DEFAULT_ACTIVATION = 'Callthrough for employees' + +# GS Cluster configuration +WRITE_GS_CLUSTER_SYNC_LOG = true +HOMEBASE_IP_ADDRESS = '0.0.0.0' diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..9e8b013 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,10 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format +# (all these examples are active by default): +# ActiveSupport::Inflector.inflections do |inflect| +# inflect.plural /^(ox)$/i, '\1en' +# inflect.singular /^(ox)en/i, '\1' +# inflect.irregular 'person', 'people' +# inflect.uncountable %w( fish sheep ) +# end diff --git a/config/initializers/load_extensions.rb b/config/initializers/load_extensions.rb new file mode 100644 index 0000000..d86993c --- /dev/null +++ b/config/initializers/load_extensions.rb @@ -0,0 +1 @@ +require 'activerecord_extensions' diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb new file mode 100644 index 0000000..6c89b3c --- /dev/null +++ b/config/initializers/mime_types.rb @@ -0,0 +1,9 @@ +# Be sure to restart your server when you modify this file. + +# Add new mime types for use in respond_to blocks: +# Mime::Type.register "text/richtext", :rtf +# Mime::Type.register_alias "text/html", :iphone + +# ".htm" file extension for Snom provisioning: +Mime::Type.register 'text/html', :htm +Mime::Type.register 'audio/x-wav', :wav diff --git a/config/initializers/secret_token.rb b/config/initializers/secret_token.rb new file mode 100644 index 0000000..6f04f07 --- /dev/null +++ b/config/initializers/secret_token.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# Your secret key for verifying the integrity of signed cookies. +# If you change this key, all old signed cookies will become invalid! +# Make sure the secret is at least 30 characters and all random, +# no regular words or you'll be exposed to dictionary attacks. +Gemeinschaft42c::Application.config.secret_token = '9a59cac7fe4b23e0253a7beb341d9498d721923e966b45983f441f991e81f758067a6d9a949247d489773288284ab96b5015be52bf7b2834e666d43f864034e4' diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb new file mode 100644 index 0000000..f77495c --- /dev/null +++ b/config/initializers/session_store.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Gemeinschaft42c::Application.config.session_store :cookie_store, key: '_Gemeinschaft42c_session' + +# Use the database for sessions instead of the cookie-based default, +# which shouldn't be used to store highly confidential information +# (create the session table with "rails generate session_migration") +Gemeinschaft42c::Application.config.session_store :active_record_store diff --git a/config/initializers/simple_form.rb b/config/initializers/simple_form.rb new file mode 100644 index 0000000..2e3d9fb --- /dev/null +++ b/config/initializers/simple_form.rb @@ -0,0 +1,19 @@ +# Use this setup block to configure all options available in SimpleForm. +SimpleForm.setup do |config| + config.wrappers :tag => :div, :class => :input, + :error_class => :field_with_errors do |b| + + # Form extensions + b.use :html5 + b.optional :pattern + b.use :maxlength + b.use :placeholder + b.use :readonly + + # Form components + b.use :label_input + b.use :error, :wrap_with => { :tag => :span, :class => :error } + b.use :hint, :wrap_with => { :tag => :span, :class => :hint } + end + +end diff --git a/config/initializers/validators.rb b/config/initializers/validators.rb new file mode 100644 index 0000000..4f6c223 --- /dev/null +++ b/config/initializers/validators.rb @@ -0,0 +1,242 @@ +ActiveRecord::Base.class_eval do + + def self.validate_mac_address( attr_names, options={} ) + validates_format_of( attr_names, { + :with => /^ [0-9A-F]{2} (?: [0-9A-F]{2} ){5} $/x, + :allow_blank => false, + :allow_nil => false, + }.merge!( options ) ) + end + + def self.validate_ip_address( attr_names, options={} ) + validates_format_of( attr_names, { + :with => /^ + (?:25[0-5]|(?:2[0-4]|1\d|[1-9])?\d) + (?:\.(?:25[0-5]|(?:2[0-4]|1\d|[1-9])?\d)){3} + $/x, # OPTIMIZE IPv6 + :allow_blank => false, + :allow_nil => false, + }.merge!( options ) ) + end + + def self.validate_ip_port( attr_names, options={} ) + validates_numericality_of( attr_names, { + :only_integer => true, + :greater_than => 0, + :less_than => 65536, + :allow_nil => false, + }.merge!( options ) ) + end + + def self.validate_netmask( attr_names, options={} ) + configuration = { + :allow_nil => false, + :allow_blank => false, + :with => + /^( + ((128|192|224|240|248|252|254)\.0\.0\.0) + |(255\.(0|128|192|224|240|248|252|254)\.0\.0) + |(255\.255\.(0|128|192|224|240|248|252|254)\.0) + |(255\.255\.255\.(0|128|192|224|240|248|252|254)) + )$/x + } + configuration.merge!( options ) + validates_format_of( attr_names, configuration ) + end + + def self.validate_hostname_or_ip( attr_names, options={} ) + # Validate the server. This is the "host" rule from RFC 3261 + # (but the patterns for IPv4 and IPv6 addresses have been fixed here). + configuration = { + :allow_nil => false, + :allow_blank => false, + :with => + /^ + (?: + (?: + (?: + (?: + [A-Za-z0-9] | + [A-Za-z0-9] [A-Za-z0-9\-]* [A-Za-z0-9] + ) + \. + )* + (?: + [A-Za-z] | + [A-Za-z] [A-Za-z0-9\-]* [A-Za-z0-9] + ) + \.? + ) + | + (?: + (?: 25[0-5] | 2[0-4]\d | 1\d\d | [1-9]?\d ) + (?: \. (?: 25[0-5] | 2[0-4]\d | 1\d\d | [1-9]?\d ) ){3} + ) + | + ( + ( + ( [0-9A-Fa-f]{1,4} [:] ){7} ( [0-9A-Fa-f]{1,4} | [:] ) + )| + ( + ( [0-9A-Fa-f]{1,4} [:] ){6} + ( + [:] [0-9A-Fa-f]{1,4} | + ( + ( 25[0-5] | 2[0-4]\d | 1\d\d | [1-9]?\d ) + ( \. ( 25[0-5] | 2[0-4]\d | 1\d\d | [1-9]?\d ) ){3} + ) | [:] + ) + )| + ( + ( [0-9A-Fa-f]{1,4} [:] ){5} + ( + ( + ( [:] [0-9A-Fa-f]{1,4} ){1,2} + )| + [:]( + ( 25[0-5] | 2[0-4]\d | 1\d\d | [1-9]?\d ) + ( \. ( 25[0-5] | 2[0-4]\d | 1\d\d | [1-9]?\d ) ){3} + )| + [:] + ) + )| + ( + ( [0-9A-Fa-f]{1,4} [:] ){4} + ( + ( ( [:] [0-9A-Fa-f]{1,4} ){1,3} ) | + ( + ( [:] [0-9A-Fa-f]{1,4} )? [:] + ( + ( 25[0-5] | 2[0-4]\d | 1\d\d | [1-9]?\d ) + ( \. ( 25[0-5] | 2[0-4]\d | 1\d\d | [1-9]?\d ) ){3} + ) + ) | [:] + ) + )| + ( + ( [0-9A-Fa-f]{1,4} [:] ){3} + ( + ( ( [:] [0-9A-Fa-f]{1,4} ){1,4} ) | + ( + ( [:] [0-9A-Fa-f]{1,4} ){0,2} [:] + ( + ( 25[0-5] | 2[0-4]\d | 1\d\d | [1-9]?\d ) + ( \. ( 25[0-5] | 2[0-4]\d | 1\d\d | [1-9]?\d ) ){3} + ) + ) | [:] + ) + )| + ( + ( [0-9A-Fa-f]{1,4} [:] ){2} + ( + ( ( [:] [0-9A-Fa-f]{1,4} ){1,5} ) | + ( + ( [:] [0-9A-Fa-f]{1,4} ){0,3} [:] + ( + ( 25[0-5] | 2[0-4]\d | 1\d\d | [1-9]?\d ) + ( \. ( 25[0-5] | 2[0-4]\d | 1\d\d | [1-9]?\d ) ){3} + ) + ) | [:] + ) + )| + ( + ( [0-9A-Fa-f]{1,4} [:] ){1} + ( + ( ( [:] [0-9A-Fa-f]{1,4} ){1,6} ) | + ( + ( [:] [0-9A-Fa-f]{1,4} ){0,4} [:] + ( + ( 25[0-5] | 2[0-4]\d | 1\d\d | [1-9]?\d ) + ( \. ( 25[0-5] | 2[0-4]\d | 1\d\d | [1-9]?\d ) ){3} + ) + ) | [:] + ) + )| + ( + [:] + ( + ( ( [:] [0-9A-Fa-f]{1,4} ){1,7} ) | + ( + ( [:] [0-9A-Fa-f]{1,4} ){0,5} [:] + ( + ( 25[0-5] | 2[0-4]\d | 1\d\d | [1-9]?\d ) + ( \. ( 25[0-5] | 2[0-4]\d | 1\d\d | [1-9]?\d ) ){3} + ) + ) | [:] + ) + ) + ) + ) + $/x + } + configuration.merge!( options ) + validates_format_of( attr_names, configuration ) + end + + # Validate SIP username. This is the "user" rule from RFC 3261. + def self.validate_username( attr_names, options={} ) + configuration = { + :allow_nil => false, + :allow_blank => false, + :with => + /^ + (?: + (?: + [A-Za-z0-9] | + [\-_.!~*'()] + ) | + %[0-9A-F]{2} | + [&=+$,;?\/] + ){1,255} + $/x + } + configuration.merge!( options ) + validates_format_of( attr_names, configuration ) + end + + # Validate SIP password. + def self.validate_sip_password( attr_names, options={} ) + configuration = { + :allow_nil => true, + :allow_blank => true, + :with => + /^ + (?: + (?: + [A-Za-z0-9] | + [\-_.!~*'()] + ) | + %[0-9A-F]{2} | + [&=+$,] + ){0,255} + $/x + } + configuration.merge!( options ) + validates_format_of( attr_names, configuration ) + end + +end + + + +module CustomValidators + + # Validates a URL. + # TODO Convert this into a proper ActiveRecord validator. + # + def self.validate_url( url_str ) + return false if url_str.blank? + require 'uri' + begin + uri = URI.parse( url_str ) + return false if ! uri.absolute? + return false if ! uri.hierarchical? + return false if !( uri.is_a?( URI::HTTP ) || uri.is_a?( URI::HTTPS ) ) + rescue URI::InvalidURIError + return false + end + return true + end + +end + diff --git a/config/initializers/wrap_parameters.rb b/config/initializers/wrap_parameters.rb new file mode 100644 index 0000000..999df20 --- /dev/null +++ b/config/initializers/wrap_parameters.rb @@ -0,0 +1,14 @@ +# Be sure to restart your server when you modify this file. +# +# This file contains settings for ActionController::ParamsWrapper which +# is enabled by default. + +# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. +ActiveSupport.on_load(:action_controller) do + wrap_parameters format: [:json] +end + +# Disable root element in JSON by default. +ActiveSupport.on_load(:active_record) do + self.include_root_in_json = false +end diff --git a/config/locales/carrierwave/de.yml b/config/locales/carrierwave/de.yml new file mode 100644 index 0000000..08dbd26 --- /dev/null +++ b/config/locales/carrierwave/de.yml @@ -0,0 +1,5 @@ +de: + carrierwave: + errors: + integrity: 'Kein Bild.' + processing: 'Das Bild kann nicht in der Größe verändert werden.' \ No newline at end of file diff --git a/config/locales/carrierwave/en.yml b/config/locales/carrierwave/en.yml new file mode 100644 index 0000000..2fa50f2 --- /dev/null +++ b/config/locales/carrierwave/en.yml @@ -0,0 +1,5 @@ +en: + carrierwave: + errors: + integrity: 'Not an image.' + processing: 'Cannot resize image.' \ No newline at end of file diff --git a/config/locales/de.yml b/config/locales/de.yml new file mode 100644 index 0000000..087a2d3 --- /dev/null +++ b/config/locales/de.yml @@ -0,0 +1,196 @@ +de: + date: + abbr_day_names: + - So + - Mo + - Di + - Mi + - Do + - Fr + - Sa + abbr_month_names: + - + - Jan + - Feb + - Mär + - Apr + - Mai + - Jun + - Jul + - Aug + - Sep + - Okt + - Nov + - Dez + day_names: + - Sonntag + - Montag + - Dienstag + - Mittwoch + - Donnerstag + - Freitag + - Samstag + formats: + default: ! '%d.%m.%Y' + long: ! '%e. %B %Y' + short: ! '%e. %b' + month_names: + - + - Januar + - Februar + - März + - April + - Mai + - Juni + - Juli + - August + - September + - Oktober + - November + - Dezember + order: + - :day + - :month + - :year + datetime: + distance_in_words: + about_x_hours: + one: etwa eine Stunde + other: etwa %{count} Stunden + about_x_months: + one: etwa ein Monat + other: etwa %{count} Monate + about_x_years: + one: etwa ein Jahr + other: etwa %{count} Jahre + almost_x_years: + one: fast ein Jahr + other: fast %{count} Jahre + half_a_minute: eine halbe Minute + less_than_x_minutes: + one: weniger als eine Minute + other: weniger als %{count} Minuten + less_than_x_seconds: + one: weniger als eine Sekunde + other: weniger als %{count} Sekunden + over_x_years: + one: mehr als ein Jahr + other: mehr als %{count} Jahre + x_days: + one: ein Tag + other: ! '%{count} Tage' + x_minutes: + one: eine Minute + other: ! '%{count} Minuten' + x_months: + one: ein Monat + other: ! '%{count} Monate' + x_seconds: + one: eine Sekunde + other: ! '%{count} Sekunden' + prompts: + day: Tag + hour: Stunden + minute: Minuten + month: Monat + second: Sekunden + year: Jahr + errors: + format: ! '%{attribute} %{message}' + messages: + accepted: muss akzeptiert werden + blank: muss ausgefüllt werden + confirmation: stimmt nicht mit der Bestätigung überein + empty: muss ausgefüllt werden + equal_to: muss genau %{count} sein + even: muss gerade sein + exclusion: ist nicht verfügbar + greater_than: muss größer als %{count} sein + greater_than_or_equal_to: muss größer oder gleich %{count} sein + inclusion: ist kein gültiger Wert + invalid: ist nicht gültig + less_than: muss kleiner als %{count} sein + less_than_or_equal_to: muss kleiner oder gleich %{count} sein + not_a_number: ist keine Zahl + not_an_integer: muss ganzzahlig sein + odd: muss ungerade sein + record_invalid: ! 'Gültigkeitsprüfung ist fehlgeschlagen: %{errors}' + taken: ist bereits vergeben + too_long: ist zu lang (nicht mehr als %{count} Zeichen) + too_short: ist zu kurz (nicht weniger als %{count} Zeichen) + wrong_length: hat die falsche Länge (muss genau %{count} Zeichen haben) + template: + body: ! 'Bitte überprüfen Sie die folgenden Felder:' + header: + one: ! 'Konnte %{model} nicht speichern: ein Fehler.' + other: ! 'Konnte %{model} nicht speichern: %{count} Fehler.' + helpers: + select: + prompt: Bitte wählen + submit: + create: ! '%{model} anlegen' + submit: ! '%{model} speichern' + update: ! '%{model} aktualisieren' + number: + currency: + format: + delimiter: . + format: ! '%n %u' + precision: 2 + separator: ! ',' + significant: false + strip_insignificant_zeros: false + unit: € + format: + delimiter: . + precision: 2 + separator: ! ',' + significant: false + strip_insignificant_zeros: false + human: + decimal_units: + format: ! '%n %u' + units: + billion: + one: Milliarde + other: Milliarden + million: Millionen + quadrillion: + one: Billiarde + other: Billiarden + thousand: Tausend + trillion: Billionen + unit: '' + format: + delimiter: '' + precision: 1 + significant: true + strip_insignificant_zeros: true + storage_units: + format: ! '%n %u' + units: + byte: + one: Byte + other: Bytes + gb: GB + kb: KB + mb: MB + tb: TB + percentage: + format: + delimiter: '' + precision: + format: + delimiter: '' + support: + array: + last_word_connector: ! ' und ' + two_words_connector: ! ' und ' + words_connector: ! ', ' + time: + am: vormittags + formats: + default: ! '%A, %d. %B %Y, %H:%M Uhr' + long: ! '%A, %d. %B %Y, %H:%M Uhr' + short: ! '%d. %B, %H:%M Uhr' + pm: nachmittags \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..dabe98d --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,6 @@ +# Don't add anything here! +en: + dont_use_me: "NO ME USES!" + # Temporal, just till we create the Voice Mail stuff. + voice_mail: "Voice Mail" + fax: "Fax" \ No newline at end of file diff --git a/config/locales/simple_form.de.yml b/config/locales/simple_form.de.yml new file mode 100644 index 0000000..1db7297 --- /dev/null +++ b/config/locales/simple_form.de.yml @@ -0,0 +1,24 @@ +de: + simple_form: + "yes": 'Ja' + "no": 'Nein' + required: + text: 'benötigt' + mark: '*' + # You can uncomment the line below if you need to overwrite the whole required html. + # When using html, text and mark won't be used. + # html: '*' + error_notification: + default_message: "Es wurden Validierungsfehler bei Ihren Eingaben gefunden." + # Labels and hints examples + # labels: + # password: 'Password' + # user: + # new: + # email: 'E-mail para efetuar o sign in.' + # edit: + # email: 'E-mail.' + # hints: + # username: 'User name to sign in.' + # password: 'No special characters, please.' + diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml new file mode 100644 index 0000000..007d9f9 --- /dev/null +++ b/config/locales/simple_form.en.yml @@ -0,0 +1,24 @@ +en: + simple_form: + "yes": 'Yes' + "no": 'No' + required: + text: 'required' + mark: '*' + # You can uncomment the line below if you need to overwrite the whole required html. + # When using html, text and mark won't be used. + # html: '*' + error_notification: + default_message: "Some errors were found, please take a look." + # Labels and hints examples + # labels: + # password: 'Password' + # user: + # new: + # email: 'E-mail para efetuar o sign in.' + # edit: + # email: 'E-mail.' + # hints: + # username: 'User name to sign in.' + # password: 'No special characters, please.' + diff --git a/config/locales/views/access_authorizations/de.yml b/config/locales/views/access_authorizations/de.yml new file mode 100644 index 0000000..1d38cc1 --- /dev/null +++ b/config/locales/views/access_authorizations/de.yml @@ -0,0 +1,45 @@ +de: + access_authorizations: + name: 'Zugangsberechtigung' + controller: + successfuly_created: 'Eine neue Zugangsberechtigung wurde erstellt.' + successfuly_updated: 'Die Zugangsberechtigung wurde aktualisiert.' + successfuly_destroyed: 'Die Zugangsberechtigung wurde gelöscht.' + index: + page_title: 'Zugangsberechtigungen' + name: 'Name' + login: 'Login' + pin: 'PIN' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Zugangsberechtigung löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neue Zugangsberechtigung für %{resource} anlegen' + show: + page_title: 'Zugangsberechtigung anzeigen' + name: 'Name' + login: 'Login' + pin: 'PIN' + index_phone_numbers: 'Telefonnummern' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Zugangsberechtigung löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle Zugangsberechtigungen anzeigen.' + new: + page_title: 'Neue Zugangsberechtigung anlegen' + edit: + page_title: 'Zugangsberechtigung bearbeiten' + form: + name: + label: 'Name' + hint: '' + login: + label: 'Login' + hint: '' + pin: + label: 'PIN' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/access_authorizations/en.yml b/config/locales/views/access_authorizations/en.yml new file mode 100644 index 0000000..9832e4a --- /dev/null +++ b/config/locales/views/access_authorizations/en.yml @@ -0,0 +1,48 @@ +en: + access_authorizations: + name: 'Access authorization' + controller: + successfuly_created: 'Successfully created access authorization.' + successfuly_updated: 'Successfully updated access authorization.' + successfuly_destroyed: 'Successfully destroyed access authorization.' + index: + page_title: 'Access authorizations' + name: 'Name' + login: 'Login' + pin: 'PIN' + actions: + confirm: 'Are you sure you want to delete this access authorization?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New access authorization for %{resource}' + show: + page_title: 'Show access authorization' + name: 'Name' + login: 'Login' + pin: 'PIN' + index_phone_numbers: 'Phone numbers' + actions: + confirm: 'Are you sure you want to delete this access authorization?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New access authorization' + edit: + page_title: 'Editing access authorization' + actions: + edit: 'Edit' + view_all: 'View All' + form: + name: + label: 'Name' + hint: '' + login: + label: 'Login' + hint: '' + pin: + label: 'PIN' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/acd_agents/de.yml b/config/locales/views/acd_agents/de.yml new file mode 100644 index 0000000..8613313 --- /dev/null +++ b/config/locales/views/acd_agents/de.yml @@ -0,0 +1,76 @@ +de: + acd_agents: + name: 'Agent' + controller: + successfuly_created: 'Ein neuer Agent wurde angelegt.' + successfuly_updated: 'Der Agent wurde aktualisiert.' + successfuly_destroyed: 'Der Agent wurde gelöscht.' + index: + page_title: 'Agenten' + uuid: 'UUID' + name: 'Name' + status: 'Status' + automatic_call_distributor_id: 'Warteschleifen ID' + last_call: 'Letzter Anruf' + calls_answered: 'Anrufe' + destination_type: 'Zieltyp' + destination_id: 'Ziel ID' + destination: 'Ziel' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Agenten löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neuen Agenten für %{resource} anlegen' + show: + page_title: 'Agent' + uuid: 'UUID' + name: 'Name' + status: 'Status' + automatic_call_distributor_id: 'Warteschleifen ID' + last_call: 'Letzter Anruf' + calls_answered: 'Anrufe' + destination_type: 'Zieltyp' + destination_id: 'Ziel ID' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Agenten löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + new: + page_title: 'Neuer Agent' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: + page_title: 'Agent bearbeiten' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + form: + uuid: + label: 'UUID' + hint: '' + name: + label: 'Name' + hint: '' + status: + label: 'Status' + hint: '' + automatic_call_distributor_id: + label: 'Warteschleifen ID' + hint: '' + last_call: + label: 'Letzter Anruf' + hint: '' + calls_answered: + label: 'Anrufe' + hint: '' + destination_type: + label: 'Zieltyp' + hint: '' + destination_id: + label: 'Ziel ID' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/acd_agents/en.yml b/config/locales/views/acd_agents/en.yml new file mode 100644 index 0000000..8287dd7 --- /dev/null +++ b/config/locales/views/acd_agents/en.yml @@ -0,0 +1,76 @@ +en: + acd_agents: + name: 'ACD Agent' + controller: + successfuly_created: 'Successfully created Agent.' + successfuly_updated: 'Successfully updated Agent.' + successfuly_destroyed: 'Successfully destroyed Agent.' + index: + page_title: 'Agents' + uuid: 'UUID' + name: 'Name' + status: 'Status' + automatic_call_distributor_id: 'ACD ID' + last_call: 'Last call' + calls_answered: 'Calls answered' + destination_type: 'Destination type' + destination_id: 'Destination ID' + destination: 'Destination' + actions: + confirm: 'Are you sure you want to delete this Agent?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New Agent for %{resource}' + show: + page_title: 'Show Agent' + uuid: 'UUID' + name: 'Name' + status: 'Status' + automatic_call_distributor_id: 'ACD ID' + last_call: 'Last call' + calls_answered: 'Calls answered' + destination_type: 'Destination type' + destination_id: 'Destination' + actions: + confirm: 'Are you sure you want to delete this element?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New Agent' + actions: + back_to_list: 'Back to Index' + edit: + page_title: 'Editing Agent' + actions: + back_to_list: 'Back to Index' + edit: 'Edit' + view_all: 'View All' + form: + uuid: + label: 'UUID' + hint: 'Universally unique identifier' + name: + label: 'Name' + hint: 'Entry name' + status: + label: 'Status' + hint: 'Entry status' + automatic_call_distributor_id: + label: 'ACD ID' + hint: 'ID of parent ACD' + last_call: + label: 'Last call' + hint: 'Last answered call' + calls_answered: + label: 'Calls answered' + hint: 'Number of calls' + destination_type: + label: 'Destination type' + hint: '' + destination_id: + label: 'Destination' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/acd_callers/de.yml b/config/locales/views/acd_callers/de.yml new file mode 100644 index 0000000..5195217 --- /dev/null +++ b/config/locales/views/acd_callers/de.yml @@ -0,0 +1,70 @@ +de: + acd_callers: + name: 'Vermittelte Anrufer' + controller: + successfuly_created: 'Ein neuer vermittelter Anrufer wurde angelegt.' + successfuly_updated: 'Der vermittelte Anrufer wurde aktualisiert.' + successfuly_destroyed: 'Der vermittelte Anrufer wurde gelöscht.' + index: + page_title: 'Vermittelte Anrufer auflisten' + channel_uuid: 'Kanal UUID' + automatic_call_distributor_id: 'Warteschleife' + status: 'Status' + enter_time: 'Eintrittszeit' + agent_answer_time: 'Antwortzeit Agent' + callback_number: 'Vermittelte Durchwahl' + callback_attempts: 'Vermittlungsversuche' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen vermittelten Anrufer löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neuen vermittelten Anrufer für %{resource} anlegen' + show: + page_title: 'Vermittelte Anrufer anzeigen' + channel_uuid: 'Kanal UUID' + automatic_call_distributor_id: 'Warteschleife' + status: 'Status' + enter_time: 'Eintrittszeit' + agent_answer_time: 'Antwortzeit Agent' + callback_number: 'Vermittelte Durchwahl' + callback_attempts: 'Vermittlungsversuche' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen vermittelten Anrufer löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + new: + page_title: 'Neuer vermittelter Anrufer' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: + page_title: 'Vermittelten Anrufer bearbeiten' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + form: + channel_uuid: + label: 'Kanal UUID' + hint: '' + automatic_call_distributor_id: + label: 'Warteschleife' + hint: '' + status: + label: 'Status' + hint: '' + enter_time: + label: 'Eintrittszeit' + hint: '' + agent_answer_time: + label: 'Antwortzeit Agent' + hint: '' + callback_number: + label: 'Vermittelte Durchwahl' + hint: '' + callback_attempts: + label: 'Vermittllungsversuche' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/acd_callers/en.yml b/config/locales/views/acd_callers/en.yml new file mode 100644 index 0000000..c435f3f --- /dev/null +++ b/config/locales/views/acd_callers/en.yml @@ -0,0 +1,70 @@ +en: + acd_callers: + name: 'Negotiated callers' + controller: + successfuly_created: 'Successfully created negotiated caller.' + successfuly_updated: 'Successfully updated negotiated caller.' + successfuly_destroyed: 'Successfully destroyed negotiated caller.' + index: + page_title: 'Listing negotiated callers' + channel_uuid: 'Channel UUID' + automatic_call_distributor_id: 'Automatic call distributor' + status: 'Status' + enter_time: 'Enter time' + agent_answer_time: 'Agent answer time' + callback_number: 'Callback number' + callback_attempts: 'Callback attempts' + actions: + confirm: 'Are you sure you want to delete this negotiated caller?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New negotiated callers for %{resource}' + show: + page_title: 'Show negotiated callers' + channel_uuid: 'Channel UUID' + automatic_call_distributor_id: 'Automatic call distributor' + status: 'Status' + enter_time: 'Enter time' + agent_answer_time: 'Agent answer time' + callback_number: 'Callback number' + callback_attempts: 'Callback attempts' + actions: + confirm: 'Are you sure you want to delete this negotiated caller?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New negotiated caller' + actions: + back_to_list: 'Back to Index' + edit: + page_title: 'Editing negotiated callers' + actions: + back_to_list: 'Back to Index' + edit: 'Edit' + view_all: 'View All' + form: + channel_uuid: + label: 'Channel UUID' + hint: '' + automatic_call_distributor_id: + label: 'Automatic call distributor' + hint: '' + status: + label: 'Status' + hint: '' + enter_time: + label: 'Enter time' + hint: '' + agent_answer_time: + label: 'Agent answer time' + hint: '' + callback_number: + label: 'Callback number' + hint: '' + callback_attempts: + label: 'Callback attempts' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/addresses/de.yml b/config/locales/views/addresses/de.yml new file mode 100644 index 0000000..96d280b --- /dev/null +++ b/config/locales/views/addresses/de.yml @@ -0,0 +1,72 @@ +de: + addresses: + name: 'Adresse' + controller: + successfuly_created: 'Eine neue Adresse wurde angelegt.' + successfuly_updated: 'Die Adresse wurde aktualisiert.' + successfuly_destroyed: 'Die Adresse wurde gelöscht.' + index: + page_title: 'Adressen' + phone_book_entry_id: 'Telefonbuch Eintrag' + line1: 'Zeile1' + line2: 'Zeile2' + street: 'Straße' + zip_code: 'PLZ' + city: 'Stadt' + country_id: 'Land' + position: 'Position' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Adresse löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + show: + page_title: 'Adresse bearbeiten' + phone_book_entry_id: 'Telefonbuch Eintrag' + line1: 'Zeile1' + line2: 'Zeile2' + street: 'Straße' + zip_code: 'PLZ' + city: 'Stadt' + country_id: 'Land' + position: 'Position' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Adresse löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle Adressen anzeigen' + new: + page_title: 'Neue Adresse' + actions: + edit: + page_title: 'Adresse edtieren' + actions: + edit: 'Bearbeiten' + view_all: 'Alle Adressen anzeigen' + form: + phone_book_entry_id: + label: 'Telefonbuch Eintrag' + hint: '' + line1: + label: 'Zeile1' + hint: '' + line2: + label: 'Zeile2' + hint: '' + street: + label: 'Straße' + hint: '' + zip_code: + label: 'PLZ' + hint: '' + city: + label: 'Stadt' + hint: '' + country_id: + label: 'Land' + hint: '' + position: + label: 'Position' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/addresses/en.yml b/config/locales/views/addresses/en.yml new file mode 100644 index 0000000..56550f1 --- /dev/null +++ b/config/locales/views/addresses/en.yml @@ -0,0 +1,72 @@ +en: + addresses: + name: 'Address' + controller: + successfuly_created: 'Successfully created address.' + successfuly_updated: 'Successfully updated address.' + successfuly_destroyed: 'Successfully destroyed address.' + index: + page_title: 'Addresses' + phone_book_entry_id: 'Phone book entry' + line1: 'Line1' + line2: 'Line2' + street: 'Street' + zip_code: 'Zip code' + city: 'City' + country_id: 'Country' + position: 'Position' + actions: + confirm: 'Are you sure you want to delete this address?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + show: + page_title: 'Editing Address' + phone_book_entry_id: 'Phone book entry' + line1: 'Line1' + line2: 'Line2' + street: 'Street' + zip_code: 'Zip code' + city: 'City' + country_id: 'Country' + position: 'Position' + actions: + confirm: 'Are you sure you want to delete this address?' + destroy: 'Delete address' + edit: 'Edit address' + view_all: 'View all addresses' + new: + page_title: 'New Address' + actions: + edit: + page_title: 'Editing Address' + actions: + edit: 'Edit address' + view_all: 'View all addresses' + form: + phone_book_entry_id: + label: 'Phone book entry' + hint: '' + line1: + label: 'Line1' + hint: '' + line2: + label: 'Line2' + hint: '' + street: + label: 'Street' + hint: '' + zip_code: + label: 'Zip code' + hint: '' + city: + label: 'City' + hint: '' + country_id: + label: 'Country' + hint: '' + position: + label: 'Position' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/automatic_call_distributors/de.yml b/config/locales/views/automatic_call_distributors/de.yml new file mode 100644 index 0000000..8618325 --- /dev/null +++ b/config/locales/views/automatic_call_distributors/de.yml @@ -0,0 +1,131 @@ +de: + automatic_call_distributors: + name: 'Warteschleife' + controller: + successfuly_created: 'Eine neue Warteschleife wurde angelegt.' + successfuly_updated: 'Die Warteschleife wurde aktualisiert.' + successfuly_destroyed: 'Die Warteschleife wurde gelöscht.' + index: + page_title: 'Warteschleifen' + uuid: 'UUID' + name: 'Name' + strategy: 'Strategie' + max_callers: 'Max. Anrufer' + agent_timeout: 'Agenten-Timeout' + retry_timeout: 'Wiederh.-Timeout' + join: 'Betreten' + leave: 'Verlassen' + phone_numbers: 'Telefonnummern' + acd_agents: 'Agenten' + gs_node_id: 'Knoten' + announce_position: 'Position ansagen' + announce_call_agents: 'Anruf ansagen' + greeting: 'Begrüßung' + goodbye: 'Abschied' + music: 'Musik' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Warteschleife löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neue Warteschleife für %{resource} anlegen' + show: + page_title: 'Warteschleife' + uuid: 'UUID' + name: 'Name' + strategy: 'Strategie' + max_callers: 'Max. Anrufer' + agent_timeout: 'Agenten-Timeout' + retry_timeout: 'Wiederholungs-Timeout' + join: 'Betreten' + leave: 'Verlassen' + gs_node_id: 'GS Knoten' + announce_position: 'Position ansagen' + announce_call_agents: 'Anruf ansagen' + greeting: 'Begrüßung' + goodbye: 'Abschied' + music: 'Musik' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Warteschleife löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + new: + page_title: 'Neue Warteschleife' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: + page_title: 'Warteschleife bearbeiten' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + form: + uuid: + label: 'UUID' + hint: '' + name: + label: 'Name' + hint: '' + strategy: + label: 'Strategie' + hint: '' + automatic_call_distributorable_type: + label: 'Warteschleifen-Typ' + hint: '' + automatic_call_distributorable_id: + label: 'Warteschleifen ID' + hint: '' + max_callers: + label: 'Maximale Anzahl von Anrufern' + hint: '' + agent_timeout: + label: 'Agenten-Timeout' + hint: '' + retry_timeout: + label: 'Wiederholungs-Timeout' + hint: '' + join: + label: 'Betreten' + hint: '' + leave: + label: 'Verlassen' + hint: '' + gs_node_id: + label: 'GS Knoten' + hint: '' + announce_position: + label: 'Position ansagen' + hint: '' + announce_call_agents: + label: 'Anruf ansagen' + hint: '' + greeting: + label: 'Begrüßung' + hint: '' + goodbye: + label: 'Abschied' + hint: '' + music: + label: 'Musik' + hint: '' + button: 'Absenden' + strategies: + round_robin: 'Ringverteilung' + ring_all: 'Alle' + join_on: + agents_available: 'Agenten verfügbar' + agents_active: 'Agenten aktiv' + always: 'Immer' + leave_on: + no_agents_available_timeout: 'Keine Agenten verfügbar oder Zeitüberschreitung' + no_agents_active_timeout: 'Keine Agenten aktiv oder Zeitüberschreitung' + no_agents_available: 'Keine Agenten verfügbar' + no_agents_active: 'Keine Agenten aktiv' + timeout: 'Zeitüberschreitung' + never: 'Nie' + announce_position: + never: 'Nie' + on_change_only: 'Ansage bei jeder Änderung der Position' + every_x_seconds: "Ansage alle %{x_seconds} Sekunden und nach jeder Änderung der Position" diff --git a/config/locales/views/automatic_call_distributors/en.yml b/config/locales/views/automatic_call_distributors/en.yml new file mode 100644 index 0000000..d481406 --- /dev/null +++ b/config/locales/views/automatic_call_distributors/en.yml @@ -0,0 +1,136 @@ +en: + automatic_call_distributors: + name: 'ACD' + controller: + successfuly_created: 'Successfully created ACD.' + successfuly_updated: 'Successfully updated ACD.' + successfuly_destroyed: 'Successfully destroyed ACD.' + index: + page_title: 'ACDs' + uuid: 'UUID' + name: 'Name' + strategy: 'Strategy' + automatic_call_distributorable_type: 'Automatic call distributorable type' + automatic_call_distributorable_id: 'Automatic call distributorable' + max_callers: 'Max callers' + agent_timeout: 'Agent timeout' + retry_timeout: 'Retry timeout' + join: 'Join' + leave: 'Leave' + phone_numbers: 'Phone numbers' + acd_agents: 'Agents' + gs_node_id: 'Gs node' + announce_position: 'Announce position' + announce_call_agents: 'Accounce calling' + greeting: 'Greeting' + goodbye: 'Goodbye' + music: 'Music' + actions: + confirm: 'Are you sure you want to delete this ACD?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New ACD for %{resource}' + show: + page_title: 'Show ACD' + uuid: 'UUID' + name: 'Name' + strategy: 'Strategy' + automatic_call_distributorable_type: 'Automatic call distributorable type' + automatic_call_distributorable_id: 'Automatic call distributorable' + max_callers: 'Max callers' + agent_timeout: 'Agent timeout' + retry_timeout: 'Retry timeout' + join: 'Join' + leave: 'Leave' + gs_node_id: 'Gs node' + announce_position: 'Announce position' + announce_call_agents: 'Accounce call' + greeting: 'Greeting' + goodbye: 'Goodbye' + music: 'Music' + actions: + confirm: 'Are you sure you want to delete this element?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New ACD' + actions: + back_to_list: 'Back to Index' + edit: + page_title: 'Editing ACD' + actions: + back_to_list: 'Back to Index' + edit: 'Edit' + view_all: 'View All' + form: + uuid: + label: 'UUID' + hint: '' + name: + label: 'Name' + hint: '' + strategy: + label: 'Strategy' + hint: '' + automatic_call_distributorable_type: + label: 'Automatic call distributorable type' + hint: '' + automatic_call_distributorable_id: + label: 'Automatic call distributorable' + hint: '' + max_callers: + label: 'Max callers' + hint: '' + agent_timeout: + label: 'Agent timeout' + hint: '' + retry_timeout: + label: 'Retry timeout' + hint: '' + join: + label: 'Join' + hint: '' + leave: + label: 'Leave' + hint: '' + gs_node_id: + label: 'Gs node' + hint: '' + announce_position: + label: 'Announce position' + hint: '' + announce_call_agents: + label: 'Accounce calling' + hint: '' + greeting: + label: 'Greeting' + hint: '' + goodbye: + label: 'Goodbye' + hint: '' + music: + label: 'Music' + hint: '' + button: 'Submit' + strategies: + round_robin: 'Round robin' + ring_all: 'Ring all' + join_on: + agents_available: 'Agents available' + agents_active: 'Agents active' + always: 'Always' + leave_on: + no_agents_available_timeout: 'No agents available or timeout' + no_agents_active_timeout: 'No agents active or timeout' + no_agents_available: 'No agents available' + no_agents_active: 'No agents active' + timeout: 'Timeout' + never: 'Never' + announce_position: + never: 'Never' + on_change_only: 'After a position update' + every_x_seconds: "Every %{x_seconds} seconds and after each position update" + diff --git a/config/locales/views/call_forward_cases/de.yml b/config/locales/views/call_forward_cases/de.yml new file mode 100644 index 0000000..b9d6598 --- /dev/null +++ b/config/locales/views/call_forward_cases/de.yml @@ -0,0 +1,7 @@ +de: + call_forward_cases: + always: 'immer' + busy: 'besetzt' + noanswer: 'keine Antwort' + offline: 'offline' + assistant: 'Chef-Sekretärin-Schaltung' \ No newline at end of file diff --git a/config/locales/views/call_forward_cases/en.yml b/config/locales/views/call_forward_cases/en.yml new file mode 100644 index 0000000..3a3734c --- /dev/null +++ b/config/locales/views/call_forward_cases/en.yml @@ -0,0 +1,7 @@ +en: + call_forward_cases: + always: 'always' + busy: 'busy' + noanswer: 'no answer' + offline: 'offline' + assistant: 'assistant' \ No newline at end of file diff --git a/config/locales/views/call_forwards/de.yml b/config/locales/views/call_forwards/de.yml new file mode 100644 index 0000000..1ec7af7 --- /dev/null +++ b/config/locales/views/call_forwards/de.yml @@ -0,0 +1,77 @@ +de: + call_forwards: + name: 'Rufumleitung' + controller: + successfuly_created: 'Eine neue Rufumleitung wurde erstellt.' + successfuly_updated: 'Die Rufumleitung wurde aktualisiert.' + successfuly_destroyed: 'Die Rufumleitung wurde gelöscht.' + index: + page_title: 'Rufumleitungen' + phone_number_id: 'Telefonnummer' + call_forward_case_id: 'Art der Rufumleitung' + timeout: 'Zeitüberschreitung' + destination: 'Ziel' + hunt_group: 'Rufgruppen-Verknüpfung' + to_voicemail: 'Anrufbeantworter' + source: 'Quelle' + depth: 'Weiterleitungs-Sprünge' + active: 'Aktiv' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Rufumleitung löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neue Rufumleitung für die %{resource} anlegen' + show: + page_title: 'Rufumleitung anzeigen' + phone_number_id: 'Telefonnummer' + call_forward_case_id: 'Art der Rufumleitung' + timeout: 'Zeitüberschreitung' + destination: 'Ziel' + hunt_group: 'Rufgruppen-Verknüpfung' + to_voicemail: 'Anrufbeantworter' + source: 'Quelle' + depth: 'Weiterleitungs-Sprünge' + active: 'Aktiv' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Rufumleitung löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle Rufumleitung anzeigen' + new: + page_title: 'Neue Rufumleitung anlegen' + edit: + page_title: 'Rufumleitung bearbeiten' + form: + phone_number_id: + label: 'Telefonnummer' + hint: '' + call_forward_case_id: + label: 'Art der Rufumleitung' + hint: '' + timeout: + label: 'Zeitüberschreitung in Sekunden' + hint: 'Nur für "nicht antworten" benötigt.' + destination: + label: 'Ziel Telefonnummer' + hint: 'Format: +49-30-2270 für eine normale Telefonnummer. 42 für eine interne Durchwahl.' + call_forwarding_destination: + label: 'Zielauswahl' + hint: 'Ziel auswählen oder Rufnummer unten eingeben.' + hunt_group: + label: 'Rufgruppen-Verknüpfung' + hint: 'Die hier ausgewählt Rufgruppe schaltet automatisch diese Weiterleitung an und aus.' + to_voicemail: + label: 'Weiterleitung zum Anrufbeantworter' + hint: 'Kann nicht zusammen mit einer Ziel Telefonnummer aktiert werden.' + source: + label: 'Quelle' + hint: "Für welche Anrufer Telefonnummern soll diese Rufumleitung aktiv sein? Wenn kein Eintrag, dann für alle." + depth: + label: 'Weiterleitungs-Sprünge' + hint: "Die maximale Anzahl von Rufumleitungssprüngen. 1 bedeutet, das der Anruf nur bis zum nächsten Ziel weitergeleitet wird." + active: + label: 'Aktiv' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/call_forwards/en.yml b/config/locales/views/call_forwards/en.yml new file mode 100644 index 0000000..4b9af7d --- /dev/null +++ b/config/locales/views/call_forwards/en.yml @@ -0,0 +1,77 @@ +en: + call_forwards: + name: 'Call forward' + controller: + successfuly_created: 'Successfully created call forward.' + successfuly_updated: 'Successfully updated call forward.' + successfuly_destroyed: 'Successfully destroyed call forward.' + index: + page_title: 'Call forwards' + phone_number_id: 'Phone number' + call_forward_case_id: 'Call forward case' + timeout: 'Timeout' + destination: 'Destination' + to_voicemail: 'Voicemail' + source: 'Source' + depth: 'Hops' + active: 'Active' + hunt_group: 'Hunt group connection' + actions: + confirm: 'Are you sure you want to delete this call forward?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New call forward for phone number %{resource}' + show: + page_title: 'Show call forward' + phone_number_id: 'Phone number' + call_forward_case_id: 'Call forward case' + timeout: 'Timeout' + destination: 'Destination' + hunt_group: 'Hunt group connection' + to_voicemail: 'Voicemail' + source: 'Source' + depth: 'Hops' + active: 'Active' + actions: + confirm: 'Are you sure you want to delete this call forward?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View all call forwards' + new: + page_title: 'New call forward' + edit: + page_title: 'Editing call forward' + form: + phone_number_id: + label: 'Phone number' + hint: '' + call_forward_case_id: + label: 'Call forward case' + hint: '' + timeout: + label: 'Timeout in seconds' + hint: 'Just needed for the "noanswer" case.' + destination: + label: 'Destination phone number' + hint: 'Format: +49-30-2270 for a normal phone number or 42 for an internal extension.' + call_forwarding_destination: + label: 'Destination Type' + hint: 'Select destination or enter phone number below' + hunt_group: + label: 'Hunt group connection' + hint: 'This hunt group auto activates this call forward.' + to_voicemail: + label: 'Forward to voicemail' + hint: 'Can not be activated together with a destination number.' + source: + label: 'Source' + hint: "The caller's ID for which this call forward should be valid. Leave empty for calls from any number." + depth: + label: 'Hops' + hint: "The maximum number of hops you want to permit. 1 means calls won't be forwarded beyond the next destination." + active: + label: 'Active' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/call_histories/de.yml b/config/locales/views/call_histories/de.yml new file mode 100644 index 0000000..3f0459d --- /dev/null +++ b/config/locales/views/call_histories/de.yml @@ -0,0 +1,66 @@ +de: + call_histories: + name: 'Anrufliste' + controller: + successfuly_created: 'Ein neuer Eintrag wurde erstellt.' + successfuly_updated: 'Der Eintrag wurde aktualisiert.' + successfuly_destroyed: 'Der Eintrag wurde gelöscht.' + index: + page_title: 'Anrufliste' + page_title_missed: 'Verpasste Anrufe' + page_title_dialed: 'Gewählte Anrufe' + page_title_received: 'Empfangene Anrufe' + page_title_forwarded: 'Weitergeleitete Anrufe' + count: 'Anzahl der Anruflisteeinträge' + missed: 'Verpasst' + dialed: 'Gewählt' + received: 'Empfangen' + forwarded: 'Weitergeleitet' + all: 'Alle' + date_format: '%d.%m.%Y %H:%M' + date_today_format: '%H:%M' + forwarded_by: 'via' + navigation: + missed: 'Verpasst: %{calls}' + dialed: 'Gewählt: %{calls}' + received: 'Empfangen: %{calls}' + forwarded: 'Weitergeleitet: %{calls}' + all: 'Alle: %{calls}' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Eintrag löschen möchten?' + confirm_selected: 'Sind Sie sicher, dass Sie die markierten Einträge löschen möchten?' + destroy: 'Löschen' + destroy_multiple: 'Markierte Einträge löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neuen Eintrag für %{resource} anlegen' + call: 'Anrufen' + show: + page_title: 'Eintrag anzeigen' + name: 'Name' + description: 'Beschreibung' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Eintrag löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Anrufliste anzeigen' + new: + page_title: 'Neuer Eintrag' + edit: + page_title: 'Anrufliste "%{resource}" bearbeiten' + form: + name: + label: 'Name' + hint: '' + description: + label: 'Beschreibung' + hint: '' + button: 'Absenden' + call_results: + UNSPECIFIED: '' + ORIGINATOR_CANCEL: 'Abgebrochen' + UNALLOCATED_NUMBER: 'Rufnummer nicht bekannt' + NO_USER_RESPONSE: 'Keine Antwort' + NOANSWER: 'Keine Antwort' + USER_NOT_REGISTERED: 'Offline' diff --git a/config/locales/views/call_histories/en.yml b/config/locales/views/call_histories/en.yml new file mode 100644 index 0000000..5adf453 --- /dev/null +++ b/config/locales/views/call_histories/en.yml @@ -0,0 +1,67 @@ +en: + call_histories: + name: 'Call History' + controller: + successfuly_created: 'Successfully created call log entry.' + successfuly_updated: 'Successfully updated call log entry.' + successfuly_destroyed: 'Successfully destroyed call log entry.' + index: + page_title: 'Call History' + page_title_missed: 'Missed calls' + page_title_dialed: 'Placed calls' + page_title_received: 'Received calls' + page_title_forwarded: 'Forwarded calls' + count: 'Number of entries' + missed: 'Missed' + dialed: 'Placed' + received: 'Received' + forwarded: 'Forwarded' + all: 'All' + date_format: '%m/%d/%Y %H:%M' + date_today_format: '%H:%M' + forwarded_by: 'via' + navigation: + missed: 'Missed:%{calls}' + dialed: 'Placed:%{calls}' + received: 'Received:%{calls}' + forwarded: 'Forwarded:%{calls}' + all: 'All:%{calls}' + actions: + confirm: 'Are you sure you want to delete this call log entry?' + confirm_selected: 'Are you sure you want to delete all selected entries?' + destroy: 'Delete' + destroy_multiple: 'Delete selected entries' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New call log entry for %{resource}' + call: 'Call' + show: + page_title: 'Call History' + name: 'Name' + description: 'Description' + actions: + confirm: 'Are you sure you want to delete this call log entry?' + destroy: 'Delete call log entry' + edit: 'Edit call log entry' + view_all: 'View all call log entries' + new: + page_title: 'New call log entry' + edit: + page_title: 'Editing call log "%{resource}"' + form: + name: + label: 'Name' + hint: '' + description: + label: 'Description' + hint: '' + button: 'Submit' + call_results: + UNSPECIFIED: '' + ORIGINATOR_CANCEL: 'Cancelled' + UNALLOCATED_NUMBER: 'Unallocated number' + NO_USER_RESPONSE: 'No user response' + NOANSWER: 'No answer' + USER_NOT_REGISTERED: 'Offline' + \ No newline at end of file diff --git a/config/locales/views/callthroughs/de.yml b/config/locales/views/callthroughs/de.yml new file mode 100644 index 0000000..c884ffa --- /dev/null +++ b/config/locales/views/callthroughs/de.yml @@ -0,0 +1,58 @@ +de: + callthroughs: + none: 'keiner' + name: 'Callthrough' + controller: + successfuly_created: 'Ein neuer Callthrough wurde erstellt.' + successfuly_updated: 'Der Callthrough wurde aktualisiert.' + successfuly_destroyed: 'Der Callthrough wurde gelöscht.' + index: + page_title: 'Callthrough' + name: 'Name' + sip_account_id: 'SIP-Konto' + phone_numbers: 'Telefonnummern' + access_authorized_phone_numbers: 'Zugelassene Telefonnummern' + whitelist_phone_numbers: 'Positivliste für Zielrufnummern' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Callthrough löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neuen Callthrough für %{resource} anlegen' + show: + page_title: 'Callthrough anzeigen' + name: 'Name' + sip_account_id: 'SIP-Konto' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Callthrough löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle Callthrough anzeigen' + new: + page_title: 'Neuen Callthrough anlegen' + edit: + page_title: 'Callthrough bearbeiten' + actions: + edit: 'Bearbeiten' + view_all: 'Alle Callthrough anzeigen' + form: + phone_numbers: + label: 'Telefonnummern' + hint: 'Unter diesen Telefonnummern ist dieser Callthrough erreichbar.' + access_authorizations: + label: 'Zugangsberechtigungen' + hint: 'Definiert, welche Telefonnummern bzw. Login/PIN Kombinationen diesen Callthrough benuzten dürfen.' + whitelists: + label: 'Positivliste für Zielrufnummern' + hint: "Wenn hier Zielrufnummern gesetzt sind, können nur diese Ziele angerufen werden." + name: + label: 'Name' + hint: '' + sip_account: + label: 'SIP-Konto' + hint: 'Wenn angegeben, werden alle Anrufe dieses Callthrough mit diesem SIP-Konto durchgeführt.' + sip_account_id: + label: 'SIP-Konto ID' + hint: 'Die SIP-Konto ID finden Sie in der URL des entsprechenden SIP-Kontos.' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/callthroughs/en.yml b/config/locales/views/callthroughs/en.yml new file mode 100644 index 0000000..648fb93 --- /dev/null +++ b/config/locales/views/callthroughs/en.yml @@ -0,0 +1,58 @@ +en: + callthroughs: + none: 'none' + name: 'Callthrough' + controller: + successfuly_created: 'Successfully created callthrough.' + successfuly_updated: 'Successfully updated callthrough.' + successfuly_destroyed: 'Successfully destroyed callthrough.' + index: + page_title: 'Callthroughs' + name: 'Name' + sip_account_id: 'SIP account' + phone_numbers: 'Phone numbers' + access_authorized_phone_numbers: 'Authorized phone numbers' + whitelist_phone_numbers: 'Whitelisted destinations' + actions: + confirm: 'Are you sure you want to delete this callthrough?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New callthrough for %{resource}' + show: + page_title: 'Show callthrough' + name: 'Name' + sip_account_id: 'SIP account' + actions: + confirm: 'Are you sure you want to delete this callthrough?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New callthrough' + edit: + page_title: 'Editing callthrough' + actions: + edit: 'Edit' + view_all: 'View All' + form: + phone_numbers: + label: 'Phone numbers' + hint: 'Use these phone numbers to access the callthrough.' + access_authorizations: + label: 'Access authorizations' + hint: 'Define what phone numbers and/or login/pin combinations can use this callthrough.' + whitelists: + label: 'Whitelists for possible destinations' + hint: "When set only these phone numbers can be called with this callthrough. It is optional. If you don't create a whitelist a user of this callthrough can call any phone number with it." + name: + label: 'Name' + hint: '' + sip_account: + label: 'SIP account' + hint: 'When chosen all callthroughs will be routed through this SIP account.' + sip_account_id: + label: 'SIP account ID' + hint: 'Please look up the SIP account ID in the URL of the SIP account.' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/conference_invitees/de.yml b/config/locales/views/conference_invitees/de.yml new file mode 100644 index 0000000..915bc5c --- /dev/null +++ b/config/locales/views/conference_invitees/de.yml @@ -0,0 +1,55 @@ +de: + conference_invitees: + name: 'Telefonkonferenz Teilnehmer' + controller: + successfuly_created: 'Ein Teilnehmer wurde der Telefonkonferenz hinzugefügt.' + successfuly_updated: 'Der Teilnehmer wurde aktualisiert.' + successfuly_destroyed: 'Der Teilnehmer wurde aus der Telefonkonferenz entfernt.' + index: + page_title: 'Telefonkonferenz Teilnehmer' + conference_id: 'Telefonkonferenz' + phone_book_entry_id: 'Telefonbucheintrag' + pin: 'PIN' + speaker: 'Sprecher-Freischaltung' + moderator: 'Moderator' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Teilnehmer aus der Telefonkonferenz entfernen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neuen Teilnehmer für die Telefonkonferenz %{resource} hinzufügen' + show: + page_title: 'Teilnehmer anzeigen' + conference_id: 'Telefonkonferenz' + phone_book_entry_id: 'Telefonbucheintrag' + pin: 'PIN' + speaker: 'Sprecher-Freischaltung' + moderator: 'Moderator' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Teilnehmer aus der Telefonkonferenz entfernen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle Telefonkonferenz Teilnehmer anzeigen' + new: + page_title: 'Neuen Teilnehmer hinzufügen' + actions: + edit: + page_title: 'Teilnehmer bearbeiten' + form: + conference_id: + label: 'Telefonkonferenz' + hint: '' + phone_book_entry_id: + label: 'Telefonbucheintrag' + hint: '' + pin: + label: 'PIN' + hint: '' + speaker: + label: 'Sprecher-Freischaltung' + hint: '' + moderator: + label: 'Moderator' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/conference_invitees/en.yml b/config/locales/views/conference_invitees/en.yml new file mode 100644 index 0000000..7e1a1ca --- /dev/null +++ b/config/locales/views/conference_invitees/en.yml @@ -0,0 +1,54 @@ +en: + conference_invitees: + name: 'Conference invitee' + controller: + successfuly_created: 'Successfully created conference invitee.' + successfuly_updated: 'Successfully updated conference invitee.' + successfuly_destroyed: 'Successfully destroyed conference invitee.' + index: + page_title: 'Conference invitees' + conference_id: 'Conference' + phone_book_entry_id: 'Phone book entry' + pin: 'PIN' + speaker: 'Speaker' + moderator: 'Moderator' + actions: + confirm: 'Are you sure you want to delete this invitee?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New conference invitee for %{resource}' + show: + page_title: 'Show conference invitee' + conference_id: 'Conference' + phone_book_entry_id: 'Phone book entry' + pin: 'PIN' + speaker: 'Speaker' + moderator: 'Moderator' + actions: + confirm: 'Are you sure you want to delete this invitee?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View all conference invitees' + new: + page_title: 'New conference invitee' + edit: + page_title: 'Editing Conference invitee' + form: + conference_id: + label: 'Conference' + hint: '' + phone_book_entry_id: + label: 'Phone book entry' + hint: '' + pin: + label: 'PIN' + hint: '' + speaker: + label: 'Speaker' + hint: '' + moderator: + label: 'Moderator' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/conferences/de.yml b/config/locales/views/conferences/de.yml new file mode 100644 index 0000000..cf3c080 --- /dev/null +++ b/config/locales/views/conferences/de.yml @@ -0,0 +1,81 @@ +de: + conferences: + name: 'Telefonkonferenz' + new_name_scaffold: 'Telefonkonferenz Nr. %{counter}' + controller: + successfuly_created: 'Eine neue Telefonkonferenz wurde erstellt.' + successfuly_updated: 'Die Telefonkonferenz wurde aktualisiert.' + successfuly_destroyed: 'Die Telefonkonferenz wurde gelöscht.' + index: + page_title: 'Telefonkonferenzen' + name: 'Name' + start: 'Start' + end: 'Ende' + description: 'Beschreibung' + phone_numbers: 'Telefonnummern' + pin: 'PIN' + max_members: 'Maximale Teilnehmeranzahl' + number_of_invitees: 'Teilnehmeranzahl' + flags: 'Flags' + open_for_anybody: 'Offen für alle' + announce_new_member_by_name: 'Betreten ankündigen' + announce_left_member_by_name: 'Verlassen ankündigen' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Telefonkonferenz löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neue Telefonkonferenz für %{resource} anlegen' + show: + page_title: 'Telefonkonferenz anzeigen' + name: 'Name' + start: 'Start' + end: 'Ende' + description: 'Beschreibung' + pin: 'PIN' + max_members: 'Maximale Teilnehmeranzahl' + open_for_anybody: 'Für jeden offen?' + announce_new_member_by_name: 'Neue Teilnehmer werden angekündigt' + announce_left_member_by_name: 'Die Konferenz verlassende Teilnehmer werden angekündigt' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Telefonkonferenz löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle Telefonkonferenzen anzeigen' + view_all_of: 'Alle Telefonkonferenzen von %{resource} anzeigen' + new: + page_title: 'Neue Telefonkonferenz' + name: "Telefonkonferenz von %{resource}" + actions: + edit: + page_title: 'Telefonkonferenz bearbeiten' + form: + name: + label: 'Name' + hint: '' + start: + label: 'Start' + hint: 'Bitte eine Start-Zeit eintragen, falls diese Telefonkonferenz zeitlich begrenzt ist.' + end: + label: 'Ende' + hint: 'Bitte eine Ende-Zeit eintragen, falls diese Telefonkonferenz zeitlich begrenzt ist.' + description: + label: 'Beschreibung' + hint: '' + max_members: + label: 'Maximale Teilnehmeranzahl' + hint: 'Die maximale Anzahl von Teilnehmern in dieser Telefonkonferenz. Der Inhaber der Konferenz kann immer eintreten (auch wenn die Konferenz bereits voll ist).' + pin: + label: 'PIN' + hint: '' + open_for_anybody: + label: 'Für jeden offen?' + hint: 'Jeder kann an dieser Konferenz teilnehmen.' + announce_new_member_by_name: + label: 'Neue Teilnehmer werden angekündigt' + hint: 'Ein neuer Teilnehmer wird bei Eintritt in die Konferenz vorgestellt.' + announce_left_member_by_name: + label: 'Die Konferenz verlassende Teilnehmer werden angekündigt' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/conferences/en.yml b/config/locales/views/conferences/en.yml new file mode 100644 index 0000000..7967123 --- /dev/null +++ b/config/locales/views/conferences/en.yml @@ -0,0 +1,81 @@ +en: + conferences: + name: 'Conference' + new_name_scaffold: 'Conference #%{counter}' + controller: + successfuly_created: 'Successfully created the conference.' + successfuly_updated: 'Successfully updated the conference.' + successfuly_destroyed: 'Successfully destroyed the conference.' + index: + page_title: 'Conferences' + name: 'Name' + start: 'Start' + end: 'End' + description: 'Description' + phone_numbers: 'Phone numbers' + pin: 'PIN' + max_members: 'Max members' + number_of_invitees: 'Number of invitees' + flags: 'Flags' + open_for_anybody: 'Open for anybody' + announce_new_member_by_name: 'Announce entering' + announce_left_member_by_name: 'Announce leaving' + actions: + confirm: 'Are you sure you want to delete this conference?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New conference for %{resource}' + show: + page_title: 'Show conference' + name: 'Name' + start: 'Start' + end: 'End' + description: 'Description' + pin: 'PIN' + max_members: 'Max members' + open_for_anybody: 'Open for anybody' + announce_new_member_by_name: 'Announce new member' + announce_left_member_by_name: 'Announce left member' + actions: + confirm: 'Are you sure you want to delete this conference?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View all conferences' + view_all_of: 'View all conferences of %{resource}' + new: + page_title: 'New conference' + name: "%{resource}'s conference" + actions: + edit: + page_title: 'Editing conference' + form: + name: + label: 'Name' + hint: '' + start: + label: 'Start' + hint: 'Please enter a start time if this conference is only valid in a special time window.' + end: + label: 'End' + hint: 'Please enter an end time if this conference is only valid in a special time window.' + description: + label: 'Description' + hint: '' + max_members: + label: 'Max members' + hint: 'The maximum number of people in this conference. The owner of a conference can always enter the conference (even a full one).' + pin: + label: 'PIN' + hint: '' + open_for_anybody: + label: 'Open for anybody' + hint: '' + announce_new_member_by_name: + label: 'Announce a new conference member' + hint: 'A new member has to record his name which played before joining the conference.' + announce_left_member_by_name: + label: 'Announce the leaving of a member' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/fax_accounts/de.yml b/config/locales/views/fax_accounts/de.yml new file mode 100644 index 0000000..5977bb3 --- /dev/null +++ b/config/locales/views/fax_accounts/de.yml @@ -0,0 +1,60 @@ +de: + fax_accounts: + name: 'Software-Fax-Konto' + controller: + successfuly_created: 'Eine neues Software-Fax-Konto wurde erstellt.' + successfuly_updated: 'Das Software-Fax-Konto wurde aktualisiert.' + successfuly_destroyed: 'Das Software-Fax-Konto wurde gelöscht.' + index: + page_title: 'Software-Fax-Konten' + name: 'Name' + station_id: 'Stations-ID' + email: 'E-Mail' + phone_numbers: 'Telefonnummern' + days_till_auto_delete: 'Anzahl der Tage bis Faxe gelöscht werden' + thumbnails: 'Vorschaubilder' + received: 'Empfangen' + sent: 'Gesendet' + retries: 'Max. Anzahl von Sendeversuchen' + last_update: 'Letzter Eintrag' + send_a_fax: 'Fax versenden' + actions: + confirm: 'Sind Sie sicher, dass Sie dieses Software-Fax-Konto löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neues Fax-Konto für %{resource} anlegen' + show: + page_title: 'Software-Fax-Konto anzeigen' + name: 'Name' + station_id: 'Stations-ID' + email: 'E-Mail' + days_till_auto_delete: 'Anzahl der Tage bis Faxe gelöscht werden' + retries: 'Max. Anzahl von Sendeversuchen' + actions: + confirm: 'Sind Sie sicher, dass Sie dieses Software-Fax-Konto löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + new: + page_title: 'Neues Software-Fax-Konto' + edit: + page_title: 'Software-Fax-Konto bearbeiten' + form: + name: + label: 'Name' + hint: '' + station_id: + label: 'Stations-ID' + hint: 'Die "Stations-ID" wird in der Kopfzeile eines Faxes als Absender angezeigt.' + email: + label: 'E-Mail' + hint: 'Ein PDF eines empfangenen Faxes wird an diese E-Mail Adresse verschickt.' + days_till_auto_delete: + label: 'Anzahl der Tage bis Faxe gelöscht werden' + hint: '' + retries: + label: 'Max. Anzahl von Sendeversuchen' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/fax_accounts/en.yml b/config/locales/views/fax_accounts/en.yml new file mode 100644 index 0000000..55e935a --- /dev/null +++ b/config/locales/views/fax_accounts/en.yml @@ -0,0 +1,60 @@ +en: + fax_accounts: + name: 'Fax account' + controller: + successfuly_created: 'Successfully created fax account.' + successfuly_updated: 'Successfully updated fax account.' + successfuly_destroyed: 'Successfully destroyed fax account.' + index: + page_title: 'Fax accounts' + name: 'Name' + station_id: 'Station ID' + email: 'E-Mail' + phone_numbers: 'Phone numbers' + days_till_auto_delete: 'Day till auto delete' + thumbnails: 'Thumbnails' + received: 'Received' + sent: 'Sent' + retries: 'Retries' + last_update: 'last update' + send_a_fax: 'send a fax' + actions: + confirm: 'Are you sure you want to delete this fax account?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New fax account for %{resource}' + show: + page_title: 'Show fax account' + name: 'Name' + station_id: 'Station ID' + email: 'E-Mail' + days_till_auto_delete: 'Day till auto delete' + retries: 'Retries' + actions: + confirm: 'Are you sure you want to delete this fax account?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New fax account' + edit: + page_title: 'Editing fax account' + form: + name: + label: 'Name' + hint: '' + station_id: + label: 'Station ID' + hint: 'This string will be displayed in the top row of a fax before the fax number.' + email: + label: 'E-Mail' + hint: 'A PDF of each received fax will be send by e-mail to this address.' + days_till_auto_delete: + label: 'Days till auto delete' + hint: 'Number of days after faxes can be automaticaly deleted in the system to save storage space.' + retries: + label: 'Retries' + hint: 'Number of times the system retries to send the fax in case the destination is busy.' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/fax_documents/de.yml b/config/locales/views/fax_documents/de.yml new file mode 100644 index 0000000..066746d --- /dev/null +++ b/config/locales/views/fax_documents/de.yml @@ -0,0 +1,148 @@ +de: + fax_documents: + name: 'Fax-Dokument' + controller: + successfuly_created: 'Eine neues Fax-Dokument wurde erstellt.' + successfuly_updated: 'Das Fax-Dokument wurde aktualisiert.' + successfuly_destroyed: 'Das Fax-Dokument wurde gelöscht.' + states: + queued_for_sending: 'In der Warteschleife zum Versand' + sending: 'Wird aktuell versendet' + unsuccessful: 'Nicht erfolgreich' + successful: 'Erfolgreich' + inbound: 'Eingehendes Fax' + result_codes: + code_0: 'OK' + code_2: 'Timeout beim Warten auf den Beginn der Kommunikation' + code_3: 'Timeout beim Warten auf die erste Nachricht' + code_5: 'Der HDLC Träger wurde nicht rechtzeitig beendet' + code_6: 'Training mit allen kompatiblen Modems fehlgeschlagen' + code_13: 'Unerwartete Nachricht erhalten' + code_14: 'Fehlerhafte Antwort auf DCS oder Training' + code_15: 'DCN von der Gegenstelle empfangen nachdem eine Seite gesendet wurde' + code_17: 'DCN empfangen während DIS erwartet wurde' + code_20: 'Keine Antwort auf DCS oder TCF empfangen' + code_23: 'Fehlerhafte ECM Antwort vom Sender empfangen' + code_31: 'Timer T2 abgelaufen während auf die Seite gewartet wurde' + code_32: 'Timer T2 abgelaufen während auf die nächse Seite gewartet wurde' + code_48: 'Nach zu vielen Fehlversuchen beendet' + code_49: 'Anruf vorzeitig beendet' + index: + page_title: 'Fax-Dokumente' + inbound: 'Eingehend' + state: 'Status' + transmission_time: 'Übertragungszeit' + sent_at: 'Sendezeit' + document_total_pages: 'Seitenanzahl' + document_transferred_pages: 'Übertragene Seiten' + ecm_requested: 'Fehlerkorrektur (ECM) angefragt' + ecm_used: 'Fehlerkorrektur (ECM) verwendet' + image_resolution: 'Bildauflösung' + image_size: 'Bildgröße' + local_station_id: 'Lokale Gegenstelle' + result_code: 'Ergebnis-Code' + result_text: 'Ergebnis-Text' + remote_station_id: 'Stations-ID der Gegenstelle' + success: 'Erfolgreich' + transfer_rate: 'Transferrate' + fax_resolution: 'Fax Auflösung' + document: 'Dokument' + destination_phone_number: 'Ziel Fax-Nummer' + actions: + confirm: 'Sind Sie sicher, dass Sie dieses Fax-Dokument löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neues Fax-Dokument' + download_pdf: 'PDF herunterladen' + show: + page_title: 'Fax-Dokument anzeigen' + inbound: 'Eingehend' + state: 'Status' + transmission_time: 'Übertragungszeit' + sent_at: 'Sendezeit' + document_total_pages: 'Seitenanzahl' + document_transferred_pages: 'Übertragende Seiten' + ecm_requested: 'Fehlerkorrektur (ECM) angefragt' + ecm_used: 'Fehlerkorrektur (ECM) verwendet' + image_resolution: 'Bildauflösung' + image_size: 'Bildgröße' + local_station_id: 'Lokale Gegenstelle' + result_code: 'Ergebnis-Code' + result_text: 'Ergebnis-Text' + remote_station_id: 'Stations-ID der Gegenstelle' + success: 'Erfolgreich' + transfer_rate: 'Transferrate' + document: 'Dokument' + fax_resolution: 'Fax Auflösung' + destination_phone_number: 'Ziel Fax-Nummer' + actions: + confirm: 'Sind Sie sicher, dass Sie dieses Fax-Dokument löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + view_all_for: 'Alle Fax-Dokumente von %{resource} anzeigen' + new: + page_title: 'Neues Fax-Dokument' + edit: + page_title: 'Fax-Dokument bearbeiten' + form: + inbound: + label: 'Eingehend' + hint: '' + state: + label: 'Status' + hint: '' + transmission_time: + label: 'Übertragungszeit' + hint: '' + sent_at: + label: 'Sendezeit' + hint: '' + document_total_pages: + label: 'Seitenanzahl' + hint: '' + document_transferred_pages: + label: 'Übertragene Seiten' + hint: '' + ecm_requested: + label: 'Fehlerkorrektur (ECM) angefragt' + hint: '' + ecm_used: + label: 'Fehlerkorrektur (ECM) verwendet' + hint: '' + image_resolution: + label: 'Bildauflösung' + hint: '' + image_size: + label: 'Bildgröße' + hint: '' + local_station_id: + label: 'Lokale Gegenstelle' + hint: '' + result_code: + label: 'Ergebnis-Code' + hint: '' + result_text: + label: 'Ergebnis-Text' + hint: '' + remote_station_id: + label: 'Stations-ID der Gegenstelle' + hint: '' + success: + label: 'Erfolgreich' + hint: '' + transfer_rate: + label: 'Transferrate' + hint: '' + document: + label: 'Dokument' + hint: '' + fax_resolution: + label: 'Fax Auflösung' + hint: '' + destination_phone_number: + label: 'Ziel Fax-Nummer' + hint: '' + button: 'Absenden' + diff --git a/config/locales/views/fax_documents/en.yml b/config/locales/views/fax_documents/en.yml new file mode 100644 index 0000000..bedb2e6 --- /dev/null +++ b/config/locales/views/fax_documents/en.yml @@ -0,0 +1,148 @@ +en: + fax_documents: + name: 'Fax' + controller: + successfuly_created: 'Successfully created fax.' + successfuly_updated: 'Successfully updated fax.' + successfuly_destroyed: 'Successfully destroyed fax.' + states: + queued_for_sending: 'Queued for sending' + sending: 'Currently sending' + unsuccessful: 'Unsuccessful' + successful: 'Successful' + inbound: 'Inbound' + result_codes: + code_0: 'OK' + code_2: 'Timed out waiting for initial communication' + code_3: 'Timed out waiting for the first message' + code_5: 'The HDLC carrier did not stop in a timely manner' + code_6: 'Failed to train with any of the compatible modems' + code_13: 'Unexpected message received' + code_14: 'Received bad response to DCS or training' + code_15: 'Received a DCN from remote after sending a page' + code_17: 'Received a DCN while waiting for a DIS' + code_20: 'Received no response to DCS or TCF' + code_23: 'Invalid ECM response received from transmitter' + code_31: 'Timer T2 expired while waiting for fax page' + code_32: 'Timer T2 expired while waiting for next fax page' + code_48: 'Disconnected after permitted retries' + code_49: 'The call dropped prematurely' + index: + page_title: 'Faxes' + inbound: 'Inbound' + state: 'State' + transmission_time: 'Transmission time' + sent_at: 'Sent at' + document_total_pages: 'Document total pages' + document_transferred_pages: 'Document transferred pages' + ecm_requested: 'ECM requested' + ecm_used: 'ECM used' + image_resolution: 'Image resolution' + image_size: 'Image size' + local_station_id: 'Local station' + result_code: 'Result code' + result_text: 'Result text' + remote_station_id: 'Remote station ID' + success: 'Success' + transfer_rate: 'Transfer rate' + fax_resolution: 'Resolution' + document: 'Document' + destination_phone_number: 'Destination phone number' + actions: + confirm: 'Are you sure you want to delete this fax?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New fax document' + download_pdf: 'Download PDF' + show: + page_title: 'Show Fax' + inbound: 'Inbound' + state: 'State' + transmission_time: 'Transmission time' + sent_at: 'Sent at' + document_total_pages: 'Document total pages' + document_transferred_pages: 'Document transferred pages' + ecm_requested: 'ECM requested' + ecm_used: 'ECM used' + image_resolution: 'Image resolution' + image_size: 'Image size' + local_station_id: 'Local station' + result_code: 'Result code' + result_text: 'Result text' + remote_station_id: 'Remote station ID' + success: 'Success' + transfer_rate: 'Transfer rate' + document: 'Document' + fax_resolution: 'Resolution' + destination_phone_number: 'Destination phone number' + actions: + confirm: 'Are you sure you want to delete this fax?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View all' + view_all_for: 'View all faxes of %{resource}' + new: + page_title: 'New Fax' + edit: + page_title: 'Editing Fax' + form: + inbound: + label: 'Inbound' + hint: '' + state: + label: 'State' + hint: '' + transmission_time: + label: 'Transmission time' + hint: '' + sent_at: + label: 'Sent at' + hint: '' + document_total_pages: + label: 'Document total pages' + hint: '' + document_transferred_pages: + label: 'Document transferred pages' + hint: '' + ecm_requested: + label: 'ECM requested' + hint: '' + ecm_used: + label: 'ECM used' + hint: '' + image_resolution: + label: 'Image resolution' + hint: '' + image_size: + label: 'Image size' + hint: '' + local_station_id: + label: 'Local station' + hint: '' + result_code: + label: 'Result code' + hint: '' + result_text: + label: 'Result text' + hint: '' + remote_station_id: + label: 'Remote station ID' + hint: '' + success: + label: 'Success' + hint: '' + transfer_rate: + label: 'Transfer rate' + hint: '' + document: + label: 'Document' + hint: '' + fax_resolution: + label: 'Resolution' + hint: '' + destination_phone_number: + label: 'Destination phone number' + hint: '' + button: 'Submit' + diff --git a/config/locales/views/gemeinschaft_setups/de.yml b/config/locales/views/gemeinschaft_setups/de.yml new file mode 100644 index 0000000..a1dd989 --- /dev/null +++ b/config/locales/views/gemeinschaft_setups/de.yml @@ -0,0 +1,28 @@ +de: + gemeinschaft_setups: + name: 'Gemeinschaft Installations-Assistent' + initial_setup: + tenant_name_default: 'Beispiel-Firma GmbH' + access_denied_only_available_on_a_new_system: 'Zugriff verweigert! Der Installations-Assistent ist nur auf einem frisch installierten System verfügbar.' + successful_setup: 'Ihr Admin-Konto wurde erstellt. Als nächsten Schritt müssen Sie einen Mandant anlegen.' + admin_name: 'admin' + super_tenant_description: 'Die Benutzer dieses Mandanten haben besondere Rechte. Sie können andere Mandanten anlegen und löschen.' + admin_group_name: 'Admins' + user_group_name: 'Benutzer' + super_admin_group_name: 'Super-Admins' + new: + page_title: 'Gemeinschaft Setup' + form: + user_id: + label: 'Benutzer' + hint: '' + sip_domain_id: + label: 'SIP-Domain' + hint: '' + country_id: + label: 'Land' + hint: '' + language_id: + label: 'Sprache' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/gemeinschaft_setups/en.yml b/config/locales/views/gemeinschaft_setups/en.yml new file mode 100644 index 0000000..aef2686 --- /dev/null +++ b/config/locales/views/gemeinschaft_setups/en.yml @@ -0,0 +1,28 @@ +en: + gemeinschaft_setups: + name: 'Gemeinschaft Setup Wizard' + initial_setup: + tenant_name_default: 'Snake Oil, Ltd.' + access_denied_only_available_on_a_new_system: 'Access denied! The setup wizard is only available on a new system.' + successful_setup: 'Your admin account has been created. The next step is to create a tenant.' + admin_name: 'admin' + super_tenant_description: 'The members of this tenant have the power to create and delete other tenants.' + admin_group_name: 'Admins' + user_group_name: 'Users' + super_admin_group_name: 'Super-Admins' + new: + page_title: 'New Gemeinschaft setup' + form: + user_id: + label: 'User' + hint: '' + sip_domain_id: + label: 'SIP domain' + hint: '' + country_id: + label: 'Country' + hint: '' + language_id: + label: 'Language' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/gs_cluster_sync_log_entries/de.yml b/config/locales/views/gs_cluster_sync_log_entries/de.yml new file mode 100644 index 0000000..454c317 --- /dev/null +++ b/config/locales/views/gs_cluster_sync_log_entries/de.yml @@ -0,0 +1,60 @@ +de: + gs_cluster_sync_log_entries: + name: 'GS Cluster Synclog Einträge' + controller: + successfuly_created: 'Ein Eintrag im GS Cluster Synclog wurde erstellt.' + successfuly_updated: 'Der Eintrag im GS Cluster Synclog wurde aktualisiert.' + successfuly_destroyed: 'Der Eintrag im GS Cluster Synclog wurde gelöscht.' + index: + page_title: 'GS Cluster Synclog Einträge auflisten' + gs_node_id: 'GS Knoten' + class_name: 'Klasse' + action: 'Aktion' + content: 'Inhalt' + status: 'Status' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Eintrag aus dem GS Cluster Synclog löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neuen GS Cluster Synclog Eintrag für %{resource}' + show: + page_title: 'Eintrag anzeigen' + gs_node_id: 'GS Knoten' + class_name: 'Klasse' + action: 'Aktion' + content: 'Inhalt' + status: 'Status' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Eintrag aus dem GS Cluster Synclog löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + new: + page_title: 'Neuer Eintrag' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: + page_title: 'Eintrag bearbeiten' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + form: + gs_node_id: + label: 'GS Knoten' + hint: '' + class_name: + label: 'Klasse' + hint: '' + action: + label: 'Aktion' + hint: '' + content: + label: 'Inhalt' + hint: '' + status: + label: 'Status' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/gs_cluster_sync_log_entries/en.yml b/config/locales/views/gs_cluster_sync_log_entries/en.yml new file mode 100644 index 0000000..63c0cbb --- /dev/null +++ b/config/locales/views/gs_cluster_sync_log_entries/en.yml @@ -0,0 +1,60 @@ +en: + gs_cluster_sync_log_entries: + name: 'Gs cluster sync log entry' + controller: + successfuly_created: 'Successfully created Gs cluster sync log entry.' + successfuly_updated: 'Successfully updated Gs cluster sync log entry.' + successfuly_destroyed: 'Successfully destroyed Gs cluster sync log entry.' + index: + page_title: 'Listing Gs cluster sync log entry' + gs_node_id: 'Gs node' + class_name: 'Class name' + action: 'Action' + content: 'Content' + status: 'Status' + actions: + confirm: 'Are you sure you want to delete this Gs cluster sync log entry?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New Gs cluster sync log entry for %{resource}' + show: + page_title: 'Show Gs cluster sync log entry' + gs_node_id: 'Gs node' + class_name: 'Class name' + action: 'Action' + content: 'Content' + status: 'Status' + actions: + confirm: 'Are you sure you want to delete this element?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New Gs cluster sync log entry' + actions: + back_to_list: 'Back to Index' + edit: + page_title: 'Editing Gs cluster sync log entry' + actions: + back_to_list: 'Back to Index' + edit: 'Edit' + view_all: 'View All' + form: + gs_node_id: + label: 'Gs node' + hint: '' + class_name: + label: 'Class name' + hint: '' + action: + label: 'Action' + hint: '' + content: + label: 'Content' + hint: '' + status: + label: 'Status' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/gs_nodes/de.yml b/config/locales/views/gs_nodes/de.yml new file mode 100644 index 0000000..62b935e --- /dev/null +++ b/config/locales/views/gs_nodes/de.yml @@ -0,0 +1,65 @@ +de: + gs_nodes: + name: 'GS Knoten' + controller: + successfuly_created: 'Ein GS Knoten wurde erstellt.' + successfuly_updated: 'Der GS Knoten wurde aktualisiert.' + successfuly_destroyed: 'Der GS Knoten wurde gelöscht.' + index: + page_title: 'GS Knoten auflisten' + name: 'Name' + ip_address: 'IP-Adresse' + push_updates_to: 'Änderungen an diesen Konten senden?' + accepts_updates_from: 'Änderungen von diesem Konten akzeptieren?' + site: 'Standort' + element_name: 'Elementenname' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen GS Knoten löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neuer GS Knoten für %{resource}' + show: + page_title: 'GS Knoten anzeigen' + name: 'Name' + ip_address: 'IP-Adresse' + push_updates_to: 'Änderungen an diesen Konten senden?' + accepts_updates_from: 'Änderungen von diesem Konten akzeptieren?' + site: 'Standort' + element_name: 'Elementenname' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen GS Knoten löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + new: + page_title: 'Neuer GS Knoten' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: + page_title: 'GS Knoten bearbeiten' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + form: + name: + label: 'Name' + hint: '' + ip_address: + label: 'IP-Adresse' + hint: '' + site: + label: 'Standort' + hint: 'z.B. http://0.0.0.0:3000/' + element_name: + label: 'Elementenname' + hint: '' + push_updates_to: + label: 'Änderungen senden' + hint: '' + accepts_updates_from: + label: 'Änderungen empfangen' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/gs_nodes/en.yml b/config/locales/views/gs_nodes/en.yml new file mode 100644 index 0000000..8fd7c03 --- /dev/null +++ b/config/locales/views/gs_nodes/en.yml @@ -0,0 +1,65 @@ +en: + gs_nodes: + name: 'GS Node' + controller: + successfuly_created: 'Successfully created GS Node.' + successfuly_updated: 'Successfully updated GS Node.' + successfuly_destroyed: 'Successfully destroyed GS Node.' + index: + page_title: 'Listing GS Nodes' + name: 'Name' + ip_address: 'IP address' + push_updates_to: 'Push updates to this node?' + accepts_updates_from: 'Accepts updates from this node?' + site: 'Site' + element_name: 'Element name' + actions: + confirm: 'Are you sure you want to delete this GS Node?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New GS Node for %{resource}' + show: + page_title: 'Show GS Node' + name: 'Name' + ip_address: 'IP address' + push_updates_to: 'Push updates' + site: 'Site' + element_name: 'Element name' + accepts_updates_from: 'Accepts updates from this node?' + actions: + confirm: 'Are you sure you want to delete this element?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New GS Node' + actions: + back_to_list: 'Back to Index' + edit: + page_title: 'Editing GS Node' + actions: + back_to_list: 'Back to Index' + edit: 'Edit' + view_all: 'View All' + form: + name: + label: 'Name' + hint: '' + ip_address: + label: 'IP address' + hint: '' + site: + label: 'Site' + hint: 'e.g. http://0.0.0.0:3000/' + element_name: + label: 'Element name' + hint: '' + push_updates_to: + label: 'Push updates to' + hint: '' + accepts_updates_from: + label: 'Accepts updates from this node?' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/gui_functions/de.yml b/config/locales/views/gui_functions/de.yml new file mode 100644 index 0000000..9f95f7d --- /dev/null +++ b/config/locales/views/gui_functions/de.yml @@ -0,0 +1,50 @@ +de: + gui_functions: + name: 'Oberflächen-Funktionen' + controller: + successfuly_created: 'Eine Oberflächen-Funktion wurde erstellt.' + successfuly_updated: 'Die Oberflächen-Funktion wurde aktualisiert.' + successfuly_destroyed: 'Die Oberflächen-Funktion wurde gelöscht.' + index: + page_title: 'Oberflächen-Funktionen' + category: 'Kategorie' + name: 'Name' + description: 'Beschreibung' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Oberflächen-Funktion löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neue Oberflächen-Funktion für %{resource}' + show: + page_title: 'Oberflächen-Funktion anzeigen' + category: 'Kategorie' + name: 'Name' + description: 'Beschreibung' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Oberflächen-Funktion löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + new: + page_title: 'Neue Oberflächen-Funktion' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: + page_title: 'Oberflächen-Funktion bearbeiten' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + form: + category: + label: 'Kategorie' + hint: '' + name: + label: 'Name' + hint: '' + description: + label: 'Beschreibung' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/gui_functions/en.yml b/config/locales/views/gui_functions/en.yml new file mode 100644 index 0000000..346f27a --- /dev/null +++ b/config/locales/views/gui_functions/en.yml @@ -0,0 +1,50 @@ +de: + gui_functions: + name: 'Gui Function' + controller: + successfuly_created: 'Successfully created a gui function.' + successfuly_updated: 'Successfully updated a gui function.' + successfuly_destroyed: 'Successfully destroyed a gui function.' + index: + page_title: 'Listing of all gui functions' + category: 'Category' + name: 'Name' + description: 'Description' + actions: + confirm: 'Are you sure you want to delete this gui function?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New gui function for %{resource}' + show: + page_title: 'Show gui function' + category: 'Category' + name: 'Name' + description: 'Description' + actions: + confirm: 'Are you sure you want to delete this element?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New gui function' + actions: + back_to_list: 'Back to Index' + edit: + page_title: 'Editing gui function' + actions: + back_to_list: 'Back to Index' + edit: 'Edit' + view_all: 'View All' + form: + category: + label: 'Category' + hint: '' + name: + label: 'Name' + hint: '' + description: + label: 'Description' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/hunt_group_members/de.yml b/config/locales/views/hunt_group_members/de.yml new file mode 100644 index 0000000..f98ecfc --- /dev/null +++ b/config/locales/views/hunt_group_members/de.yml @@ -0,0 +1,48 @@ +de: + hunt_group_members: + name: 'Rufgruppen-Teilnehmer' + controller: + successfuly_created: 'Ein neuer Rufgruppen-Teilnehmer wurde eingetragen.' + successfuly_updated: 'Der Rufgruppen-Teilnehmer wurde aktualisiert.' + successfuly_destroyed: 'Der Rufgruppen-Teilnehmer wurde entfernt.' + index: + page_title: 'Rufgruppen-Teilnehmer' + name: 'Name' + active: 'Aktiv' + phone_numbers: 'Telefonnummern' + can_switch_status_itself: 'Darf seinen Status selbst ändern' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Rufgruppen-Teilnehmer entfernen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neuen Teilnehmer für %{resource} anlegen' + show: + page_title: 'Teilnehmer anzeigen' + name: 'Name' + active: 'Aktiv' + can_switch_status_itself: 'Darf seinen Status selber ändern' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Rufgruppen-Teilnehmer entfernen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle Rufgruppen-Teilnehmer anzeigen' + new: + page_title: 'Neuen Teilnehmer anlegen' + edit: + page_title: 'Teilnehmer bearbeiten' + form: + name: + label: 'Name' + hint: '' + active: + label: 'Aktiv' + hint: '' + can_switch_status_itself: + label: 'Darf seinen Status selber ändern' + hint: 'Diese Funktion geht nur von Nummern innerhalb der Anlage.' + phone_numbers: + label: 'Telefonnummern' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/hunt_group_members/en.yml b/config/locales/views/hunt_group_members/en.yml new file mode 100644 index 0000000..0daa146 --- /dev/null +++ b/config/locales/views/hunt_group_members/en.yml @@ -0,0 +1,48 @@ +en: + hunt_group_members: + name: 'Hunt group member' + controller: + successfuly_created: 'Successfully created hunt group member.' + successfuly_updated: 'Successfully updated hunt group member.' + successfuly_destroyed: 'Successfully destroyed hunt group member.' + index: + page_title: 'Hunt group members' + name: 'Name' + active: 'Active' + phone_numbers: 'Phone numbers' + can_switch_status_itself: 'Can switch status itself' + actions: + confirm: 'Are you sure you want to delete this hunt group member?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New hunt group member for %{resource}' + show: + page_title: 'Show hunt group member' + name: 'Name' + active: 'Active' + can_switch_status_itself: 'Can switch status itself' + actions: + confirm: 'Are you sure you want to delete this element?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New hunt group member' + edit: + page_title: 'Editing hunt group member' + form: + name: + label: 'Name' + hint: '' + active: + label: 'Active' + hint: '' + can_switch_status_itself: + label: 'Can switch status itself' + hint: 'This feature is only accessible from internal extensions.' + phone_numbers: + label: 'Phone numbers' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/hunt_groups/de.yml b/config/locales/views/hunt_groups/de.yml new file mode 100644 index 0000000..6865d18 --- /dev/null +++ b/config/locales/views/hunt_groups/de.yml @@ -0,0 +1,57 @@ +de: + hunt_groups: + name: 'Rufgruppe' + strategies: + ring_all: 'Alle Rufgruppen-Teilnehmer klingeln parallel' + ring_recursively: 'Die Rufgruppen-Teilnehmer klingeln rekursiv' + controller: + successfuly_created: 'Eine neue Rufgruppe wurde angelegt.' + successfuly_updated: 'Die Rufgruppe wurde aktualisiert.' + successfuly_destroyed: 'Die Rufgruppe wurde gelöscht.' + index: + page_title: 'Rufgruppen' + name: 'Name' + strategy: 'Verteilungs-Strategie' + seconds_between_jumps: 'Sekunden zwischen Sprüngen' + phone_numbers: 'Telefonnummern' + hunt_group_members: 'Rufgruppen-Teilnehmer' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Rufgruppe löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neue Rufgruppe für %{resource} anlegen' + show: + page_title: 'Rufgruppe anzeigen' + name: 'Name' + strategy: 'Verteilungs-Strategie' + seconds_between_jumps: 'Sekunden zwischen Sprüngen' + phone_numbers: 'Telefonnummern' + hunt_group_members: 'Rufgruppen-Teilnehmer' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Rufgruppe löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle Rufgruppen anzeigen' + new: + page_title: 'Neue Rufgruppe' + edit: + page_title: 'Rufgruppe bearbeiten' + form: + name: + label: 'Name' + hint: '' + strategy: + label: 'Verteilungs-Strategie' + hint: '' + seconds_between_jumps: + label: 'Sekunden zwischen Sprüngen' + hint: '' + phone_numbers: + label: 'Telefonnummern' + hint: '' + hunt_group_members: + label: 'Rufgruppen-Teilnehmer' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/hunt_groups/en.yml b/config/locales/views/hunt_groups/en.yml new file mode 100644 index 0000000..7039c97 --- /dev/null +++ b/config/locales/views/hunt_groups/en.yml @@ -0,0 +1,57 @@ +en: + hunt_groups: + name: 'Hunt group' + strategies: + ring_all: 'Ring all' + ring_recursively: 'Ring recursively' + controller: + successfuly_created: 'Successfully created hunt group.' + successfuly_updated: 'Successfully updated hunt group.' + successfuly_destroyed: 'Successfully destroyed hunt group.' + index: + page_title: 'Hunt groups' + name: 'Name' + strategy: 'Strategy' + seconds_between_jumps: 'S.b.jumps' + phone_numbers: 'Phone numbers' + hunt_group_members: 'Members' + actions: + confirm: 'Are you sure you want to delete this hunt group?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New hunt group for %{resource}' + show: + page_title: 'Show hunt group' + name: 'Name' + strategy: 'Strategy' + seconds_between_jumps: 'Seconds between jumps' + phone_numbers: 'Phone numbers' + hunt_group_members: 'Members' + actions: + confirm: 'Are you sure you want to delete this hunt group?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New hunt group' + edit: + page_title: 'Editing hunt group' + form: + name: + label: 'Name' + hint: '' + strategy: + label: 'Strategy' + hint: '' + seconds_between_jumps: + label: 'Seconds between jumps' + hint: 'Set when the strategy is not "Ring all".' + phone_numbers: + label: 'Phone numbers' + hint: '' + hunt_group_members: + label: 'Members of this hunt group' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/manufacturers/de.yml b/config/locales/views/manufacturers/de.yml new file mode 100644 index 0000000..6620e22 --- /dev/null +++ b/config/locales/views/manufacturers/de.yml @@ -0,0 +1,49 @@ +de: + manufacturers: + name: 'Hersteller' + controller: + successfuly_created: 'Ein neuer Hersteller wurde eingetragen.' + successfuly_updated: 'Der Hersteller wurde aktualisiert.' + successfuly_destroyed: 'Der Hersteller wurde gelöscht.' + index: + page_title: 'Hersteller' + name: 'Name' + ieee_name: 'IEEE name' + homepage_url: 'Homepage URL' + phone_models: 'Telefonmodelle' + state: 'Status' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Hersteller löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + show: + page_title: 'Hersteller anzeigen' + name: 'Name' + ieee_name: 'IEEE name' + homepage_url: 'Homepage URL' + state: 'Status' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Hersteller löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + new: + page_title: 'Neuer Hersteller' + edit: + page_title: 'Hersteller bearbeiten' + form: + name: + label: 'Name' + hint: '' + ieee_name: + label: 'IEEE name' + hint: '' + homepage_url: + label: 'Homepage URL' + hint: '' + state: + label: 'Status' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/manufacturers/en.yml b/config/locales/views/manufacturers/en.yml new file mode 100644 index 0000000..f4804cf --- /dev/null +++ b/config/locales/views/manufacturers/en.yml @@ -0,0 +1,49 @@ +en: + manufacturers: + name: 'Manufacturer' + controller: + successfuly_created: 'Successfully created manufacturer.' + successfuly_updated: 'Successfully updated manufacturer.' + successfuly_destroyed: 'Successfully destroyed manufacturer.' + index: + page_title: 'Manufacturers' + name: 'Name' + ieee_name: 'IEEE name' + homepage_url: 'Homepage URL' + phone_models: 'Phone models' + state: 'State' + actions: + confirm: 'Are you sure you want to delete this manufacturer?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + show: + page_title: 'Show manufacturer' + name: 'Name' + ieee_name: 'IEEE name' + homepage_url: 'Homepage URL' + state: 'State' + actions: + confirm: 'Are you sure you want to delete this manufacturer?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New manufacturer' + edit: + page_title: 'Editing manufacturer' + form: + name: + label: 'Name' + hint: '' + ieee_name: + label: 'IEEE name' + hint: '' + homepage_url: + label: 'Homepage URL' + hint: '' + state: + label: 'State' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/notifications/de.yml b/config/locales/views/notifications/de.yml new file mode 100644 index 0000000..a66cf76 --- /dev/null +++ b/config/locales/views/notifications/de.yml @@ -0,0 +1,4 @@ +de: + notifications: + new_pin: + subject: 'Neue PIN' \ No newline at end of file diff --git a/config/locales/views/notifications/en.yml b/config/locales/views/notifications/en.yml new file mode 100644 index 0000000..c256a37 --- /dev/null +++ b/config/locales/views/notifications/en.yml @@ -0,0 +1,4 @@ +en: + notifications: + new_pin: + subject: 'New PIN' \ No newline at end of file diff --git a/config/locales/views/pages/de.yml b/config/locales/views/pages/de.yml new file mode 100644 index 0000000..bcdd28e --- /dev/null +++ b/config/locales/views/pages/de.yml @@ -0,0 +1,9 @@ +de: + pages: + name: "Webseiten" + welcome_please_log_in: "Willkommen bei Gemeinschaft! Bitte melden Sie sich beim System mit Ihrem Benutzer-Namen und Ihrem Passwort an." + not_enough_rights: "Kontaktieren Sie bitte Ihre System-Administration" # Not Enough rights to access anything in the Navigation. + controller: + access_denied_login_first: 'Zugriff verweigert! Bitte melden Sie sich erst an.' + index: + name: "Startseite" \ No newline at end of file diff --git a/config/locales/views/pages/en.yml b/config/locales/views/pages/en.yml new file mode 100644 index 0000000..589d4ea --- /dev/null +++ b/config/locales/views/pages/en.yml @@ -0,0 +1,9 @@ +en: + pages: + name: "Pages" + welcome_please_log_in: "Welcome to Gemeinschaft! Please Log In to access the System!" + not_enough_rights: "Contact Administration" # Not Enough rights to access anything in the Navigation. + controller: + access_denied_login_first: 'Access denied! You need to login first.' + index: + name: "Home" \ No newline at end of file diff --git a/config/locales/views/phone_book_entries/de.yml b/config/locales/views/phone_book_entries/de.yml new file mode 100644 index 0000000..ba9983e --- /dev/null +++ b/config/locales/views/phone_book_entries/de.yml @@ -0,0 +1,161 @@ +de: + phone_book_entries: + name: "Telefonbucheintrag" + controller: + successfuly_created: 'Der Telefonbucheintrag "%{resource}" wurde erstellt.' + successfuly_updated: 'Der Telefonbucheintrag "%{resource}" wurde aktualisiert.' + successfuly_destroyed: 'Der Telefonbucheintrag wurde gelöscht.' + index: + page_title: 'Telefonbucheinträge' + phone_book_id: 'Telefonbuch' + first_name: 'Vorname' + middle_name: 'Zweiter Vorname' + last_name: 'Nachname' + title: 'Akademischer Titel' + nickname: 'Spitzname' + organization: 'Organisation' + is_organization: 'Ist eine Organisation' + department: 'Abteilung' + job_title: 'Position (Berufsbezeichnung)' + is_male: 'männlich' + birthday: 'Geburtstag' + birth_name: 'Mädchenname' + state: 'Status' + description: 'Beschreibung' + position: 'Position' + homepage_personal: 'Persönliche Homepage' + homepage_organization: 'Homepage der Organisation' + twitter_account: 'Twitter Konto' + facebook_account: 'Facebook Konto' + google_plus_account: 'Google+ Konto' + xing_account: 'Xing Konto' + linkedin_account: 'LinkedIn Konto' + mobileme_account: 'iCloud Konto' + more_numbers: 'und %{numbers} weitere' + available_phone_books: 'Verfügbare Telefonbücher:' + create_new_phone_book_entry: 'Einen neuen Eintrag anlegen' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Telefonbucheintrag löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neuen Telefonbucheintrag für %{resource} anlegen' + show: + page_title: 'Telefonbucheinträge für "%{resource}"' + phone_book_id: 'Telefonbuch' + first_name: 'Vorname' + middle_name: 'Zweiter Vorname' + last_name: 'Nachname' + title: 'Akademischer Titel' + nickname: 'Spitzname' + organization: 'Organisation' + is_organization: 'Ist eine Organisation' + department: 'Abteilung' + job_title: 'Position (Berufsbezeichnung)' + is_male: 'männlich' + birthday: 'Geburtstag' + birth_name: 'Mädchenname' + state: 'Status' + description: 'Beschreibung' + position: 'Position' + homepage_personal: 'Persönliche Homepage' + homepage_organization: 'Homepage der Organisation' + twitter_account: 'Twitter Konto' + facebook_account: 'Facebook Konto' + google_plus_account: 'Google+ Konto' + xing_account: 'Xing Konto' + linkedin_account: 'LinkedIn Konto' + mobileme_account: 'iCloud Konto' + manage_phone_number: 'Telefonnummern verwalten.' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Telefonbucheintrag löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle Telefonbucheinträge anzeigen' + new: + page_title: 'Neuer Telefonbucheintrag' + edit: + page_title: 'Telefonbucheintrag bearbeiten' + form: + phone_book_id: + label: 'Tefonbuch' + hint: '' + first_name: + label: 'Vorname' + hint: '' + middle_name: + label: 'Zweiter Vorname' + hint: '' + gender: + label: 'Geschlecht' + hint: '' + male: "männlich" + female: "weiblich" + last_name: + label: 'Nachname' + hint: '' + title: + label: 'Akademischer Titel' + hint: 'z.B. Dr.' + nickname: + label: 'Spitzname' + hint: '' + organization: + label: 'Firmenname' + hint: 'Organisation' + is_organization: + label: 'Ist eine Organisation' + hint: '' + department: + label: 'Abteilung' + hint: '' + job_title: + label: 'Position' + hint: 'z.B. Geschäftsführer' + is_male: + label: 'Ist männlich' + hint: '' + birthday: + label: 'Geburtstag' + hint: '' + birth_name: + label: 'Mädchenname' + hint: '' + state: + label: 'Status' + hint: '' + description: + label: 'Beschreibung' + hint: '' + position: + label: 'Position' + hint: '' + homepage_personal: + label: 'Persönliche Homepage' + hint: '' + homepage_organization: + label: 'Firmen Homepage' + hint: 'http://www.example.com' + twitter_account: + label: 'Twitter Konto' + hint: '@example' + facebook_account: + label: 'Facebook Konto' + hint: '' + google_plus_account: + label: 'Google+ Konto' + hint: '' + xing_account: + label: 'Xing Konto' + hint: '' + linkedin_account: + label: 'LinkedIn Konto' + hint: '' + mobileme_account: + label: 'iCloud Konto' + hint: '' + image: + label: 'Avatar Foto' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/phone_book_entries/en.yml b/config/locales/views/phone_book_entries/en.yml new file mode 100644 index 0000000..3c861a0 --- /dev/null +++ b/config/locales/views/phone_book_entries/en.yml @@ -0,0 +1,161 @@ +en: + phone_book_entries: + name: "Phone Book Entries" + controller: + successfuly_created: 'Successfully created phone book entry "%{resource}".' + successfuly_updated: 'Successfully updated phone book entry "%{resource}".' + successfuly_destroyed: 'Successfully destroyed phone book entry.' + index: + page_title: 'Phone book entries' + phone_book_id: 'Phone book' + first_name: 'First name' + middle_name: 'Middle name' + last_name: 'Last name' + title: 'Title' + nickname: 'Nickname' + organization: 'Organization' + is_organization: 'Is organization' + department: 'Department' + job_title: 'Job title' + is_male: 'Is male' + birthday: 'Birthday' + birth_name: 'Birth name' + state: 'State' + description: 'Description' + position: 'Position' + homepage_personal: 'Homepage personal' + homepage_organization: 'Homepage organization' + twitter_account: 'Twitter account' + facebook_account: 'Facebook account' + google_plus_account: 'Google+ account' + xing_account: 'Xing account' + linkedin_account: 'LinkedIn account' + mobileme_account: 'iCloud account' + more_numbers: 'plus %{numbers} more' + available_phone_books: 'Available phone books:' + create_new_phone_book_entry: 'create a new entry' + actions: + confirm: 'Are you sure you want to delete this phone book entry?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New phone book entry for %{resource}' + show: + page_title: 'Phone book entry for "%{resource}"' + phone_book_id: 'Phone book' + first_name: 'First name' + middle_name: 'Middle name' + last_name: 'Last name' + title: 'Title' + nickname: 'Nickname' + organization: 'Organization' + is_organization: 'Is organization' + department: 'Department' + job_title: 'Job title' + is_male: 'Is male' + birthday: 'Birthday' + birth_name: 'Birth name' + state: 'State' + description: 'Description' + position: 'Position' + homepage_personal: 'Homepage personal' + homepage_organization: 'Homepage organization' + twitter_account: 'Twitter account' + facebook_account: 'Facebook account' + google_plus_account: 'Google+ account' + xing_account: 'Xing account' + linkedin_account: 'LinkedIn account' + mobileme_account: 'iCloud account' + manage_phone_number: 'Manage phone number.' + actions: + confirm: 'Are you sure you want to delete this phone book entry?' + destroy: 'Delete phone book entry' + edit: 'Edit phone book entry' + view_all: 'View all phone book entries' + new: + page_title: 'New entry' + edit: + page_title: 'Editing phone book entry' + form: + phone_book_id: + label: 'Phone book' + hint: '' + first_name: + label: 'First name' + hint: '' + middle_name: + label: 'Middle name' + hint: '' + gender: + label: 'Gender' + hint: '' + male: "Male" + female: "Female" + last_name: + label: 'Last name' + hint: '' + title: + label: 'Academic title' + hint: 'Dr.' + nickname: + label: 'Nickname' + hint: '' + organization: + label: 'Company name' + hint: 'Organization' + is_organization: + label: 'Is organization' + hint: '' + department: + label: 'Department' + hint: '' + job_title: + label: 'Job title' + hint: 'CEO' + is_male: + label: 'Is male' + hint: '' + birthday: + label: 'Birthday' + hint: '' + birth_name: + label: 'Name at birth' + hint: '' + state: + label: 'State' + hint: '' + description: + label: 'Description' + hint: '' + position: + label: 'Position' + hint: '' + homepage_personal: + label: 'Personal Home Page' + hint: '' + homepage_organization: + label: 'Organization Home Page' + hint: 'http://www.example.com' + twitter_account: + label: 'Twitter account' + hint: '@example' + facebook_account: + label: 'Facebook account' + hint: '' + google_plus_account: + label: 'Google+ account' + hint: '' + xing_account: + label: 'Xing account' + hint: '' + linkedin_account: + label: 'LinkedIn account' + hint: '' + mobileme_account: + label: 'iCloud account' + hint: '' + image: + label: 'Photo' + hint: 'Avatar photo' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/phone_books/de.yml b/config/locales/views/phone_books/de.yml new file mode 100644 index 0000000..8aa6acf --- /dev/null +++ b/config/locales/views/phone_books/de.yml @@ -0,0 +1,46 @@ +de: + phone_books: + name: 'Telefonbuch' + general_phone_book: + name: 'Firmentelefonbuch' + description: 'Ein für alle Benutzer von %{resource} lesbares Telefonbuch.' + private_phone_book: + name: 'Privates Telefonbuch von %{resource}' + description: 'Ein privates Telefonbuch.' + controller: + successfuly_created: 'Ein neues Telefonbuch wurde erstellt.' + successfuly_updated: 'Ein Telefonbuch wurde aktualisiert.' + successfuly_destroyed: 'Ein Telefonbuch wurde gelöscht.' + index: + page_title: 'Telefonbücher' + name: 'Name des Telefonbuches' + description: 'Beschreibung' + count: 'Anzahl der Telefonbucheinträge' + actions: + confirm: 'Sind Sie sicher, dass Sie dieses Telefonbuch löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neues Telefonbuch für %{resource} anlegen' + show: + page_title: 'Telefonbuch anzeigen' + name: 'Name' + description: 'Beschreibung' + actions: + confirm: 'Sind Sie sicher, dass Sie dieses Telefonbuch löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle Telefonbücher anzeigen' + new: + page_title: 'Neues Telefonbuch' + edit: + page_title: 'Telefonbuch "%{resource}" bearbeiten' + form: + name: + label: 'Name' + hint: '' + description: + label: 'Beschreibung' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/phone_books/en.yml b/config/locales/views/phone_books/en.yml new file mode 100644 index 0000000..fcab06d --- /dev/null +++ b/config/locales/views/phone_books/en.yml @@ -0,0 +1,46 @@ +en: + phone_books: + name: 'Phone book' + general_phone_book: + name: 'Public phone book' + description: 'Readable for all users of %{resource}.' + private_phone_book: + name: "%{resource}'s phone book" + description: 'A private phone book.' + controller: + successfuly_created: 'Successfully created phone book.' + successfuly_updated: 'Successfully updated phone book.' + successfuly_destroyed: 'Successfully destroyed phone book.' + index: + page_title: 'Phone books' + name: 'Name of the phone book' + description: 'Description' + count: 'Number of entries' + actions: + confirm: 'Are you sure you want to delete this phone book?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New phone book for %{resource}' + show: + page_title: 'Phone Book' + name: 'Name' + description: 'Description' + actions: + confirm: 'Are you sure you want to delete this phone book?' + destroy: 'Delete phone book' + edit: 'Edit phone book' + view_all: 'View all phone books' + new: + page_title: 'New phone book' + edit: + page_title: 'Editing phone book "%{resource}"' + form: + name: + label: 'Name' + hint: '' + description: + label: 'Description' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/phone_models/de.yml b/config/locales/views/phone_models/de.yml new file mode 100644 index 0000000..36d1663 --- /dev/null +++ b/config/locales/views/phone_models/de.yml @@ -0,0 +1,50 @@ +de: + phone_models: + name: 'Telefonmodell' + controller: + successfuly_created: 'Ein Telefonmodell wurde erstellt.' + successfuly_updated: 'Das Telefonmodell wurde aktualisiert.' + successfuly_destroyed: 'Das Telefonmodell wurde gelöscht.' + index: + page_title: 'Telefonmodelle' + name: 'Name' + manufacturer_id: 'Hersteller' + product_manual_homepage_url: 'Betriebsanleitung URL' + product_homepage_url: 'Produkt-Homepage URL' + number_of_phones: 'Anzahl von Telefonen' + actions: + confirm: 'Sind Sie sicher, dass Sie dieses Telefonmodell löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + show: + page_title: 'Telefonmodell anzeigen' + name: 'Name' + manufacturer_id: '' + manufacturer_id: 'Hersteller' + product_manual_homepage_url: 'Betriebsanleitung URL' + product_homepage_url: 'Produkt-Homepage URL' + actions: + confirm: 'Sind Sie sicher, dass Sie dieses Telefonmodell löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle Telefonmodelle anzeigen' + new: + page_title: 'Neues Telefonmodell' + edit: + page_title: 'Telefonmodell bearbeiten' + form: + name: + label: 'Name' + hint: '' + manufacturer_id: + label: 'Hersteller' + hint: '' + product_manual_homepage_url: + label: 'Betriebsanleitung URL' + hint: '' + product_homepage_url: + label: 'Produkt-Homepage URL' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/phone_models/en.yml b/config/locales/views/phone_models/en.yml new file mode 100644 index 0000000..c500920 --- /dev/null +++ b/config/locales/views/phone_models/en.yml @@ -0,0 +1,49 @@ +en: + phone_models: + name: 'Phone model' + controller: + successfuly_created: 'Successfully created phone model.' + successfuly_updated: 'Successfully updated phone model.' + successfuly_destroyed: 'Successfully destroyed phone model.' + index: + page_title: 'Phone models' + name: 'Name' + manufacturer_id: 'Manufacturer' + product_manual_homepage_url: 'Product manual homepage URL' + product_homepage_url: 'Product homepage URL' + number_of_phones: 'System count' + actions: + confirm: 'Are you sure you want to delete this phone model?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + show: + page_title: 'Show phone model' + name: 'Name' + manufacturer_id: 'Manufacturer' + product_manual_homepage_url: 'Product manual homepage URL' + product_homepage_url: 'Product homepage URL' + actions: + confirm: 'Are you sure you want to delete this phone model?' + destroy: 'Delete phone model' + edit: 'Edit phone model' + view_all: 'View all phone models' + new: + page_title: 'New phone model' + edit: + page_title: 'Editing phone model' + form: + name: + label: 'Name' + hint: '' + manufacturer_id: + label: 'Manufacturer' + hint: '' + product_manual_homepage_url: + label: 'Product manual homepage URL' + hint: '' + product_homepage_url: + label: 'Product homepage URL' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/phone_number_ranges/de.yml b/config/locales/views/phone_number_ranges/de.yml new file mode 100644 index 0000000..af97171 --- /dev/null +++ b/config/locales/views/phone_number_ranges/de.yml @@ -0,0 +1,51 @@ +de: + phone_number_ranges: + ranges: + internal_extensions: + label: 'Durchwahlen (intern)' + description: 'Interne Durchwahlen, auch Extensions genannt.' + direct_inward_dialing_numbers: + label: 'Anschlussnummern des öffentlichen Telefonnetzes (DIDs und MSNs)' + description: 'Mit diesen Telefonnummern sind Sie aus dem öffentlichen Telefonnetz erreichbar.' + service_numbers: + label: 'Service Telefonnummern' + description: 'Spezielle Telefonnummern, die nich für interne Durchwahlen benutzt werden sollten (z.B. die Feuerwehr oder Polizei).' + name: 'Rufnummernbereich' + controller: + successfuly_created: 'Ein neuer Rufnummernbereich wurde angelegt.' + successfuly_updated: 'Der Rufnummernbereich wurde aktualisiert.' + successfuly_destroyed: 'Der Rufnummernbereich wurde gelöscht.' + index: + page_title: 'Rufnummernbereiche' + name: 'Name' + description: 'Beschreibung' + amount: 'Anzahl von Rufnummern' + phone_numbers: 'Telefonnummern' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Rufnummernbereich löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Rufnummernbereich für %{resource} anlegen' + show: + page_title: 'Rufnummernbereich anzeigen' + name: 'Name' + description: 'Beschreibung' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Rufnummernbereich löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle Rufnummernbereiche anzeigen' + new: + page_title: 'Neuer Rufnummernbereich' + edit: + page_title: 'Rufnummernbereich "%{resource}" bearbeiten' + form: + name: + label: 'Name' + hint: '' + description: + label: 'Beschreibung' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/phone_number_ranges/en.yml b/config/locales/views/phone_number_ranges/en.yml new file mode 100644 index 0000000..a22a2c0 --- /dev/null +++ b/config/locales/views/phone_number_ranges/en.yml @@ -0,0 +1,51 @@ +en: + phone_number_ranges: + ranges: + internal_extensions: + label: 'Internal extensions' + description: 'These are your internal extensions.' + direct_inward_dialing_numbers: + label: 'Direct inward dialing numbers (DIDs and MSNs)' + description: 'These are the phone numbers which have to be dialed from the PSTN to access your PBX.' + service_numbers: + label: 'Service numbers' + description: 'Numbers for special services (e.g. emergency numbers). It is not possible to use one of these numbers as an internal extension.' + name: 'Phone number range' + controller: + successfuly_created: 'Successfully created phone number range.' + successfuly_updated: 'Successfully updated phone number range.' + successfuly_destroyed: 'Successfully destroyed phone number range.' + index: + page_title: 'Phone number ranges' + name: 'Name' + description: 'Description' + amount: 'Amount of numbers' + phone_numbers: 'Phone numbers' + actions: + confirm: 'Are you sure you want to delete this phone number range?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New phone number range for %{resource}' + show: + page_title: 'Show phone number range' + name: 'Name' + description: 'Description' + actions: + confirm: 'Are you sure you want to delete this phone number range?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View' + new: + page_title: 'New phone number range' + edit: + page_title: 'Editing phone number range "%{resource}"' + form: + name: + label: 'Name' + hint: '' + description: + label: 'Description' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/phone_numbers/de.yml b/config/locales/views/phone_numbers/de.yml new file mode 100644 index 0000000..40fc7f8 --- /dev/null +++ b/config/locales/views/phone_numbers/de.yml @@ -0,0 +1,64 @@ +de: + phone_numbers: + name: "Telefonnummer" + controller: + successfuly_created: 'Eine neue Telefonnummer wurde eingetragen.' + successfuly_updated: 'Die Telefonnummer wurde aktualisiert.' + successfuly_destroyed: 'Die Telefonnummer wurde gelöscht.' + index: + page_title: 'Telefonnummern' + phone_book_id: 'Telefonbuch' + name: 'Name' + number: 'Telefonnummer' + country_code: 'Ländervorwahl' + area_code: 'Ortsvorwahl' + subscriber_number: 'Telefonnummer' + extension: 'Durchwahl' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Telefonnummer löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neue Telefonnummer für %{resource} anlegen' + show: + page_title: 'Telefonnummer anzeigen' + phone_book_id: 'Telefonbuch' + name: 'Name' + number: 'Telefonnummer' + country_code: 'Ländervorwahl' + area_code: 'Ortsvorwahl' + subscriber_number: 'Telefonnummer' + extension: 'Durchwahl' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Telefonnummer löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'View all phone numbers' + new: + page_title: 'Neue Telefonnummer' + edit: + page_title: 'Telefonnummer bearbeiten' + form: + phone_book_id: + label: 'Telefonbuch' + hint: '' + name: + label: 'Name' + hint: '' + number: + label: 'Telefonnummer' + hint: 'Format: +49-30-2270 für eine normale Telefonnummer. 42 für eine interne Durchwahl.' + country_code: + label: 'Ländervorwahl' + hint: '' + area_code: + label: 'Ortsvorwahl' + hint: '' + subscriber_number: + label: 'Telefonnummer' + hint: '' + extension: + label: 'Durchwahl' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/phone_numbers/en.yml b/config/locales/views/phone_numbers/en.yml new file mode 100644 index 0000000..31af5c8 --- /dev/null +++ b/config/locales/views/phone_numbers/en.yml @@ -0,0 +1,64 @@ +en: + phone_numbers: + name: "Phone numbers" + controller: + successfuly_created: 'Successfully created phone number.' + successfuly_updated: 'Successfully updated phone number.' + successfuly_destroyed: 'Successfully destroyed phone number.' + index: + page_title: 'Phone numbers' + phone_book_id: 'Phone book' + name: 'Name' + number: 'Number' + country_code: 'Country code' + area_code: 'Area code' + subscriber_number: 'Subscriber number' + extension: 'Extension' + actions: + confirm: 'Are you sure you want to delete this phone number?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New phone number for %{resource}' + show: + page_title: 'Show Phone number' + phone_book_id: 'Phone book' + name: 'Name' + number: 'Number' + country_code: 'Country code' + area_code: 'Area code' + subscriber_number: 'Subscriber number' + extension: 'Extension' + actions: + confirm: 'Are you sure you want to delete this phone number?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View all phone numbers' + new: + page_title: 'New Phone number' + edit: + page_title: 'Editing Phone number' + form: + phone_book_id: + label: 'Phone book' + hint: '' + name: + label: 'Name' + hint: '' + number: + label: 'Phone number' + hint: 'Format: +49-30-2270 for a normal phone number or 42 for an internal extension.' + country_code: + label: 'Country code' + hint: '' + area_code: + label: 'Area code' + hint: '' + subscriber_number: + label: 'Subscriber number' + hint: '' + extension: + label: 'Extension' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/phone_sip_accounts/de.yml b/config/locales/views/phone_sip_accounts/de.yml new file mode 100644 index 0000000..98c7bc5 --- /dev/null +++ b/config/locales/views/phone_sip_accounts/de.yml @@ -0,0 +1,37 @@ +de: + phone_sip_accounts: + name: "SIP-Konten auf einem Telefon" + controller: + successfuly_created: 'Das SIP-Konto wurde auf dem Telefon eingetragen.' + successfuly_destroyed: 'Das SIP-Konto wurde von dem Telefon entfernt.' + no_existing_sip_accounts_warning: 'Aktuell gibt es keine SIP-Konten, die einem Telefon eingetragen werden können. Bitte legen Sie ein neues SIP-Konto an.' + index: + page_title: "SIP-Konten auf einem Telefon" + phone_id: 'Telefon' + sip_account_id: 'SIP-Konto' + position: 'Position' + actions: + confirm: 'Sind Sie sicher, dass Sie dieses SIP-Konto von dem Telefon entfernen möchten?' + destroy: 'Entfernen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Auf dem Telefon %{resource} ein neues SIP-Konto eintragen' + show: + page_title: 'SIP-Konten eines Telefons anzeigen' + phone_id: 'Telefon' + sip_account_id: 'SIP-Konto' + position: 'Position' + actions: + confirm: 'Sind Sie sicher, dass Sie dieses SIP-Konto von dem Telefon entfernen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + new: + page_title: 'SIP-Konto eintragen' + actions: + form: + sip_account_id: + label: 'SIP-Konto' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/phone_sip_accounts/en.yml b/config/locales/views/phone_sip_accounts/en.yml new file mode 100644 index 0000000..9577241 --- /dev/null +++ b/config/locales/views/phone_sip_accounts/en.yml @@ -0,0 +1,37 @@ +en: + phone_sip_accounts: + name: "SIP accounts of a phone" + controller: + successfuly_created: 'Successfully connected a new SIP account to a phone.' + successfuly_destroyed: 'Successfully deleted a SIP account on a phone.' + no_existing_sip_accounts_warning: 'There are no SIP accounts to connect to. Please create a new SIP account first.' + index: + page_title: "SIP accounts of a phone" + phone_id: 'Phone' + sip_account_id: 'SIP account' + position: 'Position' + actions: + confirm: 'Are you sure you want to delete this SIP account on this phone?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New SIP account connection for %{resource}' + show: + page_title: 'Show SIP account of a phone' + phone_id: 'Phone' + sip_account_id: 'SIP account' + position: 'Position' + actions: + confirm: 'Are you sure you want to delete this SIP account on this phone?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New SIP account on a phone' + actions: + form: + sip_account_id: + label: 'SIP account' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/phones/de.yml b/config/locales/views/phones/de.yml new file mode 100644 index 0000000..3a0adea --- /dev/null +++ b/config/locales/views/phones/de.yml @@ -0,0 +1,77 @@ +de: + phones: + name: 'Telefon' + controller: + successfuly_created: 'Eine neues Telefon wurde in der Datenbank eingetragen.' + successfuly_updated: 'Die Daten zum Telefon wurden aktualisiert.' + successfuly_destroyed: 'Das Telefon wurde aus dem System entfernt.' + index: + page_title: 'Telefone' + mac_address: 'MAC-Adresse' + phone_model_id: 'Telefonmodell' + hot_deskable: 'Hot-Desk fähig' + ip_address: 'IP-Adresse' + last_ip_address: 'Letzte IP-Adresse' + http_user: 'http user' + http_password: 'http password' + nightly_reboot: 'Nachts automatischer Reboot' + provisioning_key_active: 'Provisioning Schlüssel aktiv' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Telefon aus Gemeinschaft entfernen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neues Telefon für %{resource} anlegen' + show: + page_title: 'Telefon anzeigen' + mac_address: 'MAC-Adresse' + phone_model_id: 'Telefonmodell' + hot_deskable: 'Hot-Desk fähig' + ip_address: 'IP-Adresse' + last_ip_address: 'Letzte IP-Adresse' + http_user: 'http user' + http_password: 'http password' + nightly_reboot: 'Nachts automatischer Reboot' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Telefon aus Gemeinschaft entfernen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle Telefone anzeigen' + new: + page_title: 'Neues Telefon' + actions: + edit: + page_title: 'Telefondaten bearbeiten' + form: + mac_address: + label: 'MAC-Adresse' + hint: '' + phone_model_id: + label: 'Telefonmodell' + hint: '' + hot_deskable: + label: 'Hot-Desk fähig' + hint: '' + nightly_reboot: + label: 'Nachts automatischer Reboot' + hint: '' + ip_address: + label: 'IP-Adresse' + hint: '' + last_ip_address: + label: 'Letzte IP-Adresse' + hint: '' + http_user: + label: 'http user' + hint: '' + http_password: + label: 'http password' + hint: '' + provisioning_key_active: + label: 'Provisioning Schlüssel aktiv' + hint: '' + button: 'Absenden' + sip_accounts: + title: 'Auf dem Telefon eingetragene SIP-Konten' + connect_to_sip_account: 'Neues SIP-Konto auf das Telefon eintragen' \ No newline at end of file diff --git a/config/locales/views/phones/en.yml b/config/locales/views/phones/en.yml new file mode 100644 index 0000000..afcf9b5 --- /dev/null +++ b/config/locales/views/phones/en.yml @@ -0,0 +1,77 @@ +en: + phones: + name: 'Phone' + controller: + successfuly_created: 'Successfully created phone.' + successfuly_updated: 'Successfully updated phone.' + successfuly_destroyed: 'Successfully destroyed phone.' + index: + page_title: 'Phones' + mac_address: 'Mac address' + phone_model_id: 'Phone model' + hot_deskable: 'Hot-deskable' + ip_address: 'IP address' + last_ip_address: 'Last IP address' + http_user: 'http user' + http_password: 'http password' + nightly_reboot: 'Nightly reboot' + actions: + confirm: 'Are you sure you want to delete this phone?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New phone for %{resource}' + show: + page_title: 'Show phone' + mac_address: 'Mac address' + phone_model_id: 'Phone model' + hot_deskable: 'Hot-deskable' + ip_address: 'IP address' + last_ip_address: 'Last IP address' + http_user: 'http user' + http_password: 'http password' + nightly_reboot: 'Nightly reboot' + provisioning_key_active: 'Provisioning key active' + actions: + confirm: 'Are you sure you want to delete this phone?' + destroy: 'Delete phone' + edit: 'Edit phone' + view_all: 'View all phones' + new: + page_title: 'New phone' + actions: + edit: + page_title: 'Editing Phone' + form: + mac_address: + label: 'Mac address' + hint: '' + phone_model_id: + label: 'Phone model' + hint: '' + hot_deskable: + label: 'Hot-deskable' + hint: '' + nightly_reboot: + label: 'Nightly reboot' + hint: '' + ip_address: + label: 'IP address' + hint: '' + last_ip_address: + label: 'Last IP address' + hint: '' + http_user: + label: 'GUI user' + hint: 'Phone GUI user name' + http_password: + label: 'GUI password' + hint: 'Phone GUI password' + provisioning_key_active: + label: 'Provisioning key active' + hint: '' + button: 'Submit' + sip_accounts: + title: 'Listing of connected SIP accounts' + connect_to_sip_account: 'Connect to an existing SIP account' \ No newline at end of file diff --git a/config/locales/views/ringtones/de.yml b/config/locales/views/ringtones/de.yml new file mode 100644 index 0000000..6bb3683 --- /dev/null +++ b/config/locales/views/ringtones/de.yml @@ -0,0 +1,39 @@ +de: + ringtones: + name: 'Klingelton' + controller: + successfuly_created: 'Ein neuer Klingelton wurde eingetragen.' + successfuly_updated: 'Der Klingelton wurde aktualisiert.' + successfuly_destroyed: 'Der Klingelton wurde gelöscht.' + index: + page_title: 'Klingeltöne' + audio: 'Audio' + bellcore_id: 'Bellcore-ID' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Klingelton löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + show: + page_title: 'Klingelton' + audio: 'Audio' + bellcore_id: 'Bellcore-ID' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Klingelton löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + new: + page_title: 'Neuer Klingelton' + edit: + page_title: 'Klingelton bearbeiten' + form: + audio: + label: 'Audio' + hint: '' + bellcore_id: + label: 'Bellcore-ID' + hint: 'Im Telefon eingebaute Klingeltöne. "0" bedeutet lautlos.' + button: 'Absenden' + set_a_ringtone: 'Klingelton einstellen' \ No newline at end of file diff --git a/config/locales/views/ringtones/en.yml b/config/locales/views/ringtones/en.yml new file mode 100644 index 0000000..e681d96 --- /dev/null +++ b/config/locales/views/ringtones/en.yml @@ -0,0 +1,39 @@ +en: + ringtones: + name: 'Ringtone' + controller: + successfuly_created: 'Successfully created ringtone.' + successfuly_updated: 'Successfully updated ringtone.' + successfuly_destroyed: 'Successfully destroyed ringtone.' + index: + page_title: 'Ringtones' + audio: 'Audio' + bellcore_id: 'Bellcore ID' + actions: + confirm: 'Are you sure you want to delete this ringtone?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + show: + page_title: 'Show ringtone' + audio: 'Audio' + bellcore_id: 'Bellcore ID' + actions: + confirm: 'Are you sure you want to delete this ringtone?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New ringtone' + edit: + page_title: 'Editing ringtone' + form: + audio: + label: 'Audio' + hint: '' + bellcore_id: + label: 'Bellcore ID' + hint: 'Build in ringtone ID. A "0" means silence.' + button: 'Submit' + set_a_ringtone: 'Set a ringtone' \ No newline at end of file diff --git a/config/locales/views/sessions/de.yml b/config/locales/views/sessions/de.yml new file mode 100644 index 0000000..4bc80e8 --- /dev/null +++ b/config/locales/views/sessions/de.yml @@ -0,0 +1,15 @@ +de: + sessions: + controller: + successfully_created: 'Sie sind jetzt als Benutzer "%{resource}" angemeldet.' + successfully_destroyed: 'Abgemeldet.' + new: + page_title: 'Anmeldung' + form: + email: 'E-Mail oder Benutzer-Name' + password: 'Passwort' + reset_password: 'Ich habe mein Passwort vergessen' + flash_messages: + invalid_email_or_password: 'Ungültige Anmeldedaten. Bitte versuchen Sie es noch einmal und achten Sie beim Passwort auf Groß- und Kleinschreibung.' + password_recovery_successful: 'Ein neues Passwort wurde an Ihre registrierte E-Mail-Addresse gesendet.' + password_recovery_failed: 'Fehler beim setzten des Passwortes.' diff --git a/config/locales/views/sessions/en.yml b/config/locales/views/sessions/en.yml new file mode 100644 index 0000000..51dcde7 --- /dev/null +++ b/config/locales/views/sessions/en.yml @@ -0,0 +1,15 @@ +en: + sessions: + controller: + successfully_created: 'Logged in as %{resource}.' + successfully_destroyed: 'Logged out.' + new: + page_title: 'Log In' + form: + email: 'E-Mail or Username' + password: 'Password' + reset_password: 'I forgot my password' + flash_messages: + invalid_email_or_password: 'Invalid e-mail or password. Please try again.' + password_recovery_successful: 'A new password has been sent to your registered email address' + password_recovery_failed: 'There was an error updating your password.' diff --git a/config/locales/views/sip_accounts/de.yml b/config/locales/views/sip_accounts/de.yml new file mode 100644 index 0000000..ad78a93 --- /dev/null +++ b/config/locales/views/sip_accounts/de.yml @@ -0,0 +1,83 @@ +de: + sip_accounts: + name: 'SIP-Konto' + controller: + successfuly_created: 'Ein SIP-Konto für %{resource} wurde erstellt.' + successfuly_updated: 'Das SIP-Konto wurde aktualisiert.' + successfuly_destroyed: 'Das SIP-Konto wurde gelöscht.' + index: + page_title: 'SIP-Konten' + auth_name: 'Auth Name' + caller_name: 'Caller Name' + password: 'Passwort' + voicemail_pin: 'Anrufbeantworter PIN' + phone_numbers: 'Telefonnummern' + call_waiting: 'Anklopfen' + clir: 'Rufnummernunterdrückung (CLIR)' + clip: 'Rufnummernanzeige (CLIP)' + hotdeskable: 'Hot-Desk fähig' + clip_no_screening: 'Spezifische Rufnummernanzeige (CLIP -no screening-)' + callforward_rules_act_per_sip_account: 'Rufweiterleitungen gelten für das gesamte SIP-Konto' + online: 'Online' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen SIP-Konto löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neues SIP-Konto für %{resource} anlegen' + show: + page_title: 'SIP-Konto anzeigen' + auth_name: 'Auth Name' + caller_name: 'Caller Name' + password: 'Passwort' + voicemail_pin: 'Anrufbeantworter PIN' + call_waiting: 'Anklopfen' + clir: 'Rufnummernunterdrückung (CLIR)' + clip: 'Rufnummernanzeige (CLIP)' + hotdeskable: 'Hot-Desk fähig' + clip_no_screening: 'Spezifische Rufnummernanzeige (CLIP -no screening-)' + callforward_rules_act_per_sip_account: 'Rufweiterleitungen gelten für das gesamte SIP-Konto' + registration: 'Registrierung' + expires: 'Läuft ab' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen SIP-Konto löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle SIP-Konten anzeigen' + new: + page_title: 'Neues SIP-Konto' + edit: + page_title: 'SIP-Konto bearbeiten' + form: + auth_name: + label: 'Auth Name' + hint: '' + caller_name: + label: 'Caller Name' + hint: '' + password: + label: 'Passwort' + hint: '' + voicemail_pin: + label: 'Anrufbeantworter PIN' + hint: '' + call_waiting: + label: 'Anklopfen' + hint: '' + clir: + label: 'Rufnummernunterdrückung (CLIR)' + hint: '' + clip: + label: 'Rufnummernanzeige (CLIP)' + hint: '' + clip_no_screening: + label: 'Spezifische Rufnummernanzeige (CLIP -no screening-)' + hint: '' + hotdeskable: + label: 'Hot-Desk fähig' + hint: '' + callforward_rules_act_per_sip_account: + label: 'Rufweiterleitungen gelten für das gesamte SIP-Konto' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/sip_accounts/en.yml b/config/locales/views/sip_accounts/en.yml new file mode 100644 index 0000000..c1d8613 --- /dev/null +++ b/config/locales/views/sip_accounts/en.yml @@ -0,0 +1,83 @@ +en: + sip_accounts: + name: 'SIP account' + controller: + successfuly_created: 'Successfully created a new SIP account for %{resource}.' + successfuly_updated: 'Successfully updated a SIP account.' + successfuly_destroyed: 'Successfully destroyed a SIP account.' + index: + page_title: 'SIP accounts' + auth_name: 'Auth name' + caller_name: 'Caller name' + password: 'Password' + voicemail_pin: 'Voicemail PIN' + phone_numbers: 'Phone numbers' + call_waiting: 'Call waiting' + clir: 'CLIR' + clip: 'CLIP' + hotdeskable: 'Hotdeskable' + clip_no_screening: 'CLIP -no screening-' + callforward_rules_act_per_sip_account: 'Callforwards work for the whole sip account' + online: 'Online' + actions: + confirm: 'Are you sure you want to delete this SIP account?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New SIP account for %{resource}' + show: + page_title: 'Show SIP account' + auth_name: 'Auth name' + caller_name: 'Caller name' + password: 'Password' + voicemail_pin: 'Voicemail PIN' + call_waiting: 'Call waiting' + clir: 'CLIR' + clip: 'CLIP' + hotdeskable: 'Hotdeskable' + clip_no_screening: 'CLIP -no screening-' + callforward_rules_act_per_sip_account: 'Callforwards work for the whole sip account' + registration: 'Registration' + expires: 'Expires' + actions: + confirm: 'Are you sure you want to delete this SIP account?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View all SIP accounts' + new: + page_title: 'New SIP account' + edit: + page_title: 'Editing SIP account' + form: + auth_name: + label: 'Auth name' + hint: '' + caller_name: + label: 'Caller name' + hint: '' + password: + label: 'Password' + hint: '' + voicemail_pin: + label: 'Voicemail PIN' + hint: '' + call_waiting: + label: 'Call waiting' + hint: '' + clir: + label: 'CLIR' + hint: 'Calling Line Identification Restriction. If set true no number will be transmitted.' + clip: + label: 'CLIP' + hint: 'Calling Line Identification Presentation.' + clip_no_screening: + label: 'CLIP -no screening-' + hint: 'Calling Line Identification Presentation. Leave blank if you are not sure.' + callforward_rules_act_per_sip_account: + label: 'Callforwards work for the whole sip account' + hint: '' + hotdeskable: + label: 'Hotdeskable' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/sip_domains/de.yml b/config/locales/views/sip_domains/de.yml new file mode 100644 index 0000000..447caa9 --- /dev/null +++ b/config/locales/views/sip_domains/de.yml @@ -0,0 +1,38 @@ +de: + sip_domains: + name: 'SIP-Domain' + controller: + successfuly_created: 'Eine SIP-Domain wurde im System gespeichert.' + successfuly_updated: 'Die SIP-Domain wurde aktualisiert.' + successfuly_destroyed: 'Die SIP-Domain wurde gelöscht.' + index: + page_title: 'SIP-Domains' + host: 'Host' + realm: 'Realm' + actions: + confirm: 'Sind Sie sicher, dass Sie diese SIP-Domain löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + show: + page_title: 'SIP-Domain bearbeiten' + host: 'Host' + realm: 'Realm' + actions: + confirm: 'Sind Sie sicher, dass Sie diese SIP-Domain löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle SIP-Domains anzeigen' + new: + page_title: 'Neue SIP-Domain' + edit: + page_title: 'SIP-Domain von %{resource} bearbeiten' + form: + host: + label: 'Host' + hint: '' + realm: + label: 'Realm' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/sip_domains/en.yml b/config/locales/views/sip_domains/en.yml new file mode 100644 index 0000000..bf62a60 --- /dev/null +++ b/config/locales/views/sip_domains/en.yml @@ -0,0 +1,38 @@ +en: + sip_domains: + name: 'SIP domain' + controller: + successfuly_created: 'Successfully created SIP domain.' + successfuly_updated: 'Successfully updated SIP domain.' + successfuly_destroyed: 'Successfully destroyed SIP domain.' + index: + page_title: 'SIP domains' + host: 'Host' + realm: 'Realm' + actions: + confirm: 'Are you sure you want to delete this SIP domain?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + show: + page_title: 'Editing SIP domain' + host: 'Host' + realm: 'Realm' + actions: + confirm: 'Are you sure you want to delete this SIP domain?' + destroy: 'Delete SIP domain' + edit: 'Edit SIP domain' + view_all: 'View all SIP domains' + new: + page_title: 'New SIP domain' + edit: + page_title: 'Editing SIP domain %{resource}' + form: + host: + label: 'Host' + hint: '' + realm: + label: 'Realm' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/softkeys/de.yml b/config/locales/views/softkeys/de.yml new file mode 100644 index 0000000..f5f8f26 --- /dev/null +++ b/config/locales/views/softkeys/de.yml @@ -0,0 +1,68 @@ +de: + softkeys: + functions: + speed_dial: 'Kurzwahl' + blf: 'Besetzt-Lampe' + dtmf: 'DTMF' + log_in: 'Anmelden' + log_out: 'Abmelden' + conference: 'Konferenz' + call_forwarding: 'Rufumleitung ein/aus' + hold: 'Halten' + hunt_group_membership: 'Rufgruppen-Mitgliedschaft' + deactivated: 'Deaktiviert' + acd_membership: 'Warteschleife' + name: 'Softkey' + controller: + successfuly_created: 'Ein neuer Softkey wurde erstellt.' + successfuly_updated: 'Der Softkey wurde aktualisiert.' + successfuly_destroyed: 'Der Softkey wurde gelöscht.' + index: + page_title: 'Tastenbelegungen' + phone_id: 'Telefon' + function: 'Funktion' + number: 'Nummer' + label: 'Beschriftung' + position: 'Position' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Softkey löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neuer Softkey' + create_for: 'Neuer Softkey für %{resource}' + show: + page_title: 'Softkey anzeigen' + phone_id: 'Telefon' + function: 'Funktion' + number: 'Nummer' + label: 'Beschriftung' + position: 'Position' + call_forward: 'Rufumleitung' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Softkey löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + new: + page_title: 'Neuer Softkey' + actions: + edit: + page_title: 'Softkey bearbeiten' + actions: + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + form: + function: + label: 'Funktion' + hint: '' + call_forward: + label: 'Rufumleitung' + hint: '' + number: + label: 'Nummer' + hint: '' + label: + label: 'Beschriftung' + hint: 'Je nach Telefonmodell gibt es die Möglichkeit eine Beschriftung bzw. eine Beschreibung auf dem Telefon anzuzeigen.' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/softkeys/en.yml b/config/locales/views/softkeys/en.yml new file mode 100644 index 0000000..e29e4c6 --- /dev/null +++ b/config/locales/views/softkeys/en.yml @@ -0,0 +1,64 @@ +en: + softkeys: + functions: + speed_dial: 'Speed Dial' + blf: 'BLF' + dtmf: 'DTMF' + log_in: 'Log in' + log_out: 'Log out' + conference: 'Conference' + call_forwarding: 'Toggle Call Forwarding' + hold: 'Hold' + hunt_group_membership: 'Hunt Group' + deactivated: 'Deactivated' + acd_membership: 'ACD' + name: 'Softkey' + controller: + successfuly_created: 'Successfully created softkeys.' + successfuly_updated: 'Successfully updated softkeys.' + successfuly_destroyed: 'Successfully destroyed softkeys.' + index: + page_title: 'Softkeys' + phone_id: 'Phone' + function: 'Function' + number: 'Number' + label: 'Label' + position: 'Position' + actions: + confirm: 'Are you sure you want to delete this softkey?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New softkey' + create_for: 'New softkey for %{resource}' + show: + page_title: 'Show softkey' + phone_id: 'Phone' + function: 'Function' + number: 'Number' + label: 'Label' + position: 'Position' + call_forward: 'Call forward' + actions: + confirm: 'Are you sure you want to delete this softkey?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New softkey' + edit: + page_title: 'Editing softkey' + form: + function: + label: 'Function' + hint: '' + call_forward: + label: 'Call forward' + hint: '' + number: + label: 'Number' + hint: '' + label: + label: 'Label' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/system_messages/de.yml b/config/locales/views/system_messages/de.yml new file mode 100644 index 0000000..9bdce48 --- /dev/null +++ b/config/locales/views/system_messages/de.yml @@ -0,0 +1,38 @@ +de: + system_messages: + name: 'Systemnachricht' + controller: + successfuly_created: 'Eine Systemnachricht wurde erstellt.' + successfuly_updated: 'Eine Systemnachricht wurde aktualisiert.' + successfuly_destroyed: 'Eine Systemnachricht wurde gelöscht.' + index: + page_title: 'Systemnachrichten' + user_id: 'Benutzer' + content: 'Nachricht' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Systemnachricht löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + show: + page_title: 'Systemnachricht anzeigen' + user_id: 'Benutzer' + content: 'Nachricht' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Systemnachricht löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + new: + page_title: 'Neue Systemnachricht' + edit: + page_title: 'Systemnachricht bezüglich %{resource} bearbeiten' + form: + user_id: + label: 'Benutzer' + hint: '' + content: + label: 'Nachricht' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/system_messages/en.yml b/config/locales/views/system_messages/en.yml new file mode 100644 index 0000000..05e0836 --- /dev/null +++ b/config/locales/views/system_messages/en.yml @@ -0,0 +1,38 @@ +en: + system_messages: + name: 'System message' + controller: + successfuly_created: 'Successfully created System message.' + successfuly_updated: 'Successfully updated System message.' + successfuly_destroyed: 'Successfully destroyed System message.' + index: + page_title: 'System messages' + user_id: 'User' + content: 'Content' + actions: + confirm: 'Are you sure you want to delete this element?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + show: + page_title: 'Editing System message' + user_id: 'User' + content: 'Content' + actions: + confirm: 'Are you sure you want to delete this element?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New System message' + edit: + page_title: 'Editing System message %{resource}' + form: + user_id: + label: 'User' + hint: '' + content: + label: 'Content' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/tenants/de.yml b/config/locales/views/tenants/de.yml new file mode 100644 index 0000000..66d9d0a --- /dev/null +++ b/config/locales/views/tenants/de.yml @@ -0,0 +1,73 @@ +de: + tenants: + name: "Mandant" + new_name_scaffold: 'Beispiel Firma Nr. %{counter} GmbH' + controller: + successfuly_created: 'Der Mandant "%{resource}" wurde angelegt.' + successfuly_created_plus_delayed_jobs: 'Der Mandant "%{resource}" wurde angelegt. %{amount_of_numbers} Durchwahlen und Telefonnummern werden jetzt im Hintergrund ins System gespielt. Dies kann je nach benutzter Hardware ein paar Minuten dauern. ' + successfuly_updated: 'Der Mandant wurde aktualisiert.' + successfuly_destroyed: 'Der Mandant wurde gelöscht.' + index: + page_title: 'Mandanten' + name: 'Name' + description: 'Beschreibung' + state: 'Status' + position: 'Position' + from_field_voicemail_email: 'Anrufbeantworter Absender' + from_field_pin_change_email: 'Neue PIN Absender' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Mandant löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neuen Mandanten anlegen' + show: + page_title: 'Mandant anzeigen' + name: 'Name' + description: 'Beschreibung' + state: 'Status' + position: 'Position' + from_field_voicemail_email: 'Anrufbeantworter Absender' + from_field_pin_change_email: 'Neue PIN Absender' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Mandant löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle Mandanten anzeigen' + new: + page_title: 'Neuen Mandant anlegen' + edit: + page_title: 'Mandant %{resource} bearbeiten' + form: + phone_numbers: 'Telefonnummern' + intro: 'Gemeinschaft verwaltet alle Durchwahlen und kann so sicher stellen, dass Nummern nicht doppelt vergeben werden. Dazu müssen Sie an dieser Stelle die möglichen Rufnummern definieren.' + name: + label: 'Name' + hint: '' + description: + label: 'Beschreibung' + hint: '' + country_id: + label: 'Land' + hint: '' + language_id: + label: 'Sprache' + hint: '' + sip_domain: + label: 'SIP-Domain' + hint: '' + from_field_voicemail_email: + label: 'Absender Sprachnachrichten' + hint: 'Absender für E-Mails mit Sprachnachrichten.' + from_field_pin_change_email: + label: 'Absender PIN Änderung' + hint: 'Absender für E-Mails bezüglich PIN Änderungen.' + internal_extension_ranges: + label: 'Interne Durchwahlen' + hint: 'Hier können Sie Rufnummernbereiche für die von Ihnen gewünschten internen Durchwahlen definieren (z.B. "10-99" für 2-stellige Durchwahlen, "10-20,50-85" oder "150-299").' + did_list: + label: 'Externe Rufnummern' + hint: 'Hier können Sie die Rufnummern eintragen, mit denen Sie vom Festnetz aus erreichbar sind. Sollten Sie nur eine Nummer haben, dann bitte diese eintragen. Sie können das x als Wildcard für die oben angegebenen Durchwahlen benutzen. Beispiele: "0228-12345x, 0228-123450" (ein typisches Beispiel für einen Anlagenanschluss mit 2-stelligen Durchwahlen), "0228-123456", "0228-123456,0228-123999"' + button: 'Absenden' + + switch_to_tenant: "Mandant wechseln" diff --git a/config/locales/views/tenants/en.yml b/config/locales/views/tenants/en.yml new file mode 100644 index 0000000..adbf45f --- /dev/null +++ b/config/locales/views/tenants/en.yml @@ -0,0 +1,73 @@ +en: + tenants: + name: "Tenant" + new_name_scaffold: 'Snake Oil #%{counter}, Ltd.' + controller: + successfuly_created: 'Successfully created the tenant "%{resource}".' + successfuly_created_plus_delayed_jobs: 'Successfully created the tenant "%{resource}". A total of %{amount_of_numbers} extensions and external numbers is being proccessed in the background. Depending on your hardware that can take a couple of minutes.' + successfuly_updated: 'Successfully updated tenant.' + successfuly_destroyed: 'Successfully destroyed tenant.' + index: + page_title: 'Tenants' + name: 'Name' + description: 'Description' + state: 'State' + position: 'Position' + from_field_voicemail_email: 'Voicemail sender' + from_field_pin_change_email: 'PIN change sender' + actions: + confirm: 'Are you sure you want to delete this tenant?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + show: + page_title: 'Show Tenant' + name: 'Name' + description: 'Description' + state: 'State' + position: 'Position' + from_field_voicemail_email: 'Voicemail sender' + from_field_pin_change_email: 'PIN change sender' + actions: + confirm: 'Are you sure you want to delete this tenant?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View all tenants' + new: + page_title: 'New Tenant' + edit: + page_title: 'Editing Tenant %{resource}' + form: + phone_numbers: 'Phone numbers' + intro: 'Gemeinschaft is strict with phone numbers. You need to define the range of available numbers.' + name: + label: 'Name' + hint: '' + description: + label: 'Description' + hint: '' + country_id: + label: 'Country' + hint: '' + language_id: + label: 'Language' + hint: '' + sip_domain: + label: 'SIP domain' + hint: '' + from_field_voicemail_email: + label: 'Voicemail sender' + hint: 'From field for e-mails with voicemails.' + from_field_pin_change_email: + label: 'PIN change sender' + hint: 'From field for e-mails about PIN changes.' + internal_extension_ranges: + label: 'Internal extensions' + hint: 'Define ranges (e.g. "10-99", "10-20,50-85" or "150-299").' + did_list: + label: 'External numbers' + hint: 'These are the phone numbers which can be called from the outside (seperated by commas). The x represents all internal extensions (can be added to a trunk number). You can mix MSNs and DIDs. Examples: "0228-12345x, 0228-123450" (this would be the solution for most companies), "0228-123456", "0228-123456,0228-123999"' + button: 'Submit' + + switch_to_tenant: "Switch to tenant" diff --git a/config/locales/views/user_group_memberships/de.yml b/config/locales/views/user_group_memberships/de.yml new file mode 100644 index 0000000..35dbac8 --- /dev/null +++ b/config/locales/views/user_group_memberships/de.yml @@ -0,0 +1,35 @@ +de: + user_group_memberships: + name: "Gruppenzugehörigkeit" + controller: + successfuly_created: 'Ein Benutzer wurde einer Gruppe zugeordnet.' + successfuly_updated: 'Die Gruppenzugehörigkeit wurde aktualisiert.' + successfuly_destroyed: 'Die Gruppenzugehörigkeit wurde gelöscht.' + no_more_user_to_add: 'Es gibt keine weiteren Benutzer, die dieser Gruppe zugeordnet werden können.' + index: + page_title: 'Gruppenzugehörigkeiten' + user: 'Benutzer' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Gruppenzugehörigkeit löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neue Gruppenzugehörigkeiten für %{resource}' + show: + page_title: 'Gruppenzugehörigkeiten anzeigen' + user: 'Benutzer' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Gruppenzugehörigkeit löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle Gruppenzugehörigkeitenen anzeigen' + new: + page_title: 'Neue Gruppenzugehörigkeit' + edit: + page_title: 'Gruppenzugehörigkeiten von "%{resource}" bearbeiten' + form: + name: + user: 'Benutzer' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/user_group_memberships/en.yml b/config/locales/views/user_group_memberships/en.yml new file mode 100644 index 0000000..d31a87a --- /dev/null +++ b/config/locales/views/user_group_memberships/en.yml @@ -0,0 +1,35 @@ +en: + user_group_memberships: + name: "User group membership" + controller: + successfuly_created: 'Successfully created user group membership.' + successfuly_updated: 'Successfully updated user group membership.' + successfuly_destroyed: 'Successfully destroyed user group membership.' + no_more_user_to_add: 'There are no more users to add to this user group.' + index: + page_title: 'User group memberships' + user: 'User' + actions: + confirm: 'Are you sure you want to delete this user group membership?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New user group membership for %{resource}' + show: + page_title: 'Show user group membership' + user: 'User' + actions: + confirm: 'Are you sure you want to delete this user group membership?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View all user group memberships' + new: + page_title: 'New user group membership' + edit: + page_title: 'Editing user group membership "%{resource}"' + form: + name: + user: 'User' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/user_groups/de.yml b/config/locales/views/user_groups/de.yml new file mode 100644 index 0000000..40b3da8 --- /dev/null +++ b/config/locales/views/user_groups/de.yml @@ -0,0 +1,42 @@ +de: + user_groups: + name: "Gruppe" + controller: + successfuly_created: 'Eine Gruppe wurde angelegt.' + successfuly_updated: 'Die Gruppe wurde aktualisiert.' + successfuly_destroyed: 'Die Gruppe wurde gelöscht.' + index: + page_title: 'Gruppen' + name: 'Name' + description: 'Beschreibung' + tenant_id: 'Mandant' + number_of_members: 'Benutzerzahl' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Gruppe löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neue Gruppe für %{resource} anlegen' + show: + page_title: 'Gruppe anzeigen' + name: 'Name' + description: 'Beschreibung' + tenant_id: 'Mandant' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Gruppe löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle Gruppen anzeigen' + new: + page_title: 'Neue Gruppe' + edit: + page_title: 'Gruppe "%{resource}" bearbeiten' + form: + name: + label: 'Name' + hint: '' + description: + label: 'Beschreibung' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/user_groups/en.yml b/config/locales/views/user_groups/en.yml new file mode 100644 index 0000000..a2db293 --- /dev/null +++ b/config/locales/views/user_groups/en.yml @@ -0,0 +1,42 @@ +en: + user_groups: + name: "User groups" + controller: + successfuly_created: 'Successfully created user group.' + successfuly_updated: 'Successfully updated user group.' + successfuly_destroyed: 'Successfully destroyed user group.' + index: + page_title: 'User groups' + name: 'Name' + description: 'Description' + tenant_id: 'Tenant' + number_of_members: 'Number of members' + actions: + confirm: 'Are you sure you want to delete this user group?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New user group for %{resource}' + show: + page_title: 'Show user group' + name: 'Name' + description: 'Description' + tenant_id: 'Tenant' + actions: + confirm: 'Are you sure you want to delete this user group?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View all user groups' + new: + page_title: 'New user group' + edit: + page_title: 'Editing user group "%{resource}"' + form: + name: + label: 'Name' + hint: '' + description: + label: 'Description' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/users/de.yml b/config/locales/views/users/de.yml new file mode 100644 index 0000000..951600d --- /dev/null +++ b/config/locales/views/users/de.yml @@ -0,0 +1,95 @@ +de: + users: + name: "Benutzer" + controller: + successfuly_created: 'Der Benutzer %{resource} wurde erstellt.' + successfuly_created_and_login: 'Der Benutzer %{resource} wurde erstellt. Sie sind jetzt als dieser Benutzer angemeldet.' + successfuly_updated: 'Benutzer-Daten aktualisiert.' + successfuly_destroyed: 'Der Benutzer wurde gelöscht.' + avatar_destroyed: 'Der Avatar wurde gelöscht.' + index: + page_title: 'Benutzer' + user_name: 'Benutzer-Name' + email: 'E-Mail Adresse' + first_name: 'Vorname' + middle_name: 'Zweiter Vorname' + last_name: 'Nachname' + male: 'männlich' + gemeinschaft_unique_id: 'Eindeutige Bezeichnung' + state: 'Status' + language_id: 'Sprache' + send_voicemail_as_email_attachment: 'Sprachnachrichten per E-Mail' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Benutzer löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neuen Benutzer anlegen' + create_for: 'Neuen Benutzer für %{resource} anlegen' + show: + page_title: 'Benutzer anzeigen' + user_name: 'Benutzer-Name' + email: 'E-Mail Adresse' + first_name: 'Vorname' + middle_name: 'Zweiter Vorname' + last_name: 'Nachname' + male: 'männlich' + gemeinschaft_unique_id: 'Eindeutige Bezeichnung' + state: 'Status' + language_id: 'Sprache' + send_voicemail_as_email_attachment: 'Sprachnachrichten per E-Mail' + actions: + confirm: 'Sind Sie sicher, dass Sie diesen Benutzer löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle Benutzer anzeigen' + new: + page_title: 'Neuen Benutzer anlegen' + edit: + page_title: 'Benutzer %{resource} bearbeiten' + form: + user_name: + label: 'Benutzer-Name' + hint: '' + email: + label: 'E-Mail Adresse' + hint: '' + password: + label: 'Passwort' + hint: 'Mit diesem Passwort können Sie sich später in dieser Web-Oberfläche anmelden.' + password_confirmation: + label: 'Wiederholung des Passwortes' + hint: '' + new_pin: + label: 'PIN' + hint: 'Mit dieser PIN können Sie sich in Hot-Desk Umgebungen am Telefon anmelden.' + new_pin_confirmation: + label: 'Wiederholung der PIN' + hint: '' + first_name: + label: 'Vorname' + hint: '' + middle_name: + label: 'Zweiter Vorname' + hint: '' + last_name: + label: 'Nachname' + hint: '' + gender: + label: 'Geschlecht' + hint: '' + male: "Männlich" + female: "Weiblich" + gemeinschaft_unique_id: + label: 'Eindeutige Bezeichnung' + hint: '' + image: + label: 'Avatar Foto' + hint: '' + language_id: + label: 'Sprache' + hint: '' + send_voicemail_as_email_attachment: + label: 'Sprachnachrichten per E-Mail verschicken' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/users/en.yml b/config/locales/views/users/en.yml new file mode 100644 index 0000000..317e616 --- /dev/null +++ b/config/locales/views/users/en.yml @@ -0,0 +1,95 @@ +en: + users: + name: "Users" + controller: + successfuly_created: 'Successfully created user %{resource}.' + successfuly_created_and_login: 'Successfully created user %{resource}. You are now logged in.' + successfuly_updated: 'Successfully updated user.' + successfuly_destroyed: 'Successfully destroyed user.' + avatar_destroyed: 'The avatar was deleted.' + index: + page_title: 'Users' + user_name: 'Username' + email: 'E-mail address' + first_name: 'First name' + middle_name: 'Middle name' + last_name: 'Last name' + male: 'Male' + gemeinschaft_unique_id: 'Unique identifier' + state: 'State' + language_id: 'Language' + send_voicemail_as_email_attachment: 'Send voicemails by e-mail' + actions: + confirm: 'Are you sure you want to delete this user?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'Create a new user' + create_for: 'Create a new user for %{resource}' + show: + page_title: 'Show User' + user_name: 'Username' + email: 'E-mail address' + first_name: 'First name' + middle_name: 'Middle name' + last_name: 'Last name' + male: 'Male' + gemeinschaft_unique_id: 'Unique identifier' + state: 'State' + language_id: 'Language' + send_voicemail_as_email_attachment: 'Send voicemails by e-mail' + actions: + confirm: 'Are you sure you want to delete this user?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View all users' + new: + page_title: 'New User' + edit: + page_title: 'Editing user %{resource}' + form: + user_name: + label: 'Username' + hint: '' + email: + label: 'E-mail address' + hint: '' + password: + label: 'Password' + hint: 'This password needs to be entered in the WebGUI.' + password_confirmation: + label: 'Password (confirmation)' + hint: '' + new_pin: + label: 'PIN' + hint: 'This PIN is needed in hotdesking environments to log into a phone.' + new_pin_confirmation: + label: 'PIN (confirmation)' + hint: '' + first_name: + label: 'First name' + hint: '' + middle_name: + label: 'Middle name' + hint: '' + last_name: + label: 'Last name' + hint: '' + gender: + label: 'Gender' + hint: '' + male: "Male" + female: "Female" + gemeinschaft_unique_id: + label: 'Unique identifier' + hint: '' + image: + label: 'Avatar photo' + hint: '' + language_id: + label: 'Language' + hint: '' + send_voicemail_as_email_attachment: + label: 'Send voicemails as e-mail attachments' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/locales/views/voicemail_messages/de.yml b/config/locales/views/voicemail_messages/de.yml new file mode 100644 index 0000000..61ee837 --- /dev/null +++ b/config/locales/views/voicemail_messages/de.yml @@ -0,0 +1,34 @@ +de: + voicemail_messages: + name: 'Sprachnachrichten' + controller: + successfuly_destroyed: 'Die Nachricht wurde gelöscht.' + index: + page_title: 'Nachrichten' + page_title_read: 'Gelesene Nachrichten' + page_title_unread: 'Ungelesene Nachrichten' + date_format: '%d.%m.%Y %H:%M' + date_today_format: '%H:%M' + navigation: + read: 'Gelesen: %{count}' + unread: 'Ungelesen: %{count}' + all: 'Alle: %{count}' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Nachricht löschen möchten?' + confirm_selected: 'Sind Sie sicher, dass Sie die markierten Nachrichten löschen möchten?' + destroy: 'Löschen' + destroy_multiple: 'Markierte Nachrichten löschen' + call: 'Anrufen' + mark_read: 'gelesen' + mark_unread: 'ungelesen' + mailbox: + inbox: 'Eingang' + flags: + save: 'Gespeichert' + call_results: + UNSPECIFIED: '' + ORIGINATOR_CANCEL: 'Abgebrochen' + UNALLOCATED_NUMBER: 'Rufnummer nicht bekannt' + NO_USER_RESPONSE: 'Keine Antwort' + NOANSWER: 'Keine Antwort' + USER_NOT_REGISTERED: 'Offline' diff --git a/config/locales/views/voicemail_messages/en.yml b/config/locales/views/voicemail_messages/en.yml new file mode 100644 index 0000000..3c02b6d --- /dev/null +++ b/config/locales/views/voicemail_messages/en.yml @@ -0,0 +1,35 @@ +en: + voicemail_messages: + name: 'Voicemail Messages' + controller: + successfuly_destroyed: 'Successfully destroyed voicemail message.' + index: + page_title: 'Messages' + page_title_read: 'Read Messages' + page_title_unread: 'Unread Messages' + date_format: '%m/%d/%Y %H:%M' + date_today_format: '%H:%M' + navigation: + read: 'Read: %{count}' + unread: 'Unread: %{count}' + all: 'All: %{count}' + actions: + confirm: 'Are you sure you want to delete this message?' + confirm_selected: 'Are you sure you want to delete all selected messages?' + destroy: 'Delete' + destroy_multiple: 'Delete selected messages' + call: 'Call' + mark_read: 'Mark read' + mark_unread: 'Mark unread' + mailbox: + inbox: 'Inbox' + flags: + save: 'Saved' + call_results: + UNSPECIFIED: '' + ORIGINATOR_CANCEL: 'Cancelled' + UNALLOCATED_NUMBER: 'Unallocated number' + NO_USER_RESPONSE: 'No user response' + NOANSWER: 'No answer' + USER_NOT_REGISTERED: 'Offline' + \ No newline at end of file diff --git a/config/locales/views/voicemail_settings/de.yml b/config/locales/views/voicemail_settings/de.yml new file mode 100644 index 0000000..184fcac --- /dev/null +++ b/config/locales/views/voicemail_settings/de.yml @@ -0,0 +1,52 @@ +de: + voicemail_settings: + name: 'Anrufbeantworter Einstellungen' + controller: + successfuly_destroyed: 'Einstellungen wurden gelöscht.' + successfuly_created: 'Einstellungen wurden erstellt.' + successfuly_updated: 'Einstellungen wurden aktuallisiert.' + index: + page_title: 'Anrufbeantworter Einstellungen' + actions: + confirm: 'Sind Sie sicher, dass Sie die Einstellungen löschen möchten?' + destroy: 'Löschen' + show: + page_title: 'Anrufbeantworter Einstellungen' + greeting_path: 'Begrüßung' + name_path: 'Name' + flags: 'Flags' + notify: 'Benachrichtigung' + attachment: 'Datei anfügen' + mark_read: 'Als gelesen markieren' + purge: 'Löschen' + actions: + confirm: 'Sind Sie sicher, dass Sie die Einstellungen löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + new: + page_title: 'Anrufbeantworter Einstellungen' + edit: + page_title: 'Anrufbeantworter Einstellungen' + form: + greeting: + label: 'Begrüßung' + hint: '' + name: + label: 'Name' + hint: '' + pin: + label: 'Anrufbeantworter PIN' + hint: '' + notify: + label: 'Benachrichtigung' + hint: 'Benachrichtigung per E-Mail' + attachment: + label: 'Datei anfügen' + hint: 'Datei an E-Mail anfügen' + mark_read: + label: 'Als gelesen markieren' + hint: 'Markieren als gelesen' + purge: + label: 'Löschen' + hint: 'Nachricht löschen' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/voicemail_settings/en.yml b/config/locales/views/voicemail_settings/en.yml new file mode 100644 index 0000000..ddade59 --- /dev/null +++ b/config/locales/views/voicemail_settings/en.yml @@ -0,0 +1,52 @@ +en: + voicemail_settings: + name: 'Voicemail Settings' + controller: + successfuly_destroyed: 'Successfully destroyed voicemail settings.' + successfuly_created: 'Successfully created voicemail settings.' + successfuly_updated: 'Successfully updated voicemail settings.' + index: + page_title: 'Voicemail Settings' + actions: + confirm: 'Are you sure you want to delete voicemail settings?' + destroy: 'Delete' + show: + page_title: 'Voicemail Settings' + greeting_path: 'Greeting' + name_path: 'Name' + flags: 'Flags' + notify: 'Notify by email' + attachment: 'Attach file' + mark_read: 'Mark read' + purge: 'Delete' + actions: + confirm: 'Are you sure you want to delete voicemail settings?' + destroy: 'Delete' + edit: 'Edit' + new: + page_title: 'Voicemail Settings' + edit: + page_title: 'Voicemail Settings' + form: + greeting: + label: 'Greeting' + hint: 'Voicemail greeting' + name: + label: 'Name' + hint: 'Voicemail name' + pin: + label: 'Voicemail PIN' + hint: 'Voicemail PIN' + notify: + label: 'Notify by email' + hint: 'Notify user by email' + attachment: + label: 'Attach file' + hint: 'Attach file to notification email' + mark_read: + label: 'Mark read' + hint: 'Mark message read after notification is sent' + purge: + label: 'Delete' + hint: 'Delete message after notification is sent' + button: 'Submit' diff --git a/config/locales/views/whitelists/de.yml b/config/locales/views/whitelists/de.yml new file mode 100644 index 0000000..7710de6 --- /dev/null +++ b/config/locales/views/whitelists/de.yml @@ -0,0 +1,38 @@ +de: + whitelists: + name: 'Positivliste' + controller: + successfuly_created: 'Eine Positivliste wurde erstellt.' + successfuly_updated: 'Die Positivliste wurde aktualisiert.' + successfuly_destroyed: 'Die Positivliste wurde gelöscht.' + index: + page_title: 'Positivlisten' + name: 'Name' + phone_numbers: 'Telefonnummern' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Positivliste löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Neue Positivliste für %{resource} anlegen' + show: + page_title: 'Positivliste anzeigen' + name: 'Name' + actions: + confirm: 'Sind Sie sicher, dass Sie diese Positivliste löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + new: + page_title: 'Neue Positivliste' + edit: + page_title: 'Positivliste bearbeiten' + form: + name: + label: 'Name' + hint: '' + phone_numbers: + label: 'Telefonnummern' + hint: '' + button: 'Absenden' \ No newline at end of file diff --git a/config/locales/views/whitelists/en.yml b/config/locales/views/whitelists/en.yml new file mode 100644 index 0000000..d681153 --- /dev/null +++ b/config/locales/views/whitelists/en.yml @@ -0,0 +1,38 @@ +en: + whitelists: + name: 'Whitelist' + controller: + successfuly_created: 'Successfully created whitelist.' + successfuly_updated: 'Successfully updated whitelist.' + successfuly_destroyed: 'Successfully destroyed whitelist.' + index: + page_title: 'Whitelists' + name: 'Name' + phone_numbers: 'Phone numbers' + actions: + confirm: 'Are you sure you want to delete this whitelist?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New whitelist for %{resource}' + show: + page_title: 'Show whitelist' + name: 'Name' + actions: + confirm: 'Are you sure you want to delete this whitelist?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New whitelist' + edit: + page_title: 'Editing whitelist' + form: + name: + label: 'Name' + hint: '' + phone_numbers: + label: 'Phone numbers' + hint: '' + button: 'Submit' \ No newline at end of file diff --git a/config/private_pub.yml b/config/private_pub.yml new file mode 100644 index 0000000..19a7e9e --- /dev/null +++ b/config/private_pub.yml @@ -0,0 +1,10 @@ +development: + server: "http://localhost:9292/faye" + secret_token: "secret" +test: + server: "http://localhost:9292/faye" + secret_token: "secret" +production: + server: "http://example.com/faye" + secret_token: "ade2c51226bf26e7fbbce1e0d8848082b750d23516b46dc5bc12e910e0e64558" + signature_expiration: 3600 # one hour diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..64d64cf --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,375 @@ +Gemeinschaft42c::Application.routes.draw do + resources :automatic_call_distributors + + resources :gs_cluster_sync_log_entries + + resources :gs_nodes do + member do + get 'sync' + end + end + + resources :gui_functions + + namespace :api do + resources :rows + end + + resources :acd_agents, :only => [] do + resources :phone_numbers do + member do + put 'move_higher' + put 'move_lower' + end + end + end + + resources :automatic_call_distributors, :only => [] do + resources :acd_agents + resources :phone_numbers do + member do + put 'move_higher' + put 'move_lower' + end + end + end + + resources :hunt_group_members, :only => [] do + resources :phone_numbers do + member do + put 'move_higher' + put 'move_lower' + end + end + end + + resources :hunt_groups, :only => [] do + resources :hunt_group_members + resources :phone_numbers do + member do + put 'move_higher' + put 'move_lower' + end + end + end + + if CALLTHROUGH_HAS_WHITELISTS == true + resources :whitelists, :only => [] do + resources :phone_numbers do + member do + put 'move_higher' + put 'move_lower' + end + end + end + end + + resources :access_authorizations, :only => [] do + resources :phone_numbers do + member do + put 'move_higher' + put 'move_lower' + end + end + end + + resources :fax_documents + + resources :fax_accounts, :only => [] do + resources :fax_documents + resources :phone_numbers do + member do + put 'move_higher' + put 'move_lower' + end + end + end + + resources :gemeinschaft_setups, :only => [:new, :create] + + resources :phone_number_ranges, :only => [] do + resources :phone_numbers do + member do + put 'move_higher' + put 'move_lower' + end + end + end + + resources :conferences, :only => [] do + resources :conference_invitees + resources :phone_numbers do + member do + put 'move_higher' + put 'move_lower' + end + end + end + + resources :phone_numbers, :only => [] do + resources :call_forwards + resources :ringtones + end + + resources :addresses + + resources :sip_domains + + resources :manufacturers do + resources :phone_models + end + + # Log-in / log-out / sign-up: + get "log_in" => "sessions#new" , :as => "log_in" + get "log_out" => "sessions#destroy" , :as => "log_out" + get "sign_up" => "users#new" , :as => "sign_up" + get "login" => "sessions#new" , :as => "log_in" + get "logout" => "sessions#destroy" , :as => "log_out" + get "signup" => "users#new" , :as => "sign_up" + + # Provisioning: + # Snom + get "config_snom/:phone/:sip_account/idle_screen" => "config_snom#idle_screen" + get "config_snom/:phone/:sip_account/log_in" => "config_snom#log_in" + get "config_snom/:phone/:sip_account/phone_book" => "config_snom#phone_book" + get "config_snom/:phone/:sip_account/call_history" => "config_snom#call_history" + get "config_snom/:phone/:sip_account/call_history_:type" => "config_snom#call_history" + get "config_snom/:phone/:sip_account/call_forwarding" => "config_snom#call_forwarding" + get "config_snom/exit" => "config_snom#exit" + get "config_snom/:phone/exit" => "config_snom#exit" + get "config_snom/:phone/:sip_account/exit" => "config_snom#exit" + get "config_snom/:phone/:sip_account/hunt_group" => "config_snom#hunt_group" + get "config_snom/:phone/state_settings" => "config_snom#state_settings" + get "config_snom/:phone/log_out" => "config_snom#log_out" + get "config_snom/:phone/:sip_account/log_out" => "config_snom#log_out" + get "config_snom/:phone/log_in" => "config_snom#log_in" + get "config_snom/:phone/:sip_account/log_in" => "config_snom#log_in" + get "config_snom/:phone/:sip_account/acd" => "config_snom#acd" + + # Siemens + get "config_siemens/:phone/call_history" => "config_siemens#call_history" + get "config_siemens/:phone/:sip_account/call_history" => "config_siemens#call_history" + get "config_siemens/:phone/:sip_account/call_forwarding" => "config_siemens#call_forwarding" + get "config_siemens/:phone/hunt_group" => "config_siemens#hunt_group" + get "config_siemens/:phone/:sip_account/hunt_group" => "config_siemens#hunt_group" + get "config_siemens/:phone/menu" => "config_siemens#menu" + get "config_siemens/:phone/:sip_account/menu" => "config_siemens#menu" + + #Polycom + get "config_polycom/:phone/:sip_account/phone_book" => "config_polycom#phone_book" + get "config_polycom/:phone/:sip_account/call_history" => "config_polycom#call_history" + get "config_polycom/:phone/:sip_account/idle_screen" => "config_polycom#idle_screen" + + # Unified path for Snom phones. + # Enter e.g. "http://192.168.1.105:3000/settings" + # as the Setting URL (Advanced -> Update). + match 'snom-:provisioning_key' => 'config_snom#show', + :via => [:get], + :format => 'xml' + match 'settings-:mac_address' => 'config_snom#show', + :constraints => { :mac_address => /000413[0-9A-F]{6}/i }, + :via => [:get], + :format => 'xml' + match "/DeploymentService/LoginService" => 'config_siemens#index', + :via => [:post], + :format => 'xml' + match ':mac_address.cfg' => 'config_polycom#config_files', + :constraints => { :mac_address => /0004f2[0-9A-F]{6}/i }, + :via => [:get], + :format => 'xml' + match 'settings-:mac_address.cfg' => 'config_polycom#settings', + :constraints => { :mac_address => /0004f2[0-9A-F]{6}/i }, + :via => [:get], + :format => 'xml' + match ':mac_address-directory' => 'config_polycom#settings_directory', + :constraints => { :mac_address => /0004f2[0-9A-F]{6}/i }, + :via => [:get], + :format => 'xml' + + # Snom default path. + # e.g. "/snom360-000413000000.htm" + # Enter e.g. "http://192.168.1.105:3000" + # as the Setting URL (Advanced -> Update). + match 'snom:model-:mac_address' => 'config_snom#show', + :constraints => { :mac_address => /000413[0-9A-F]{6}/i, :model => /[0-9]{3}/ }, + :via => [:get], + :format => 'xml' + + resources :sessions + + get "page/index" + get "page/conference" + + root :to => "page#index" + + get "wizards/new_initial_setup" + post "wizards/create_initial_setup" + + resources :users do + # Display all phone books that the current user owns: + resources :phone_books + resources :user_groups, :only => [ :index, :show ] + resources :sip_accounts + resources :phones + resources :conferences + resources :fax_accounts + resources :system_messages, :except => [ :edit, :update, :destroy ] + end + + resources :user_groups do + # Display all phone books that the group of the current user owns: + resources :phone_books + resources :sip_accounts + resources :fax_accounts + resources :user_group_memberships + end + + resources :tenants do + # Display all phone books that the tenant of the current user owns: + resources :phone_books + resources :users do + get "destroy_avatar" + end + resources :user_groups + resources :sip_accounts + resources :phones + resources :conferences + resources :phone_number_ranges + resources :callthroughs + if CALLTHROUGH_HAS_WHITELISTS == true + resources :whitelists + end + resources :hunt_groups + resources :automatic_call_distributors + end + + resources :callthroughs, :only => [] do + resources :access_authorizations + resources :phone_numbers do + member do + put 'move_higher' + put 'move_lower' + end + end + if CALLTHROUGH_HAS_WHITELISTS == true + resources :whitelists + end + end + + resources :sip_accounts, :only => [] do + resources :phones_sip_accounts + resources :phone_numbers do + member do + put 'move_higher' + put 'move_lower' + end + end + resources :softkeys do + member do + put 'move_higher' + put 'move_lower' + end + end + resources :call_histories do + collection do + delete 'destroy_multiple' + end + member do + put 'call' + end + end + resources :voicemail_messages do + collection do + delete 'destroy_multiple' + end + member do + put 'call' + put 'mark_read' + put 'mark_unread' + end + end + resources :voicemail_settings + end + + resources :phones, :only => [] do + resources :phone_sip_accounts + end + + # Display all phone book entries that the current user can access: + resources :phone_book_entries, :only => [ :index, :show ] do + resources :phone_numbers do + member do + put 'move_higher' + put 'move_lower' + end + end + end + + # Display all phone books that the current user can access: + resources :phone_books, :only => [ :index, :show ] do + resources :phone_book_entries + end + + # Search + post "search" => "phone_book_entries#index", :as => 'search' + + # http://0.0.0.0:3000/phone_books/3?name=Wintermeyer + + + # The priority is based upon order of creation: + # first created -> highest priority. + + # Sample of regular route: + # match 'products/:id' => 'catalog#view' + # Keep in mind you can assign values other than :controller and :action + + # Sample of named route: + # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase + # This route can be invoked with purchase_url(:id => product.id) + + # Sample resource route (maps HTTP verbs to controller actions automatically): + # resources :products + + # Sample resource route with options: + # resources :products do + # member do + # get 'short' + # post 'toggle' + # end + # + # collection do + # get 'sold' + # end + # end + + # Sample resource route with sub-resources: + # resources :products do + # resources :comments, :sales + # resource :seller + # end + + # Sample resource route with more complex sub-resources + # resources :products do + # resources :comments + # resources :sales do + # get 'recent', :on => :collection + # end + # end + + # Sample resource route within a namespace: + # namespace :admin do + # # Directs /admin/products/* to Admin::ProductsController + # # (app/controllers/admin/products_controller.rb) + # resources :products + # end + + # You can have the root of your site routed with "root" + # just remember to delete public/index.html. + # root :to => 'welcome#index' + + # See how all your routes lay out with "rake routes" + + # This is a legacy wild controller route that's not recommended for RESTful applications. + # Note: This route will make all actions in every controller accessible via GET requests. + # match ':controller(/:action(/:id(.:format)))' +end diff --git a/db/migrate/20111006073436_create_tenants.rb b/db/migrate/20111006073436_create_tenants.rb new file mode 100644 index 0000000..290379c --- /dev/null +++ b/db/migrate/20111006073436_create_tenants.rb @@ -0,0 +1,15 @@ +class CreateTenants < ActiveRecord::Migration + def self.up + create_table :tenants do |t| + t.string :name + t.text :description + t.string :state + t.integer :position + t.timestamps + end + end + + def self.down + drop_table :tenants + end +end diff --git a/db/migrate/20111006074623_create_users.rb b/db/migrate/20111006074623_create_users.rb new file mode 100644 index 0000000..dab37c5 --- /dev/null +++ b/db/migrate/20111006074623_create_users.rb @@ -0,0 +1,20 @@ +class CreateUsers < ActiveRecord::Migration + def self.up + create_table :users do |t| + t.string :user_name + t.string :email + t.string :password_digest + t.string :first_name + t.string :middle_name + t.string :last_name + t.boolean :male + t.string :gemeinschaft_unique_id + t.string :state + t.timestamps + end + end + + def self.down + drop_table :users + end +end diff --git a/db/migrate/20111006081257_create_tenant_memberships.rb b/db/migrate/20111006081257_create_tenant_memberships.rb new file mode 100644 index 0000000..d65d82b --- /dev/null +++ b/db/migrate/20111006081257_create_tenant_memberships.rb @@ -0,0 +1,12 @@ +class CreateTenantMemberships < ActiveRecord::Migration + def change + create_table :tenant_memberships do |t| + t.integer :tenant_id + t.integer :user_id + t.string :state + t.integer :position + + t.timestamps + end + end +end diff --git a/db/migrate/20111006081936_create_user_groups.rb b/db/migrate/20111006081936_create_user_groups.rb new file mode 100644 index 0000000..611102d --- /dev/null +++ b/db/migrate/20111006081936_create_user_groups.rb @@ -0,0 +1,15 @@ +class CreateUserGroups < ActiveRecord::Migration + def self.up + create_table :user_groups do |t| + t.string :name + t.text :description + t.integer :tenant_id + t.integer :position + t.timestamps + end + end + + def self.down + drop_table :user_groups + end +end diff --git a/db/migrate/20111006082944_create_user_group_memberships.rb b/db/migrate/20111006082944_create_user_group_memberships.rb new file mode 100644 index 0000000..de4d207 --- /dev/null +++ b/db/migrate/20111006082944_create_user_group_memberships.rb @@ -0,0 +1,11 @@ +class CreateUserGroupMemberships < ActiveRecord::Migration + def change + create_table :user_group_memberships do |t| + t.integer :user_group_id + t.integer :user_id + t.string :state + + t.timestamps + end + end +end diff --git a/db/migrate/20111006082945_create_phone_books.rb b/db/migrate/20111006082945_create_phone_books.rb new file mode 100644 index 0000000..7a4e967 --- /dev/null +++ b/db/migrate/20111006082945_create_phone_books.rb @@ -0,0 +1,17 @@ +class CreatePhoneBooks < ActiveRecord::Migration + def self.up + create_table :phone_books do |t| + t.string :name + t.string :description + t.integer :phone_bookable_id + t.string :phone_bookable_type + t.string :state + t.integer :position + t.timestamps + end + end + + def self.down + drop_table :phone_books + end +end diff --git a/db/migrate/20111006101543_create_phone_book_entries.rb b/db/migrate/20111006101543_create_phone_book_entries.rb new file mode 100644 index 0000000..fab48b3 --- /dev/null +++ b/db/migrate/20111006101543_create_phone_book_entries.rb @@ -0,0 +1,35 @@ +class CreatePhoneBookEntries < ActiveRecord::Migration + def self.up + create_table :phone_book_entries do |t| + t.integer :phone_book_id + t.string :first_name + t.string :middle_name + t.string :last_name + t.string :title + t.string :nickname + t.string :organization + t.boolean :is_organization + t.string :department + t.string :job_title + t.boolean :is_male + t.date :birthday + t.string :birth_name + t.string :state + t.text :description + t.integer :position + t.string :homepage_personal + t.string :homepage_organization + t.string :twitter_account + t.string :facebook_account + t.string :google_plus_account + t.string :xing_account + t.string :linkedin_account + t.string :mobileme_account + t.timestamps + end + end + + def self.down + drop_table :phone_book_entries + end +end diff --git a/db/migrate/20111007084820_add_image_to_user.rb b/db/migrate/20111007084820_add_image_to_user.rb new file mode 100644 index 0000000..ca32b2b --- /dev/null +++ b/db/migrate/20111007084820_add_image_to_user.rb @@ -0,0 +1,5 @@ +class AddImageToUser < ActiveRecord::Migration + def change + add_column :users, :image, :string + end +end diff --git a/db/migrate/20111007092546_add_image_to_phone_book_entry.rb b/db/migrate/20111007092546_add_image_to_phone_book_entry.rb new file mode 100644 index 0000000..f4ae09e --- /dev/null +++ b/db/migrate/20111007092546_add_image_to_phone_book_entry.rb @@ -0,0 +1,5 @@ +class AddImageToPhoneBookEntry < ActiveRecord::Migration + def change + add_column :phone_book_entries, :image, :string + end +end diff --git a/db/migrate/20111007110029_remove_position_from_phone_book.rb b/db/migrate/20111007110029_remove_position_from_phone_book.rb new file mode 100644 index 0000000..401a273 --- /dev/null +++ b/db/migrate/20111007110029_remove_position_from_phone_book.rb @@ -0,0 +1,9 @@ +class RemovePositionFromPhoneBook < ActiveRecord::Migration + def up + remove_column :phone_books, :position + end + + def down + add_column :phone_books, :position, :integer + end +end diff --git a/db/migrate/20111007110258_remove_position_from_tenant.rb b/db/migrate/20111007110258_remove_position_from_tenant.rb new file mode 100644 index 0000000..1415114 --- /dev/null +++ b/db/migrate/20111007110258_remove_position_from_tenant.rb @@ -0,0 +1,9 @@ +class RemovePositionFromTenant < ActiveRecord::Migration + def up + remove_column :tenants, :position + end + + def down + add_column :tenants, :position, :integer + end +end diff --git a/db/migrate/20111007123901_remove_position_from_tenant_membership.rb b/db/migrate/20111007123901_remove_position_from_tenant_membership.rb new file mode 100644 index 0000000..03e380a --- /dev/null +++ b/db/migrate/20111007123901_remove_position_from_tenant_membership.rb @@ -0,0 +1,9 @@ +class RemovePositionFromTenantMembership < ActiveRecord::Migration + def up + remove_column :tenant_memberships, :position + end + + def down + add_column :tenant_memberships, :position, :integer + end +end diff --git a/db/migrate/20111008112922_add_current_tenant_id_to_users.rb b/db/migrate/20111008112922_add_current_tenant_id_to_users.rb new file mode 100644 index 0000000..ff0d78b --- /dev/null +++ b/db/migrate/20111008112922_add_current_tenant_id_to_users.rb @@ -0,0 +1,5 @@ +class AddCurrentTenantIdToUsers < ActiveRecord::Migration + def change + add_column :users, :current_tenant_id, :integer + end +end diff --git a/db/migrate/20111009184013_add_sessions_table.rb b/db/migrate/20111009184013_add_sessions_table.rb new file mode 100644 index 0000000..fd942cc --- /dev/null +++ b/db/migrate/20111009184013_add_sessions_table.rb @@ -0,0 +1,16 @@ +class AddSessionsTable < ActiveRecord::Migration + def up + create_table :sessions do |t| + t.string :session_id, :null => false + t.text :data + t.timestamps + end + + add_index :sessions, :session_id + add_index :sessions, :updated_at + end + + def down + drop_table :sessions + end +end diff --git a/db/migrate/20111009202027_create_phone_numbers.rb b/db/migrate/20111009202027_create_phone_numbers.rb new file mode 100644 index 0000000..a7d15b4 --- /dev/null +++ b/db/migrate/20111009202027_create_phone_numbers.rb @@ -0,0 +1,19 @@ +class CreatePhoneNumbers < ActiveRecord::Migration + def self.up + create_table :phone_numbers do |t| + t.integer :phone_book_id + t.string :name + t.string :number + t.string :country_code + t.string :area_code + t.string :subscriber_number + t.string :extension + t.integer :position + t.timestamps + end + end + + def self.down + drop_table :phone_numbers + end +end diff --git a/db/migrate/20111009202500_create_countries.rb b/db/migrate/20111009202500_create_countries.rb new file mode 100644 index 0000000..d22fb42 --- /dev/null +++ b/db/migrate/20111009202500_create_countries.rb @@ -0,0 +1,12 @@ +class CreateCountries < ActiveRecord::Migration + def change + create_table :countries do |t| + t.string :name + t.string :country_code + t.string :international_call_prefix + t.string :trunk_prefix + + t.timestamps + end + end +end diff --git a/db/migrate/20111009202910_create_area_codes.rb b/db/migrate/20111009202910_create_area_codes.rb new file mode 100644 index 0000000..7719bd9 --- /dev/null +++ b/db/migrate/20111009202910_create_area_codes.rb @@ -0,0 +1,11 @@ +class CreateAreaCodes < ActiveRecord::Migration + def change + create_table :area_codes do |t| + t.integer :country_id + t.string :name + t.string :area_code + + t.timestamps + end + end +end diff --git a/db/migrate/20111009203233_add_country_id_to_tenant.rb b/db/migrate/20111009203233_add_country_id_to_tenant.rb new file mode 100644 index 0000000..9ba0288 --- /dev/null +++ b/db/migrate/20111009203233_add_country_id_to_tenant.rb @@ -0,0 +1,5 @@ +class AddCountryIdToTenant < ActiveRecord::Migration + def change + add_column :tenants, :country_id, :integer + end +end diff --git a/db/migrate/20111010110232_add_phone_book_entry_id_to_phone_number.rb b/db/migrate/20111010110232_add_phone_book_entry_id_to_phone_number.rb new file mode 100644 index 0000000..f9efda7 --- /dev/null +++ b/db/migrate/20111010110232_add_phone_book_entry_id_to_phone_number.rb @@ -0,0 +1,6 @@ +class AddPhoneBookEntryIdToPhoneNumber < ActiveRecord::Migration + def change + remove_column :phone_numbers, :phone_book_id + add_column :phone_numbers, :phone_book_entry_id, :integer + end +end diff --git a/db/migrate/20111011080014_add_central_office_code_to_phone_number.rb b/db/migrate/20111011080014_add_central_office_code_to_phone_number.rb new file mode 100644 index 0000000..4a15b82 --- /dev/null +++ b/db/migrate/20111011080014_add_central_office_code_to_phone_number.rb @@ -0,0 +1,5 @@ +class AddCentralOfficeCodeToPhoneNumber < ActiveRecord::Migration + def change + add_column :phone_numbers, :central_office_code, :string + end +end diff --git a/db/migrate/20111011181421_add_central_office_code_to_area_code.rb b/db/migrate/20111011181421_add_central_office_code_to_area_code.rb new file mode 100644 index 0000000..b5d0d12 --- /dev/null +++ b/db/migrate/20111011181421_add_central_office_code_to_area_code.rb @@ -0,0 +1,5 @@ +class AddCentralOfficeCodeToAreaCode < ActiveRecord::Migration + def change + add_column :area_codes, :central_office_code, :string + end +end diff --git a/db/migrate/20111012113547_create_ouis.rb b/db/migrate/20111012113547_create_ouis.rb new file mode 100644 index 0000000..ad81508 --- /dev/null +++ b/db/migrate/20111012113547_create_ouis.rb @@ -0,0 +1,11 @@ +class CreateOuis < ActiveRecord::Migration + def change + create_table :ouis do |t| + t.integer :manufacturer_id + t.string :value + t.string :state + + t.timestamps + end + end +end diff --git a/db/migrate/20111012121851_create_manufacturers.rb b/db/migrate/20111012121851_create_manufacturers.rb new file mode 100644 index 0000000..0f8b132 --- /dev/null +++ b/db/migrate/20111012121851_create_manufacturers.rb @@ -0,0 +1,15 @@ +class CreateManufacturers < ActiveRecord::Migration + def self.up + create_table :manufacturers do |t| + t.string :name + t.string :ieee_name + t.string :homepage_url + t.string :state + t.timestamps + end + end + + def self.down + drop_table :manufacturers + end +end diff --git a/db/migrate/20111012131652_create_phones.rb b/db/migrate/20111012131652_create_phones.rb new file mode 100644 index 0000000..96d88f7 --- /dev/null +++ b/db/migrate/20111012131652_create_phones.rb @@ -0,0 +1,17 @@ +class CreatePhones < ActiveRecord::Migration + def self.up + create_table :phones do |t| + t.string :mac_address + t.integer :phone_model_id + t.string :ip_address + t.string :last_ip_address + t.string :http_user + t.string :http_password + t.timestamps + end + end + + def self.down + drop_table :phones + end +end diff --git a/db/migrate/20111012142952_add_state_to_phone.rb b/db/migrate/20111012142952_add_state_to_phone.rb new file mode 100644 index 0000000..c5601d9 --- /dev/null +++ b/db/migrate/20111012142952_add_state_to_phone.rb @@ -0,0 +1,5 @@ +class AddStateToPhone < ActiveRecord::Migration + def change + add_column :phones, :state, :string + end +end diff --git a/db/migrate/20111012143922_create_phone_models.rb b/db/migrate/20111012143922_create_phone_models.rb new file mode 100644 index 0000000..50221c0 --- /dev/null +++ b/db/migrate/20111012143922_create_phone_models.rb @@ -0,0 +1,15 @@ +class CreatePhoneModels < ActiveRecord::Migration + def self.up + create_table :phone_models do |t| + t.string :name + t.string :manufacturer_id + t.string :product_manual_homepage_url + t.string :product_homepage_url + t.timestamps + end + end + + def self.down + drop_table :phone_models + end +end diff --git a/db/migrate/20111013110804_add_state_to_phone_models.rb b/db/migrate/20111013110804_add_state_to_phone_models.rb new file mode 100644 index 0000000..3820372 --- /dev/null +++ b/db/migrate/20111013110804_add_state_to_phone_models.rb @@ -0,0 +1,5 @@ +class AddStateToPhoneModels < ActiveRecord::Migration + def change + add_column :phone_models, :state, :string + end +end diff --git a/db/migrate/20111013173838_create_sip_domains.rb b/db/migrate/20111013173838_create_sip_domains.rb new file mode 100644 index 0000000..1977c5c --- /dev/null +++ b/db/migrate/20111013173838_create_sip_domains.rb @@ -0,0 +1,13 @@ +class CreateSipDomains < ActiveRecord::Migration + def self.up + create_table :sip_domains do |t| + t.string :host + t.string :realm + t.timestamps + end + end + + def self.down + drop_table :sip_domains + end +end diff --git a/db/migrate/20111013173845_add_sip_domain_id_to_tenant.rb b/db/migrate/20111013173845_add_sip_domain_id_to_tenant.rb new file mode 100644 index 0000000..562059b --- /dev/null +++ b/db/migrate/20111013173845_add_sip_domain_id_to_tenant.rb @@ -0,0 +1,5 @@ +class AddSipDomainIdToTenant < ActiveRecord::Migration + def change + add_column :tenants, :sip_domain_id, :integer + end +end diff --git a/db/migrate/20111013180505_create_sip_accounts.rb b/db/migrate/20111013180505_create_sip_accounts.rb new file mode 100644 index 0000000..eca8db2 --- /dev/null +++ b/db/migrate/20111013180505_create_sip_accounts.rb @@ -0,0 +1,18 @@ +class CreateSipAccounts < ActiveRecord::Migration + def self.up + create_table :sip_accounts do |t| + t.string :sip_accountable_type + t.integer :sip_accountable_id + t.string :auth_name + t.string :caller_name + t.string :password + t.string :voicemail_pin + t.string :state + t.timestamps + end + end + + def self.down + drop_table :sip_accounts + end +end diff --git a/db/migrate/20111031125955_create_addresses.rb b/db/migrate/20111031125955_create_addresses.rb new file mode 100644 index 0000000..6f31593 --- /dev/null +++ b/db/migrate/20111031125955_create_addresses.rb @@ -0,0 +1,19 @@ +class CreateAddresses < ActiveRecord::Migration + def self.up + create_table :addresses do |t| + t.integer :phone_book_entry_id + t.string :line1 + t.string :line2 + t.string :street + t.string :zip_code + t.string :city + t.integer :country_id + t.integer :position + t.timestamps + end + end + + def self.down + drop_table :addresses + end +end diff --git a/db/migrate/20111101155754_add_phonetics_to_phone_book_entry.rb b/db/migrate/20111101155754_add_phonetics_to_phone_book_entry.rb new file mode 100644 index 0000000..a8e42c2 --- /dev/null +++ b/db/migrate/20111101155754_add_phonetics_to_phone_book_entry.rb @@ -0,0 +1,7 @@ +class AddPhoneticsToPhoneBookEntry < ActiveRecord::Migration + def change + add_column :phone_book_entries, :first_name_phonetic, :string + add_column :phone_book_entries, :last_name_phonetic, :string + add_column :phone_book_entries, :organization_phonetic, :string + end +end diff --git a/db/migrate/20111101155952_add_index_to_phone_book_entry.rb b/db/migrate/20111101155952_add_index_to_phone_book_entry.rb new file mode 100644 index 0000000..1627e0f --- /dev/null +++ b/db/migrate/20111101155952_add_index_to_phone_book_entry.rb @@ -0,0 +1,10 @@ +class AddIndexToPhoneBookEntry < ActiveRecord::Migration + def change + add_index :phone_book_entries, :first_name + add_index :phone_book_entries, :last_name + add_index :phone_book_entries, :organization + add_index :phone_book_entries, :first_name_phonetic + add_index :phone_book_entries, :last_name_phonetic + add_index :phone_book_entries, :organization_phonetic + end +end diff --git a/db/migrate/20111104114634_add_polymorphic_to_phone_number.rb b/db/migrate/20111104114634_add_polymorphic_to_phone_number.rb new file mode 100644 index 0000000..29400cf --- /dev/null +++ b/db/migrate/20111104114634_add_polymorphic_to_phone_number.rb @@ -0,0 +1,8 @@ +class AddPolymorphicToPhoneNumber < ActiveRecord::Migration + def change + add_column :phone_numbers, :phone_numberable_type, :string + add_column :phone_numbers, :phone_numberable_id, :integer + + remove_column :phone_numbers, :phone_book_entry_id + end +end diff --git a/db/migrate/20111104140800_create_calls.rb b/db/migrate/20111104140800_create_calls.rb new file mode 100644 index 0000000..1b66a76 --- /dev/null +++ b/db/migrate/20111104140800_create_calls.rb @@ -0,0 +1,28 @@ +class CreateCalls < ActiveRecord::Migration + def self.up + create_table :calls, :id => false do |t| + t.string :call_uuid, :limit=>'255', :primary => true + t.string :call_created, :limit=>'128' + t.integer :call_created_epoch + t.string :function, :limit=>'1024' + t.string :caller_cid_name, :limit=>'1024' + t.string :caller_cid_num, :limit=>'256' + t.string :caller_dest_num, :limit=>'256' + t.string :caller_chan_name, :limit=>'1024' + t.string :caller_uuid, :limit=>'256' + t.string :callee_cid_name, :limit=>'1024' + t.string :callee_cid_numcallee_dest_num, :limit=>'256' + t.string :callee_chan_name, :limit=>'1024' + t.string :callee_uuid, :limit=>'256' + t.string :hostname, :limit=>'256' + end + add_index :calls, [ :hostname ], :unique => false, :name => 'calls1' + add_index :calls, [ :callee_uuid, :hostname ], :unique => false, :name => 'eeuuindex' + add_index :calls, [ :call_uuid, :hostname ], :unique => false, :name => 'eeuuindex2' + add_index :calls, [ :caller_uuid, :hostname ], :unique => false, :name => 'eruuindex' + end + + def self.down + drop_table :calls + end +end diff --git a/db/migrate/20111104140900_create_channels.rb b/db/migrate/20111104140900_create_channels.rb new file mode 100644 index 0000000..eb81844 --- /dev/null +++ b/db/migrate/20111104140900_create_channels.rb @@ -0,0 +1,42 @@ +class CreateChannels < ActiveRecord::Migration + def self.up + create_table :channels, :id => false do |t| + t.string :uuid, :limit=>'256', :primary => true + t.string :direction, :limit=>'32' + t.string :created, :limit=>'128' + t.integer :created_epoch + t.string :name, :limit=>'1024' + t.string :state, :limit=>'64' + t.string :cid_name, :limit=>'1024' + t.string :cid_num, :limit=>'256' + t.string :ip_addr, :limit=>'256' + t.string :dest, :limit=>'1024' + t.string :application, :limit=>'128' + t.string :application_data, :limit=>'4096' + t.string :dialplan, :limit=>'128' + t.string :context, :limit=>'128' + t.string :read_codec, :limit=>'128' + t.string :read_rate, :limit=>'32' + t.string :read_bit_rate, :limit=>'32' + t.string :write_codec, :limit=>'128' + t.string :write_rate, :limit=>'32' + t.string :write_bit_rate, :limit=>'32' + t.string :secure, :limit=>'32' + t.string :hostname, :limit=>'256' + t.string :presence_id, :limit=>'4096' + t.string :presence_data, :limit=>'4096' + t.string :callstate, :limit=>'64' + t.string :callee_name, :limit=>'1024' + t.string :callee_num, :limit=>'256' + t.string :callee_direction, :limit=>'5' + t.string :call_uuid, :limit=>'256' + end + add_index :channels, [ :hostname ], :unique => false, :name => 'channels1' + add_index :channels, [ :uuid, :hostname ], :unique => true, :name => 'uuindex' + add_index :channels, [ :call_uuid, :hostname ], :unique => false, :name => 'uuindex2' + end + + def self.down + drop_table :channels + end +end diff --git a/db/migrate/20111104140901_create_interfaces.rb b/db/migrate/20111104140901_create_interfaces.rb new file mode 100644 index 0000000..eede6a3 --- /dev/null +++ b/db/migrate/20111104140901_create_interfaces.rb @@ -0,0 +1,17 @@ +class CreateInterfaces < ActiveRecord::Migration + def self.up + create_table :interfaces, :id => false do |t| + t.string :type, :limit=>'128' + t.string :name, :limit=>'1024' + t.string :description, :limit=>'4096' + t.string :ikey, :limit=>'1024' + t.string :filename, :limit=>'4096' + t.string :syntax, :limit=>'4096' + t.string :hostname, :limit=>'256' + end + end + + def self.down + drop_table :interfaces + end +end diff --git a/db/migrate/20111104141000_create_aliases.rb b/db/migrate/20111104141000_create_aliases.rb new file mode 100644 index 0000000..e645ef5 --- /dev/null +++ b/db/migrate/20111104141000_create_aliases.rb @@ -0,0 +1,15 @@ +class CreateAliases < ActiveRecord::Migration + def self.up + create_table :aliases, :id => false do |t| + t.integer :sticky + t.string :alias, :limit=>'128' + t.string :command, :limit=>'4096' + t.string :hostname, :limit=>'256' + end + add_index :aliases, [ :alias ], :unique => false, :name => 'alias1' + end + + def self.down + drop_table :aliases + end +end diff --git a/db/migrate/20111104141001_create_complete.rb b/db/migrate/20111104141001_create_complete.rb new file mode 100644 index 0000000..e5f0a63 --- /dev/null +++ b/db/migrate/20111104141001_create_complete.rb @@ -0,0 +1,33 @@ +class CreateComplete < ActiveRecord::Migration + def self.up + create_table :complete, :id => false do |t| + t.integer :sticky + t.string :a1, :limit=>'128' + t.string :a2, :limit=>'128' + t.string :a3, :limit=>'128' + t.string :a4, :limit=>'128' + t.string :a5, :limit=>'128' + t.string :a6, :limit=>'128' + t.string :a7, :limit=>'128' + t.string :a8, :limit=>'128' + t.string :a9, :limit=>'128' + t.string :a10, :limit=>'128' + t.string :hostname, :limit=>'256' + end + add_index :complete, [ :a1, :hostname ], :unique => false, :name => 'complete1' + add_index :complete, [ :a2, :hostname ], :unique => false, :name => 'complete2' + add_index :complete, [ :a3, :hostname ], :unique => false, :name => 'complete3' + add_index :complete, [ :a4, :hostname ], :unique => false, :name => 'complete4' + add_index :complete, [ :a5, :hostname ], :unique => false, :name => 'complete5' + add_index :complete, [ :a6, :hostname ], :unique => false, :name => 'complete6' + add_index :complete, [ :a7, :hostname ], :unique => false, :name => 'complete7' + add_index :complete, [ :a8, :hostname ], :unique => false, :name => 'complete8' + add_index :complete, [ :a9, :hostname ], :unique => false, :name => 'complete9' + add_index :complete, [ :a10, :hostname ], :unique => false, :name => 'complete10' + add_index :complete, [ :a1, :a2, :a3, :a4, :a5, :a6, :a7, :a8, :a9, :a10, :hostname ], :unique => false, :name => 'complete11' + end + + def self.down + drop_table :complete + end +end diff --git a/db/migrate/20111104141002_create_tasks.rb b/db/migrate/20111104141002_create_tasks.rb new file mode 100644 index 0000000..d7539bc --- /dev/null +++ b/db/migrate/20111104141002_create_tasks.rb @@ -0,0 +1,16 @@ +class CreateTasks < ActiveRecord::Migration + def self.up + create_table :tasks, :id => false do |t| + t.integer :task_id, :primary => true + t.string :task_desc, :limit=>'4096' + t.string :task_group, :limit=>'1024' + t.integer :task_sql_manager + t.string :hostname, :limit=>'256' + end + add_index :tasks, [ :hostname, :task_id ], :unique => true, :name => 'tasks1' + end + + def self.down + drop_table :tasks + end +end diff --git a/db/migrate/20111104141100_create_nat.rb b/db/migrate/20111104141100_create_nat.rb new file mode 100644 index 0000000..7c5cde4 --- /dev/null +++ b/db/migrate/20111104141100_create_nat.rb @@ -0,0 +1,15 @@ +class CreateNat < ActiveRecord::Migration + def self.up + create_table :nat, :id => false do |t| + t.integer :sticky + t.integer :port + t.integer :proto + t.string :hostname, :limit => '256' + end + add_index :nat, [ :port, :proto, :hostname ], :unique => false, :name => 'nat_map_port_proto' + end + + def self.down + drop_table :nat + end +end diff --git a/db/migrate/20111104141101_create_registrations.rb b/db/migrate/20111104141101_create_registrations.rb new file mode 100644 index 0000000..e2683d7 --- /dev/null +++ b/db/migrate/20111104141101_create_registrations.rb @@ -0,0 +1,20 @@ +class CreateRegistrations < ActiveRecord::Migration + def self.up + create_table :registrations, :id => false do |t| + t.string :reg_user + t.string :realm, :limit => '256' + t.string :token, :limit => '256' + t.text :url + t.integer :expires + t.string :network_ip, :limit => '256' + t.string :network_port, :limit => '256' + t.string :network_proto, :limit => '256' + t.string :hostname, :limit => '256' + end + add_index :registrations, [ :reg_user, :realm, :hostname ], :unique => false, :name => 'regindex1' + end + + def self.down + drop_table :registrations + end +end diff --git a/db/migrate/20111106081300_create_fifo_bridge.rb b/db/migrate/20111106081300_create_fifo_bridge.rb new file mode 100644 index 0000000..090d0d7 --- /dev/null +++ b/db/migrate/20111106081300_create_fifo_bridge.rb @@ -0,0 +1,17 @@ +class CreateFifoBridge < ActiveRecord::Migration + def self.up + create_table :fifo_bridge, :id => false do |t| + t.string :fifo_name, :limit => '1024', :null => false + t.string :caller_uuid, :limit => '255', :null => false + t.string :caller_caller_id_name, :limit => '255', :null => false + t.string :caller_caller_id_number, :limit => '255', :null => false + t.string :consumer_uuid, :limit => '255', :null => false + t.string :consumer_outgoing_uuid, :limit => '255' + t.integer :bridge_start + end + end + + def self.down + drop_table :fifo_bridge + end +end diff --git a/db/migrate/20111106082100_create_fifo_callers.rb b/db/migrate/20111106082100_create_fifo_callers.rb new file mode 100644 index 0000000..084e811 --- /dev/null +++ b/db/migrate/20111106082100_create_fifo_callers.rb @@ -0,0 +1,15 @@ +class CreateFifoCallers < ActiveRecord::Migration + def self.up + create_table :fifo_callers, :id => false do |t| + t.string :fifo_name, :limit => '255', :null => false + t.string :uuid, :limit => '255', :null => false + t.string :caller_caller_id_name, :limit => '255' + t.string :caller_caller_id_number, :limit => '255' + t.integer :timestamp + end + end + + def self.down + drop_table :fifo_callers + end +end diff --git a/db/migrate/20111106082500_create_fifo_outbound.rb b/db/migrate/20111106082500_create_fifo_outbound.rb new file mode 100644 index 0000000..0f06855 --- /dev/null +++ b/db/migrate/20111106082500_create_fifo_outbound.rb @@ -0,0 +1,36 @@ +class CreateFifoOutbound < ActiveRecord::Migration + def self.up + create_table :fifo_outbound, :id => false do |t| + t.string :uuid, :limit => '255' + t.string :fifo_name, :limit => '255' + t.string :originate_string, :limit => '255' + t.integer :simo_count + t.integer :use_count + t.integer :timeout + t.integer :lag + t.integer :next_avail, :null => false, :default => 0 + t.integer :expires, :null => false, :default => 0 + t.integer :static, :null => false, :default => 0 + t.integer :outbound_call_count, :null => false, :default => 0 + t.integer :outbound_fail_count, :null => false, :default => 0 + t.string :hostname, :limit => '255' + t.integer :taking_calls, :null => false, :default => 1 + t.string :status, :limit => '255' + t.integer :outbound_call_total_count, :null => false, :default => 0 + t.integer :outbound_fail_total_count, :null => false, :default => 0 + t.integer :active_time, :null => false, :default => 0 + t.integer :inactive_time, :null => false, :default => 0 + t.integer :manual_calls_out_count, :null => false, :default => 0 + t.integer :manual_calls_in_count, :null => false, :default => 0 + t.integer :manual_calls_out_total_count, :null => false, :default => 0 + t.integer :manual_calls_in_total_count, :null => false, :default => 0 + t.integer :ring_count, :null => false, :default => 0 + t.integer :start_time, :null => false, :default => 0 + t.integer :stop_time, :null => false, :default => 0 + end + end + + def self.down + drop_table :fifo_outbound + end +end diff --git a/db/migrate/20111106083400_create_voicemail_msgs.rb b/db/migrate/20111106083400_create_voicemail_msgs.rb new file mode 100644 index 0000000..9b78430 --- /dev/null +++ b/db/migrate/20111106083400_create_voicemail_msgs.rb @@ -0,0 +1,30 @@ +class CreateVoicemailMsgs < ActiveRecord::Migration + def self.up + create_table :voicemail_msgs, :id => false do |t| + t.integer :created_epoch + t.integer :read_epoch + t.string :username, :limit => '255' + t.string :domain, :limit => '255' + t.string :uuid, :limit => '255' + t.string :cid_name, :limit => '255' + t.string :cid_number, :limit => '255' + t.string :in_folder, :limit => '255' + t.string :file_path, :limit => '255' + t.integer :message_len + t.string :flags, :limit => '255' + t.string :read_flags, :limit => '255' + t.string :forwarded_by, :limit => '255' + end + add_index :voicemail_msgs, [ :created_epoch ], :unique => false, :name => 'voicemail_msgs_idx1' + add_index :voicemail_msgs, [ :username ], :unique => false, :name => 'voicemail_msgs_idx2' + add_index :voicemail_msgs, [ :domain ], :unique => false, :name => 'voicemail_msgs_idx3' + add_index :voicemail_msgs, [ :uuid ], :unique => false, :name => 'voicemail_msgs_idx4' + add_index :voicemail_msgs, [ :in_folder ], :unique => false, :name => 'voicemail_msgs_idx5' + add_index :voicemail_msgs, [ :read_flags ], :unique => false, :name => 'voicemail_msgs_idx6' + add_index :voicemail_msgs, [ :forwarded_by ], :unique => false, :name => 'voicemail_msgs_idx7' + end + + def self.down + drop_table :voicemail_msgs + end +end diff --git a/db/migrate/20111106084200_create_voicemail_prefs.rb b/db/migrate/20111106084200_create_voicemail_prefs.rb new file mode 100644 index 0000000..162fa8a --- /dev/null +++ b/db/migrate/20111106084200_create_voicemail_prefs.rb @@ -0,0 +1,17 @@ +class CreateVoicemailPrefs < ActiveRecord::Migration + def self.up + create_table :voicemail_prefs, :id => false do |t| + t.string :username, :limit => '255' + t.string :domain, :limit => '255' + t.string :name_path, :limit => '255' + t.string :greeting_path, :limit => '255' + t.string :password, :limit => '255' + end + add_index :voicemail_prefs, [ :username ], :unique => false, :name => 'voicemail_prefs_idx1' + add_index :voicemail_prefs, [ :domain ], :unique => false, :name => 'voicemail_prefs_idx2' + end + + def self.down + drop_table :voicemail_prefs + end +end diff --git a/db/migrate/20111106162141_add_phoneable_to_phone.rb b/db/migrate/20111106162141_add_phoneable_to_phone.rb new file mode 100644 index 0000000..7b60ac6 --- /dev/null +++ b/db/migrate/20111106162141_add_phoneable_to_phone.rb @@ -0,0 +1,6 @@ +class AddPhoneableToPhone < ActiveRecord::Migration + def change + add_column :phones, :phoneable_type, :string + add_column :phones, :phoneable_id, :integer + end +end diff --git a/db/migrate/20111119124303_add_hot_deskable_to_phone.rb b/db/migrate/20111119124303_add_hot_deskable_to_phone.rb new file mode 100644 index 0000000..620fb1b --- /dev/null +++ b/db/migrate/20111119124303_add_hot_deskable_to_phone.rb @@ -0,0 +1,5 @@ +class AddHotDeskableToPhone < ActiveRecord::Migration + def change + add_column :phones, :hot_deskable, :boolean + end +end diff --git a/db/migrate/20111119153939_add_state_to_phone_number.rb b/db/migrate/20111119153939_add_state_to_phone_number.rb new file mode 100644 index 0000000..69e650a --- /dev/null +++ b/db/migrate/20111119153939_add_state_to_phone_number.rb @@ -0,0 +1,5 @@ +class AddStateToPhoneNumber < ActiveRecord::Migration + def change + add_column :phone_numbers, :state, :string + end +end diff --git a/db/migrate/20111120110056_add_value_of_to_s_to_phone_number.rb b/db/migrate/20111120110056_add_value_of_to_s_to_phone_number.rb new file mode 100644 index 0000000..39b13fc --- /dev/null +++ b/db/migrate/20111120110056_add_value_of_to_s_to_phone_number.rb @@ -0,0 +1,6 @@ +class AddValueOfToSToPhoneNumber < ActiveRecord::Migration + def change + add_column :phone_numbers, :value_of_to_s, :string + add_column :sip_accounts, :value_of_to_s, :string + end +end diff --git a/db/migrate/20111120112448_add_value_of_to_s_to_phone_book_entry.rb b/db/migrate/20111120112448_add_value_of_to_s_to_phone_book_entry.rb new file mode 100644 index 0000000..8658453 --- /dev/null +++ b/db/migrate/20111120112448_add_value_of_to_s_to_phone_book_entry.rb @@ -0,0 +1,5 @@ +class AddValueOfToSToPhoneBookEntry < ActiveRecord::Migration + def change + add_column :phone_book_entries, :value_of_to_s, :string + end +end diff --git a/db/migrate/20111120180010_create_call_forward_cases.rb b/db/migrate/20111120180010_create_call_forward_cases.rb new file mode 100644 index 0000000..d29c246 --- /dev/null +++ b/db/migrate/20111120180010_create_call_forward_cases.rb @@ -0,0 +1,21 @@ +class CreateCallForwardCases < ActiveRecord::Migration + + def self.up + create_table :call_forward_cases do |t| + t.string :value + t.timestamps + end + add_index( :call_forward_cases, :value, { + :name => "call_forward_cases_value_index", + :unique => true, + }) + end + + def self.down + remove_index( :call_forward_cases, { + :name => "call_forward_cases_value_index", + }) + drop_table :call_forward_cases + end + +end diff --git a/db/migrate/20111120180020_create_call_forwards.rb b/db/migrate/20111120180020_create_call_forwards.rb new file mode 100644 index 0000000..e8795eb --- /dev/null +++ b/db/migrate/20111120180020_create_call_forwards.rb @@ -0,0 +1,25 @@ +class CreateCallForwards < ActiveRecord::Migration + + def self.up + create_table :call_forwards do |t| + t.integer :sip_account_id + t.integer :call_forward_case_id + t.integer :timeout + t.string :destination + t.string :source + t.boolean :active + t.timestamps + end + add_index( :call_forwards, :sip_account_id, { + :name => "call_forwards_sip_account_index", + }) + end + + def self.down + remove_index( :call_forwards, { + :name => "call_forwards_sip_account_index", + }) + drop_table :call_forwards + end + +end diff --git a/db/migrate/20111121105916_add_sip_domain_id_to_sip_accounts.rb b/db/migrate/20111121105916_add_sip_domain_id_to_sip_accounts.rb new file mode 100644 index 0000000..86f7743 --- /dev/null +++ b/db/migrate/20111121105916_add_sip_domain_id_to_sip_accounts.rb @@ -0,0 +1,5 @@ +class AddSipDomainIdToSipAccounts < ActiveRecord::Migration + def change + add_column :sip_accounts, :sip_domain_id, :integer + end +end diff --git a/db/migrate/20111121152220_create_conferences.rb b/db/migrate/20111121152220_create_conferences.rb new file mode 100644 index 0000000..fe32ee8 --- /dev/null +++ b/db/migrate/20111121152220_create_conferences.rb @@ -0,0 +1,20 @@ +class CreateConferences < ActiveRecord::Migration + def self.up + create_table :conferences do |t| + t.string :name + t.datetime :start + t.datetime :end + t.text :description + t.string :pin + t.text :state + t.boolean :open_for_anybody + t.string :conferenceable_type + t.integer :conferenceable_id + t.timestamps + end + end + + def self.down + drop_table :conferences + end +end diff --git a/db/migrate/20111122172513_create_conference_invitees.rb b/db/migrate/20111122172513_create_conference_invitees.rb new file mode 100644 index 0000000..3ec293e --- /dev/null +++ b/db/migrate/20111122172513_create_conference_invitees.rb @@ -0,0 +1,16 @@ +class CreateConferenceInvitees < ActiveRecord::Migration + def self.up + create_table :conference_invitees do |t| + t.integer :conference_id + t.integer :phone_book_entry_id + t.string :pin + t.boolean :speaker + t.boolean :moderator + t.timestamps + end + end + + def self.down + drop_table :conference_invitees + end +end diff --git a/db/migrate/20111123124113_create_phone_number_ranges.rb b/db/migrate/20111123124113_create_phone_number_ranges.rb new file mode 100644 index 0000000..e20014b --- /dev/null +++ b/db/migrate/20111123124113_create_phone_number_ranges.rb @@ -0,0 +1,14 @@ +class CreatePhoneNumberRanges < ActiveRecord::Migration + def self.up + create_table :phone_number_ranges do |t| + t.integer :tenant_id + t.string :name + t.text :description + t.timestamps + end + end + + def self.down + drop_table :phone_number_ranges + end +end diff --git a/db/migrate/20111123132658_create_languages.rb b/db/migrate/20111123132658_create_languages.rb new file mode 100644 index 0000000..48a5da5 --- /dev/null +++ b/db/migrate/20111123132658_create_languages.rb @@ -0,0 +1,10 @@ +class CreateLanguages < ActiveRecord::Migration + def change + create_table :languages do |t| + t.string :name + t.string :code + + t.timestamps + end + end +end diff --git a/db/migrate/20111123141120_create_gemeinschaft_setups.rb b/db/migrate/20111123141120_create_gemeinschaft_setups.rb new file mode 100644 index 0000000..cc17e7a --- /dev/null +++ b/db/migrate/20111123141120_create_gemeinschaft_setups.rb @@ -0,0 +1,19 @@ +class CreateGemeinschaftSetups < ActiveRecord::Migration + def self.up + create_table :gemeinschaft_setups do |t| + t.integer :tenant_id + t.integer :user_id + t.integer :sip_domain_id + t.integer :default_extension_length + t.integer :country_id + t.integer :language_id + t.string :human_area_code + t.integer :area_code_id + t.timestamps + end + end + + def self.down + drop_table :gemeinschaft_setups + end +end diff --git a/db/migrate/20111123211631_rename_columns_of_phone_number_range.rb b/db/migrate/20111123211631_rename_columns_of_phone_number_range.rb new file mode 100644 index 0000000..f7e129a --- /dev/null +++ b/db/migrate/20111123211631_rename_columns_of_phone_number_range.rb @@ -0,0 +1,8 @@ +class RenameColumnsOfPhoneNumberRange < ActiveRecord::Migration + def change + # I'm not going to revert all existing entries here. + add_column :phone_number_ranges, :phone_number_rangeable_type, :string + add_column :phone_number_ranges, :phone_number_rangeable_id, :integer + remove_column :phone_number_ranges, :tenant_id + end +end diff --git a/db/migrate/20111125124957_add_phone_number_id_to_call_forward.rb b/db/migrate/20111125124957_add_phone_number_id_to_call_forward.rb new file mode 100644 index 0000000..8d5f02a --- /dev/null +++ b/db/migrate/20111125124957_add_phone_number_id_to_call_forward.rb @@ -0,0 +1,9 @@ +class AddPhoneNumberIdToCallForward < ActiveRecord::Migration + + def change + remove_column :call_forwards, :sip_account_id + add_column :call_forwards, :phone_number_id, :integer + add_index( :call_forwards, :phone_number_id ) + end + +end diff --git a/db/migrate/20111125150925_add_hops_to_call_forward.rb b/db/migrate/20111125150925_add_hops_to_call_forward.rb new file mode 100644 index 0000000..d7d580c --- /dev/null +++ b/db/migrate/20111125150925_add_hops_to_call_forward.rb @@ -0,0 +1,5 @@ +class AddHopsToCallForward < ActiveRecord::Migration + def change + add_column :call_forwards, :hops, :integer + end +end diff --git a/db/migrate/20111126180826_add_depth_to_call_forward.rb b/db/migrate/20111126180826_add_depth_to_call_forward.rb new file mode 100644 index 0000000..4cb44b2 --- /dev/null +++ b/db/migrate/20111126180826_add_depth_to_call_forward.rb @@ -0,0 +1,5 @@ +class AddDepthToCallForward < ActiveRecord::Migration + def change + rename_column :call_forwards, :hops, :depth + end +end diff --git a/db/migrate/20111127112235_add_internal_extension_ranges_to_gemeinschaft_setup.rb b/db/migrate/20111127112235_add_internal_extension_ranges_to_gemeinschaft_setup.rb new file mode 100644 index 0000000..8f4643c --- /dev/null +++ b/db/migrate/20111127112235_add_internal_extension_ranges_to_gemeinschaft_setup.rb @@ -0,0 +1,6 @@ +class AddInternalExtensionRangesToGemeinschaftSetup < ActiveRecord::Migration + def change + add_column :gemeinschaft_setups, :internal_extension_ranges, :string + remove_column :gemeinschaft_setups, :default_extension_length + end +end diff --git a/db/migrate/20111128100949_add_pin_to_user.rb b/db/migrate/20111128100949_add_pin_to_user.rb new file mode 100644 index 0000000..d193452 --- /dev/null +++ b/db/migrate/20111128100949_add_pin_to_user.rb @@ -0,0 +1,6 @@ +class AddPinToUser < ActiveRecord::Migration + def change + add_column :users, :pin_salt, :string + add_column :users, :pin_hash, :string + end +end diff --git a/db/migrate/20111203164007_add_tenant_id_to_sip_account.rb b/db/migrate/20111203164007_add_tenant_id_to_sip_account.rb new file mode 100644 index 0000000..2efea2b --- /dev/null +++ b/db/migrate/20111203164007_add_tenant_id_to_sip_account.rb @@ -0,0 +1,5 @@ +class AddTenantIdToSipAccount < ActiveRecord::Migration + def change + add_column :sip_accounts, :tenant_id, :integer + end +end diff --git a/db/migrate/20111210124447_remove_sip_domain_id_from_sip_account.rb b/db/migrate/20111210124447_remove_sip_domain_id_from_sip_account.rb new file mode 100644 index 0000000..eeb5afe --- /dev/null +++ b/db/migrate/20111210124447_remove_sip_domain_id_from_sip_account.rb @@ -0,0 +1,9 @@ +class RemoveSipDomainIdFromSipAccount < ActiveRecord::Migration + def up + remove_column :sip_accounts, :sip_domain_id + end + + def down + add_column :sip_accounts, :sip_domain_id, :integer + end +end diff --git a/db/migrate/20111211184853_remove_state_from_sip_account.rb b/db/migrate/20111211184853_remove_state_from_sip_account.rb new file mode 100644 index 0000000..e0ed8ed --- /dev/null +++ b/db/migrate/20111211184853_remove_state_from_sip_account.rb @@ -0,0 +1,9 @@ +class RemoveStateFromSipAccount < ActiveRecord::Migration + def up + remove_column :sip_accounts, :state + end + + def down + add_column :sip_accounts, :state, :string + end +end diff --git a/db/migrate/20111211192350_add_sip_domain_id_to_sip_account.rb b/db/migrate/20111211192350_add_sip_domain_id_to_sip_account.rb new file mode 100644 index 0000000..5344247 --- /dev/null +++ b/db/migrate/20111211192350_add_sip_domain_id_to_sip_account.rb @@ -0,0 +1,5 @@ +class AddSipDomainIdToSipAccount < ActiveRecord::Migration + def change + add_column :sip_accounts, :sip_domain_id, :integer + end +end diff --git a/db/migrate/20111212193532_create_faxes.rb b/db/migrate/20111212193532_create_faxes.rb new file mode 100644 index 0000000..d713f2d --- /dev/null +++ b/db/migrate/20111212193532_create_faxes.rb @@ -0,0 +1,19 @@ +class CreateFaxes < ActiveRecord::Migration + def self.up + create_table :faxes do |t| + t.boolean :inbound + t.string :pdf + t.integer :faxable_id + t.string :faxable_type + t.string :state + t.integer :number_of_pages + t.integer :transmission_time + t.datetime :sent_at + t.timestamps + end + end + + def self.down + drop_table :faxes + end +end diff --git a/db/migrate/20111212201847_create_fax_pages.rb b/db/migrate/20111212201847_create_fax_pages.rb new file mode 100644 index 0000000..de8c708 --- /dev/null +++ b/db/migrate/20111212201847_create_fax_pages.rb @@ -0,0 +1,13 @@ +class CreateFaxPages < ActiveRecord::Migration + def self.up + create_table :fax_pages do |t| + t.string :page + t.integer :position + t.timestamps + end + end + + def self.down + drop_table :fax_pages + end +end diff --git a/db/migrate/20111213122843_add_external_numbers_to_gemeinschaft_setup.rb b/db/migrate/20111213122843_add_external_numbers_to_gemeinschaft_setup.rb new file mode 100644 index 0000000..056f532 --- /dev/null +++ b/db/migrate/20111213122843_add_external_numbers_to_gemeinschaft_setup.rb @@ -0,0 +1,5 @@ +class AddExternalNumbersToGemeinschaftSetup < ActiveRecord::Migration + def change + add_column :gemeinschaft_setups, :external_numbers, :string + end +end diff --git a/db/migrate/20111213170837_add_language_id_to_tenant.rb b/db/migrate/20111213170837_add_language_id_to_tenant.rb new file mode 100644 index 0000000..a2bf018 --- /dev/null +++ b/db/migrate/20111213170837_add_language_id_to_tenant.rb @@ -0,0 +1,7 @@ +class AddLanguageIdToTenant < ActiveRecord::Migration + def change + add_column :tenants, :language_id, :integer + add_column :tenants, :internal_extension_ranges, :string + add_column :tenants, :did_list, :string + end +end diff --git a/db/migrate/20111213182546_remove_tenant_id_from_gemeinschaft_setup.rb b/db/migrate/20111213182546_remove_tenant_id_from_gemeinschaft_setup.rb new file mode 100644 index 0000000..d91b195 --- /dev/null +++ b/db/migrate/20111213182546_remove_tenant_id_from_gemeinschaft_setup.rb @@ -0,0 +1,17 @@ +class RemoveTenantIdFromGemeinschaftSetup < ActiveRecord::Migration + def up + remove_column :gemeinschaft_setups, :tenant_id + remove_column :gemeinschaft_setups, :human_area_code + remove_column :gemeinschaft_setups, :area_code_id + remove_column :gemeinschaft_setups, :internal_extension_ranges + remove_column :gemeinschaft_setups, :external_numbers + end + + def down + add_column :gemeinschaft_setups, :external_numbers, :string + add_column :gemeinschaft_setups, :internal_extension_ranges, :string + add_column :gemeinschaft_setups, :area_code_id, :integer + add_column :gemeinschaft_setups, :human_area_code, :string + add_column :gemeinschaft_setups, :tenant_id, :integer + end +end diff --git a/db/migrate/20111214182903_add_max_members_to_conference.rb b/db/migrate/20111214182903_add_max_members_to_conference.rb new file mode 100644 index 0000000..c7f1013 --- /dev/null +++ b/db/migrate/20111214182903_add_max_members_to_conference.rb @@ -0,0 +1,5 @@ +class AddMaxMembersToConference < ActiveRecord::Migration + def change + add_column :conferences, :max_members, :integer + end +end diff --git a/db/migrate/20111215172021_create_fax_accounts.rb b/db/migrate/20111215172021_create_fax_accounts.rb new file mode 100644 index 0000000..1039585 --- /dev/null +++ b/db/migrate/20111215172021_create_fax_accounts.rb @@ -0,0 +1,16 @@ +class CreateFaxAccounts < ActiveRecord::Migration + def self.up + create_table :fax_accounts do |t| + t.string :fax_accountable_type + t.integer :fax_accountable_id + t.string :name + t.string :email + t.boolean :delete_after_email + t.timestamps + end + end + + def self.down + drop_table :fax_accounts + end +end diff --git a/db/migrate/20111216112614_add_information_to_fax.rb b/db/migrate/20111216112614_add_information_to_fax.rb new file mode 100644 index 0000000..d5c03da --- /dev/null +++ b/db/migrate/20111216112614_add_information_to_fax.rb @@ -0,0 +1,19 @@ +class AddInformationToFax < ActiveRecord::Migration + def change + remove_column :faxes, :number_of_pages + add_column :faxes, :document_total_pages, :integer + add_column :faxes, :document_transferred_pages, :integer + add_column :faxes, :ecm_requested, :boolean + add_column :faxes, :ecm_used, :boolean + add_column :faxes, :image_resolution, :string + add_column :faxes, :image_size, :string + add_column :faxes, :local_station_id, :string + add_column :faxes, :result_code, :integer + add_column :faxes, :result_text, :string + add_column :faxes, :remote_station_id, :string + add_column :faxes, :success, :boolean + add_column :faxes, :transfer_rate, :integer + add_column :faxes, :t38_gateway_format, :string + add_column :faxes, :t38_peer, :string + end +end diff --git a/db/migrate/20111217162506_add_fax_to_faxes.rb b/db/migrate/20111217162506_add_fax_to_faxes.rb new file mode 100644 index 0000000..fe5d7b6 --- /dev/null +++ b/db/migrate/20111217162506_add_fax_to_faxes.rb @@ -0,0 +1,8 @@ +class AddFaxToFaxes < ActiveRecord::Migration + def change + remove_column :faxes, :pdf + remove_column :fax_pages, :page + add_column :faxes, :fax, :string + add_column :fax_pages, :fax_page, :string + end +end diff --git a/db/migrate/20111218085222_create_fax_documents.rb b/db/migrate/20111218085222_create_fax_documents.rb new file mode 100644 index 0000000..00bf73f --- /dev/null +++ b/db/migrate/20111218085222_create_fax_documents.rb @@ -0,0 +1,32 @@ +class CreateFaxDocuments < ActiveRecord::Migration + def self.up + create_table :fax_documents do |t| + t.string :fax_documentable_type + t.integer :fax_documentable_id + t.boolean :inbound + t.string :state + t.integer :transmission_time + t.datetime :sent_at + t.integer :document_total_pages + t.integer :document_transferred_pages + t.boolean :ecm_requested + t.boolean :ecm_used + t.string :image_resolution + t.string :image_size + t.string :local_station_id + t.integer :result_code + t.string :result_text + t.string :remote_station_id + t.boolean :success + t.integer :transfer_rate + t.string :t38_gateway_format + t.string :t38_peer + t.string :document + t.timestamps + end + end + + def self.down + drop_table :fax_documents + end +end diff --git a/db/migrate/20111218100048_add_fax_account_id_to_fax_documents.rb b/db/migrate/20111218100048_add_fax_account_id_to_fax_documents.rb new file mode 100644 index 0000000..d7fb7a0 --- /dev/null +++ b/db/migrate/20111218100048_add_fax_account_id_to_fax_documents.rb @@ -0,0 +1,5 @@ +class AddFaxAccountIdToFaxDocuments < ActiveRecord::Migration + def change + add_column :fax_documents, :fax_account_id, :integer + end +end diff --git a/db/migrate/20111218143152_add_tenant_id_to_fax_account.rb b/db/migrate/20111218143152_add_tenant_id_to_fax_account.rb new file mode 100644 index 0000000..1c352b8 --- /dev/null +++ b/db/migrate/20111218143152_add_tenant_id_to_fax_account.rb @@ -0,0 +1,6 @@ +class AddTenantIdToFaxAccount < ActiveRecord::Migration + def change + add_column :fax_accounts, :tenant_id, :integer + add_column :fax_accounts, :station_id, :string + end +end diff --git a/db/migrate/20111218145713_add_days_till_auto_delete_to_fax_accounts.rb b/db/migrate/20111218145713_add_days_till_auto_delete_to_fax_accounts.rb new file mode 100644 index 0000000..0df0965 --- /dev/null +++ b/db/migrate/20111218145713_add_days_till_auto_delete_to_fax_accounts.rb @@ -0,0 +1,6 @@ +class AddDaysTillAutoDeleteToFaxAccounts < ActiveRecord::Migration + def change + add_column :fax_accounts, :days_till_auto_delete, :integer + remove_column :fax_accounts, :delete_after_email + end +end diff --git a/db/migrate/20111219131952_create_fax_thumbnails.rb b/db/migrate/20111219131952_create_fax_thumbnails.rb new file mode 100644 index 0000000..3474e0a --- /dev/null +++ b/db/migrate/20111219131952_create_fax_thumbnails.rb @@ -0,0 +1,11 @@ +class CreateFaxThumbnails < ActiveRecord::Migration + def change + create_table :fax_thumbnails do |t| + t.integer :fax_document_id + t.integer :position + t.string :thumbnail + + t.timestamps + end + end +end diff --git a/db/migrate/20111219163426_remove_fax_documentable_from_fax_documents.rb b/db/migrate/20111219163426_remove_fax_documentable_from_fax_documents.rb new file mode 100644 index 0000000..f8a55ec --- /dev/null +++ b/db/migrate/20111219163426_remove_fax_documentable_from_fax_documents.rb @@ -0,0 +1,11 @@ +class RemoveFaxDocumentableFromFaxDocuments < ActiveRecord::Migration + def up + remove_column :fax_documents, :fax_documentable_type + remove_column :fax_documents, :fax_documentable_id + end + + def down + add_column :fax_documents, :fax_documentable_id, :integer + add_column :fax_documents, :fax_documentable_type, :string + end +end diff --git a/db/migrate/20111220151633_add_caller_id_number_to_fax_documents.rb b/db/migrate/20111220151633_add_caller_id_number_to_fax_documents.rb new file mode 100644 index 0000000..fe1461e --- /dev/null +++ b/db/migrate/20111220151633_add_caller_id_number_to_fax_documents.rb @@ -0,0 +1,8 @@ +class AddCallerIdNumberToFaxDocuments < ActiveRecord::Migration + def change + add_column :fax_documents, :caller_id_number, :string + add_column :fax_documents, :caller_id_name, :string + remove_column :fax_documents, :t38_gateway_format + remove_column :fax_documents, :t38_peer + end +end diff --git a/db/migrate/20111222173947_remove_result_text_from_fax_documents.rb b/db/migrate/20111222173947_remove_result_text_from_fax_documents.rb new file mode 100644 index 0000000..46acafd --- /dev/null +++ b/db/migrate/20111222173947_remove_result_text_from_fax_documents.rb @@ -0,0 +1,13 @@ +class RemoveResultTextFromFaxDocuments < ActiveRecord::Migration + def up + remove_column :fax_documents, :result_text + add_column :fax_documents, :retry_counter, :integer + add_column :fax_accounts, :retries, :integer + end + + def down + add_column :fax_documents, :result_text, :string + remove_column :fax_documents, :retry_counter + remove_column :fax_accounts, :retries + end +end diff --git a/db/migrate/20111222184203_add_tiff_to_fax_documents.rb b/db/migrate/20111222184203_add_tiff_to_fax_documents.rb new file mode 100644 index 0000000..523c1c0 --- /dev/null +++ b/db/migrate/20111222184203_add_tiff_to_fax_documents.rb @@ -0,0 +1,5 @@ +class AddTiffToFaxDocuments < ActiveRecord::Migration + def change + add_column :fax_documents, :tiff, :string + end +end diff --git a/db/migrate/20111222184912_add_resolution_to_fax_documents.rb b/db/migrate/20111222184912_add_resolution_to_fax_documents.rb new file mode 100644 index 0000000..48631aa --- /dev/null +++ b/db/migrate/20111222184912_add_resolution_to_fax_documents.rb @@ -0,0 +1,5 @@ +class AddResolutionToFaxDocuments < ActiveRecord::Migration + def change + add_column :fax_documents, :fax_resolution_id, :integer + end +end diff --git a/db/migrate/20111222185426_create_fax_resolutions.rb b/db/migrate/20111222185426_create_fax_resolutions.rb new file mode 100644 index 0000000..6782021 --- /dev/null +++ b/db/migrate/20111222185426_create_fax_resolutions.rb @@ -0,0 +1,11 @@ +class CreateFaxResolutions < ActiveRecord::Migration + def change + create_table :fax_resolutions do |t| + t.string :name + t.string :resolution_value + t.integer :position + + t.timestamps + end + end +end diff --git a/db/migrate/20111226180221_create_delayed_jobs.rb b/db/migrate/20111226180221_create_delayed_jobs.rb new file mode 100644 index 0000000..ac579df --- /dev/null +++ b/db/migrate/20111226180221_create_delayed_jobs.rb @@ -0,0 +1,21 @@ +class CreateDelayedJobs < ActiveRecord::Migration + def self.up + create_table :delayed_jobs, :force => true do |table| + table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue + table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually. + table.text :handler # YAML-encoded string of the object that will do work + table.text :last_error # reason for last failure (See Note below) + table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future. + table.datetime :locked_at # Set when a client is working on this object + table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead) + table.string :locked_by # Who is working on this object (if locked) + table.timestamps + end + + add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority' + end + + def self.down + drop_table :delayed_jobs + end +end \ No newline at end of file diff --git a/db/migrate/20111228194037_create_phone_sip_accounts.rb b/db/migrate/20111228194037_create_phone_sip_accounts.rb new file mode 100644 index 0000000..7fd5e39 --- /dev/null +++ b/db/migrate/20111228194037_create_phone_sip_accounts.rb @@ -0,0 +1,14 @@ +class CreatePhoneSipAccounts < ActiveRecord::Migration + def self.up + create_table :phone_sip_accounts do |t| + t.integer :phone_id + t.integer :sip_account_id + t.integer :position + t.timestamps + end + end + + def self.down + drop_table :phone_sip_accounts + end +end diff --git a/db/migrate/20120104142556_create_ringtones.rb b/db/migrate/20120104142556_create_ringtones.rb new file mode 100644 index 0000000..b671375 --- /dev/null +++ b/db/migrate/20120104142556_create_ringtones.rb @@ -0,0 +1,15 @@ +class CreateRingtones < ActiveRecord::Migration + def self.up + create_table :ringtones do |t| + t.string :ringtoneable_type + t.integer :ringtoneable_id + t.string :audio + t.integer :bellcore_id + t.timestamps + end + end + + def self.down + drop_table :ringtones + end +end diff --git a/db/migrate/20120112094631_add_announcement_of_a_new_member_to_conference.rb b/db/migrate/20120112094631_add_announcement_of_a_new_member_to_conference.rb new file mode 100644 index 0000000..104f419 --- /dev/null +++ b/db/migrate/20120112094631_add_announcement_of_a_new_member_to_conference.rb @@ -0,0 +1,6 @@ +class AddAnnouncementOfANewMemberToConference < ActiveRecord::Migration + def change + add_column :conferences, :announce_new_member_by_name, :boolean + add_column :conferences, :announce_left_member_by_name, :boolean + end +end diff --git a/db/migrate/20120118195740_create_softkeys.rb b/db/migrate/20120118195740_create_softkeys.rb new file mode 100644 index 0000000..a8d7d64 --- /dev/null +++ b/db/migrate/20120118195740_create_softkeys.rb @@ -0,0 +1,17 @@ +class CreateSoftkeys < ActiveRecord::Migration + def self.up + create_table :softkeys do |t| + t.integer :phone_id + t.string :name + t.string :function + t.string :number + t.string :label + t.integer :position + t.timestamps + end + end + + def self.down + drop_table :softkeys + end +end diff --git a/db/migrate/20120119103852_add_sip_account_to_softkeys.rb b/db/migrate/20120119103852_add_sip_account_to_softkeys.rb new file mode 100644 index 0000000..74bfaee --- /dev/null +++ b/db/migrate/20120119103852_add_sip_account_to_softkeys.rb @@ -0,0 +1,6 @@ +class AddSipAccountToSoftkeys < ActiveRecord::Migration + def change + add_column :softkeys, :sip_account_id, :integer + remove_column :softkeys, :phone_id + end +end diff --git a/db/migrate/20120119111944_add_call_waiting_to_sip_accounts.rb b/db/migrate/20120119111944_add_call_waiting_to_sip_accounts.rb new file mode 100644 index 0000000..f23e9a0 --- /dev/null +++ b/db/migrate/20120119111944_add_call_waiting_to_sip_accounts.rb @@ -0,0 +1,5 @@ +class AddCallWaitingToSipAccounts < ActiveRecord::Migration + def change + add_column :sip_accounts, :call_waiting, :boolean + end +end diff --git a/db/migrate/20120119114329_add_clir_and_clip_phone_number_to_sip_accounts.rb b/db/migrate/20120119114329_add_clir_and_clip_phone_number_to_sip_accounts.rb new file mode 100644 index 0000000..d21916c --- /dev/null +++ b/db/migrate/20120119114329_add_clir_and_clip_phone_number_to_sip_accounts.rb @@ -0,0 +1,6 @@ +class AddClirAndClipPhoneNumberToSipAccounts < ActiveRecord::Migration + def change + add_column :sip_accounts, :clir, :boolean + add_column :sip_accounts, :clip_phone_number_id, :integer + end +end diff --git a/db/migrate/20120119154422_fax_defaults.rb b/db/migrate/20120119154422_fax_defaults.rb new file mode 100644 index 0000000..76ccb47 --- /dev/null +++ b/db/migrate/20120119154422_fax_defaults.rb @@ -0,0 +1,15 @@ +# ruby encoding: utf-8 + +class FaxDefaults < ActiveRecord::Migration + def up + ################################################################ + # Fax resolutions + ################################################################ + FaxResolution.create(:name => 'Standard', :resolution_value => '204x98') + FaxResolution.create(:name => 'Fine', :resolution_value => '204x196') + end + + def down + FaxResolution.destroy_all + end +end diff --git a/db/migrate/20120119154633_language_defaults.rb b/db/migrate/20120119154633_language_defaults.rb new file mode 100644 index 0000000..a67b641 --- /dev/null +++ b/db/migrate/20120119154633_language_defaults.rb @@ -0,0 +1,15 @@ +# ruby encoding: utf-8 + +class LanguageDefaults < ActiveRecord::Migration + def up + ################################################################ + # Languages + ################################################################ + Language.create(:name => 'Deutsch', :code => 'de') + Language.create(:name => 'English', :code => 'en') + end + + def down + Language.destroy_all + end +end diff --git a/db/migrate/20120119154759_country_defaults.rb b/db/migrate/20120119154759_country_defaults.rb new file mode 100644 index 0000000..dd8fd43 --- /dev/null +++ b/db/migrate/20120119154759_country_defaults.rb @@ -0,0 +1,254 @@ +# ruby encoding: utf-8 + +class CountryDefaults < ActiveRecord::Migration + def up + ################################################################ + # Countries + ################################################################ + + ActiveRecord::Base.transaction do + Country.create(:name => "American Samoa", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Anguilla", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Antigua and Barbuda", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Bahamas", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Barbados", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Bermuda", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "British Virgin Islands", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Canada", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Cayman Islands", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Dominica", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Dominican Republic", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Grenada", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Guam", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Jamaica", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Montserrat", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Northern Mariana Islands", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Puerto Rico", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Saint Kitts and Nevis", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Saint Lucia", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Saint Vincent and the Grenadines", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Trinidad and Tobago", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Turks and Caicos Islands", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "United States of America", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "United States Virgin Islands", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Egypt", :country_code => "20", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Morocco", :country_code => "212", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Algeria", :country_code => "213", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Tunisia", :country_code => "216", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Libya", :country_code => "218", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Gambia", :country_code => "220", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Senegal", :country_code => "221", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Mauritania", :country_code => "222", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Mali", :country_code => "223", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Guinea", :country_code => "224", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Côte d'Ivoire", :country_code => "225", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Burkina Faso", :country_code => "226", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Niger", :country_code => "227", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Togolese Republic", :country_code => "228", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Benin", :country_code => "229", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Mauritius", :country_code => "230", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Liberia", :country_code => "231", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Sierra Leone", :country_code => "232", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Ghana", :country_code => "233", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Nigeria", :country_code => "234", :international_call_prefix => "009", :trunk_prefix => "" ) + Country.create(:name => "Chad", :country_code => "235", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Central African Republic", :country_code => "236", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Cameroon", :country_code => "237", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Cape Verde", :country_code => "238", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Sao Tome and Principe", :country_code => "239", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Equatorial Guinea", :country_code => "240", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Gabonese Republic", :country_code => "241", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Congo", :country_code => "242", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Democratic Republic of the Congo", :country_code => "243", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Angola", :country_code => "244", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Guinea-Bissau", :country_code => "245", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Diego Garcia", :country_code => "246", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Ascension", :country_code => "247", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Seychelles", :country_code => "248", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Sudan", :country_code => "249", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Rwanda", :country_code => "250", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Ethiopia", :country_code => "251", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Somali Democratic Republic", :country_code => "252", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Djibouti", :country_code => "253", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Kenya", :country_code => "254", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Tanzania", :country_code => "255", :international_call_prefix => "000", :trunk_prefix => "" ) + Country.create(:name => "Uganda", :country_code => "256", :international_call_prefix => "000", :trunk_prefix => "" ) + Country.create(:name => "Burundi", :country_code => "257", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Mozambique", :country_code => "258", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Zambia", :country_code => "260", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Madagascar", :country_code => "261", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Reunion", :country_code => "262", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Zimbabwe", :country_code => "263", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Namibia", :country_code => "264", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Malawi", :country_code => "265", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Lesotho", :country_code => "266", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Botswana", :country_code => "267", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Swaziland", :country_code => "268", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Comoros", :country_code => "269", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Mayotte", :country_code => "269", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "South Africa", :country_code => "27", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Saint Helena", :country_code => "290", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Eritrea", :country_code => "291", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Aruba", :country_code => "297", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Faroe Islands", :country_code => "298", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Greenland", :country_code => "299", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Greece", :country_code => "30", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Netherlands", :country_code => "31", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Belgium", :country_code => "32", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "France", :country_code => "33", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Spain", :country_code => "34", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Gibraltar", :country_code => "350", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Portugal", :country_code => "351", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Luxembourg", :country_code => "352", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Ireland", :country_code => "353", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Iceland", :country_code => "354", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Albania", :country_code => "355", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Malta", :country_code => "356", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Cyprus", :country_code => "357", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Finland", :country_code => "358", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Bulgaria", :country_code => "359", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Hungary", :country_code => "36", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Lithuania", :country_code => "370", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Latvia", :country_code => "371", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Estonia", :country_code => "372", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Moldova", :country_code => "373", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Armenia", :country_code => "374", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Belarus", :country_code => "375", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Andorra", :country_code => "376", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Monaco", :country_code => "377", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "San Marino", :country_code => "378", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Vatican City State", :country_code => "379", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Ukraine", :country_code => "380", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Serbia and Montenegro", :country_code => "381", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Croatia", :country_code => "385", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Slovenia", :country_code => "386", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Bosnia and Herzegovina", :country_code => "387", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Group of countries, shared code", :country_code => "388", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "The Former Yugoslav Republic of Macedonia", :country_code => "389", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Italy", :country_code => "39", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Vatican City State", :country_code => "39", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Romania", :country_code => "40", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Switzerland", :country_code => "41", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Czech Republic", :country_code => "420", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Slovak Republic", :country_code => "421", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Liechtenstein", :country_code => "423", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Austria", :country_code => "43", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "United Kingdom of Great Britain and Northern Ireland", :country_code => "44", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Denmark", :country_code => "45", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Sweden", :country_code => "46", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Norway", :country_code => "47", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Poland", :country_code => "48", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Germany", :country_code => "49", :international_call_prefix => "00", :trunk_prefix => "0" ) + Country.create(:name => "Falkland Islands", :country_code => "500", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Belize", :country_code => "501", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Guatemala", :country_code => "502", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "El Salvador", :country_code => "503", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Honduras", :country_code => "504", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Nicaragua", :country_code => "505", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Costa Rica", :country_code => "506", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Panama", :country_code => "507", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Saint Pierre and Miquelon", :country_code => "508", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Haiti", :country_code => "509", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Peru", :country_code => "51", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Mexico", :country_code => "52", :international_call_prefix => "00", :trunk_prefix => "01" ) + Country.create(:name => "Cuba", :country_code => "53", :international_call_prefix => "119", :trunk_prefix => "" ) + Country.create(:name => "Argentine Republic", :country_code => "54", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Brazil", :country_code => "55", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Chile", :country_code => "56", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Colombia", :country_code => "57", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Venezuela", :country_code => "58", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Guadeloupe", :country_code => "590", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Bolivia", :country_code => "591", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Guyana", :country_code => "592", :international_call_prefix => "001", :trunk_prefix => "" ) + Country.create(:name => "Ecuador", :country_code => "593", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "French Guiana", :country_code => "594", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Paraguay", :country_code => "595", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Martinique", :country_code => "596", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Suriname", :country_code => "597", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Uruguay", :country_code => "598", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Netherlands Antilles", :country_code => "599", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Malaysia", :country_code => "60", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Australia", :country_code => "61", :international_call_prefix => "0011", :trunk_prefix => "" ) + Country.create(:name => "Indonesia", :country_code => "62", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Philippines", :country_code => "63", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "New Zealand", :country_code => "64", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Singapore", :country_code => "65", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Thailand", :country_code => "66", :international_call_prefix => "001", :trunk_prefix => "" ) + Country.create(:name => "Democratic Republic of Timor-Leste", :country_code => "670", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Australian External Territories", :country_code => "672", :international_call_prefix => "0011", :trunk_prefix => "" ) + Country.create(:name => "Brunei Darussalam", :country_code => "673", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Nauru", :country_code => "674", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Papua New Guinea", :country_code => "675", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Tonga", :country_code => "676", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Solomon Islands", :country_code => "677", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Vanuatu", :country_code => "678", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Fiji", :country_code => "679", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Palau", :country_code => "680", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Wallis and Futuna", :country_code => "681", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Cook Islands", :country_code => "682", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Niue", :country_code => "683", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Samoa", :country_code => "685", :international_call_prefix => "0", :trunk_prefix => "" ) + Country.create(:name => "Kiribati", :country_code => "686", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "New Caledonia", :country_code => "687", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Tuvalu", :country_code => "688", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "French Polynesia", :country_code => "689", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Tokelau", :country_code => "690", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Micronesia", :country_code => "691", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Marshall Islands", :country_code => "692", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Kazakhstan", :country_code => "7", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Russian Federation", :country_code => "7", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "International Freephone Service", :country_code => "800", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "International Shared Cost Service", :country_code => "808", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Japan", :country_code => "81", :international_call_prefix => "010", :trunk_prefix => "" ) + Country.create(:name => "Korea", :country_code => "82", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Viet Nam", :country_code => "84", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Democratic People's Republic of Korea", :country_code => "850", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Hong Kong, China", :country_code => "852", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Macao, China", :country_code => "853", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Cambodia", :country_code => "855", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Lao People's Democratic Republic", :country_code => "856", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "China", :country_code => "86", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Inmarsat SNAC", :country_code => "870", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Inmarsat (871)", :country_code => "871", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Inmarsat (872)", :country_code => "872", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Inmarsat (873)", :country_code => "873", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Inmarsat (874)", :country_code => "874", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Universal Personal Telecommunication Service", :country_code => "878", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Bangladesh", :country_code => "880", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Turkey", :country_code => "90", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "India", :country_code => "91", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Pakistan", :country_code => "92", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Afghanistan", :country_code => "93", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Sri Lanka", :country_code => "94", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Myanmar", :country_code => "95", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Maldives", :country_code => "960", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Lebanon", :country_code => "961", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Jordan", :country_code => "962", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Syrian Arab Republic", :country_code => "963", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Iraq", :country_code => "964", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Kuwait", :country_code => "965", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Saudi Arabia", :country_code => "966", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Yemen", :country_code => "967", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Oman", :country_code => "968", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "United Arab Emirates", :country_code => "971", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Israel", :country_code => "972", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Bahrain", :country_code => "973", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Qatar", :country_code => "974", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Bhutan", :country_code => "975", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Mongolia", :country_code => "976", :international_call_prefix => "001", :trunk_prefix => "" ) + Country.create(:name => "Nepal", :country_code => "977", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "International Premium Rate Service", :country_code => "979", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Iran", :country_code => "98", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Tajikistan", :country_code => "992", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Turkmenistan", :country_code => "993", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Azerbaijani Republic", :country_code => "994", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Georgia", :country_code => "995", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Kyrgyz Republic", :country_code => "996", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Uzbekistan", :country_code => "998", :international_call_prefix => "00", :trunk_prefix => "" ) + end + end + + def down + Country.destroy_all + end +end diff --git a/db/migrate/20120119154952_area_codes_germany.rb b/db/migrate/20120119154952_area_codes_germany.rb new file mode 100644 index 0000000..6a4ce56 --- /dev/null +++ b/db/migrate/20120119154952_area_codes_germany.rb @@ -0,0 +1,5245 @@ +# ruby encoding: utf-8 + +class AreaCodesGermany < ActiveRecord::Migration + def up + germany = Country.find_by_name('Germany') + + ################################################################ + # AreaCodes Germany + ################################################################ + + ActiveRecord::Base.transaction do + AreaCode.create(:country => germany, :name => "Essen", :area_code => "201") + AreaCode.create(:country => germany, :name => "Wuppertal", :area_code => "202") + AreaCode.create(:country => germany, :name => "Duisburg", :area_code => "203") + AreaCode.create(:country => germany, :name => "Bottrop", :area_code => "2041") + AreaCode.create(:country => germany, :name => "Gladbeck", :area_code => "2043") + AreaCode.create(:country => germany, :name => "Bottrop-Kirchhellen", :area_code => "2045") + AreaCode.create(:country => germany, :name => "Velbert", :area_code => "2051") + AreaCode.create(:country => germany, :name => "Velbert-Langenberg", :area_code => "2052") + AreaCode.create(:country => germany, :name => "Velbert-Neviges", :area_code => "2053") + AreaCode.create(:country => germany, :name => "Essen-Kettwig", :area_code => "2054") + AreaCode.create(:country => germany, :name => "Heiligenhaus", :area_code => "2056") + AreaCode.create(:country => germany, :name => "Wülfrath", :area_code => "2058") + AreaCode.create(:country => germany, :name => "Dinslaken", :area_code => "2064") + AreaCode.create(:country => germany, :name => "Duisburg-Rheinhausen", :area_code => "2065") + AreaCode.create(:country => germany, :name => "Duisburg-Homberg", :area_code => "2066") + AreaCode.create(:country => germany, :name => "Oberhausen Rheinl", :area_code => "208") + AreaCode.create(:country => germany, :name => "Gelsenkirchen", :area_code => "209") + AreaCode.create(:country => germany, :name => "Ratingen", :area_code => "2102") + AreaCode.create(:country => germany, :name => "Hilden", :area_code => "2103") + AreaCode.create(:country => germany, :name => "Mettmann", :area_code => "2104") + AreaCode.create(:country => germany, :name => "Düsseldorf", :area_code => "211") + AreaCode.create(:country => germany, :name => "Solingen", :area_code => "212") + AreaCode.create(:country => germany, :name => "Haan Rheinl", :area_code => "2129") + AreaCode.create(:country => germany, :name => "Neuss", :area_code => "2131") + AreaCode.create(:country => germany, :name => "Meerbusch-Büderich", :area_code => "2132") + AreaCode.create(:country => germany, :name => "Dormagen", :area_code => "2133") + AreaCode.create(:country => germany, :name => "Neuss-Norf", :area_code => "2137") + AreaCode.create(:country => germany, :name => "Leverkusen", :area_code => "214") + AreaCode.create(:country => germany, :name => "Meerbusch-Lank", :area_code => "2150") + AreaCode.create(:country => germany, :name => "Krefeld", :area_code => "2151") + AreaCode.create(:country => germany, :name => "Kempen", :area_code => "2152") + AreaCode.create(:country => germany, :name => "Nettetal-Lobberich", :area_code => "2153") + AreaCode.create(:country => germany, :name => "Willich", :area_code => "2154") + AreaCode.create(:country => germany, :name => "Willich-Anrath", :area_code => "2156") + AreaCode.create(:country => germany, :name => "Nettetal-Kaldenkirchen", :area_code => "2157") + AreaCode.create(:country => germany, :name => "Grefrath b Krefeld", :area_code => "2158") + AreaCode.create(:country => germany, :name => "Meerbusch-Osterath", :area_code => "2159") + AreaCode.create(:country => germany, :name => "Mönchengladbach", :area_code => "2161") + AreaCode.create(:country => germany, :name => "Viersen", :area_code => "2162") + AreaCode.create(:country => germany, :name => "Schwalmtal Niederrhein", :area_code => "2163") + AreaCode.create(:country => germany, :name => "Jüchen-Otzenrath", :area_code => "2164") + AreaCode.create(:country => germany, :name => "Jüchen", :area_code => "2165") + AreaCode.create(:country => germany, :name => "Mönchengladbach-Rheydt", :area_code => "2166") + AreaCode.create(:country => germany, :name => "Leverkusen-Opladen", :area_code => "2171") + AreaCode.create(:country => germany, :name => "Langenfeld Rheinland", :area_code => "2173") + AreaCode.create(:country => germany, :name => "Burscheid Rheinl", :area_code => "2174") + AreaCode.create(:country => germany, :name => "Leichlingen Rheinland", :area_code => "2175") + AreaCode.create(:country => germany, :name => "Grevenbroich", :area_code => "2181") + AreaCode.create(:country => germany, :name => "Grevenbroich-Kapellen", :area_code => "2182") + AreaCode.create(:country => germany, :name => "Rommerskirchen", :area_code => "2183") + AreaCode.create(:country => germany, :name => "Remscheid", :area_code => "2191") + AreaCode.create(:country => germany, :name => "Hückeswagen", :area_code => "2192") + AreaCode.create(:country => germany, :name => "Dabringhausen", :area_code => "2193") + AreaCode.create(:country => germany, :name => "Radevormwald", :area_code => "2195") + AreaCode.create(:country => germany, :name => "Wermelskirchen", :area_code => "2196") + AreaCode.create(:country => germany, :name => "Bergisch Gladbach", :area_code => "2202") + AreaCode.create(:country => germany, :name => "Köln-Porz", :area_code => "2203") + AreaCode.create(:country => germany, :name => "Bensberg", :area_code => "2204") + AreaCode.create(:country => germany, :name => "Rösrath", :area_code => "2205") + AreaCode.create(:country => germany, :name => "Overath", :area_code => "2206") + AreaCode.create(:country => germany, :name => "Kürten-Dürscheid", :area_code => "2207") + AreaCode.create(:country => germany, :name => "Niederkassel", :area_code => "2208") + AreaCode.create(:country => germany, :name => "Köln", :area_code => "221") + AreaCode.create(:country => germany, :name => "Bornheim Rheinl", :area_code => "2222") + AreaCode.create(:country => germany, :name => "Königswinter", :area_code => "2223") + AreaCode.create(:country => germany, :name => "Bad Honnef", :area_code => "2224") + AreaCode.create(:country => germany, :name => "Meckenheim Rheinl", :area_code => "2225") + AreaCode.create(:country => germany, :name => "Rheinbach", :area_code => "2226") + AreaCode.create(:country => germany, :name => "Bornheim-Merten", :area_code => "2227") + AreaCode.create(:country => germany, :name => "Remagen-Rolandseck", :area_code => "2228") + AreaCode.create(:country => germany, :name => "Brühl Rheinl", :area_code => "2232") + AreaCode.create(:country => germany, :name => "Hürth Rheinl", :area_code => "2233") + AreaCode.create(:country => germany, :name => "Frechen", :area_code => "2234") + AreaCode.create(:country => germany, :name => "Erftstadt", :area_code => "2235") + AreaCode.create(:country => germany, :name => "Wesseling Rheinl", :area_code => "2236") + AreaCode.create(:country => germany, :name => "Kerpen Rheinl-Türnich", :area_code => "2237") + AreaCode.create(:country => germany, :name => "Pulheim", :area_code => "2238") + AreaCode.create(:country => germany, :name => "Siegburg", :area_code => "2241") + AreaCode.create(:country => germany, :name => "Hennef Sieg", :area_code => "2242") + AreaCode.create(:country => germany, :name => "Eitorf", :area_code => "2243") + AreaCode.create(:country => germany, :name => "Königswinter-Oberpleis", :area_code => "2244") + AreaCode.create(:country => germany, :name => "Much", :area_code => "2245") + AreaCode.create(:country => germany, :name => "Lohmar", :area_code => "2246") + AreaCode.create(:country => germany, :name => "Neunkirchen-Seelscheid", :area_code => "2247") + AreaCode.create(:country => germany, :name => "Hennef-Uckerath", :area_code => "2248") + AreaCode.create(:country => germany, :name => "Euskirchen", :area_code => "2251") + AreaCode.create(:country => germany, :name => "Zülpich", :area_code => "2252") + AreaCode.create(:country => germany, :name => "Bad Münstereifel", :area_code => "2253") + AreaCode.create(:country => germany, :name => "Weilerswist", :area_code => "2254") + AreaCode.create(:country => germany, :name => "Euskirchen-Flamersheim", :area_code => "2255") + AreaCode.create(:country => germany, :name => "Mechernich-Satzvey", :area_code => "2256") + AreaCode.create(:country => germany, :name => "Reckerscheid", :area_code => "2257") + AreaCode.create(:country => germany, :name => "Gummersbach", :area_code => "2261") + AreaCode.create(:country => germany, :name => "Wiehl", :area_code => "2262") + AreaCode.create(:country => germany, :name => "Engelskirchen", :area_code => "2263") + AreaCode.create(:country => germany, :name => "Marienheide", :area_code => "2264") + AreaCode.create(:country => germany, :name => "Reichshof-Eckenhagen", :area_code => "2265") + AreaCode.create(:country => germany, :name => "Lindlar", :area_code => "2266") + AreaCode.create(:country => germany, :name => "Wipperfürth", :area_code => "2267") + AreaCode.create(:country => germany, :name => "Kürten", :area_code => "2268") + AreaCode.create(:country => germany, :name => "Kierspe-Rönsahl", :area_code => "2269") + AreaCode.create(:country => germany, :name => "Bergheim Erft", :area_code => "2271") + AreaCode.create(:country => germany, :name => "Bedburg Erft", :area_code => "2272") + AreaCode.create(:country => germany, :name => "Kerpen-Horrem", :area_code => "2273") + AreaCode.create(:country => germany, :name => "Elsdorf Rheinl", :area_code => "2274") + AreaCode.create(:country => germany, :name => "Kerpen-Buir", :area_code => "2275") + AreaCode.create(:country => germany, :name => "Bonn", :area_code => "228") + AreaCode.create(:country => germany, :name => "Waldbröl", :area_code => "2291") + AreaCode.create(:country => germany, :name => "Windeck Sieg", :area_code => "2292") + AreaCode.create(:country => germany, :name => "Nümbrecht", :area_code => "2293") + AreaCode.create(:country => germany, :name => "Morsbach Sieg", :area_code => "2294") + AreaCode.create(:country => germany, :name => "Ruppichteroth", :area_code => "2295") + AreaCode.create(:country => germany, :name => "Reichshof-Brüchermühle", :area_code => "2296") + AreaCode.create(:country => germany, :name => "Wildbergerhütte", :area_code => "2297") + AreaCode.create(:country => germany, :name => "Holzwickede", :area_code => "2301") + AreaCode.create(:country => germany, :name => "Witten", :area_code => "2302") + AreaCode.create(:country => germany, :name => "Unna", :area_code => "2303") + AreaCode.create(:country => germany, :name => "Schwerte", :area_code => "2304") + AreaCode.create(:country => germany, :name => "Castrop-Rauxel", :area_code => "2305") + AreaCode.create(:country => germany, :name => "Lünen", :area_code => "2306") + AreaCode.create(:country => germany, :name => "Kamen", :area_code => "2307") + AreaCode.create(:country => germany, :name => "Unna-Hemmerde", :area_code => "2308") + AreaCode.create(:country => germany, :name => "Waltrop", :area_code => "2309") + AreaCode.create(:country => germany, :name => "Dortmund", :area_code => "231") + AreaCode.create(:country => germany, :name => "Herne", :area_code => "2323") + AreaCode.create(:country => germany, :name => "Hattingen Ruhr", :area_code => "2324") + AreaCode.create(:country => germany, :name => "Wanne-Eickel", :area_code => "2325") + AreaCode.create(:country => germany, :name => "Bochum-Wattenscheid", :area_code => "2327") + AreaCode.create(:country => germany, :name => "Herdecke", :area_code => "2330") + AreaCode.create(:country => germany, :name => "Hagen Westf", :area_code => "2331") + AreaCode.create(:country => germany, :name => "Gevelsberg", :area_code => "2332") + AreaCode.create(:country => germany, :name => "Ennepetal", :area_code => "2333") + AreaCode.create(:country => germany, :name => "Hagen-Hohenlimburg", :area_code => "2334") + AreaCode.create(:country => germany, :name => "Wetter Ruhr", :area_code => "2335") + AreaCode.create(:country => germany, :name => "Schwelm", :area_code => "2336") + AreaCode.create(:country => germany, :name => "Hagen-Dahl", :area_code => "2337") + AreaCode.create(:country => germany, :name => "Breckerfeld", :area_code => "2338") + AreaCode.create(:country => germany, :name => "Sprockhövel-Haßlinghausen", :area_code => "2339") + AreaCode.create(:country => germany, :name => "Bochum", :area_code => "234") + AreaCode.create(:country => germany, :name => "Lüdenscheid", :area_code => "2351") + AreaCode.create(:country => germany, :name => "Altena Westf", :area_code => "2352") + AreaCode.create(:country => germany, :name => "Halver", :area_code => "2353") + AreaCode.create(:country => germany, :name => "Meinerzhagen", :area_code => "2354") + AreaCode.create(:country => germany, :name => "Schalksmühle", :area_code => "2355") + AreaCode.create(:country => germany, :name => "Herscheid Westf", :area_code => "2357") + AreaCode.create(:country => germany, :name => "Meinerzhagen-Valbert", :area_code => "2358") + AreaCode.create(:country => germany, :name => "Kierspe", :area_code => "2359") + AreaCode.create(:country => germany, :name => "Haltern-Lippramsdorf", :area_code => "2360") + AreaCode.create(:country => germany, :name => "Recklinghausen", :area_code => "2361") + AreaCode.create(:country => germany, :name => "Dorsten", :area_code => "2362") + AreaCode.create(:country => germany, :name => "Datteln", :area_code => "2363") + AreaCode.create(:country => germany, :name => "Haltern Westf", :area_code => "2364") + AreaCode.create(:country => germany, :name => "Marl", :area_code => "2365") + AreaCode.create(:country => germany, :name => "Herten Westf", :area_code => "2366") + AreaCode.create(:country => germany, :name => "Henrichenburg", :area_code => "2367") + AreaCode.create(:country => germany, :name => "Oer-Erkenschwick", :area_code => "2368") + AreaCode.create(:country => germany, :name => "Dorsten-Wulfen", :area_code => "2369") + AreaCode.create(:country => germany, :name => "Iserlohn", :area_code => "2371") + AreaCode.create(:country => germany, :name => "Hemer", :area_code => "2372") + AreaCode.create(:country => germany, :name => "Menden Sauerland", :area_code => "2373") + AreaCode.create(:country => germany, :name => "Iserlohn-Letmathe", :area_code => "2374") + AreaCode.create(:country => germany, :name => "Balve", :area_code => "2375") + AreaCode.create(:country => germany, :name => "Wickede Ruhr", :area_code => "2377") + AreaCode.create(:country => germany, :name => "Fröndenberg-Langschede", :area_code => "2378") + AreaCode.create(:country => germany, :name => "Menden-Asbeck", :area_code => "2379") + AreaCode.create(:country => germany, :name => "Hamm Westf", :area_code => "2381") + AreaCode.create(:country => germany, :name => "Ahlen Westf", :area_code => "2382") + AreaCode.create(:country => germany, :name => "Bönen", :area_code => "2383") + AreaCode.create(:country => germany, :name => "Welver", :area_code => "2384") + AreaCode.create(:country => germany, :name => "Hamm-Rhynern", :area_code => "2385") + AreaCode.create(:country => germany, :name => "Drensteinfurt-Walstedde", :area_code => "2387") + AreaCode.create(:country => germany, :name => "Hamm-Uentrop", :area_code => "2388") + AreaCode.create(:country => germany, :name => "Werne", :area_code => "2389") + AreaCode.create(:country => germany, :name => "Plettenberg", :area_code => "2391") + AreaCode.create(:country => germany, :name => "Werdohl", :area_code => "2392") + AreaCode.create(:country => germany, :name => "Sundern-Allendorf", :area_code => "2393") + AreaCode.create(:country => germany, :name => "Neuenrade-Affeln", :area_code => "2394") + AreaCode.create(:country => germany, :name => "Finnentrop-Rönkhausen", :area_code => "2395") + AreaCode.create(:country => germany, :name => "Baesweiler", :area_code => "2401") + AreaCode.create(:country => germany, :name => "Stolberg Rheinl", :area_code => "2402") + AreaCode.create(:country => germany, :name => "Eschweiler Rheinl", :area_code => "2403") + AreaCode.create(:country => germany, :name => "Alsdorf Rheinl", :area_code => "2404") + AreaCode.create(:country => germany, :name => "Würselen", :area_code => "2405") + AreaCode.create(:country => germany, :name => "Herzogenrath", :area_code => "2406") + AreaCode.create(:country => germany, :name => "Herzogenrath-Kohlscheid", :area_code => "2407") + AreaCode.create(:country => germany, :name => "Aachen-Kornelimünster", :area_code => "2408") + AreaCode.create(:country => germany, :name => "Stolberg-Gressenich", :area_code => "2409") + AreaCode.create(:country => germany, :name => "Aachen", :area_code => "241") + AreaCode.create(:country => germany, :name => "Düren", :area_code => "2421") + AreaCode.create(:country => germany, :name => "Kreuzau", :area_code => "2422") + AreaCode.create(:country => germany, :name => "Langerwehe", :area_code => "2423") + AreaCode.create(:country => germany, :name => "Vettweiss", :area_code => "2424") + AreaCode.create(:country => germany, :name => "Nideggen-Embken", :area_code => "2425") + AreaCode.create(:country => germany, :name => "Nörvenich", :area_code => "2426") + AreaCode.create(:country => germany, :name => "Nideggen", :area_code => "2427") + AreaCode.create(:country => germany, :name => "Niederzier", :area_code => "2428") + AreaCode.create(:country => germany, :name => "Hürtgenwald", :area_code => "2429") + AreaCode.create(:country => germany, :name => "Erkelenz", :area_code => "2431") + AreaCode.create(:country => germany, :name => "Wassenberg", :area_code => "2432") + AreaCode.create(:country => germany, :name => "Hückelhoven", :area_code => "2433") + AreaCode.create(:country => germany, :name => "Wegberg", :area_code => "2434") + AreaCode.create(:country => germany, :name => "Erkelenz-Lövenich", :area_code => "2435") + AreaCode.create(:country => germany, :name => "Wegberg-Rödgen", :area_code => "2436") + AreaCode.create(:country => germany, :name => "Nettersheim-Tondorf", :area_code => "2440") + AreaCode.create(:country => germany, :name => "Kall", :area_code => "2441") + AreaCode.create(:country => germany, :name => "Mechernich", :area_code => "2443") + AreaCode.create(:country => germany, :name => "Schleiden-Gemünd", :area_code => "2444") + AreaCode.create(:country => germany, :name => "Schleiden Eifel", :area_code => "2445") + AreaCode.create(:country => germany, :name => "Heimbach Eifel", :area_code => "2446") + AreaCode.create(:country => germany, :name => "Dahlem b Kall", :area_code => "2447") + AreaCode.create(:country => germany, :name => "Hellenthal-Rescheid", :area_code => "2448") + AreaCode.create(:country => germany, :name => "Blankenheim Ahr", :area_code => "2449") + AreaCode.create(:country => germany, :name => "Geilenkirchen", :area_code => "2451") + AreaCode.create(:country => germany, :name => "Heinsberg Rheinl", :area_code => "2452") + AreaCode.create(:country => germany, :name => "Heinsberg-Randerath", :area_code => "2453") + AreaCode.create(:country => germany, :name => "Gangelt", :area_code => "2454") + AreaCode.create(:country => germany, :name => "Waldfeucht", :area_code => "2455") + AreaCode.create(:country => germany, :name => "Selfkant", :area_code => "2456") + AreaCode.create(:country => germany, :name => "Jülich", :area_code => "2461") + AreaCode.create(:country => germany, :name => "Linnich", :area_code => "2462") + AreaCode.create(:country => germany, :name => "Titz", :area_code => "2463") + AreaCode.create(:country => germany, :name => "Aldenhoven b Jülich", :area_code => "2464") + AreaCode.create(:country => germany, :name => "Inden", :area_code => "2465") + AreaCode.create(:country => germany, :name => "Roetgen Eifel", :area_code => "2471") + AreaCode.create(:country => germany, :name => "Monschau", :area_code => "2472") + AreaCode.create(:country => germany, :name => "Simmerath", :area_code => "2473") + AreaCode.create(:country => germany, :name => "Nideggen-Schmidt", :area_code => "2474") + AreaCode.create(:country => germany, :name => "Hellenthal", :area_code => "2482") + AreaCode.create(:country => germany, :name => "Mechernich-Eiserfey", :area_code => "2484") + AreaCode.create(:country => germany, :name => "Schleiden-Dreiborn", :area_code => "2485") + AreaCode.create(:country => germany, :name => "Nettersheim", :area_code => "2486") + AreaCode.create(:country => germany, :name => "Münster-Hiltrup", :area_code => "2501") + AreaCode.create(:country => germany, :name => "Nottuln", :area_code => "2502") + AreaCode.create(:country => germany, :name => "Telgte", :area_code => "2504") + AreaCode.create(:country => germany, :name => "Altenberge Westf", :area_code => "2505") + AreaCode.create(:country => germany, :name => "Münster-Wolbeck", :area_code => "2506") + AreaCode.create(:country => germany, :name => "Havixbeck", :area_code => "2507") + AreaCode.create(:country => germany, :name => "Drensteinfurt", :area_code => "2508") + AreaCode.create(:country => germany, :name => "Nottuln-Appelhülsen", :area_code => "2509") + AreaCode.create(:country => germany, :name => "Münster", :area_code => "251") + AreaCode.create(:country => germany, :name => "Wadersloh-Diestedde", :area_code => "2520") + AreaCode.create(:country => germany, :name => "Beckum", :area_code => "2521") + AreaCode.create(:country => germany, :name => "Oelde", :area_code => "2522") + AreaCode.create(:country => germany, :name => "Wadersloh", :area_code => "2523") + AreaCode.create(:country => germany, :name => "Ennigerloh", :area_code => "2524") + AreaCode.create(:country => germany, :name => "Beckum-Neubeckum", :area_code => "2525") + AreaCode.create(:country => germany, :name => "Sendenhorst", :area_code => "2526") + AreaCode.create(:country => germany, :name => "Lippetal-Lippborg", :area_code => "2527") + AreaCode.create(:country => germany, :name => "Ennigerloh-Enniger", :area_code => "2528") + AreaCode.create(:country => germany, :name => "Oelde-Stromberg", :area_code => "2529") + AreaCode.create(:country => germany, :name => "Ostbevern", :area_code => "2532") + AreaCode.create(:country => germany, :name => "Münster-Nienberge", :area_code => "2533") + AreaCode.create(:country => germany, :name => "Münster-Roxel", :area_code => "2534") + AreaCode.create(:country => germany, :name => "Sendenhorst-Albersloh", :area_code => "2535") + AreaCode.create(:country => germany, :name => "Münster-Albachten", :area_code => "2536") + AreaCode.create(:country => germany, :name => "Drensteinfurt-Rinkerode", :area_code => "2538") + AreaCode.create(:country => germany, :name => "Coesfeld", :area_code => "2541") + AreaCode.create(:country => germany, :name => "Gescher", :area_code => "2542") + AreaCode.create(:country => germany, :name => "Billerbeck Westf", :area_code => "2543") + AreaCode.create(:country => germany, :name => "Rosendahl-Darfeld", :area_code => "2545") + AreaCode.create(:country => germany, :name => "Coesfeld-Lette", :area_code => "2546") + AreaCode.create(:country => germany, :name => "Rosendahl-Osterwick", :area_code => "2547") + AreaCode.create(:country => germany, :name => "Dülmen-Rorup", :area_code => "2548") + AreaCode.create(:country => germany, :name => "Steinfurt-Burgsteinfurt", :area_code => "2551") + AreaCode.create(:country => germany, :name => "Steinfurt-Borghorst", :area_code => "2552") + AreaCode.create(:country => germany, :name => "Ochtrup", :area_code => "2553") + AreaCode.create(:country => germany, :name => "Laer Kr Steinfurt", :area_code => "2554") + AreaCode.create(:country => germany, :name => "Schöppingen", :area_code => "2555") + AreaCode.create(:country => germany, :name => "Metelen", :area_code => "2556") + AreaCode.create(:country => germany, :name => "Wettringen Kr Steinfurt", :area_code => "2557") + AreaCode.create(:country => germany, :name => "Horstmar", :area_code => "2558") + AreaCode.create(:country => germany, :name => "Ahaus", :area_code => "2561") + AreaCode.create(:country => germany, :name => "Gronau Westfalen", :area_code => "2562") + AreaCode.create(:country => germany, :name => "Stadtlohn", :area_code => "2563") + AreaCode.create(:country => germany, :name => "Vreden", :area_code => "2564") + AreaCode.create(:country => germany, :name => "Gronau-Epe", :area_code => "2565") + AreaCode.create(:country => germany, :name => "Legden", :area_code => "2566") + AreaCode.create(:country => germany, :name => "Ahaus-Alstätte", :area_code => "2567") + AreaCode.create(:country => germany, :name => "Heek", :area_code => "2568") + AreaCode.create(:country => germany, :name => "Greven Westf", :area_code => "2571") + AreaCode.create(:country => germany, :name => "Emsdetten", :area_code => "2572") + AreaCode.create(:country => germany, :name => "Nordwalde", :area_code => "2573") + AreaCode.create(:country => germany, :name => "Saerbeck", :area_code => "2574") + AreaCode.create(:country => germany, :name => "Greven-Reckenfeld", :area_code => "2575") + AreaCode.create(:country => germany, :name => "Warendorf", :area_code => "2581") + AreaCode.create(:country => germany, :name => "Everswinkel", :area_code => "2582") + AreaCode.create(:country => germany, :name => "Sassenberg", :area_code => "2583") + AreaCode.create(:country => germany, :name => "Warendorf-Milte", :area_code => "2584") + AreaCode.create(:country => germany, :name => "Warendorf-Hoetmar", :area_code => "2585") + AreaCode.create(:country => germany, :name => "Beelen", :area_code => "2586") + AreaCode.create(:country => germany, :name => "Ennigerloh-Westkirchen", :area_code => "2587") + AreaCode.create(:country => germany, :name => "Harsewinkel-Greffen", :area_code => "2588") + AreaCode.create(:country => germany, :name => "Dülmen-Buldern", :area_code => "2590") + AreaCode.create(:country => germany, :name => "Lüdinghausen", :area_code => "2591") + AreaCode.create(:country => germany, :name => "Selm", :area_code => "2592") + AreaCode.create(:country => germany, :name => "Ascheberg Westf", :area_code => "2593") + AreaCode.create(:country => germany, :name => "Dülmen", :area_code => "2594") + AreaCode.create(:country => germany, :name => "Olfen", :area_code => "2595") + AreaCode.create(:country => germany, :name => "Nordkirchen", :area_code => "2596") + AreaCode.create(:country => germany, :name => "Senden Westf", :area_code => "2597") + AreaCode.create(:country => germany, :name => "Senden-Ottmarsbocholt", :area_code => "2598") + AreaCode.create(:country => germany, :name => "Ascheberg-Herbern", :area_code => "2599") + AreaCode.create(:country => germany, :name => "Nauort", :area_code => "2601") + AreaCode.create(:country => germany, :name => "Montabaur", :area_code => "2602") + AreaCode.create(:country => germany, :name => "Bad Ems", :area_code => "2603") + AreaCode.create(:country => germany, :name => "Nassau Lahn", :area_code => "2604") + AreaCode.create(:country => germany, :name => "Löf", :area_code => "2605") + AreaCode.create(:country => germany, :name => "Winningen Mosel", :area_code => "2606") + AreaCode.create(:country => germany, :name => "Kobern-Gondorf", :area_code => "2607") + AreaCode.create(:country => germany, :name => "Welschneudorf", :area_code => "2608") + AreaCode.create(:country => germany, :name => "Koblenz am Rhein", :area_code => "261") + AreaCode.create(:country => germany, :name => "Neuhäusel Westerw", :area_code => "2620") + AreaCode.create(:country => germany, :name => "Lahnstein", :area_code => "2621") + AreaCode.create(:country => germany, :name => "Bendorf", :area_code => "2622") + AreaCode.create(:country => germany, :name => "Ransbach-Baumbach", :area_code => "2623") + AreaCode.create(:country => germany, :name => "Höhr-Grenzhausen", :area_code => "2624") + AreaCode.create(:country => germany, :name => "Ochtendung", :area_code => "2625") + AreaCode.create(:country => germany, :name => "Selters Westerwald", :area_code => "2626") + AreaCode.create(:country => germany, :name => "Braubach", :area_code => "2627") + AreaCode.create(:country => germany, :name => "Rhens", :area_code => "2628") + AreaCode.create(:country => germany, :name => "Mülheim-Kärlich", :area_code => "2630") + AreaCode.create(:country => germany, :name => "Neuwied", :area_code => "2631") + AreaCode.create(:country => germany, :name => "Andernach", :area_code => "2632") + AreaCode.create(:country => germany, :name => "Brohl-Lützing", :area_code => "2633") + AreaCode.create(:country => germany, :name => "Rengsdorf", :area_code => "2634") + AreaCode.create(:country => germany, :name => "Rheinbrohl", :area_code => "2635") + AreaCode.create(:country => germany, :name => "Burgbrohl", :area_code => "2636") + AreaCode.create(:country => germany, :name => "Weissenthurm", :area_code => "2637") + AreaCode.create(:country => germany, :name => "Waldbreitbach", :area_code => "2638") + AreaCode.create(:country => germany, :name => "Anhausen Kr Neuwied", :area_code => "2639") + AreaCode.create(:country => germany, :name => "Bad Neuenahr-Ahrweiler", :area_code => "2641") + AreaCode.create(:country => germany, :name => "Remagen", :area_code => "2642") + AreaCode.create(:country => germany, :name => "Altenahr", :area_code => "2643") + AreaCode.create(:country => germany, :name => "Linz am Rhein", :area_code => "2644") + AreaCode.create(:country => germany, :name => "Vettelschoss", :area_code => "2645") + AreaCode.create(:country => germany, :name => "Königsfeld Eifel", :area_code => "2646") + AreaCode.create(:country => germany, :name => "Kesseling", :area_code => "2647") + AreaCode.create(:country => germany, :name => "Mayen", :area_code => "2651") + AreaCode.create(:country => germany, :name => "Mendig", :area_code => "2652") + AreaCode.create(:country => germany, :name => "Kaisersesch", :area_code => "2653") + AreaCode.create(:country => germany, :name => "Polch", :area_code => "2654") + AreaCode.create(:country => germany, :name => "Weibern", :area_code => "2655") + AreaCode.create(:country => germany, :name => "Virneburg", :area_code => "2656") + AreaCode.create(:country => germany, :name => "Uersfeld", :area_code => "2657") + AreaCode.create(:country => germany, :name => "Bad Marienberg Westerwald", :area_code => "2661") + AreaCode.create(:country => germany, :name => "Hachenburg", :area_code => "2662") + AreaCode.create(:country => germany, :name => "Westerburg Westerw", :area_code => "2663") + AreaCode.create(:country => germany, :name => "Rennerod", :area_code => "2664") + AreaCode.create(:country => germany, :name => "Freilingen Westerw", :area_code => "2666") + AreaCode.create(:country => germany, :name => "Stein-Neukirch", :area_code => "2667") + AreaCode.create(:country => germany, :name => "Cochem", :area_code => "2671") + AreaCode.create(:country => germany, :name => "Treis-Karden", :area_code => "2672") + AreaCode.create(:country => germany, :name => "Ellenz-Poltersdorf", :area_code => "2673") + AreaCode.create(:country => germany, :name => "Bad Bertrich", :area_code => "2674") + AreaCode.create(:country => germany, :name => "Ediger-Eller", :area_code => "2675") + AreaCode.create(:country => germany, :name => "Ulmen", :area_code => "2676") + AreaCode.create(:country => germany, :name => "Lutzerath", :area_code => "2677") + AreaCode.create(:country => germany, :name => "Büchel b Cochem", :area_code => "2678") + AreaCode.create(:country => germany, :name => "Mündersbach", :area_code => "2680") + AreaCode.create(:country => germany, :name => "Altenkirchen Westerwald", :area_code => "2681") + AreaCode.create(:country => germany, :name => "Hamm Sieg", :area_code => "2682") + AreaCode.create(:country => germany, :name => "Asbach Westerw", :area_code => "2683") + AreaCode.create(:country => germany, :name => "Puderbach Westerw", :area_code => "2684") + AreaCode.create(:country => germany, :name => "Flammersfeld", :area_code => "2685") + AreaCode.create(:country => germany, :name => "Weyerbusch", :area_code => "2686") + AreaCode.create(:country => germany, :name => "Horhausen Westerwald", :area_code => "2687") + AreaCode.create(:country => germany, :name => "Kroppach", :area_code => "2688") + AreaCode.create(:country => germany, :name => "Dierdorf", :area_code => "2689") + AreaCode.create(:country => germany, :name => "Adenau", :area_code => "2691") + AreaCode.create(:country => germany, :name => "Kelberg", :area_code => "2692") + AreaCode.create(:country => germany, :name => "Antweiler", :area_code => "2693") + AreaCode.create(:country => germany, :name => "Wershofen", :area_code => "2694") + AreaCode.create(:country => germany, :name => "Insul", :area_code => "2695") + AreaCode.create(:country => germany, :name => "Nohn Eifel", :area_code => "2696") + AreaCode.create(:country => germany, :name => "Blankenheim-Ahrhütte", :area_code => "2697") + AreaCode.create(:country => germany, :name => "Siegen", :area_code => "271") + AreaCode.create(:country => germany, :name => "Lennestadt", :area_code => "2721") + AreaCode.create(:country => germany, :name => "Attendorn", :area_code => "2722") + AreaCode.create(:country => germany, :name => "Kirchhundem", :area_code => "2723") + AreaCode.create(:country => germany, :name => "Finnentrop-Serkenrode", :area_code => "2724") + AreaCode.create(:country => germany, :name => "Lennestadt-Oedingen", :area_code => "2725") + AreaCode.create(:country => germany, :name => "Kreuztal", :area_code => "2732") + AreaCode.create(:country => germany, :name => "Hilchenbach", :area_code => "2733") + AreaCode.create(:country => germany, :name => "Freudenberg Westf", :area_code => "2734") + AreaCode.create(:country => germany, :name => "Neunkirchen Siegerl", :area_code => "2735") + AreaCode.create(:country => germany, :name => "Burbach Siegerl", :area_code => "2736") + AreaCode.create(:country => germany, :name => "Netphen-Deuz", :area_code => "2737") + AreaCode.create(:country => germany, :name => "Netphen", :area_code => "2738") + AreaCode.create(:country => germany, :name => "Wilnsdorf", :area_code => "2739") + AreaCode.create(:country => germany, :name => "Betzdorf", :area_code => "2741") + AreaCode.create(:country => germany, :name => "Wissen", :area_code => "2742") + AreaCode.create(:country => germany, :name => "Daaden", :area_code => "2743") + AreaCode.create(:country => germany, :name => "Herdorf", :area_code => "2744") + AreaCode.create(:country => germany, :name => "Brachbach Sieg", :area_code => "2745") + AreaCode.create(:country => germany, :name => "Molzhain", :area_code => "2747") + AreaCode.create(:country => germany, :name => "Diedenshausen", :area_code => "2750") + AreaCode.create(:country => germany, :name => "Bad Berleburg", :area_code => "2751") + AreaCode.create(:country => germany, :name => "Bad Laasphe", :area_code => "2752") + AreaCode.create(:country => germany, :name => "Erndtebrück", :area_code => "2753") + AreaCode.create(:country => germany, :name => "Bad Laasphe-Feudingen", :area_code => "2754") + AreaCode.create(:country => germany, :name => "Bad Berleburg-Schwarzenau", :area_code => "2755") + AreaCode.create(:country => germany, :name => "Bad Berleburg-Girkhausen", :area_code => "2758") + AreaCode.create(:country => germany, :name => "Bad Berleburg-Aue", :area_code => "2759") + AreaCode.create(:country => germany, :name => "Olpe Biggesee", :area_code => "2761") + AreaCode.create(:country => germany, :name => "Wenden Südsauerland", :area_code => "2762") + AreaCode.create(:country => germany, :name => "Drolshagen-Bleche", :area_code => "2763") + AreaCode.create(:country => germany, :name => "Welschen Ennest", :area_code => "2764") + AreaCode.create(:country => germany, :name => "Eschenburg", :area_code => "2770") + AreaCode.create(:country => germany, :name => "Dillenburg", :area_code => "2771") + AreaCode.create(:country => germany, :name => "Herborn Hess", :area_code => "2772") + AreaCode.create(:country => germany, :name => "Haiger", :area_code => "2773") + AreaCode.create(:country => germany, :name => "Dietzhölztal", :area_code => "2774") + AreaCode.create(:country => germany, :name => "Driedorf", :area_code => "2775") + AreaCode.create(:country => germany, :name => "Bad Endbach-Hartenrod", :area_code => "2776") + AreaCode.create(:country => germany, :name => "Breitscheid Hess", :area_code => "2777") + AreaCode.create(:country => germany, :name => "Siegbach", :area_code => "2778") + AreaCode.create(:country => germany, :name => "Greifenstein-Beilstein", :area_code => "2779") + AreaCode.create(:country => germany, :name => "Xanten", :area_code => "2801") + AreaCode.create(:country => germany, :name => "Alpen", :area_code => "2802") + AreaCode.create(:country => germany, :name => "Wesel-Büderich", :area_code => "2803") + AreaCode.create(:country => germany, :name => "Xanten-Marienbaum", :area_code => "2804") + AreaCode.create(:country => germany, :name => "Wesel", :area_code => "281") + AreaCode.create(:country => germany, :name => "Kleve Niederrhein", :area_code => "2821") + AreaCode.create(:country => germany, :name => "Emmerich", :area_code => "2822") + AreaCode.create(:country => germany, :name => "Goch", :area_code => "2823") + AreaCode.create(:country => germany, :name => "Kalkar", :area_code => "2824") + AreaCode.create(:country => germany, :name => "Uedem", :area_code => "2825") + AreaCode.create(:country => germany, :name => "Kranenburg Niederrhein", :area_code => "2826") + AreaCode.create(:country => germany, :name => "Goch-Hassum", :area_code => "2827") + AreaCode.create(:country => germany, :name => "Emmerich-Elten", :area_code => "2828") + AreaCode.create(:country => germany, :name => "Geldern", :area_code => "2831") + AreaCode.create(:country => germany, :name => "Kevelaer", :area_code => "2832") + AreaCode.create(:country => germany, :name => "Kerken", :area_code => "2833") + AreaCode.create(:country => germany, :name => "Straelen", :area_code => "2834") + AreaCode.create(:country => germany, :name => "Issum", :area_code => "2835") + AreaCode.create(:country => germany, :name => "Wachtendonk", :area_code => "2836") + AreaCode.create(:country => germany, :name => "Weeze", :area_code => "2837") + AreaCode.create(:country => germany, :name => "Sonsbeck", :area_code => "2838") + AreaCode.create(:country => germany, :name => "Straelen-Herongen", :area_code => "2839") + AreaCode.create(:country => germany, :name => "Moers", :area_code => "2841") + AreaCode.create(:country => germany, :name => "Kamp-Lintfort", :area_code => "2842") + AreaCode.create(:country => germany, :name => "Rheinberg", :area_code => "2843") + AreaCode.create(:country => germany, :name => "Rheinberg-Orsoy", :area_code => "2844") + AreaCode.create(:country => germany, :name => "Neukirchen-Vluyn", :area_code => "2845") + AreaCode.create(:country => germany, :name => "Rees-Haldern", :area_code => "2850") + AreaCode.create(:country => germany, :name => "Rees", :area_code => "2851") + AreaCode.create(:country => germany, :name => "Hamminkeln", :area_code => "2852") + AreaCode.create(:country => germany, :name => "Schermbeck", :area_code => "2853") + AreaCode.create(:country => germany, :name => "Voerde Niederrhein", :area_code => "2855") + AreaCode.create(:country => germany, :name => "Hamminkeln-Brünen", :area_code => "2856") + AreaCode.create(:country => germany, :name => "Rees-Mehr", :area_code => "2857") + AreaCode.create(:country => germany, :name => "Hünxe", :area_code => "2858") + AreaCode.create(:country => germany, :name => "Wesel-Bislich", :area_code => "2859") + AreaCode.create(:country => germany, :name => "Borken Westf", :area_code => "2861") + AreaCode.create(:country => germany, :name => "Südlohn", :area_code => "2862") + AreaCode.create(:country => germany, :name => "Velen", :area_code => "2863") + AreaCode.create(:country => germany, :name => "Reken", :area_code => "2864") + AreaCode.create(:country => germany, :name => "Raesfeld", :area_code => "2865") + AreaCode.create(:country => germany, :name => "Dorsten-Rhade", :area_code => "2866") + AreaCode.create(:country => germany, :name => "Heiden Kr Borken", :area_code => "2867") + AreaCode.create(:country => germany, :name => "Bocholt", :area_code => "2871") + AreaCode.create(:country => germany, :name => "Rhede Westf", :area_code => "2872") + AreaCode.create(:country => germany, :name => "Isselburg-Werth", :area_code => "2873") + AreaCode.create(:country => germany, :name => "Isselburg", :area_code => "2874") + AreaCode.create(:country => germany, :name => "Warstein", :area_code => "2902") + AreaCode.create(:country => germany, :name => "Meschede-Freienohl", :area_code => "2903") + AreaCode.create(:country => germany, :name => "Bestwig", :area_code => "2904") + AreaCode.create(:country => germany, :name => "Bestwig-Ramsbeck", :area_code => "2905") + AreaCode.create(:country => germany, :name => "Meschede", :area_code => "291") + AreaCode.create(:country => germany, :name => "Soest", :area_code => "2921") + AreaCode.create(:country => germany, :name => "Werl", :area_code => "2922") + AreaCode.create(:country => germany, :name => "Lippetal-Herzfeld", :area_code => "2923") + AreaCode.create(:country => germany, :name => "Möhnesee", :area_code => "2924") + AreaCode.create(:country => germany, :name => "Warstein-Allagen", :area_code => "2925") + AreaCode.create(:country => germany, :name => "Neuengeseke", :area_code => "2927") + AreaCode.create(:country => germany, :name => "Soest-Ostönnen", :area_code => "2928") + AreaCode.create(:country => germany, :name => "Arnsberg", :area_code => "2931") + AreaCode.create(:country => germany, :name => "Neheim-Hüsten", :area_code => "2932") + AreaCode.create(:country => germany, :name => "Sundern Sauerland", :area_code => "2933") + AreaCode.create(:country => germany, :name => "Sundern-Altenhellefeld", :area_code => "2934") + AreaCode.create(:country => germany, :name => "Sundern-Hachen", :area_code => "2935") + AreaCode.create(:country => germany, :name => "Arnsberg-Oeventrop", :area_code => "2937") + AreaCode.create(:country => germany, :name => "Ense", :area_code => "2938") + AreaCode.create(:country => germany, :name => "Lippstadt", :area_code => "2941") + AreaCode.create(:country => germany, :name => "Geseke", :area_code => "2942") + AreaCode.create(:country => germany, :name => "Erwitte", :area_code => "2943") + AreaCode.create(:country => germany, :name => "Rietberg-Mastholte", :area_code => "2944") + AreaCode.create(:country => germany, :name => "Lippstadt-Benninghausen", :area_code => "2945") + AreaCode.create(:country => germany, :name => "Anröchte", :area_code => "2947") + AreaCode.create(:country => germany, :name => "Lippstadt-Rebbeke", :area_code => "2948") + AreaCode.create(:country => germany, :name => "Büren", :area_code => "2951") + AreaCode.create(:country => germany, :name => "Rüthen", :area_code => "2952") + AreaCode.create(:country => germany, :name => "Wünnenberg", :area_code => "2953") + AreaCode.create(:country => germany, :name => "Rüthen-Oestereiden", :area_code => "2954") + AreaCode.create(:country => germany, :name => "Büren-Wewelsburg", :area_code => "2955") + AreaCode.create(:country => germany, :name => "Wünnenberg-Haaren", :area_code => "2957") + AreaCode.create(:country => germany, :name => "Büren-Harth", :area_code => "2958") + AreaCode.create(:country => germany, :name => "Brilon", :area_code => "2961") + AreaCode.create(:country => germany, :name => "Olsberg", :area_code => "2962") + AreaCode.create(:country => germany, :name => "Brilon-Messinghausen", :area_code => "2963") + AreaCode.create(:country => germany, :name => "Brilon-Alme", :area_code => "2964") + AreaCode.create(:country => germany, :name => "Schmallenberg-Dorlar", :area_code => "2971") + AreaCode.create(:country => germany, :name => "Schmallenberg", :area_code => "2972") + AreaCode.create(:country => germany, :name => "Eslohe Sauerland", :area_code => "2973") + AreaCode.create(:country => germany, :name => "Schmallenberg-Fredeburg", :area_code => "2974") + AreaCode.create(:country => germany, :name => "Schmallenberg-Oberkirchen", :area_code => "2975") + AreaCode.create(:country => germany, :name => "Schmallenberg-Bödefeld", :area_code => "2977") + AreaCode.create(:country => germany, :name => "Winterberg Westf", :area_code => "2981") + AreaCode.create(:country => germany, :name => "Medebach", :area_code => "2982") + AreaCode.create(:country => germany, :name => "Winterberg-Siedlinghausen", :area_code => "2983") + AreaCode.create(:country => germany, :name => "Hallenberg", :area_code => "2984") + AreaCode.create(:country => germany, :name => "Winterberg-Niedersfeld", :area_code => "2985") + AreaCode.create(:country => germany, :name => "Marsberg-Bredelar", :area_code => "2991") + AreaCode.create(:country => germany, :name => "Marsberg", :area_code => "2992") + AreaCode.create(:country => germany, :name => "Marsberg-Canstein", :area_code => "2993") + AreaCode.create(:country => germany, :name => "Marsberg-Westheim", :area_code => "2994") + AreaCode.create(:country => germany, :name => "Berlin", :area_code => "30") + AreaCode.create(:country => germany, :name => "Oranienburg", :area_code => "3301") + AreaCode.create(:country => germany, :name => "Hennigsdorf", :area_code => "3302") + AreaCode.create(:country => germany, :name => "Birkenwerder", :area_code => "3303") + AreaCode.create(:country => germany, :name => "Velten", :area_code => "3304") + AreaCode.create(:country => germany, :name => "Nassenheide", :area_code => "33051") + AreaCode.create(:country => germany, :name => "Zehlendorf Kr Oberhavel", :area_code => "33053") + AreaCode.create(:country => germany, :name => "Liebenwalde", :area_code => "33054") + AreaCode.create(:country => germany, :name => "Kremmen", :area_code => "33055") + AreaCode.create(:country => germany, :name => "Mühlenbeck Kr Oberhavel", :area_code => "33056") + AreaCode.create(:country => germany, :name => "Gransee", :area_code => "3306") + AreaCode.create(:country => germany, :name => "Zehdenick", :area_code => "3307") + AreaCode.create(:country => germany, :name => "Marienthal Kr Oberhavel", :area_code => "33080") + AreaCode.create(:country => germany, :name => "Menz Kr Oberhavel", :area_code => "33082") + AreaCode.create(:country => germany, :name => "Schulzendorf Kr Oberhavel", :area_code => "33083") + AreaCode.create(:country => germany, :name => "Gutengermendorf", :area_code => "33084") + AreaCode.create(:country => germany, :name => "Seilershof", :area_code => "33085") + AreaCode.create(:country => germany, :name => "Grieben Kr Oberhavel", :area_code => "33086") + AreaCode.create(:country => germany, :name => "Bredereiche", :area_code => "33087") + AreaCode.create(:country => germany, :name => "Falkenthal", :area_code => "33088") + AreaCode.create(:country => germany, :name => "Himmelpfort", :area_code => "33089") + AreaCode.create(:country => germany, :name => "Fürstenberg Havel", :area_code => "33093") + AreaCode.create(:country => germany, :name => "Löwenberg", :area_code => "33094") + AreaCode.create(:country => germany, :name => "Potsdam", :area_code => "331") + AreaCode.create(:country => germany, :name => "Bergholz-Rehbrücke", :area_code => "33200") + AreaCode.create(:country => germany, :name => "Gross Glienicke", :area_code => "33201") + AreaCode.create(:country => germany, :name => "Töplitz", :area_code => "33202") + AreaCode.create(:country => germany, :name => "Kleinmachnow", :area_code => "33203") + AreaCode.create(:country => germany, :name => "Beelitz Mark", :area_code => "33204") + AreaCode.create(:country => germany, :name => "Michendorf", :area_code => "33205") + AreaCode.create(:country => germany, :name => "Fichtenwalde", :area_code => "33206") + AreaCode.create(:country => germany, :name => "Gross Kreutz", :area_code => "33207") + AreaCode.create(:country => germany, :name => "Fahrland", :area_code => "33208") + AreaCode.create(:country => germany, :name => "Caputh", :area_code => "33209") + AreaCode.create(:country => germany, :name => "Nauen Brandenb", :area_code => "3321") + AreaCode.create(:country => germany, :name => "Falkensee", :area_code => "3322") + AreaCode.create(:country => germany, :name => "Börnicke Kr Havelland", :area_code => "33230") + AreaCode.create(:country => germany, :name => "Pausin", :area_code => "33231") + AreaCode.create(:country => germany, :name => "Brieselang", :area_code => "33232") + AreaCode.create(:country => germany, :name => "Ketzin", :area_code => "33233") + AreaCode.create(:country => germany, :name => "Wustermark", :area_code => "33234") + AreaCode.create(:country => germany, :name => "Friesack", :area_code => "33235") + AreaCode.create(:country => germany, :name => "Paulinenaue", :area_code => "33237") + AreaCode.create(:country => germany, :name => "Senzke", :area_code => "33238") + AreaCode.create(:country => germany, :name => "Gross Behnitz", :area_code => "33239") + AreaCode.create(:country => germany, :name => "Werder Havel", :area_code => "3327") + AreaCode.create(:country => germany, :name => "Teltow", :area_code => "3328") + AreaCode.create(:country => germany, :name => "Stahnsdorf", :area_code => "3329") + AreaCode.create(:country => germany, :name => "Angermünde", :area_code => "3331") + AreaCode.create(:country => germany, :name => "Schwedt/Oder", :area_code => "3332") + AreaCode.create(:country => germany, :name => "Casekow", :area_code => "33331") + AreaCode.create(:country => germany, :name => "Gartz Oder", :area_code => "33332") + AreaCode.create(:country => germany, :name => "Tantow", :area_code => "33333") + AreaCode.create(:country => germany, :name => "Greiffenberg", :area_code => "33334") + AreaCode.create(:country => germany, :name => "Pinnow Kr Uckermark", :area_code => "33335") + AreaCode.create(:country => germany, :name => "Passow Kr Uckermark", :area_code => "33336") + AreaCode.create(:country => germany, :name => "Altkünkendorf", :area_code => "33337") + AreaCode.create(:country => germany, :name => "Stolpe/Oder", :area_code => "33338") + AreaCode.create(:country => germany, :name => "Eberswalde", :area_code => "3334") + AreaCode.create(:country => germany, :name => "Finowfurt", :area_code => "3335") + AreaCode.create(:country => germany, :name => "Joachimsthal", :area_code => "33361") + AreaCode.create(:country => germany, :name => "Liepe Kr Barnim", :area_code => "33362") + AreaCode.create(:country => germany, :name => "Altenhof Kr Barnim", :area_code => "33363") + AreaCode.create(:country => germany, :name => "Gross Ziethen Kr Barnim", :area_code => "33364") + AreaCode.create(:country => germany, :name => "Lüdersdorf Kr Barnim", :area_code => "33365") + AreaCode.create(:country => germany, :name => "Chorin", :area_code => "33366") + AreaCode.create(:country => germany, :name => "Friedrichswalde Brandenb", :area_code => "33367") + AreaCode.create(:country => germany, :name => "Hohensaaten", :area_code => "33368") + AreaCode.create(:country => germany, :name => "Oderberg", :area_code => "33369") + AreaCode.create(:country => germany, :name => "Biesenthal Brandenb", :area_code => "3337") + AreaCode.create(:country => germany, :name => "Bernau Brandenb", :area_code => "3338") + AreaCode.create(:country => germany, :name => "Gross Schönebeck Kr Barnim", :area_code => "33393") + AreaCode.create(:country => germany, :name => "Blumberg Kr Barnim", :area_code => "33394") + AreaCode.create(:country => germany, :name => "Zerpenschleuse", :area_code => "33395") + AreaCode.create(:country => germany, :name => "Klosterfelde", :area_code => "33396") + AreaCode.create(:country => germany, :name => "Wandlitz", :area_code => "33397") + AreaCode.create(:country => germany, :name => "Werneuchen", :area_code => "33398") + AreaCode.create(:country => germany, :name => "Strausberg", :area_code => "3341") + AreaCode.create(:country => germany, :name => "Neuenhagen b Berlin", :area_code => "3342") + AreaCode.create(:country => germany, :name => "Müncheberg", :area_code => "33432") + AreaCode.create(:country => germany, :name => "Buckow Märk Schweiz", :area_code => "33433") + AreaCode.create(:country => germany, :name => "Herzfelde b Strausberg", :area_code => "33434") + AreaCode.create(:country => germany, :name => "Rehfelde", :area_code => "33435") + AreaCode.create(:country => germany, :name => "Prötzel", :area_code => "33436") + AreaCode.create(:country => germany, :name => "Reichenberg b Strausberg", :area_code => "33437") + AreaCode.create(:country => germany, :name => "Altlandsberg", :area_code => "33438") + AreaCode.create(:country => germany, :name => "Fredersdorf-Vogelsdorf", :area_code => "33439") + AreaCode.create(:country => germany, :name => "Bad Freienwalde", :area_code => "3344") + AreaCode.create(:country => germany, :name => "Heckelberg", :area_code => "33451") + AreaCode.create(:country => germany, :name => "Neulewin", :area_code => "33452") + AreaCode.create(:country => germany, :name => "Wölsickendorf/Wollenberg", :area_code => "33454") + AreaCode.create(:country => germany, :name => "Wriezen", :area_code => "33456") + AreaCode.create(:country => germany, :name => "Altreetz", :area_code => "33457") + AreaCode.create(:country => germany, :name => "Falkenberg Mark", :area_code => "33458") + AreaCode.create(:country => germany, :name => "Seelow", :area_code => "3346") + AreaCode.create(:country => germany, :name => "Lietzen", :area_code => "33470") + AreaCode.create(:country => germany, :name => "Golzow b Seelow", :area_code => "33472") + AreaCode.create(:country => germany, :name => "Zechin", :area_code => "33473") + AreaCode.create(:country => germany, :name => "Neutrebbin", :area_code => "33474") + AreaCode.create(:country => germany, :name => "Letschin", :area_code => "33475") + AreaCode.create(:country => germany, :name => "Neuhardenberg", :area_code => "33476") + AreaCode.create(:country => germany, :name => "Trebnitz b Müncheberg", :area_code => "33477") + AreaCode.create(:country => germany, :name => "Gross Neuendorf", :area_code => "33478") + AreaCode.create(:country => germany, :name => "Küstrin-Kietz", :area_code => "33479") + AreaCode.create(:country => germany, :name => "Frankfurt (Oder)", :area_code => "335") + AreaCode.create(:country => germany, :name => "Podelzig", :area_code => "33601") + AreaCode.create(:country => germany, :name => "Alt Zeschdorf", :area_code => "33602") + AreaCode.create(:country => germany, :name => "Falkenhagen b Seelow", :area_code => "33603") + AreaCode.create(:country => germany, :name => "Lebus", :area_code => "33604") + AreaCode.create(:country => germany, :name => "Boossen", :area_code => "33605") + AreaCode.create(:country => germany, :name => "Müllrose", :area_code => "33606") + AreaCode.create(:country => germany, :name => "Briesen Mark", :area_code => "33607") + AreaCode.create(:country => germany, :name => "Jacobsdorf Mark", :area_code => "33608") + AreaCode.create(:country => germany, :name => "Brieskow-Finkenheerd", :area_code => "33609") + AreaCode.create(:country => germany, :name => "Fürstenwalde Spree", :area_code => "3361") + AreaCode.create(:country => germany, :name => "Erkner", :area_code => "3362") + AreaCode.create(:country => germany, :name => "Bad Saarow-Pieskow", :area_code => "33631") + AreaCode.create(:country => germany, :name => "Hangelsberg", :area_code => "33632") + AreaCode.create(:country => germany, :name => "Spreenhagen", :area_code => "33633") + AreaCode.create(:country => germany, :name => "Berkenbrück Kr Oder-Spree", :area_code => "33634") + AreaCode.create(:country => germany, :name => "Arensdorf Kr Oder-Spree", :area_code => "33635") + AreaCode.create(:country => germany, :name => "Steinhöfel Kr Oder-Spree", :area_code => "33636") + AreaCode.create(:country => germany, :name => "Beerfelde", :area_code => "33637") + AreaCode.create(:country => germany, :name => "Rüdersdorf b Berlin", :area_code => "33638") + AreaCode.create(:country => germany, :name => "Eisenhüttenstadt", :area_code => "3364") + AreaCode.create(:country => germany, :name => "Neuzelle", :area_code => "33652") + AreaCode.create(:country => germany, :name => "Ziltendorf", :area_code => "33653") + AreaCode.create(:country => germany, :name => "Fünfeichen", :area_code => "33654") + AreaCode.create(:country => germany, :name => "Grunow Kr Oder-Spree", :area_code => "33655") + AreaCode.create(:country => germany, :name => "Bahro", :area_code => "33656") + AreaCode.create(:country => germany, :name => "Steinsdorf Brandenb", :area_code => "33657") + AreaCode.create(:country => germany, :name => "Beeskow", :area_code => "3366") + AreaCode.create(:country => germany, :name => "Lieberose", :area_code => "33671") + AreaCode.create(:country => germany, :name => "Pfaffendorf b Beeskow", :area_code => "33672") + AreaCode.create(:country => germany, :name => "Weichensdorf", :area_code => "33673") + AreaCode.create(:country => germany, :name => "Trebatsch", :area_code => "33674") + AreaCode.create(:country => germany, :name => "Tauche", :area_code => "33675") + AreaCode.create(:country => germany, :name => "Friedland b Beeskow", :area_code => "33676") + AreaCode.create(:country => germany, :name => "Glienicke b Beeskow", :area_code => "33677") + AreaCode.create(:country => germany, :name => "Storkow Mark", :area_code => "33678") + AreaCode.create(:country => germany, :name => "Wendisch Rietz", :area_code => "33679") + AreaCode.create(:country => germany, :name => "Grossbeeren", :area_code => "33701") + AreaCode.create(:country => germany, :name => "Wünsdorf", :area_code => "33702") + AreaCode.create(:country => germany, :name => "Sperenberg", :area_code => "33703") + AreaCode.create(:country => germany, :name => "Baruth Mark", :area_code => "33704") + AreaCode.create(:country => germany, :name => "Rangsdorf", :area_code => "33708") + AreaCode.create(:country => germany, :name => "Luckenwalde", :area_code => "3371") + AreaCode.create(:country => germany, :name => "Jüterbog", :area_code => "3372") + AreaCode.create(:country => germany, :name => "Trebbin", :area_code => "33731") + AreaCode.create(:country => germany, :name => "Hennickendorf b Luckenwalde", :area_code => "33732") + AreaCode.create(:country => germany, :name => "Stülpe", :area_code => "33733") + AreaCode.create(:country => germany, :name => "Felgentreu", :area_code => "33734") + AreaCode.create(:country => germany, :name => "Niedergörsdorf", :area_code => "33741") + AreaCode.create(:country => germany, :name => "Oehna Brandenb", :area_code => "33742") + AreaCode.create(:country => germany, :name => "Blönsdorf", :area_code => "33743") + AreaCode.create(:country => germany, :name => "Hohenseefeld", :area_code => "33744") + AreaCode.create(:country => germany, :name => "Petkus", :area_code => "33745") + AreaCode.create(:country => germany, :name => "Werbig b Jüterbog", :area_code => "33746") + AreaCode.create(:country => germany, :name => "Marzahna", :area_code => "33747") + AreaCode.create(:country => germany, :name => "Treuenbrietzen", :area_code => "33748") + AreaCode.create(:country => germany, :name => "Königs Wusterhausen", :area_code => "3375") + AreaCode.create(:country => germany, :name => "Münchehofe Kr Dahme-Spreewald", :area_code => "33760") + AreaCode.create(:country => germany, :name => "Zeuthen", :area_code => "33762") + AreaCode.create(:country => germany, :name => "Bestensee", :area_code => "33763") + AreaCode.create(:country => germany, :name => "Mittenwalde Mark", :area_code => "33764") + AreaCode.create(:country => germany, :name => "Märkisch Buchholz", :area_code => "33765") + AreaCode.create(:country => germany, :name => "Teupitz", :area_code => "33766") + AreaCode.create(:country => germany, :name => "Friedersdorf b Berlin", :area_code => "33767") + AreaCode.create(:country => germany, :name => "Prieros", :area_code => "33768") + AreaCode.create(:country => germany, :name => "Töpchin", :area_code => "33769") + AreaCode.create(:country => germany, :name => "Zossen Brandenb", :area_code => "3377") + AreaCode.create(:country => germany, :name => "Ludwigsfelde", :area_code => "3378") + AreaCode.create(:country => germany, :name => "Mahlow", :area_code => "3379") + AreaCode.create(:country => germany, :name => "Brandenburg an der Havel", :area_code => "3381") + AreaCode.create(:country => germany, :name => "Lehnin", :area_code => "3382") + AreaCode.create(:country => germany, :name => "Ziesar", :area_code => "33830") + AreaCode.create(:country => germany, :name => "Weseram", :area_code => "33831") + AreaCode.create(:country => germany, :name => "Rogäsen", :area_code => "33832") + AreaCode.create(:country => germany, :name => "Wollin b Brandenburg", :area_code => "33833") + AreaCode.create(:country => germany, :name => "Pritzerbe", :area_code => "33834") + AreaCode.create(:country => germany, :name => "Golzow b Brandenburg", :area_code => "33835") + AreaCode.create(:country => germany, :name => "Butzow b Brandenburg", :area_code => "33836") + AreaCode.create(:country => germany, :name => "Brielow", :area_code => "33837") + AreaCode.create(:country => germany, :name => "Päwesin", :area_code => "33838") + AreaCode.create(:country => germany, :name => "Wusterwitz", :area_code => "33839") + AreaCode.create(:country => germany, :name => "Belzig", :area_code => "33841") + AreaCode.create(:country => germany, :name => "Niemegk", :area_code => "33843") + AreaCode.create(:country => germany, :name => "Brück Brandenb", :area_code => "33844") + AreaCode.create(:country => germany, :name => "Borkheide", :area_code => "33845") + AreaCode.create(:country => germany, :name => "Dippmannsdorf", :area_code => "33846") + AreaCode.create(:country => germany, :name => "Görzke", :area_code => "33847") + AreaCode.create(:country => germany, :name => "Raben", :area_code => "33848") + AreaCode.create(:country => germany, :name => "Wiesenburg Mark", :area_code => "33849") + AreaCode.create(:country => germany, :name => "Rathenow", :area_code => "3385") + AreaCode.create(:country => germany, :name => "Premnitz", :area_code => "3386") + AreaCode.create(:country => germany, :name => "Zollchow b Rathenow", :area_code => "33870") + AreaCode.create(:country => germany, :name => "Hohennauen", :area_code => "33872") + AreaCode.create(:country => germany, :name => "Grosswudicke", :area_code => "33873") + AreaCode.create(:country => germany, :name => "Stechow Brandenb", :area_code => "33874") + AreaCode.create(:country => germany, :name => "Rhinow", :area_code => "33875") + AreaCode.create(:country => germany, :name => "Buschow", :area_code => "33876") + AreaCode.create(:country => germany, :name => "Nitzahn", :area_code => "33877") + AreaCode.create(:country => germany, :name => "Nennhausen", :area_code => "33878") + AreaCode.create(:country => germany, :name => "Neuruppin", :area_code => "3391") + AreaCode.create(:country => germany, :name => "Walsleben b Neuruppin", :area_code => "33920") + AreaCode.create(:country => germany, :name => "Zechlinerhütte", :area_code => "33921") + AreaCode.create(:country => germany, :name => "Karwesee", :area_code => "33922") + AreaCode.create(:country => germany, :name => "Flecken Zechlin", :area_code => "33923") + AreaCode.create(:country => germany, :name => "Rägelin", :area_code => "33924") + AreaCode.create(:country => germany, :name => "Wustrau-Altfriesack", :area_code => "33925") + AreaCode.create(:country => germany, :name => "Herzberg Mark", :area_code => "33926") + AreaCode.create(:country => germany, :name => "Wildberg Brandenb", :area_code => "33928") + AreaCode.create(:country => germany, :name => "Gühlen-Glienicke", :area_code => "33929") + AreaCode.create(:country => germany, :name => "Rheinsberg Mark", :area_code => "33931") + AreaCode.create(:country => germany, :name => "Fehrbellin", :area_code => "33932") + AreaCode.create(:country => germany, :name => "Lindow Mark", :area_code => "33933") + AreaCode.create(:country => germany, :name => "Wittstock Dosse", :area_code => "3394") + AreaCode.create(:country => germany, :name => "Pritzwalk", :area_code => "3395") + AreaCode.create(:country => germany, :name => "Heiligengrabe", :area_code => "33962") + AreaCode.create(:country => germany, :name => "Wulfersdorf b Wittstock", :area_code => "33963") + AreaCode.create(:country => germany, :name => "Fretzdorf", :area_code => "33964") + AreaCode.create(:country => germany, :name => "Herzsprung b Wittstock", :area_code => "33965") + AreaCode.create(:country => germany, :name => "Dranse", :area_code => "33966") + AreaCode.create(:country => germany, :name => "Freyenstein", :area_code => "33967") + AreaCode.create(:country => germany, :name => "Meyenburg Kr Prignitz", :area_code => "33968") + AreaCode.create(:country => germany, :name => "Stepenitz", :area_code => "33969") + AreaCode.create(:country => germany, :name => "Neustadt Dosse", :area_code => "33970") + AreaCode.create(:country => germany, :name => "Kyritz Brandenb", :area_code => "33971") + AreaCode.create(:country => germany, :name => "Breddin", :area_code => "33972") + AreaCode.create(:country => germany, :name => "Zernitz b Neustadt Dosse", :area_code => "33973") + AreaCode.create(:country => germany, :name => "Dessow", :area_code => "33974") + AreaCode.create(:country => germany, :name => "Dannenwalde Kr Prignitz", :area_code => "33975") + AreaCode.create(:country => germany, :name => "Wutike", :area_code => "33976") + AreaCode.create(:country => germany, :name => "Gumtow", :area_code => "33977") + AreaCode.create(:country => germany, :name => "Segeletz", :area_code => "33978") + AreaCode.create(:country => germany, :name => "Wusterhausen Dosse", :area_code => "33979") + AreaCode.create(:country => germany, :name => "Putlitz", :area_code => "33981") + AreaCode.create(:country => germany, :name => "Hoppenrade Kr Prignitz", :area_code => "33982") + AreaCode.create(:country => germany, :name => "Gross Pankow Kr Prignitz", :area_code => "33983") + AreaCode.create(:country => germany, :name => "Blumenthal b Pritzwalk", :area_code => "33984") + AreaCode.create(:country => germany, :name => "Falkenhagen Kr Prignitz", :area_code => "33986") + AreaCode.create(:country => germany, :name => "Sadenbeck", :area_code => "33989") + AreaCode.create(:country => germany, :name => "Dessau Anh", :area_code => "340") + AreaCode.create(:country => germany, :name => "Leipzig", :area_code => "341") + AreaCode.create(:country => germany, :name => "Delitzsch", :area_code => "34202") + AreaCode.create(:country => germany, :name => "Zwenkau", :area_code => "34203") + AreaCode.create(:country => germany, :name => "Schkeuditz", :area_code => "34204") + AreaCode.create(:country => germany, :name => "Markranstädt", :area_code => "34205") + AreaCode.create(:country => germany, :name => "Rötha", :area_code => "34206") + AreaCode.create(:country => germany, :name => "Zwochau", :area_code => "34207") + AreaCode.create(:country => germany, :name => "Löbnitz b Delitzsch", :area_code => "34208") + AreaCode.create(:country => germany, :name => "Torgau", :area_code => "3421") + AreaCode.create(:country => germany, :name => "Schildau Gneisenaustadt", :area_code => "34221") + AreaCode.create(:country => germany, :name => "Arzberg b Torgau", :area_code => "34222") + AreaCode.create(:country => germany, :name => "Dommitzsch", :area_code => "34223") + AreaCode.create(:country => germany, :name => "Belgern Sachs", :area_code => "34224") + AreaCode.create(:country => germany, :name => "Eilenburg", :area_code => "3423") + AreaCode.create(:country => germany, :name => "Jesewitz", :area_code => "34241") + AreaCode.create(:country => germany, :name => "Hohenpriessnitz", :area_code => "34242") + AreaCode.create(:country => germany, :name => "Bad Düben", :area_code => "34243") + AreaCode.create(:country => germany, :name => "Mockrehna", :area_code => "34244") + AreaCode.create(:country => germany, :name => "Wurzen", :area_code => "3425") + AreaCode.create(:country => germany, :name => "Kühren b Wurzen", :area_code => "34261") + AreaCode.create(:country => germany, :name => "Falkenhain b Wurzen", :area_code => "34262") + AreaCode.create(:country => germany, :name => "Hohburg", :area_code => "34263") + AreaCode.create(:country => germany, :name => "Borsdorf", :area_code => "34291") + AreaCode.create(:country => germany, :name => "Brandis b Wurzen", :area_code => "34292") + AreaCode.create(:country => germany, :name => "Naunhof b Grimma", :area_code => "34293") + AreaCode.create(:country => germany, :name => "Rackwitz", :area_code => "34294") + AreaCode.create(:country => germany, :name => "Krensitz", :area_code => "34295") + AreaCode.create(:country => germany, :name => "Groitzsch b Pegau", :area_code => "34296") + AreaCode.create(:country => germany, :name => "Liebertwolkwitz", :area_code => "34297") + AreaCode.create(:country => germany, :name => "Taucha b Leipzig", :area_code => "34298") + AreaCode.create(:country => germany, :name => "Gaschwitz", :area_code => "34299") + AreaCode.create(:country => germany, :name => "Döbeln", :area_code => "3431") + AreaCode.create(:country => germany, :name => "Leisnig", :area_code => "34321") + AreaCode.create(:country => germany, :name => "Rosswein", :area_code => "34322") + AreaCode.create(:country => germany, :name => "Ostrau Sachs", :area_code => "34324") + AreaCode.create(:country => germany, :name => "Mochau-Lüttewitz", :area_code => "34325") + AreaCode.create(:country => germany, :name => "Waldheim Sachs", :area_code => "34327") + AreaCode.create(:country => germany, :name => "Hartha b Döbeln", :area_code => "34328") + AreaCode.create(:country => germany, :name => "Borna Stadt", :area_code => "3433") + AreaCode.create(:country => germany, :name => "Geithain", :area_code => "34341") + AreaCode.create(:country => germany, :name => "Neukieritzsch", :area_code => "34342") + AreaCode.create(:country => germany, :name => "Regis-Breitingen", :area_code => "34343") + AreaCode.create(:country => germany, :name => "Kohren-Sahlis", :area_code => "34344") + AreaCode.create(:country => germany, :name => "Bad Lausick", :area_code => "34345") + AreaCode.create(:country => germany, :name => "Narsdorf", :area_code => "34346") + AreaCode.create(:country => germany, :name => "Oelzschau b Borna", :area_code => "34347") + AreaCode.create(:country => germany, :name => "Frohburg", :area_code => "34348") + AreaCode.create(:country => germany, :name => "Oschatz", :area_code => "3435") + AreaCode.create(:country => germany, :name => "Dahlen Sachs", :area_code => "34361") + AreaCode.create(:country => germany, :name => "Mügeln b Oschatz", :area_code => "34362") + AreaCode.create(:country => germany, :name => "Cavertitz", :area_code => "34363") + AreaCode.create(:country => germany, :name => "Wermsdorf", :area_code => "34364") + AreaCode.create(:country => germany, :name => "Grimma", :area_code => "3437") + AreaCode.create(:country => germany, :name => "Colditz", :area_code => "34381") + AreaCode.create(:country => germany, :name => "Nerchau", :area_code => "34382") + AreaCode.create(:country => germany, :name => "Trebsen Mulde", :area_code => "34383") + AreaCode.create(:country => germany, :name => "Grossbothen", :area_code => "34384") + AreaCode.create(:country => germany, :name => "Mutzschen", :area_code => "34385") + AreaCode.create(:country => germany, :name => "Dürrweitzschen b Grimma", :area_code => "34386") + AreaCode.create(:country => germany, :name => "Zeitz", :area_code => "3441") + AreaCode.create(:country => germany, :name => "Osterfeld", :area_code => "34422") + AreaCode.create(:country => germany, :name => "Heuckewalde", :area_code => "34423") + AreaCode.create(:country => germany, :name => "Reuden b Zeitz", :area_code => "34424") + AreaCode.create(:country => germany, :name => "Droyssig", :area_code => "34425") + AreaCode.create(:country => germany, :name => "Kayna", :area_code => "34426") + AreaCode.create(:country => germany, :name => "Weissenfels Sachs-Anh", :area_code => "3443") + AreaCode.create(:country => germany, :name => "Hohenmölsen", :area_code => "34441") + AreaCode.create(:country => germany, :name => "Teuchern", :area_code => "34443") + AreaCode.create(:country => germany, :name => "Lützen", :area_code => "34444") + AreaCode.create(:country => germany, :name => "Stößen", :area_code => "34445") + AreaCode.create(:country => germany, :name => "Grosskorbetha", :area_code => "34446") + AreaCode.create(:country => germany, :name => "Naumburg Saale", :area_code => "3445") + AreaCode.create(:country => germany, :name => "Nebra Unstrut", :area_code => "34461") + AreaCode.create(:country => germany, :name => "Laucha Unstrut", :area_code => "34462") + AreaCode.create(:country => germany, :name => "Bad Kösen", :area_code => "34463") + AreaCode.create(:country => germany, :name => "Freyburg Unstrut", :area_code => "34464") + AreaCode.create(:country => germany, :name => "Bad Bibra", :area_code => "34465") + AreaCode.create(:country => germany, :name => "Janisroda", :area_code => "34466") + AreaCode.create(:country => germany, :name => "Eckartsberga", :area_code => "34467") + AreaCode.create(:country => germany, :name => "Altenburg Thür", :area_code => "3447") + AreaCode.create(:country => germany, :name => "Meuselwitz Thür", :area_code => "3448") + AreaCode.create(:country => germany, :name => "Schmölln Thür", :area_code => "34491") + AreaCode.create(:country => germany, :name => "Lucka", :area_code => "34492") + AreaCode.create(:country => germany, :name => "Gößnitz Thür", :area_code => "34493") + AreaCode.create(:country => germany, :name => "Ehrenhain", :area_code => "34494") + AreaCode.create(:country => germany, :name => "Dobitschen", :area_code => "34495") + AreaCode.create(:country => germany, :name => "Nöbdenitz", :area_code => "34496") + AreaCode.create(:country => germany, :name => "Langenleuba-Niederhain", :area_code => "34497") + AreaCode.create(:country => germany, :name => "Rositz", :area_code => "34498") + AreaCode.create(:country => germany, :name => "Halle Saale", :area_code => "345") + AreaCode.create(:country => germany, :name => "Ostrau Saalkreis", :area_code => "34600") + AreaCode.create(:country => germany, :name => "Teutschenthal", :area_code => "34601") + AreaCode.create(:country => germany, :name => "Landsberg Sachs-Anh", :area_code => "34602") + AreaCode.create(:country => germany, :name => "Nauendorf Sachs-Anh", :area_code => "34603") + AreaCode.create(:country => germany, :name => "Niemberg", :area_code => "34604") + AreaCode.create(:country => germany, :name => "Gröbers", :area_code => "34605") + AreaCode.create(:country => germany, :name => "Teicha Sachs-Anh", :area_code => "34606") + AreaCode.create(:country => germany, :name => "Wettin", :area_code => "34607") + AreaCode.create(:country => germany, :name => "Salzmünde", :area_code => "34609") + AreaCode.create(:country => germany, :name => "Merseburg Saale", :area_code => "3461") + AreaCode.create(:country => germany, :name => "Bad Dürrenberg", :area_code => "3462") + AreaCode.create(:country => germany, :name => "Mücheln Geiseltal", :area_code => "34632") + AreaCode.create(:country => germany, :name => "Braunsbedra", :area_code => "34633") + AreaCode.create(:country => germany, :name => "Bad Lauchstädt", :area_code => "34635") + AreaCode.create(:country => germany, :name => "Schafstädt", :area_code => "34636") + AreaCode.create(:country => germany, :name => "Frankleben", :area_code => "34637") + AreaCode.create(:country => germany, :name => "Zöschen", :area_code => "34638") + AreaCode.create(:country => germany, :name => "Wallendorf Luppe", :area_code => "34639") + AreaCode.create(:country => germany, :name => "Sangerhausen", :area_code => "3464") + AreaCode.create(:country => germany, :name => "Rossla", :area_code => "34651") + AreaCode.create(:country => germany, :name => "Allstedt", :area_code => "34652") + AreaCode.create(:country => germany, :name => "Rottleberode", :area_code => "34653") + AreaCode.create(:country => germany, :name => "Stolberg Harz", :area_code => "34654") + AreaCode.create(:country => germany, :name => "Wallhausen Sachs-Anh", :area_code => "34656") + AreaCode.create(:country => germany, :name => "Hayn Harz", :area_code => "34658") + AreaCode.create(:country => germany, :name => "Blankenheim b Sangerhausen", :area_code => "34659") + AreaCode.create(:country => germany, :name => "Artern Unstrut", :area_code => "3466") + AreaCode.create(:country => germany, :name => "Bad Frankenhausen Kyffhäuser", :area_code => "34671") + AreaCode.create(:country => germany, :name => "Rossleben", :area_code => "34672") + AreaCode.create(:country => germany, :name => "Heldrungen", :area_code => "34673") + AreaCode.create(:country => germany, :name => "Könnern", :area_code => "34691") + AreaCode.create(:country => germany, :name => "Alsleben Saale", :area_code => "34692") + AreaCode.create(:country => germany, :name => "Bernburg Saale", :area_code => "3471") + AreaCode.create(:country => germany, :name => "Nienburg Saale", :area_code => "34721") + AreaCode.create(:country => germany, :name => "Preusslitz", :area_code => "34722") + AreaCode.create(:country => germany, :name => "Aschersleben Sachs-Anh", :area_code => "3473") + AreaCode.create(:country => germany, :name => "Frose", :area_code => "34741") + AreaCode.create(:country => germany, :name => "Sylda", :area_code => "34742") + AreaCode.create(:country => germany, :name => "Ermsleben", :area_code => "34743") + AreaCode.create(:country => germany, :name => "Winningen Sachs-Anh", :area_code => "34745") + AreaCode.create(:country => germany, :name => "Giersleben", :area_code => "34746") + AreaCode.create(:country => germany, :name => "Lutherstadt Eisleben", :area_code => "3475") + AreaCode.create(:country => germany, :name => "Hettstedt Sachs-Anh", :area_code => "3476") + AreaCode.create(:country => germany, :name => "Querfurt", :area_code => "34771") + AreaCode.create(:country => germany, :name => "Helbra", :area_code => "34772") + AreaCode.create(:country => germany, :name => "Schwittersdorf", :area_code => "34773") + AreaCode.create(:country => germany, :name => "Röblingen am See", :area_code => "34774") + AreaCode.create(:country => germany, :name => "Wippra", :area_code => "34775") + AreaCode.create(:country => germany, :name => "Rothenschirmbach", :area_code => "34776") + AreaCode.create(:country => germany, :name => "Abberode", :area_code => "34779") + AreaCode.create(:country => germany, :name => "Greifenhagen", :area_code => "34781") + AreaCode.create(:country => germany, :name => "Mansfeld Südharz", :area_code => "34782") + AreaCode.create(:country => germany, :name => "Gerbstedt", :area_code => "34783") + AreaCode.create(:country => germany, :name => "Sandersleben", :area_code => "34785") + AreaCode.create(:country => germany, :name => "Roßlau Elbe", :area_code => "34901") + AreaCode.create(:country => germany, :name => "Coswig Anhalt", :area_code => "34903") + AreaCode.create(:country => germany, :name => "Oranienbaum", :area_code => "34904") + AreaCode.create(:country => germany, :name => "Wörlitz", :area_code => "34905") + AreaCode.create(:country => germany, :name => "Raguhn", :area_code => "34906") + AreaCode.create(:country => germany, :name => "Jeber-Bergfrieden", :area_code => "34907") + AreaCode.create(:country => germany, :name => "Aken Elbe", :area_code => "34909") + AreaCode.create(:country => germany, :name => "Lutherstadt Wittenberg", :area_code => "3491") + AreaCode.create(:country => germany, :name => "Kropstädt", :area_code => "34920") + AreaCode.create(:country => germany, :name => "Kemberg", :area_code => "34921") + AreaCode.create(:country => germany, :name => "Mühlanger", :area_code => "34922") + AreaCode.create(:country => germany, :name => "Cobbelsdorf", :area_code => "34923") + AreaCode.create(:country => germany, :name => "Zahna", :area_code => "34924") + AreaCode.create(:country => germany, :name => "Bad Schmiedeberg", :area_code => "34925") + AreaCode.create(:country => germany, :name => "Pretzsch Elbe", :area_code => "34926") + AreaCode.create(:country => germany, :name => "Globig-Bleddin", :area_code => "34927") + AreaCode.create(:country => germany, :name => "Seegrehna", :area_code => "34928") + AreaCode.create(:country => germany, :name => "Straach", :area_code => "34929") + AreaCode.create(:country => germany, :name => "Bitterfeld", :area_code => "3493") + AreaCode.create(:country => germany, :name => "Wolfen", :area_code => "3494") + AreaCode.create(:country => germany, :name => "Gräfenhainichen", :area_code => "34953") + AreaCode.create(:country => germany, :name => "Roitzsch b Bitterfeld", :area_code => "34954") + AreaCode.create(:country => germany, :name => "Gossa", :area_code => "34955") + AreaCode.create(:country => germany, :name => "Zörbig", :area_code => "34956") + AreaCode.create(:country => germany, :name => "Köthen Anhalt", :area_code => "3496") + AreaCode.create(:country => germany, :name => "Osternienburg", :area_code => "34973") + AreaCode.create(:country => germany, :name => "Görzig Kr Köthen", :area_code => "34975") + AreaCode.create(:country => germany, :name => "Gröbzig", :area_code => "34976") + AreaCode.create(:country => germany, :name => "Quellendorf", :area_code => "34977") + AreaCode.create(:country => germany, :name => "Radegast Kr Köthen", :area_code => "34978") + AreaCode.create(:country => germany, :name => "Wulfen Sachs-Anh", :area_code => "34979") + AreaCode.create(:country => germany, :name => "Pirna", :area_code => "3501") + AreaCode.create(:country => germany, :name => "Struppen", :area_code => "35020") + AreaCode.create(:country => germany, :name => "Königstein Sächs Schweiz", :area_code => "35021") + AreaCode.create(:country => germany, :name => "Bad Schandau", :area_code => "35022") + AreaCode.create(:country => germany, :name => "Bad Gottleuba", :area_code => "35023") + AreaCode.create(:country => germany, :name => "Stadt Wehlen", :area_code => "35024") + AreaCode.create(:country => germany, :name => "Liebstadt", :area_code => "35025") + AreaCode.create(:country => germany, :name => "Dürrröhrsdorf-Dittersbach", :area_code => "35026") + AreaCode.create(:country => germany, :name => "Weesenstein", :area_code => "35027") + AreaCode.create(:country => germany, :name => "Krippen", :area_code => "35028") + AreaCode.create(:country => germany, :name => "Langenhennersdorf", :area_code => "35032") + AreaCode.create(:country => germany, :name => "Rosenthal Sächs Schweiz", :area_code => "35033") + AreaCode.create(:country => germany, :name => "Dippoldiswalde", :area_code => "3504") + AreaCode.create(:country => germany, :name => "Kipsdorf Kurort", :area_code => "35052") + AreaCode.create(:country => germany, :name => "Glashütte Sachs", :area_code => "35053") + AreaCode.create(:country => germany, :name => "Lauenstein Sachs", :area_code => "35054") + AreaCode.create(:country => germany, :name => "Höckendorf b Dippoldiswalde", :area_code => "35055") + AreaCode.create(:country => germany, :name => "Altenberg Sachs", :area_code => "35056") + AreaCode.create(:country => germany, :name => "Hermsdorf Erzgeb", :area_code => "35057") + AreaCode.create(:country => germany, :name => "Pretzschendorf", :area_code => "35058") + AreaCode.create(:country => germany, :name => "Dresden", :area_code => "351") + AreaCode.create(:country => germany, :name => "Arnsdorf b Dresden", :area_code => "35200") + AreaCode.create(:country => germany, :name => "Langebrück", :area_code => "35201") + AreaCode.create(:country => germany, :name => "Klingenberg Sachs", :area_code => "35202") + AreaCode.create(:country => germany, :name => "Tharandt", :area_code => "35203") + AreaCode.create(:country => germany, :name => "Wilsdruff", :area_code => "35204") + AreaCode.create(:country => germany, :name => "Ottendorf-Okrilla", :area_code => "35205") + AreaCode.create(:country => germany, :name => "Kreischa b Dresden", :area_code => "35206") + AreaCode.create(:country => germany, :name => "Moritzburg", :area_code => "35207") + AreaCode.create(:country => germany, :name => "Radeburg", :area_code => "35208") + AreaCode.create(:country => germany, :name => "Mohorn", :area_code => "35209") + AreaCode.create(:country => germany, :name => "Meissen", :area_code => "3521") + AreaCode.create(:country => germany, :name => "Grossenhain Sachs", :area_code => "3522") + AreaCode.create(:country => germany, :name => "Coswig b Dresden", :area_code => "3523") + AreaCode.create(:country => germany, :name => "Tauscha b Großenhain", :area_code => "35240") + AreaCode.create(:country => germany, :name => "Lommatzsch", :area_code => "35241") + AreaCode.create(:country => germany, :name => "Nossen", :area_code => "35242") + AreaCode.create(:country => germany, :name => "Weinböhla", :area_code => "35243") + AreaCode.create(:country => germany, :name => "Krögis", :area_code => "35244") + AreaCode.create(:country => germany, :name => "Burkhardswalde-Munzig", :area_code => "35245") + AreaCode.create(:country => germany, :name => "Ziegenhain Sachs", :area_code => "35246") + AreaCode.create(:country => germany, :name => "Zehren Sachs", :area_code => "35247") + AreaCode.create(:country => germany, :name => "Schönfeld b Großenhain", :area_code => "35248") + AreaCode.create(:country => germany, :name => "Basslitz", :area_code => "35249") + AreaCode.create(:country => germany, :name => "Riesa", :area_code => "3525") + AreaCode.create(:country => germany, :name => "Gröditz b Riesa", :area_code => "35263") + AreaCode.create(:country => germany, :name => "Strehla", :area_code => "35264") + AreaCode.create(:country => germany, :name => "Glaubitz", :area_code => "35265") + AreaCode.create(:country => germany, :name => "Heyda b Riesa", :area_code => "35266") + AreaCode.create(:country => germany, :name => "Diesbar-Seusslitz", :area_code => "35267") + AreaCode.create(:country => germany, :name => "Stauchitz", :area_code => "35268") + AreaCode.create(:country => germany, :name => "Radeberg", :area_code => "3528") + AreaCode.create(:country => germany, :name => "Heidenau Sachs", :area_code => "3529") + AreaCode.create(:country => germany, :name => "Finsterwalde", :area_code => "3531") + AreaCode.create(:country => germany, :name => "Doberlug-Kirchhain", :area_code => "35322") + AreaCode.create(:country => germany, :name => "Sonnewalde", :area_code => "35323") + AreaCode.create(:country => germany, :name => "Crinitz", :area_code => "35324") + AreaCode.create(:country => germany, :name => "Rückersdorf b Finsterwalde", :area_code => "35325") + AreaCode.create(:country => germany, :name => "Schönborn Kr Elbe-Elster", :area_code => "35326") + AreaCode.create(:country => germany, :name => "Priessen", :area_code => "35327") + AreaCode.create(:country => germany, :name => "Dollenchen", :area_code => "35329") + AreaCode.create(:country => germany, :name => "Elsterwerda", :area_code => "3533") + AreaCode.create(:country => germany, :name => "Bad Liebenwerda", :area_code => "35341") + AreaCode.create(:country => germany, :name => "Mühlberg Elbe", :area_code => "35342") + AreaCode.create(:country => germany, :name => "Hirschfeld b Elsterwerda", :area_code => "35343") + AreaCode.create(:country => germany, :name => "Herzberg Elster", :area_code => "3535") + AreaCode.create(:country => germany, :name => "Schlieben", :area_code => "35361") + AreaCode.create(:country => germany, :name => "Schönewalde b Herzberg", :area_code => "35362") + AreaCode.create(:country => germany, :name => "Fermerswalde", :area_code => "35363") + AreaCode.create(:country => germany, :name => "Lebusa", :area_code => "35364") + AreaCode.create(:country => germany, :name => "Falkenberg Elster", :area_code => "35365") + AreaCode.create(:country => germany, :name => "Jessen Elster", :area_code => "3537") + AreaCode.create(:country => germany, :name => "Elster Elbe", :area_code => "35383") + AreaCode.create(:country => germany, :name => "Steinsdorf b Jessen", :area_code => "35384") + AreaCode.create(:country => germany, :name => "Annaburg", :area_code => "35385") + AreaCode.create(:country => germany, :name => "Prettin", :area_code => "35386") + AreaCode.create(:country => germany, :name => "Seyda", :area_code => "35387") + AreaCode.create(:country => germany, :name => "Klöden", :area_code => "35388") + AreaCode.create(:country => germany, :name => "Holzdorf Elster", :area_code => "35389") + AreaCode.create(:country => germany, :name => "Calau", :area_code => "3541") + AreaCode.create(:country => germany, :name => "Lübbenau Spreewald", :area_code => "3542") + AreaCode.create(:country => germany, :name => "Vetschau", :area_code => "35433") + AreaCode.create(:country => germany, :name => "Altdöbern", :area_code => "35434") + AreaCode.create(:country => germany, :name => "Gollmitz b Calau", :area_code => "35435") + AreaCode.create(:country => germany, :name => "Laasow b Calau", :area_code => "35436") + AreaCode.create(:country => germany, :name => "Zinnitz", :area_code => "35439") + AreaCode.create(:country => germany, :name => "Luckau Brandenb", :area_code => "3544") + AreaCode.create(:country => germany, :name => "Dahme Brandenb", :area_code => "35451") + AreaCode.create(:country => germany, :name => "Golssen", :area_code => "35452") + AreaCode.create(:country => germany, :name => "Drahnsdorf", :area_code => "35453") + AreaCode.create(:country => germany, :name => "Uckro", :area_code => "35454") + AreaCode.create(:country => germany, :name => "Walddrehna", :area_code => "35455") + AreaCode.create(:country => germany, :name => "Terpt", :area_code => "35456") + AreaCode.create(:country => germany, :name => "Lübben Spreewald", :area_code => "3546") + AreaCode.create(:country => germany, :name => "Birkenhainchen", :area_code => "35471") + AreaCode.create(:country => germany, :name => "Schlepzig", :area_code => "35472") + AreaCode.create(:country => germany, :name => "Neu Lübbenau", :area_code => "35473") + AreaCode.create(:country => germany, :name => "Schönwalde b Lübben", :area_code => "35474") + AreaCode.create(:country => germany, :name => "Straupitz", :area_code => "35475") + AreaCode.create(:country => germany, :name => "Wittmannsdorf-Bückchen", :area_code => "35476") + AreaCode.create(:country => germany, :name => "Rietzneuendorf-Friedrichshof", :area_code => "35477") + AreaCode.create(:country => germany, :name => "Goyatz", :area_code => "35478") + AreaCode.create(:country => germany, :name => "Cottbus", :area_code => "355") + AreaCode.create(:country => germany, :name => "Döbern NL", :area_code => "35600") + AreaCode.create(:country => germany, :name => "Peitz", :area_code => "35601") + AreaCode.create(:country => germany, :name => "Drebkau", :area_code => "35602") + AreaCode.create(:country => germany, :name => "Burg Spreewald", :area_code => "35603") + AreaCode.create(:country => germany, :name => "Krieschow", :area_code => "35604") + AreaCode.create(:country => germany, :name => "Komptendorf", :area_code => "35605") + AreaCode.create(:country => germany, :name => "Briesen b Cottbus", :area_code => "35606") + AreaCode.create(:country => germany, :name => "Jänschwalde", :area_code => "35607") + AreaCode.create(:country => germany, :name => "Gross Ossnig", :area_code => "35608") + AreaCode.create(:country => germany, :name => "Drachhausen", :area_code => "35609") + AreaCode.create(:country => germany, :name => "Guben", :area_code => "3561") + AreaCode.create(:country => germany, :name => "Forst Lausitz", :area_code => "3562") + AreaCode.create(:country => germany, :name => "Spremberg", :area_code => "3563") + AreaCode.create(:country => germany, :name => "Schwarze Pumpe", :area_code => "3564") + AreaCode.create(:country => germany, :name => "Bärenklau NL", :area_code => "35691") + AreaCode.create(:country => germany, :name => "Kerkwitz", :area_code => "35692") + AreaCode.create(:country => germany, :name => "Lauschütz", :area_code => "35693") + AreaCode.create(:country => germany, :name => "Gosda b Klinge", :area_code => "35694") + AreaCode.create(:country => germany, :name => "Simmersdorf", :area_code => "35695") + AreaCode.create(:country => germany, :name => "Briesnig", :area_code => "35696") + AreaCode.create(:country => germany, :name => "Bagenz", :area_code => "35697") + AreaCode.create(:country => germany, :name => "Hornow", :area_code => "35698") + AreaCode.create(:country => germany, :name => "Hoyerswerda", :area_code => "3571") + AreaCode.create(:country => germany, :name => "Lauta b Hoyerswerda", :area_code => "35722") + AreaCode.create(:country => germany, :name => "Bernsdorf OL", :area_code => "35723") + AreaCode.create(:country => germany, :name => "Lohsa", :area_code => "35724") + AreaCode.create(:country => germany, :name => "Wittichenau", :area_code => "35725") + AreaCode.create(:country => germany, :name => "Groß Särchen", :area_code => "35726") + AreaCode.create(:country => germany, :name => "Burghammer", :area_code => "35727") + AreaCode.create(:country => germany, :name => "Uhyst Spree", :area_code => "35728") + AreaCode.create(:country => germany, :name => "Senftenberg", :area_code => "3573") + AreaCode.create(:country => germany, :name => "Lauchhammer", :area_code => "3574") + AreaCode.create(:country => germany, :name => "Welzow", :area_code => "35751") + AreaCode.create(:country => germany, :name => "Ruhland", :area_code => "35752") + AreaCode.create(:country => germany, :name => "Großräschen", :area_code => "35753") + AreaCode.create(:country => germany, :name => "Klettwitz", :area_code => "35754") + AreaCode.create(:country => germany, :name => "Ortrand", :area_code => "35755") + AreaCode.create(:country => germany, :name => "Hosena", :area_code => "35756") + AreaCode.create(:country => germany, :name => "Weisswasser", :area_code => "3576") + AreaCode.create(:country => germany, :name => "Bad Muskau", :area_code => "35771") + AreaCode.create(:country => germany, :name => "Rietschen", :area_code => "35772") + AreaCode.create(:country => germany, :name => "Schleife", :area_code => "35773") + AreaCode.create(:country => germany, :name => "Boxberg Sachs", :area_code => "35774") + AreaCode.create(:country => germany, :name => "Pechern", :area_code => "35775") + AreaCode.create(:country => germany, :name => "Kamenz", :area_code => "3578") + AreaCode.create(:country => germany, :name => "Ossling", :area_code => "35792") + AreaCode.create(:country => germany, :name => "Elstra", :area_code => "35793") + AreaCode.create(:country => germany, :name => "Königsbrück", :area_code => "35795") + AreaCode.create(:country => germany, :name => "Panschwitz-Kuckau", :area_code => "35796") + AreaCode.create(:country => germany, :name => "Schwepnitz", :area_code => "35797") + AreaCode.create(:country => germany, :name => "Görlitz", :area_code => "3581") + AreaCode.create(:country => germany, :name => "Zodel", :area_code => "35820") + AreaCode.create(:country => germany, :name => "Hagenwerder", :area_code => "35822") + AreaCode.create(:country => germany, :name => "Ostritz", :area_code => "35823") + AreaCode.create(:country => germany, :name => "Kodersdorf", :area_code => "35825") + AreaCode.create(:country => germany, :name => "Königshain b Görlitz", :area_code => "35826") + AreaCode.create(:country => germany, :name => "Nieder-Seifersdorf", :area_code => "35827") + AreaCode.create(:country => germany, :name => "Reichenbach OL", :area_code => "35828") + AreaCode.create(:country => germany, :name => "Gersdorf b Görlitz", :area_code => "35829") + AreaCode.create(:country => germany, :name => "Zittau", :area_code => "3583") + AreaCode.create(:country => germany, :name => "Großschönau Sachs", :area_code => "35841") + AreaCode.create(:country => germany, :name => "Oderwitz", :area_code => "35842") + AreaCode.create(:country => germany, :name => "Hirschfelde b Zittau", :area_code => "35843") + AreaCode.create(:country => germany, :name => "Oybin Kurort", :area_code => "35844") + AreaCode.create(:country => germany, :name => "Löbau", :area_code => "3585") + AreaCode.create(:country => germany, :name => "Neugersdorf ,Sachs", :area_code => "3586") + AreaCode.create(:country => germany, :name => "Neusalza-Spremberg", :area_code => "35872") + AreaCode.create(:country => germany, :name => "Herrnhut", :area_code => "35873") + AreaCode.create(:country => germany, :name => "Bernstadt a d Eigen", :area_code => "35874") + AreaCode.create(:country => germany, :name => "Obercunnersdorf b Löbau", :area_code => "35875") + AreaCode.create(:country => germany, :name => "Weissenberg Sachs", :area_code => "35876") + AreaCode.create(:country => germany, :name => "Cunewalde", :area_code => "35877") + AreaCode.create(:country => germany, :name => "Niesky", :area_code => "3588") + AreaCode.create(:country => germany, :name => "Rothenburg OL", :area_code => "35891") + AreaCode.create(:country => germany, :name => "Horka OL", :area_code => "35892") + AreaCode.create(:country => germany, :name => "Mücka", :area_code => "35893") + AreaCode.create(:country => germany, :name => "Hähnichen", :area_code => "35894") + AreaCode.create(:country => germany, :name => "Klitten", :area_code => "35895") + AreaCode.create(:country => germany, :name => "Bautzen", :area_code => "3591") + AreaCode.create(:country => germany, :name => "Kirschau", :area_code => "3592") + AreaCode.create(:country => germany, :name => "Seitschen", :area_code => "35930") + AreaCode.create(:country => germany, :name => "Königswartha", :area_code => "35931") + AreaCode.create(:country => germany, :name => "Guttau", :area_code => "35932") + AreaCode.create(:country => germany, :name => "Neschwitz", :area_code => "35933") + AreaCode.create(:country => germany, :name => "Grossdubrau", :area_code => "35934") + AreaCode.create(:country => germany, :name => "Kleinwelka", :area_code => "35935") + AreaCode.create(:country => germany, :name => "Sohland Spree", :area_code => "35936") + AreaCode.create(:country => germany, :name => "Prischwitz", :area_code => "35937") + AreaCode.create(:country => germany, :name => "Großpostwitz OL", :area_code => "35938") + AreaCode.create(:country => germany, :name => "Hochkirch", :area_code => "35939") + AreaCode.create(:country => germany, :name => "Bischofswerda", :area_code => "3594") + AreaCode.create(:country => germany, :name => "Neukirch Lausitz", :area_code => "35951") + AreaCode.create(:country => germany, :name => "Großröhrsdorf OL", :area_code => "35952") + AreaCode.create(:country => germany, :name => "Burkau", :area_code => "35953") + AreaCode.create(:country => germany, :name => "Grossharthau", :area_code => "35954") + AreaCode.create(:country => germany, :name => "Pulsnitz", :area_code => "35955") + AreaCode.create(:country => germany, :name => "Neustadt i Sa", :area_code => "3596") + AreaCode.create(:country => germany, :name => "Sebnitz", :area_code => "35971") + AreaCode.create(:country => germany, :name => "Stolpen", :area_code => "35973") + AreaCode.create(:country => germany, :name => "Hinterhermsdorf", :area_code => "35974") + AreaCode.create(:country => germany, :name => "Hohnstein", :area_code => "35975") + AreaCode.create(:country => germany, :name => "Mühlhausen Thür", :area_code => "3601") + AreaCode.create(:country => germany, :name => "Ebeleben", :area_code => "36020") + AreaCode.create(:country => germany, :name => "Schlotheim", :area_code => "36021") + AreaCode.create(:country => germany, :name => "Grossengottern", :area_code => "36022") + AreaCode.create(:country => germany, :name => "Horsmar", :area_code => "36023") + AreaCode.create(:country => germany, :name => "Diedorf b Mühlhausen Thür", :area_code => "36024") + AreaCode.create(:country => germany, :name => "Körner", :area_code => "36025") + AreaCode.create(:country => germany, :name => "Struth b Mühlhausen Thür", :area_code => "36026") + AreaCode.create(:country => germany, :name => "Lengenfeld Unterm Stein", :area_code => "36027") + AreaCode.create(:country => germany, :name => "Kammerforst Thür", :area_code => "36028") + AreaCode.create(:country => germany, :name => "Menteroda", :area_code => "36029") + AreaCode.create(:country => germany, :name => "Bad Langensalza", :area_code => "3603") + AreaCode.create(:country => germany, :name => "Bad Tennstedt", :area_code => "36041") + AreaCode.create(:country => germany, :name => "Tonna", :area_code => "36042") + AreaCode.create(:country => germany, :name => "Kirchheilingen", :area_code => "36043") + AreaCode.create(:country => germany, :name => "Leinefelde", :area_code => "3605") + AreaCode.create(:country => germany, :name => "Heiligenstadt Heilbad", :area_code => "3606") + AreaCode.create(:country => germany, :name => "Teistungen", :area_code => "36071") + AreaCode.create(:country => germany, :name => "Weißenborn-Lüderode", :area_code => "36072") + AreaCode.create(:country => germany, :name => "Worbis", :area_code => "36074") + AreaCode.create(:country => germany, :name => "Dingelstädt Eichsfeld", :area_code => "36075") + AreaCode.create(:country => germany, :name => "Niederorschel", :area_code => "36076") + AreaCode.create(:country => germany, :name => "Grossbodungen", :area_code => "36077") + AreaCode.create(:country => germany, :name => "Arenshausen", :area_code => "36081") + AreaCode.create(:country => germany, :name => "Ershausen", :area_code => "36082") + AreaCode.create(:country => germany, :name => "Uder", :area_code => "36083") + AreaCode.create(:country => germany, :name => "Heuthen", :area_code => "36084") + AreaCode.create(:country => germany, :name => "Reinholterode", :area_code => "36085") + AreaCode.create(:country => germany, :name => "Wüstheuterode", :area_code => "36087") + AreaCode.create(:country => germany, :name => "Erfurt", :area_code => "361") + AreaCode.create(:country => germany, :name => "Elxleben b Arnstadt", :area_code => "36200") + AreaCode.create(:country => germany, :name => "Walschleben", :area_code => "36201") + AreaCode.create(:country => germany, :name => "Neudietendorf", :area_code => "36202") + AreaCode.create(:country => germany, :name => "Vieselbach", :area_code => "36203") + AreaCode.create(:country => germany, :name => "Stotternheim", :area_code => "36204") + AreaCode.create(:country => germany, :name => "Gräfenroda", :area_code => "36205") + AreaCode.create(:country => germany, :name => "Grossfahner", :area_code => "36206") + AreaCode.create(:country => germany, :name => "Plaue Thür", :area_code => "36207") + AreaCode.create(:country => germany, :name => "Ermstedt", :area_code => "36208") + AreaCode.create(:country => germany, :name => "Klettbach", :area_code => "36209") + AreaCode.create(:country => germany, :name => "Gotha Thür", :area_code => "3621") + AreaCode.create(:country => germany, :name => "Waltershausen Thür", :area_code => "3622") + AreaCode.create(:country => germany, :name => "Friedrichroda", :area_code => "3623") + AreaCode.create(:country => germany, :name => "Ohrdruf", :area_code => "3624") + AreaCode.create(:country => germany, :name => "Tambach-Dietharz Thür Wald", :area_code => "36252") + AreaCode.create(:country => germany, :name => "Georgenthal Thür Wald", :area_code => "36253") + AreaCode.create(:country => germany, :name => "Friedrichswerth", :area_code => "36254") + AreaCode.create(:country => germany, :name => "Goldbach b Gotha", :area_code => "36255") + AreaCode.create(:country => germany, :name => "Wechmar", :area_code => "36256") + AreaCode.create(:country => germany, :name => "Luisenthal Thür", :area_code => "36257") + AreaCode.create(:country => germany, :name => "Friemar", :area_code => "36258") + AreaCode.create(:country => germany, :name => "Tabarz Thür Wald", :area_code => "36259") + AreaCode.create(:country => germany, :name => "Arnstadt", :area_code => "3628") + AreaCode.create(:country => germany, :name => "Stadtilm", :area_code => "3629") + AreaCode.create(:country => germany, :name => "Nordhausen Thür", :area_code => "3631") + AreaCode.create(:country => germany, :name => "Sondershausen", :area_code => "3632") + AreaCode.create(:country => germany, :name => "Grossberndten", :area_code => "36330") + AreaCode.create(:country => germany, :name => "Ilfeld", :area_code => "36331") + AreaCode.create(:country => germany, :name => "Ellrich", :area_code => "36332") + AreaCode.create(:country => germany, :name => "Heringen Helme", :area_code => "36333") + AreaCode.create(:country => germany, :name => "Wolkramshausen", :area_code => "36334") + AreaCode.create(:country => germany, :name => "Grosswechsungen", :area_code => "36335") + AreaCode.create(:country => germany, :name => "Klettenberg", :area_code => "36336") + AreaCode.create(:country => germany, :name => "Schiedungen", :area_code => "36337") + AreaCode.create(:country => germany, :name => "Bleicherode", :area_code => "36338") + AreaCode.create(:country => germany, :name => "Sömmerda", :area_code => "3634") + AreaCode.create(:country => germany, :name => "Kölleda", :area_code => "3635") + AreaCode.create(:country => germany, :name => "Greussen", :area_code => "3636") + AreaCode.create(:country => germany, :name => "Grossenehrich", :area_code => "36370") + AreaCode.create(:country => germany, :name => "Schlossvippach", :area_code => "36371") + AreaCode.create(:country => germany, :name => "Kleinneuhausen", :area_code => "36372") + AreaCode.create(:country => germany, :name => "Buttstädt", :area_code => "36373") + AreaCode.create(:country => germany, :name => "Weissensee", :area_code => "36374") + AreaCode.create(:country => germany, :name => "Kindelbrück", :area_code => "36375") + AreaCode.create(:country => germany, :name => "Straussfurt", :area_code => "36376") + AreaCode.create(:country => germany, :name => "Rastenberg", :area_code => "36377") + AreaCode.create(:country => germany, :name => "Ostramondra", :area_code => "36378") + AreaCode.create(:country => germany, :name => "Holzengel", :area_code => "36379") + AreaCode.create(:country => germany, :name => "Jena", :area_code => "3641") + AreaCode.create(:country => germany, :name => "Camburg", :area_code => "36421") + AreaCode.create(:country => germany, :name => "Reinstädt Thür", :area_code => "36422") + AreaCode.create(:country => germany, :name => "Orlamünde", :area_code => "36423") + AreaCode.create(:country => germany, :name => "Kahla Thür", :area_code => "36424") + AreaCode.create(:country => germany, :name => "Isserstedt", :area_code => "36425") + AreaCode.create(:country => germany, :name => "Ottendorf b Stadtroda", :area_code => "36426") + AreaCode.create(:country => germany, :name => "Dornburg Saale", :area_code => "36427") + AreaCode.create(:country => germany, :name => "Stadtroda", :area_code => "36428") + AreaCode.create(:country => germany, :name => "Weimar Thür", :area_code => "3643") + AreaCode.create(:country => germany, :name => "Apolda", :area_code => "3644") + AreaCode.create(:country => germany, :name => "Kranichfeld", :area_code => "36450") + AreaCode.create(:country => germany, :name => "Buttelstedt", :area_code => "36451") + AreaCode.create(:country => germany, :name => "Berlstedt", :area_code => "36452") + AreaCode.create(:country => germany, :name => "Mellingen", :area_code => "36453") + AreaCode.create(:country => germany, :name => "Magdala", :area_code => "36454") + AreaCode.create(:country => germany, :name => "Bad Berka", :area_code => "36458") + AreaCode.create(:country => germany, :name => "Blankenhain Thür", :area_code => "36459") + AreaCode.create(:country => germany, :name => "Bad Sulza", :area_code => "36461") + AreaCode.create(:country => germany, :name => "Ossmannstedt", :area_code => "36462") + AreaCode.create(:country => germany, :name => "Gebstedt", :area_code => "36463") + AreaCode.create(:country => germany, :name => "Wormstedt", :area_code => "36464") + AreaCode.create(:country => germany, :name => "Oberndorf b Apolda", :area_code => "36465") + AreaCode.create(:country => germany, :name => "Pößneck", :area_code => "3647") + AreaCode.create(:country => germany, :name => "Neustadt an der Orla", :area_code => "36481") + AreaCode.create(:country => germany, :name => "Triptis", :area_code => "36482") + AreaCode.create(:country => germany, :name => "Ziegenrück", :area_code => "36483") + AreaCode.create(:country => germany, :name => "Knau b Pößneck", :area_code => "36484") + AreaCode.create(:country => germany, :name => "Gera", :area_code => "365") + AreaCode.create(:country => germany, :name => "Hermsdorf Thür", :area_code => "36601") + AreaCode.create(:country => germany, :name => "Ronneburg Thür", :area_code => "36602") + AreaCode.create(:country => germany, :name => "Weida", :area_code => "36603") + AreaCode.create(:country => germany, :name => "Münchenbernsdorf", :area_code => "36604") + AreaCode.create(:country => germany, :name => "Bad Köstritz", :area_code => "36605") + AreaCode.create(:country => germany, :name => "Kraftsdorf", :area_code => "36606") + AreaCode.create(:country => germany, :name => "Niederpöllnitz", :area_code => "36607") + AreaCode.create(:country => germany, :name => "Seelingstädt b Gera", :area_code => "36608") + AreaCode.create(:country => germany, :name => "Greiz", :area_code => "3661") + AreaCode.create(:country => germany, :name => "Elsterberg b Plauen", :area_code => "36621") + AreaCode.create(:country => germany, :name => "Triebes", :area_code => "36622") + AreaCode.create(:country => germany, :name => "Berga Elster", :area_code => "36623") + AreaCode.create(:country => germany, :name => "Teichwolframsdorf", :area_code => "36624") + AreaCode.create(:country => germany, :name => "Langenwetzendorf", :area_code => "36625") + AreaCode.create(:country => germany, :name => "Auma", :area_code => "36626") + AreaCode.create(:country => germany, :name => "Zeulenroda", :area_code => "36628") + AreaCode.create(:country => germany, :name => "Schleiz", :area_code => "3663") + AreaCode.create(:country => germany, :name => "Remptendorf", :area_code => "36640") + AreaCode.create(:country => germany, :name => "Harra", :area_code => "36642") + AreaCode.create(:country => germany, :name => "Thimmendorf", :area_code => "36643") + AreaCode.create(:country => germany, :name => "Hirschberg Saale", :area_code => "36644") + AreaCode.create(:country => germany, :name => "Mühltroff", :area_code => "36645") + AreaCode.create(:country => germany, :name => "Tanna b Schleiz", :area_code => "36646") + AreaCode.create(:country => germany, :name => "Saalburg Thür", :area_code => "36647") + AreaCode.create(:country => germany, :name => "Dittersdorf b Schleiz", :area_code => "36648") + AreaCode.create(:country => germany, :name => "Gefell b Schleiz", :area_code => "36649") + AreaCode.create(:country => germany, :name => "Lobenstein", :area_code => "36651") + AreaCode.create(:country => germany, :name => "Wurzbach", :area_code => "36652") + AreaCode.create(:country => germany, :name => "Lehesten Thür Wald", :area_code => "36653") + AreaCode.create(:country => germany, :name => "Eisenberg Thür", :area_code => "36691") + AreaCode.create(:country => germany, :name => "Bürgel", :area_code => "36692") + AreaCode.create(:country => germany, :name => "Crossen an der Elster", :area_code => "36693") + AreaCode.create(:country => germany, :name => "Schkölen Thür", :area_code => "36694") + AreaCode.create(:country => germany, :name => "Söllmnitz", :area_code => "36695") + AreaCode.create(:country => germany, :name => "Lichte", :area_code => "36701") + AreaCode.create(:country => germany, :name => "Lauscha", :area_code => "36702") + AreaCode.create(:country => germany, :name => "Gräfenthal", :area_code => "36703") + AreaCode.create(:country => germany, :name => "Steinheid", :area_code => "36704") + AreaCode.create(:country => germany, :name => "Oberweißbach Thür Wald", :area_code => "36705") + AreaCode.create(:country => germany, :name => "Saalfeld Saale", :area_code => "3671") + AreaCode.create(:country => germany, :name => "Rudolstadt", :area_code => "3672") + AreaCode.create(:country => germany, :name => "Sitzendorf", :area_code => "36730") + AreaCode.create(:country => germany, :name => "Unterloquitz", :area_code => "36731") + AreaCode.create(:country => germany, :name => "Könitz", :area_code => "36732") + AreaCode.create(:country => germany, :name => "Kaulsdorf", :area_code => "36733") + AreaCode.create(:country => germany, :name => "Leutenberg", :area_code => "36734") + AreaCode.create(:country => germany, :name => "Probstzella", :area_code => "36735") + AreaCode.create(:country => germany, :name => "Arnsgereuth", :area_code => "36736") + AreaCode.create(:country => germany, :name => "Drognitz", :area_code => "36737") + AreaCode.create(:country => germany, :name => "Königsee", :area_code => "36738") + AreaCode.create(:country => germany, :name => "Rottenbach", :area_code => "36739") + AreaCode.create(:country => germany, :name => "Bad Blankenburg", :area_code => "36741") + AreaCode.create(:country => germany, :name => "Uhlstädt", :area_code => "36742") + AreaCode.create(:country => germany, :name => "Teichel", :area_code => "36743") + AreaCode.create(:country => germany, :name => "Remda", :area_code => "36744") + AreaCode.create(:country => germany, :name => "Sonneberg Thür", :area_code => "3675") + AreaCode.create(:country => germany, :name => "Heubisch", :area_code => "36761") + AreaCode.create(:country => germany, :name => "Steinach Thür", :area_code => "36762") + AreaCode.create(:country => germany, :name => "Neuhaus-Schierschnitz", :area_code => "36764") + AreaCode.create(:country => germany, :name => "Schalkau", :area_code => "36766") + AreaCode.create(:country => germany, :name => "Ilmenau Thür", :area_code => "3677") + AreaCode.create(:country => germany, :name => "Grossbreitenbach", :area_code => "36781") + AreaCode.create(:country => germany, :name => "Schmiedefeld a Rennsteig", :area_code => "36782") + AreaCode.create(:country => germany, :name => "Gehren Thür", :area_code => "36783") + AreaCode.create(:country => germany, :name => "Stützerbach", :area_code => "36784") + AreaCode.create(:country => germany, :name => "Gräfinau-Angstedt", :area_code => "36785") + AreaCode.create(:country => germany, :name => "Neuhaus a Rennweg", :area_code => "3679") + AreaCode.create(:country => germany, :name => "Suhl", :area_code => "3681") + AreaCode.create(:country => germany, :name => "Zella-Mehlis", :area_code => "3682") + AreaCode.create(:country => germany, :name => "Schmalkalden", :area_code => "3683") + AreaCode.create(:country => germany, :name => "Trusetal", :area_code => "36840") + AreaCode.create(:country => germany, :name => "Schleusingen", :area_code => "36841") + AreaCode.create(:country => germany, :name => "Oberhof Thür", :area_code => "36842") + AreaCode.create(:country => germany, :name => "Benshausen", :area_code => "36843") + AreaCode.create(:country => germany, :name => "Rohr Thür", :area_code => "36844") + AreaCode.create(:country => germany, :name => "Gehlberg", :area_code => "36845") + AreaCode.create(:country => germany, :name => "Suhl-Dietzhausen", :area_code => "36846") + AreaCode.create(:country => germany, :name => "Steinbach-Hallenberg", :area_code => "36847") + AreaCode.create(:country => germany, :name => "Wernshausen", :area_code => "36848") + AreaCode.create(:country => germany, :name => "Kleinschmalkalden", :area_code => "36849") + AreaCode.create(:country => germany, :name => "Hildburghausen", :area_code => "3685") + AreaCode.create(:country => germany, :name => "Eisfeld", :area_code => "3686") + AreaCode.create(:country => germany, :name => "Masserberg", :area_code => "36870") + AreaCode.create(:country => germany, :name => "Bad Colberg-Heldburg", :area_code => "36871") + AreaCode.create(:country => germany, :name => "Themar", :area_code => "36873") + AreaCode.create(:country => germany, :name => "Schönbrunn b Hildburghaus", :area_code => "36874") + AreaCode.create(:country => germany, :name => "Straufhain-Streufdorf", :area_code => "36875") + AreaCode.create(:country => germany, :name => "Oberland", :area_code => "36878") + AreaCode.create(:country => germany, :name => "Eisenach Thür", :area_code => "3691") + AreaCode.create(:country => germany, :name => "Grossenlupnitz", :area_code => "36920") + AreaCode.create(:country => germany, :name => "Wutha-Farnroda", :area_code => "36921") + AreaCode.create(:country => germany, :name => "Gerstungen", :area_code => "36922") + AreaCode.create(:country => germany, :name => "Treffurt", :area_code => "36923") + AreaCode.create(:country => germany, :name => "Mihla", :area_code => "36924") + AreaCode.create(:country => germany, :name => "Marksuhl", :area_code => "36925") + AreaCode.create(:country => germany, :name => "Creuzburg", :area_code => "36926") + AreaCode.create(:country => germany, :name => "Unterellen", :area_code => "36927") + AreaCode.create(:country => germany, :name => "Neuenhof Thür", :area_code => "36928") + AreaCode.create(:country => germany, :name => "Ruhla", :area_code => "36929") + AreaCode.create(:country => germany, :name => "Meiningen", :area_code => "3693") + AreaCode.create(:country => germany, :name => "Oepfershausen", :area_code => "36940") + AreaCode.create(:country => germany, :name => "Wasungen", :area_code => "36941") + AreaCode.create(:country => germany, :name => "Bettenhausen Thür", :area_code => "36943") + AreaCode.create(:country => germany, :name => "Rentwertshausen", :area_code => "36944") + AreaCode.create(:country => germany, :name => "Henneberg", :area_code => "36945") + AreaCode.create(:country => germany, :name => "Erbenhausen Thür", :area_code => "36946") + AreaCode.create(:country => germany, :name => "Jüchsen", :area_code => "36947") + AreaCode.create(:country => germany, :name => "Römhild", :area_code => "36948") + AreaCode.create(:country => germany, :name => "Obermaßfeld-Grimmenthal", :area_code => "36949") + AreaCode.create(:country => germany, :name => "Bad Salzungen", :area_code => "3695") + AreaCode.create(:country => germany, :name => "Bad Liebenstein", :area_code => "36961") + AreaCode.create(:country => germany, :name => "Vacha", :area_code => "36962") + AreaCode.create(:country => germany, :name => "Dorndorf Rhön", :area_code => "36963") + AreaCode.create(:country => germany, :name => "Dermbach Rhön", :area_code => "36964") + AreaCode.create(:country => germany, :name => "Stadtlengsfeld", :area_code => "36965") + AreaCode.create(:country => germany, :name => "Kaltennordheim", :area_code => "36966") + AreaCode.create(:country => germany, :name => "Geisa", :area_code => "36967") + AreaCode.create(:country => germany, :name => "Rossdorf Rhön", :area_code => "36968") + AreaCode.create(:country => germany, :name => "Merkers", :area_code => "36969") + AreaCode.create(:country => germany, :name => "Chemnitz Sachs", :area_code => "371") + AreaCode.create(:country => germany, :name => "Wittgensdorf b Chemnitz", :area_code => "37200") + AreaCode.create(:country => germany, :name => "Claussnitz b Chemnitz", :area_code => "37202") + AreaCode.create(:country => germany, :name => "Gersdorf b Chemnitz", :area_code => "37203") + AreaCode.create(:country => germany, :name => "Lichtenstein Sachs", :area_code => "37204") + AreaCode.create(:country => germany, :name => "Frankenberg", :area_code => "37206") + AreaCode.create(:country => germany, :name => "Hainichen", :area_code => "37207") + AreaCode.create(:country => germany, :name => "Auerswalde", :area_code => "37208") + AreaCode.create(:country => germany, :name => "Einsiedel b Chemnitz", :area_code => "37209") + AreaCode.create(:country => germany, :name => "Meinersdorf", :area_code => "3721") + AreaCode.create(:country => germany, :name => "Limbach-Oberfrohna", :area_code => "3722") + AreaCode.create(:country => germany, :name => "Hohenstein-Ernstthal", :area_code => "3723") + AreaCode.create(:country => germany, :name => "Burgstädt", :area_code => "3724") + AreaCode.create(:country => germany, :name => "Zschopau", :area_code => "3725") + AreaCode.create(:country => germany, :name => "Flöha", :area_code => "3726") + AreaCode.create(:country => germany, :name => "Mittweida", :area_code => "3727") + AreaCode.create(:country => germany, :name => "Augustusburg", :area_code => "37291") + AreaCode.create(:country => germany, :name => "Oederan", :area_code => "37292") + AreaCode.create(:country => germany, :name => "Eppendorf Sachs", :area_code => "37293") + AreaCode.create(:country => germany, :name => "Grünhainichen", :area_code => "37294") + AreaCode.create(:country => germany, :name => "Lugau Erzgeb", :area_code => "37295") + AreaCode.create(:country => germany, :name => "Stollberg Erzgeb", :area_code => "37296") + AreaCode.create(:country => germany, :name => "Thum Sachs", :area_code => "37297") + AreaCode.create(:country => germany, :name => "Oelsnitz Erzgeb", :area_code => "37298") + AreaCode.create(:country => germany, :name => "Freiberg Sachs", :area_code => "3731") + AreaCode.create(:country => germany, :name => "Mulda Sachs", :area_code => "37320") + AreaCode.create(:country => germany, :name => "Frankenstein Sachs", :area_code => "37321") + AreaCode.create(:country => germany, :name => "Brand-Erbisdorf", :area_code => "37322") + AreaCode.create(:country => germany, :name => "Lichtenberg Erzgeb", :area_code => "37323") + AreaCode.create(:country => germany, :name => "Reinsberg Sachs", :area_code => "37324") + AreaCode.create(:country => germany, :name => "Niederbobritzsch", :area_code => "37325") + AreaCode.create(:country => germany, :name => "Frauenstein Sachs", :area_code => "37326") + AreaCode.create(:country => germany, :name => "Rechenberg-Bienenmühle", :area_code => "37327") + AreaCode.create(:country => germany, :name => "Grossschirma", :area_code => "37328") + AreaCode.create(:country => germany, :name => "Grosshartmannsdorf", :area_code => "37329") + AreaCode.create(:country => germany, :name => "Annaberg-Buchholz", :area_code => "3733") + AreaCode.create(:country => germany, :name => "Ehrenfriedersdorf", :area_code => "37341") + AreaCode.create(:country => germany, :name => "Cranzahl", :area_code => "37342") + AreaCode.create(:country => germany, :name => "Jöhstadt", :area_code => "37343") + AreaCode.create(:country => germany, :name => "Crottendorf Sachs", :area_code => "37344") + AreaCode.create(:country => germany, :name => "Geyer", :area_code => "37346") + AreaCode.create(:country => germany, :name => "Bärenstein Kr Annaberg", :area_code => "37347") + AreaCode.create(:country => germany, :name => "Oberwiesenthal Kurort", :area_code => "37348") + AreaCode.create(:country => germany, :name => "Scheibenberg", :area_code => "37349") + AreaCode.create(:country => germany, :name => "Marienberg Sachs", :area_code => "3735") + AreaCode.create(:country => germany, :name => "Olbernhau", :area_code => "37360") + AreaCode.create(:country => germany, :name => "Neuhausen Erzgeb", :area_code => "37361") + AreaCode.create(:country => germany, :name => "Seiffen Erzgeb", :area_code => "37362") + AreaCode.create(:country => germany, :name => "Zöblitz", :area_code => "37363") + AreaCode.create(:country => germany, :name => "Reitzenhain Erzgeb", :area_code => "37364") + AreaCode.create(:country => germany, :name => "Sayda", :area_code => "37365") + AreaCode.create(:country => germany, :name => "Rübenau", :area_code => "37366") + AreaCode.create(:country => germany, :name => "Lengefeld Erzgeb", :area_code => "37367") + AreaCode.create(:country => germany, :name => "Deutschneudorf", :area_code => "37368") + AreaCode.create(:country => germany, :name => "Wolkenstein", :area_code => "37369") + AreaCode.create(:country => germany, :name => "Rochlitz", :area_code => "3737") + AreaCode.create(:country => germany, :name => "Penig", :area_code => "37381") + AreaCode.create(:country => germany, :name => "Geringswalde", :area_code => "37382") + AreaCode.create(:country => germany, :name => "Lunzenau", :area_code => "37383") + AreaCode.create(:country => germany, :name => "Wechselburg", :area_code => "37384") + AreaCode.create(:country => germany, :name => "Plauen", :area_code => "3741") + AreaCode.create(:country => germany, :name => "Oelsnitz Vogtl", :area_code => "37421") + AreaCode.create(:country => germany, :name => "Markneukirchen", :area_code => "37422") + AreaCode.create(:country => germany, :name => "Adorf Vogtl", :area_code => "37423") + AreaCode.create(:country => germany, :name => "Eichigt", :area_code => "37430") + AreaCode.create(:country => germany, :name => "Mehltheuer Vogtl", :area_code => "37431") + AreaCode.create(:country => germany, :name => "Pausa Vogtl", :area_code => "37432") + AreaCode.create(:country => germany, :name => "Gutenfürst", :area_code => "37433") + AreaCode.create(:country => germany, :name => "Bobenneukirchen", :area_code => "37434") + AreaCode.create(:country => germany, :name => "Reuth b Plauen", :area_code => "37435") + AreaCode.create(:country => germany, :name => "Weischlitz", :area_code => "37436") + AreaCode.create(:country => germany, :name => "Bad Elster", :area_code => "37437") + AreaCode.create(:country => germany, :name => "Bad Brambach", :area_code => "37438") + AreaCode.create(:country => germany, :name => "Jocketa", :area_code => "37439") + AreaCode.create(:country => germany, :name => "Auerbach Vogtl.", :area_code => "3744") + AreaCode.create(:country => germany, :name => "Falkenstein Vogtl", :area_code => "3745") + AreaCode.create(:country => germany, :name => "Rothenkirchen Vogtl", :area_code => "37462") + AreaCode.create(:country => germany, :name => "Bergen Vogtl", :area_code => "37463") + AreaCode.create(:country => germany, :name => "Schöneck Vogtl", :area_code => "37464") + AreaCode.create(:country => germany, :name => "Tannenbergsthal Vogtl", :area_code => "37465") + AreaCode.create(:country => germany, :name => "Klingenthal Sachs", :area_code => "37467") + AreaCode.create(:country => germany, :name => "Treuen Vogtl", :area_code => "37468") + AreaCode.create(:country => germany, :name => "Zwickau", :area_code => "375") + AreaCode.create(:country => germany, :name => "Neumark Sachs", :area_code => "37600") + AreaCode.create(:country => germany, :name => "Mülsen Skt Jacob", :area_code => "37601") + AreaCode.create(:country => germany, :name => "Kirchberg Sachs", :area_code => "37602") + AreaCode.create(:country => germany, :name => "Wildenfels", :area_code => "37603") + AreaCode.create(:country => germany, :name => "Mosel", :area_code => "37604") + AreaCode.create(:country => germany, :name => "Hartenstein Sachs", :area_code => "37605") + AreaCode.create(:country => germany, :name => "Lengenfeld Vogtl", :area_code => "37606") + AreaCode.create(:country => germany, :name => "Ebersbrunn Sachs", :area_code => "37607") + AreaCode.create(:country => germany, :name => "Waldenburg Sachs", :area_code => "37608") + AreaCode.create(:country => germany, :name => "Wolkenburg Mulde", :area_code => "37609") + AreaCode.create(:country => germany, :name => "Werdau Sachs", :area_code => "3761") + AreaCode.create(:country => germany, :name => "Crimmitschau", :area_code => "3762") + AreaCode.create(:country => germany, :name => "Glauchau", :area_code => "3763") + AreaCode.create(:country => germany, :name => "Meerane", :area_code => "3764") + AreaCode.create(:country => germany, :name => "Reichenbach Vogtl", :area_code => "3765") + AreaCode.create(:country => germany, :name => "Aue Sachs", :area_code => "3771") + AreaCode.create(:country => germany, :name => "Schneeberg Erzgeb", :area_code => "3772") + AreaCode.create(:country => germany, :name => "Johanngeorgenstadt", :area_code => "3773") + AreaCode.create(:country => germany, :name => "Schwarzenberg", :area_code => "3774") + AreaCode.create(:country => germany, :name => "Eibenstock", :area_code => "37752") + AreaCode.create(:country => germany, :name => "Zwönitz", :area_code => "37754") + AreaCode.create(:country => germany, :name => "Schönheide Erzgeb", :area_code => "37755") + AreaCode.create(:country => germany, :name => "Breitenbrunn Erzgeb", :area_code => "37756") + AreaCode.create(:country => germany, :name => "Rittersgrün", :area_code => "37757") + AreaCode.create(:country => germany, :name => "Rostock", :area_code => "381") + AreaCode.create(:country => germany, :name => "Gelbensande", :area_code => "38201") + AreaCode.create(:country => germany, :name => "Volkenshagen", :area_code => "38202") + AreaCode.create(:country => germany, :name => "Bad Doberan", :area_code => "38203") + AreaCode.create(:country => germany, :name => "Broderstorf", :area_code => "38204") + AreaCode.create(:country => germany, :name => "Tessin b Rostock", :area_code => "38205") + AreaCode.create(:country => germany, :name => "Graal-Müritz Seeheilbad", :area_code => "38206") + AreaCode.create(:country => germany, :name => "Stäbelow", :area_code => "38207") + AreaCode.create(:country => germany, :name => "Kavelstorf", :area_code => "38208") + AreaCode.create(:country => germany, :name => "Sanitz b Rostock", :area_code => "38209") + AreaCode.create(:country => germany, :name => "Ribnitz-Damgarten", :area_code => "3821") + AreaCode.create(:country => germany, :name => "Wustrow Ostseebad", :area_code => "38220") + AreaCode.create(:country => germany, :name => "Marlow", :area_code => "38221") + AreaCode.create(:country => germany, :name => "Semlow", :area_code => "38222") + AreaCode.create(:country => germany, :name => "Saal Vorpom", :area_code => "38223") + AreaCode.create(:country => germany, :name => "Gresenhorst", :area_code => "38224") + AreaCode.create(:country => germany, :name => "Trinwillershagen", :area_code => "38225") + AreaCode.create(:country => germany, :name => "Dierhagen Ostseebad", :area_code => "38226") + AreaCode.create(:country => germany, :name => "Lüdershagen b Barth", :area_code => "38227") + AreaCode.create(:country => germany, :name => "Dettmannsdorf-Kölzow", :area_code => "38228") + AreaCode.create(:country => germany, :name => "Bad Sülze", :area_code => "38229") + AreaCode.create(:country => germany, :name => "Barth", :area_code => "38231") + AreaCode.create(:country => germany, :name => "Zingst Ostseebad", :area_code => "38232") + AreaCode.create(:country => germany, :name => "Prerow Ostseebad", :area_code => "38233") + AreaCode.create(:country => germany, :name => "Born a Darß", :area_code => "38234") + AreaCode.create(:country => germany, :name => "Kröpelin", :area_code => "38292") + AreaCode.create(:country => germany, :name => "Kühlungsborn Ostseebad", :area_code => "38293") + AreaCode.create(:country => germany, :name => "Neubukow", :area_code => "38294") + AreaCode.create(:country => germany, :name => "Satow b Bad Doberan", :area_code => "38295") + AreaCode.create(:country => germany, :name => "Rerik Ostseebad", :area_code => "38296") + AreaCode.create(:country => germany, :name => "Moitin", :area_code => "38297") + AreaCode.create(:country => germany, :name => "Insel Hiddensee", :area_code => "38300") + AreaCode.create(:country => germany, :name => "Putbus", :area_code => "38301") + AreaCode.create(:country => germany, :name => "Sagard", :area_code => "38302") + AreaCode.create(:country => germany, :name => "Sellin Ostseebad", :area_code => "38303") + AreaCode.create(:country => germany, :name => "Garz Rügen", :area_code => "38304") + AreaCode.create(:country => germany, :name => "Gingst", :area_code => "38305") + AreaCode.create(:country => germany, :name => "Samtens", :area_code => "38306") + AreaCode.create(:country => germany, :name => "Poseritz", :area_code => "38307") + AreaCode.create(:country => germany, :name => "Göhren Rügen", :area_code => "38308") + AreaCode.create(:country => germany, :name => "Trent", :area_code => "38309") + AreaCode.create(:country => germany, :name => "Stralsund", :area_code => "3831") + AreaCode.create(:country => germany, :name => "Tribsees", :area_code => "38320") + AreaCode.create(:country => germany, :name => "Martensdorf b Stralsund", :area_code => "38321") + AreaCode.create(:country => germany, :name => "Richtenberg", :area_code => "38322") + AreaCode.create(:country => germany, :name => "Prohn", :area_code => "38323") + AreaCode.create(:country => germany, :name => "Velgast", :area_code => "38324") + AreaCode.create(:country => germany, :name => "Rolofshagen", :area_code => "38325") + AreaCode.create(:country => germany, :name => "Grimmen", :area_code => "38326") + AreaCode.create(:country => germany, :name => "Elmenhorst Vorpom", :area_code => "38327") + AreaCode.create(:country => germany, :name => "Miltzow", :area_code => "38328") + AreaCode.create(:country => germany, :name => "Rakow Vorpom", :area_code => "38331") + AreaCode.create(:country => germany, :name => "Gross Bisdorf", :area_code => "38332") + AreaCode.create(:country => germany, :name => "Horst b Grimmen", :area_code => "38333") + AreaCode.create(:country => germany, :name => "Grammendorf", :area_code => "38334") + AreaCode.create(:country => germany, :name => "Greifswald", :area_code => "3834") + AreaCode.create(:country => germany, :name => "Mesekenhagen", :area_code => "38351") + AreaCode.create(:country => germany, :name => "Kemnitz b Greifswald", :area_code => "38352") + AreaCode.create(:country => germany, :name => "Gützkow b Greifswald", :area_code => "38353") + AreaCode.create(:country => germany, :name => "Wusterhusen", :area_code => "38354") + AreaCode.create(:country => germany, :name => "Züssow", :area_code => "38355") + AreaCode.create(:country => germany, :name => "Behrenhoff", :area_code => "38356") + AreaCode.create(:country => germany, :name => "Wolgast", :area_code => "3836") + AreaCode.create(:country => germany, :name => "Kröslin", :area_code => "38370") + AreaCode.create(:country => germany, :name => "Karlshagen", :area_code => "38371") + AreaCode.create(:country => germany, :name => "Usedom", :area_code => "38372") + AreaCode.create(:country => germany, :name => "Katzow", :area_code => "38373") + AreaCode.create(:country => germany, :name => "Lassan b Wolgast", :area_code => "38374") + AreaCode.create(:country => germany, :name => "Koserow", :area_code => "38375") + AreaCode.create(:country => germany, :name => "Zirchow", :area_code => "38376") + AreaCode.create(:country => germany, :name => "Zinnowitz", :area_code => "38377") + AreaCode.create(:country => germany, :name => "Heringsdorf Seebad", :area_code => "38378") + AreaCode.create(:country => germany, :name => "Benz Usedom", :area_code => "38379") + AreaCode.create(:country => germany, :name => "Bergen auf Rügen", :area_code => "3838") + AreaCode.create(:country => germany, :name => "Altenkirchen Rügen", :area_code => "38391") + AreaCode.create(:country => germany, :name => "Sassnitz", :area_code => "38392") + AreaCode.create(:country => germany, :name => "Binz Ostseebad", :area_code => "38393") + AreaCode.create(:country => germany, :name => "Wismar Meckl", :area_code => "3841") + AreaCode.create(:country => germany, :name => "Neukloster", :area_code => "38422") + AreaCode.create(:country => germany, :name => "Bad Kleinen", :area_code => "38423") + AreaCode.create(:country => germany, :name => "Bobitz", :area_code => "38424") + AreaCode.create(:country => germany, :name => "Kirchdorf Poel", :area_code => "38425") + AreaCode.create(:country => germany, :name => "Neuburg-Steinhausen", :area_code => "38426") + AreaCode.create(:country => germany, :name => "Blowatz", :area_code => "38427") + AreaCode.create(:country => germany, :name => "Hohenkirchen b Wismar", :area_code => "38428") + AreaCode.create(:country => germany, :name => "Glasin", :area_code => "38429") + AreaCode.create(:country => germany, :name => "Güstrow", :area_code => "3843") + AreaCode.create(:country => germany, :name => "Schwaan", :area_code => "3844") + AreaCode.create(:country => germany, :name => "Tarnow b Bützow", :area_code => "38450") + AreaCode.create(:country => germany, :name => "Hoppenrade b Güstrow", :area_code => "38451") + AreaCode.create(:country => germany, :name => "Lalendorf", :area_code => "38452") + AreaCode.create(:country => germany, :name => "Mistorf", :area_code => "38453") + AreaCode.create(:country => germany, :name => "Kritzkow", :area_code => "38454") + AreaCode.create(:country => germany, :name => "Plaaz", :area_code => "38455") + AreaCode.create(:country => germany, :name => "Langhagen b Güstrow", :area_code => "38456") + AreaCode.create(:country => germany, :name => "Krakow am See", :area_code => "38457") + AreaCode.create(:country => germany, :name => "Zehna", :area_code => "38458") + AreaCode.create(:country => germany, :name => "Laage", :area_code => "38459") + AreaCode.create(:country => germany, :name => "Bützow", :area_code => "38461") + AreaCode.create(:country => germany, :name => "Baumgarten Meckl", :area_code => "38462") + AreaCode.create(:country => germany, :name => "Bernitt", :area_code => "38464") + AreaCode.create(:country => germany, :name => "Jürgenshagen", :area_code => "38466") + AreaCode.create(:country => germany, :name => "Sternberg", :area_code => "3847") + AreaCode.create(:country => germany, :name => "Witzin", :area_code => "38481") + AreaCode.create(:country => germany, :name => "Warin", :area_code => "38482") + AreaCode.create(:country => germany, :name => "Brüel", :area_code => "38483") + AreaCode.create(:country => germany, :name => "Ventschow", :area_code => "38484") + AreaCode.create(:country => germany, :name => "Dabel", :area_code => "38485") + AreaCode.create(:country => germany, :name => "Gustävel", :area_code => "38486") + AreaCode.create(:country => germany, :name => "Demen", :area_code => "38488") + AreaCode.create(:country => germany, :name => "Schwerin Meckl", :area_code => "385") + AreaCode.create(:country => germany, :name => "Raben Steinfeld", :area_code => "3860") + AreaCode.create(:country => germany, :name => "Plate", :area_code => "3861") + AreaCode.create(:country => germany, :name => "Crivitz", :area_code => "3863") + AreaCode.create(:country => germany, :name => "Holthusen", :area_code => "3865") + AreaCode.create(:country => germany, :name => "Cambs", :area_code => "3866") + AreaCode.create(:country => germany, :name => "Lübstorf", :area_code => "3867") + AreaCode.create(:country => germany, :name => "Rastow", :area_code => "3868") + AreaCode.create(:country => germany, :name => "Dümmer", :area_code => "3869") + AreaCode.create(:country => germany, :name => "Parchim", :area_code => "3871") + AreaCode.create(:country => germany, :name => "Grebbin", :area_code => "38720") + AreaCode.create(:country => germany, :name => "Ziegendorf", :area_code => "38721") + AreaCode.create(:country => germany, :name => "Raduhn", :area_code => "38722") + AreaCode.create(:country => germany, :name => "Kladrum", :area_code => "38723") + AreaCode.create(:country => germany, :name => "Siggelkow", :area_code => "38724") + AreaCode.create(:country => germany, :name => "Gross Godems", :area_code => "38725") + AreaCode.create(:country => germany, :name => "Spornitz", :area_code => "38726") + AreaCode.create(:country => germany, :name => "Mestlin", :area_code => "38727") + AreaCode.create(:country => germany, :name => "Domsühl", :area_code => "38728") + AreaCode.create(:country => germany, :name => "Marnitz", :area_code => "38729") + AreaCode.create(:country => germany, :name => "Lübz", :area_code => "38731") + AreaCode.create(:country => germany, :name => "Gallin b Lübz", :area_code => "38732") + AreaCode.create(:country => germany, :name => "Karbow-Vietlübbe", :area_code => "38733") + AreaCode.create(:country => germany, :name => "Plau am See", :area_code => "38735") + AreaCode.create(:country => germany, :name => "Goldberg Meckl", :area_code => "38736") + AreaCode.create(:country => germany, :name => "Ganzlin", :area_code => "38737") + AreaCode.create(:country => germany, :name => "Karow b Lübz", :area_code => "38738") + AreaCode.create(:country => germany, :name => "Ludwigslust Meckl", :area_code => "3874") + AreaCode.create(:country => germany, :name => "Malliss", :area_code => "38750") + AreaCode.create(:country => germany, :name => "Picher", :area_code => "38751") + AreaCode.create(:country => germany, :name => "Zierzow b Ludwigslust", :area_code => "38752") + AreaCode.create(:country => germany, :name => "Wöbbelin", :area_code => "38753") + AreaCode.create(:country => germany, :name => "Leussow b Ludwigslust", :area_code => "38754") + AreaCode.create(:country => germany, :name => "Eldena", :area_code => "38755") + AreaCode.create(:country => germany, :name => "Grabow Meckl", :area_code => "38756") + AreaCode.create(:country => germany, :name => "Neustadt-Glewe", :area_code => "38757") + AreaCode.create(:country => germany, :name => "Dömitz", :area_code => "38758") + AreaCode.create(:country => germany, :name => "Tewswoos", :area_code => "38759") + AreaCode.create(:country => germany, :name => "Perleberg", :area_code => "3876") + AreaCode.create(:country => germany, :name => "Wittenberge", :area_code => "3877") + AreaCode.create(:country => germany, :name => "Lanz Brandenb", :area_code => "38780") + AreaCode.create(:country => germany, :name => "Mellen", :area_code => "38781") + AreaCode.create(:country => germany, :name => "Reetz b Perleberg", :area_code => "38782") + AreaCode.create(:country => germany, :name => "Dallmin", :area_code => "38783") + AreaCode.create(:country => germany, :name => "Kleinow Kr Prignitz", :area_code => "38784") + AreaCode.create(:country => germany, :name => "Berge b Perleberg", :area_code => "38785") + AreaCode.create(:country => germany, :name => "Glöwen", :area_code => "38787") + AreaCode.create(:country => germany, :name => "Gross Warnow", :area_code => "38788") + AreaCode.create(:country => germany, :name => "Wolfshagen b Perleberg", :area_code => "38789") + AreaCode.create(:country => germany, :name => "Bad Wilsnack", :area_code => "38791") + AreaCode.create(:country => germany, :name => "Lenzen (Elbe)", :area_code => "38792") + AreaCode.create(:country => germany, :name => "Dergenthin", :area_code => "38793") + AreaCode.create(:country => germany, :name => "Cumlosen", :area_code => "38794") + AreaCode.create(:country => germany, :name => "Viesecke", :area_code => "38796") + AreaCode.create(:country => germany, :name => "Karstädt Kr Prignitz", :area_code => "38797") + AreaCode.create(:country => germany, :name => "Grevesmühlen", :area_code => "3881") + AreaCode.create(:country => germany, :name => "Lüdersdorf Meckl", :area_code => "38821") + AreaCode.create(:country => germany, :name => "Diedrichshagen b Grevesmühlen", :area_code => "38822") + AreaCode.create(:country => germany, :name => "Selmsdorf", :area_code => "38823") + AreaCode.create(:country => germany, :name => "Mallentin", :area_code => "38824") + AreaCode.create(:country => germany, :name => "Klütz", :area_code => "38825") + AreaCode.create(:country => germany, :name => "Dassow", :area_code => "38826") + AreaCode.create(:country => germany, :name => "Kalkhorst", :area_code => "38827") + AreaCode.create(:country => germany, :name => "Schönberg Meckl", :area_code => "38828") + AreaCode.create(:country => germany, :name => "Hagenow", :area_code => "3883") + AreaCode.create(:country => germany, :name => "Neuhaus Elbe", :area_code => "38841") + AreaCode.create(:country => germany, :name => "Lüttenmark", :area_code => "38842") + AreaCode.create(:country => germany, :name => "Bennin", :area_code => "38843") + AreaCode.create(:country => germany, :name => "Gülze", :area_code => "38844") + AreaCode.create(:country => germany, :name => "Kaarssen", :area_code => "38845") + AreaCode.create(:country => germany, :name => "Boizenburg Elbe", :area_code => "38847") + AreaCode.create(:country => germany, :name => "Vellahn", :area_code => "38848") + AreaCode.create(:country => germany, :name => "Gammelin", :area_code => "38850") + AreaCode.create(:country => germany, :name => "Zarrentin Meckl", :area_code => "38851") + AreaCode.create(:country => germany, :name => "Wittenburg", :area_code => "38852") + AreaCode.create(:country => germany, :name => "Drönnewitz b Hagenow", :area_code => "38853") + AreaCode.create(:country => germany, :name => "Redefin", :area_code => "38854") + AreaCode.create(:country => germany, :name => "Lübtheen", :area_code => "38855") + AreaCode.create(:country => germany, :name => "Pritzier b Hagenow", :area_code => "38856") + AreaCode.create(:country => germany, :name => "Lassahn", :area_code => "38858") + AreaCode.create(:country => germany, :name => "Alt Zachun", :area_code => "38859") + AreaCode.create(:country => germany, :name => "Gadebusch", :area_code => "3886") + AreaCode.create(:country => germany, :name => "Mühlen Eichsen", :area_code => "38871") + AreaCode.create(:country => germany, :name => "Rehna", :area_code => "38872") + AreaCode.create(:country => germany, :name => "Carlow", :area_code => "38873") + AreaCode.create(:country => germany, :name => "Lützow", :area_code => "38874") + AreaCode.create(:country => germany, :name => "Schlagsdorf b Gadebusch", :area_code => "38875") + AreaCode.create(:country => germany, :name => "Roggendorf", :area_code => "38876") + AreaCode.create(:country => germany, :name => "Beetzendorf", :area_code => "39000") + AreaCode.create(:country => germany, :name => "Apenburg", :area_code => "39001") + AreaCode.create(:country => germany, :name => "Oebisfelde", :area_code => "39002") + AreaCode.create(:country => germany, :name => "Jübar", :area_code => "39003") + AreaCode.create(:country => germany, :name => "Köckte b Gardelegen", :area_code => "39004") + AreaCode.create(:country => germany, :name => "Kusey", :area_code => "39005") + AreaCode.create(:country => germany, :name => "Miesterhorst", :area_code => "39006") + AreaCode.create(:country => germany, :name => "Tangeln", :area_code => "39007") + AreaCode.create(:country => germany, :name => "Kunrau", :area_code => "39008") + AreaCode.create(:country => germany, :name => "Badel", :area_code => "39009") + AreaCode.create(:country => germany, :name => "Salzwedel", :area_code => "3901") + AreaCode.create(:country => germany, :name => "Diesdorf Altm", :area_code => "3902") + AreaCode.create(:country => germany, :name => "Brunau", :area_code => "39030") + AreaCode.create(:country => germany, :name => "Dähre", :area_code => "39031") + AreaCode.create(:country => germany, :name => "Mahlsdorf b Salzwedel", :area_code => "39032") + AreaCode.create(:country => germany, :name => "Wallstawe", :area_code => "39033") + AreaCode.create(:country => germany, :name => "Fleetmark", :area_code => "39034") + AreaCode.create(:country => germany, :name => "Kuhfelde", :area_code => "39035") + AreaCode.create(:country => germany, :name => "Binde", :area_code => "39036") + AreaCode.create(:country => germany, :name => "Pretzier", :area_code => "39037") + AreaCode.create(:country => germany, :name => "Henningen", :area_code => "39038") + AreaCode.create(:country => germany, :name => "Bonese", :area_code => "39039") + AreaCode.create(:country => germany, :name => "Haldensleben", :area_code => "3904") + AreaCode.create(:country => germany, :name => "Bartensleben", :area_code => "39050") + AreaCode.create(:country => germany, :name => "Calvörde", :area_code => "39051") + AreaCode.create(:country => germany, :name => "Erxleben b Haldensleben", :area_code => "39052") + AreaCode.create(:country => germany, :name => "Süplingen", :area_code => "39053") + AreaCode.create(:country => germany, :name => "Flechtingen", :area_code => "39054") + AreaCode.create(:country => germany, :name => "Hörsingen", :area_code => "39055") + AreaCode.create(:country => germany, :name => "Klüden", :area_code => "39056") + AreaCode.create(:country => germany, :name => "Rätzlingen Sachs-Anh", :area_code => "39057") + AreaCode.create(:country => germany, :name => "Uthmöden", :area_code => "39058") + AreaCode.create(:country => germany, :name => "Wegenstedt", :area_code => "39059") + AreaCode.create(:country => germany, :name => "Weferlingen", :area_code => "39061") + AreaCode.create(:country => germany, :name => "Bebertal", :area_code => "39062") + AreaCode.create(:country => germany, :name => "Gardelegen", :area_code => "3907") + AreaCode.create(:country => germany, :name => "Kalbe Milde", :area_code => "39080") + AreaCode.create(:country => germany, :name => "Kakerbeck Sachs-Anh", :area_code => "39081") + AreaCode.create(:country => germany, :name => "Mieste", :area_code => "39082") + AreaCode.create(:country => germany, :name => "Messdorf", :area_code => "39083") + AreaCode.create(:country => germany, :name => "Lindstedt", :area_code => "39084") + AreaCode.create(:country => germany, :name => "Zichtau", :area_code => "39085") + AreaCode.create(:country => germany, :name => "Jävenitz", :area_code => "39086") + AreaCode.create(:country => germany, :name => "Jerchel Altmark", :area_code => "39087") + AreaCode.create(:country => germany, :name => "Letzlingen", :area_code => "39088") + AreaCode.create(:country => germany, :name => "Bismark Altmark", :area_code => "39089") + AreaCode.create(:country => germany, :name => "Klötze Altmark", :area_code => "3909") + AreaCode.create(:country => germany, :name => "Magdeburg", :area_code => "391") + AreaCode.create(:country => germany, :name => "Gommern", :area_code => "39200") + AreaCode.create(:country => germany, :name => "Wolmirstedt", :area_code => "39201") + AreaCode.create(:country => germany, :name => "Gross Ammensleben", :area_code => "39202") + AreaCode.create(:country => germany, :name => "Barleben", :area_code => "39203") + AreaCode.create(:country => germany, :name => "Niederndodeleben", :area_code => "39204") + AreaCode.create(:country => germany, :name => "Langenweddingen", :area_code => "39205") + AreaCode.create(:country => germany, :name => "Eichenbarleben", :area_code => "39206") + AreaCode.create(:country => germany, :name => "Colbitz", :area_code => "39207") + AreaCode.create(:country => germany, :name => "Loitsche", :area_code => "39208") + AreaCode.create(:country => germany, :name => "Wanzleben", :area_code => "39209") + AreaCode.create(:country => germany, :name => "Burg b Magdeburg", :area_code => "3921") + AreaCode.create(:country => germany, :name => "Möckern b Magdeburg", :area_code => "39221") + AreaCode.create(:country => germany, :name => "Möser", :area_code => "39222") + AreaCode.create(:country => germany, :name => "Theessen", :area_code => "39223") + AreaCode.create(:country => germany, :name => "Büden", :area_code => "39224") + AreaCode.create(:country => germany, :name => "Altengrabow", :area_code => "39225") + AreaCode.create(:country => germany, :name => "Hohenziatz", :area_code => "39226") + AreaCode.create(:country => germany, :name => "Zerbst", :area_code => "3923") + AreaCode.create(:country => germany, :name => "Leitzkau", :area_code => "39241") + AreaCode.create(:country => germany, :name => "Prödel", :area_code => "39242") + AreaCode.create(:country => germany, :name => "Nedlitz b Zerbst", :area_code => "39243") + AreaCode.create(:country => germany, :name => "Steutz", :area_code => "39244") + AreaCode.create(:country => germany, :name => "Loburg", :area_code => "39245") + AreaCode.create(:country => germany, :name => "Lindau Anh", :area_code => "39246") + AreaCode.create(:country => germany, :name => "Güterglück", :area_code => "39247") + AreaCode.create(:country => germany, :name => "Dobritz", :area_code => "39248") + AreaCode.create(:country => germany, :name => "Stassfurt", :area_code => "3925") + AreaCode.create(:country => germany, :name => "Güsten Anh", :area_code => "39262") + AreaCode.create(:country => germany, :name => "Unseburg", :area_code => "39263") + AreaCode.create(:country => germany, :name => "Kroppenstedt", :area_code => "39264") + AreaCode.create(:country => germany, :name => "Löderburg", :area_code => "39265") + AreaCode.create(:country => germany, :name => "Förderstedt", :area_code => "39266") + AreaCode.create(:country => germany, :name => "Schneidlingen", :area_code => "39267") + AreaCode.create(:country => germany, :name => "Egeln", :area_code => "39268") + AreaCode.create(:country => germany, :name => "Schönebeck Elbe", :area_code => "3928") + AreaCode.create(:country => germany, :name => "Calbe Saale", :area_code => "39291") + AreaCode.create(:country => germany, :name => "Biederitz", :area_code => "39292") + AreaCode.create(:country => germany, :name => "Dreileben", :area_code => "39293") + AreaCode.create(:country => germany, :name => "Gross Rosenburg", :area_code => "39294") + AreaCode.create(:country => germany, :name => "Zuchau", :area_code => "39295") + AreaCode.create(:country => germany, :name => "Welsleben", :area_code => "39296") + AreaCode.create(:country => germany, :name => "Eickendorf Kr Schönebeck", :area_code => "39297") + AreaCode.create(:country => germany, :name => "Barby Elbe", :area_code => "39298") + AreaCode.create(:country => germany, :name => "Stendal", :area_code => "3931") + AreaCode.create(:country => germany, :name => "Schinne", :area_code => "39320") + AreaCode.create(:country => germany, :name => "Arneburg", :area_code => "39321") + AreaCode.create(:country => germany, :name => "Tangermünde", :area_code => "39322") + AreaCode.create(:country => germany, :name => "Schönhausen Elbe", :area_code => "39323") + AreaCode.create(:country => germany, :name => "Kläden b Stendal", :area_code => "39324") + AreaCode.create(:country => germany, :name => "Vinzelberg", :area_code => "39325") + AreaCode.create(:country => germany, :name => "Klietz", :area_code => "39327") + AreaCode.create(:country => germany, :name => "Rochau", :area_code => "39328") + AreaCode.create(:country => germany, :name => "Möringen", :area_code => "39329") + AreaCode.create(:country => germany, :name => "Genthin", :area_code => "3933") + AreaCode.create(:country => germany, :name => "Redekin", :area_code => "39341") + AreaCode.create(:country => germany, :name => "Gladau", :area_code => "39342") + AreaCode.create(:country => germany, :name => "Jerichow", :area_code => "39343") + AreaCode.create(:country => germany, :name => "Güsen", :area_code => "39344") + AreaCode.create(:country => germany, :name => "Parchen", :area_code => "39345") + AreaCode.create(:country => germany, :name => "Tucheim", :area_code => "39346") + AreaCode.create(:country => germany, :name => "Kade", :area_code => "39347") + AreaCode.create(:country => germany, :name => "Klitsche", :area_code => "39348") + AreaCode.create(:country => germany, :name => "Parey Elbe", :area_code => "39349") + AreaCode.create(:country => germany, :name => "Tangerhütte", :area_code => "3935") + AreaCode.create(:country => germany, :name => "Lüderitz", :area_code => "39361") + AreaCode.create(:country => germany, :name => "Grieben b Tangerhütte", :area_code => "39362") + AreaCode.create(:country => germany, :name => "Angern", :area_code => "39363") + AreaCode.create(:country => germany, :name => "Dolle", :area_code => "39364") + AreaCode.create(:country => germany, :name => "Bellingen b Stendal", :area_code => "39365") + AreaCode.create(:country => germany, :name => "Kehnert", :area_code => "39366") + AreaCode.create(:country => germany, :name => "Osterburg Altmark", :area_code => "3937") + AreaCode.create(:country => germany, :name => "Kamern", :area_code => "39382") + AreaCode.create(:country => germany, :name => "Sandau Elbe", :area_code => "39383") + AreaCode.create(:country => germany, :name => "Arendsee Altmark", :area_code => "39384") + AreaCode.create(:country => germany, :name => "Seehausen Altmark", :area_code => "39386") + AreaCode.create(:country => germany, :name => "Havelberg", :area_code => "39387") + AreaCode.create(:country => germany, :name => "Goldbeck Altm", :area_code => "39388") + AreaCode.create(:country => germany, :name => "Schollene", :area_code => "39389") + AreaCode.create(:country => germany, :name => "Iden", :area_code => "39390") + AreaCode.create(:country => germany, :name => "Lückstedt", :area_code => "39391") + AreaCode.create(:country => germany, :name => "Rönnebeck Sachs-Ahn", :area_code => "39392") + AreaCode.create(:country => germany, :name => "Werben Elbe", :area_code => "39393") + AreaCode.create(:country => germany, :name => "Hohenberg-Krusemark", :area_code => "39394") + AreaCode.create(:country => germany, :name => "Wanzer", :area_code => "39395") + AreaCode.create(:country => germany, :name => "Neukirchen Altmark", :area_code => "39396") + AreaCode.create(:country => germany, :name => "Geestgottberg", :area_code => "39397") + AreaCode.create(:country => germany, :name => "Gross Garz", :area_code => "39398") + AreaCode.create(:country => germany, :name => "Kleinau", :area_code => "39399") + AreaCode.create(:country => germany, :name => "Wefensleben", :area_code => "39400") + AreaCode.create(:country => germany, :name => "Neuwegersleben", :area_code => "39401") + AreaCode.create(:country => germany, :name => "Völpke", :area_code => "39402") + AreaCode.create(:country => germany, :name => "Gröningen Sachs-Ahn", :area_code => "39403") + AreaCode.create(:country => germany, :name => "Ausleben", :area_code => "39404") + AreaCode.create(:country => germany, :name => "Hötensleben", :area_code => "39405") + AreaCode.create(:country => germany, :name => "Harbke", :area_code => "39406") + AreaCode.create(:country => germany, :name => "Seehausen Börde", :area_code => "39407") + AreaCode.create(:country => germany, :name => "Hadmersleben", :area_code => "39408") + AreaCode.create(:country => germany, :name => "Eilsleben", :area_code => "39409") + AreaCode.create(:country => germany, :name => "Halberstadt", :area_code => "3941") + AreaCode.create(:country => germany, :name => "Osterwieck", :area_code => "39421") + AreaCode.create(:country => germany, :name => "Badersleben", :area_code => "39422") + AreaCode.create(:country => germany, :name => "Wegeleben", :area_code => "39423") + AreaCode.create(:country => germany, :name => "Schwanebeck Sachs-Anh", :area_code => "39424") + AreaCode.create(:country => germany, :name => "Dingelstedt a Huy", :area_code => "39425") + AreaCode.create(:country => germany, :name => "Hessen", :area_code => "39426") + AreaCode.create(:country => germany, :name => "Ströbeck", :area_code => "39427") + AreaCode.create(:country => germany, :name => "Pabstorf", :area_code => "39428") + AreaCode.create(:country => germany, :name => "Wernigerode", :area_code => "3943") + AreaCode.create(:country => germany, :name => "Blankenburg Harz", :area_code => "3944") + AreaCode.create(:country => germany, :name => "Wasserleben", :area_code => "39451") + AreaCode.create(:country => germany, :name => "Ilsenburg", :area_code => "39452") + AreaCode.create(:country => germany, :name => "Derenburg", :area_code => "39453") + AreaCode.create(:country => germany, :name => "Elbingerode Harz", :area_code => "39454") + AreaCode.create(:country => germany, :name => "Schierke", :area_code => "39455") + AreaCode.create(:country => germany, :name => "Altenbrak", :area_code => "39456") + AreaCode.create(:country => germany, :name => "Benneckenstein Harz", :area_code => "39457") + AreaCode.create(:country => germany, :name => "Heudeber", :area_code => "39458") + AreaCode.create(:country => germany, :name => "Hasselfelde", :area_code => "39459") + AreaCode.create(:country => germany, :name => "Quedlinburg", :area_code => "3946") + AreaCode.create(:country => germany, :name => "Thale", :area_code => "3947") + AreaCode.create(:country => germany, :name => "Hedersleben b Aschersleben", :area_code => "39481") + AreaCode.create(:country => germany, :name => "Gatersleben", :area_code => "39482") + AreaCode.create(:country => germany, :name => "Ballenstedt", :area_code => "39483") + AreaCode.create(:country => germany, :name => "Harzgerode", :area_code => "39484") + AreaCode.create(:country => germany, :name => "Gernrode Harz", :area_code => "39485") + AreaCode.create(:country => germany, :name => "Friedrichsbrunn", :area_code => "39487") + AreaCode.create(:country => germany, :name => "Güntersberge", :area_code => "39488") + AreaCode.create(:country => germany, :name => "Strassberg Harz", :area_code => "39489") + AreaCode.create(:country => germany, :name => "Oschersleben Bode", :area_code => "3949") + AreaCode.create(:country => germany, :name => "Neubrandenburg", :area_code => "395") + AreaCode.create(:country => germany, :name => "Zwiedorf", :area_code => "39600") + AreaCode.create(:country => germany, :name => "Friedland Meckl", :area_code => "39601") + AreaCode.create(:country => germany, :name => "Kleeth", :area_code => "39602") + AreaCode.create(:country => germany, :name => "Burg Stargard", :area_code => "39603") + AreaCode.create(:country => germany, :name => "Wildberg b Altentreptow", :area_code => "39604") + AreaCode.create(:country => germany, :name => "Gross Nemerow", :area_code => "39605") + AreaCode.create(:country => germany, :name => "Glienke", :area_code => "39606") + AreaCode.create(:country => germany, :name => "Kotelow", :area_code => "39607") + AreaCode.create(:country => germany, :name => "Staven", :area_code => "39608") + AreaCode.create(:country => germany, :name => "Altentreptow", :area_code => "3961") + AreaCode.create(:country => germany, :name => "Penzlin b Waren", :area_code => "3962") + AreaCode.create(:country => germany, :name => "Woldegk", :area_code => "3963") + AreaCode.create(:country => germany, :name => "Bredenfelde b Strasburg", :area_code => "3964") + AreaCode.create(:country => germany, :name => "Burow b Altentreptow", :area_code => "3965") + AreaCode.create(:country => germany, :name => "Cölpin", :area_code => "3966") + AreaCode.create(:country => germany, :name => "Oertzenhof b Strasburg", :area_code => "3967") + AreaCode.create(:country => germany, :name => "Schönbeck Meckl", :area_code => "3968") + AreaCode.create(:country => germany, :name => "Siedenbollentin", :area_code => "3969") + AreaCode.create(:country => germany, :name => "Anklam", :area_code => "3971") + AreaCode.create(:country => germany, :name => "Liepen b Anklam", :area_code => "39721") + AreaCode.create(:country => germany, :name => "Sarnow b Anklam", :area_code => "39722") + AreaCode.create(:country => germany, :name => "Krien", :area_code => "39723") + AreaCode.create(:country => germany, :name => "Klein Bünzow", :area_code => "39724") + AreaCode.create(:country => germany, :name => "Ducherow", :area_code => "39726") + AreaCode.create(:country => germany, :name => "Spantekow", :area_code => "39727") + AreaCode.create(:country => germany, :name => "Medow b Anklam", :area_code => "39728") + AreaCode.create(:country => germany, :name => "Pasewalk", :area_code => "3973") + AreaCode.create(:country => germany, :name => "Nechlin", :area_code => "39740") + AreaCode.create(:country => germany, :name => "Jatznick", :area_code => "39741") + AreaCode.create(:country => germany, :name => "Brüssow b Pasewalk", :area_code => "39742") + AreaCode.create(:country => germany, :name => "Zerrenthin", :area_code => "39743") + AreaCode.create(:country => germany, :name => "Rothenklempenow", :area_code => "39744") + AreaCode.create(:country => germany, :name => "Hetzdorf b Strasburg", :area_code => "39745") + AreaCode.create(:country => germany, :name => "Krackow", :area_code => "39746") + AreaCode.create(:country => germany, :name => "Züsedom", :area_code => "39747") + AreaCode.create(:country => germany, :name => "Viereck", :area_code => "39748") + AreaCode.create(:country => germany, :name => "Grambow b Pasewalk", :area_code => "39749") + AreaCode.create(:country => germany, :name => "Penkun", :area_code => "39751") + AreaCode.create(:country => germany, :name => "Blumenhagen b Strasburg", :area_code => "39752") + AreaCode.create(:country => germany, :name => "Strasburg", :area_code => "39753") + AreaCode.create(:country => germany, :name => "Löcknitz Vorpom", :area_code => "39754") + AreaCode.create(:country => germany, :name => "Torgelow b Ueckermünde", :area_code => "3976") + AreaCode.create(:country => germany, :name => "Ueckermünde", :area_code => "39771") + AreaCode.create(:country => germany, :name => "Rothemühl", :area_code => "39772") + AreaCode.create(:country => germany, :name => "Altwarp", :area_code => "39773") + AreaCode.create(:country => germany, :name => "Mönkebude", :area_code => "39774") + AreaCode.create(:country => germany, :name => "Ahlbeck b Torgelow", :area_code => "39775") + AreaCode.create(:country => germany, :name => "Hintersee", :area_code => "39776") + AreaCode.create(:country => germany, :name => "Borkenfriede", :area_code => "39777") + AreaCode.create(:country => germany, :name => "Ferdinandshof b Torgelow", :area_code => "39778") + AreaCode.create(:country => germany, :name => "Eggesin", :area_code => "39779") + AreaCode.create(:country => germany, :name => "Neustrelitz", :area_code => "3981") + AreaCode.create(:country => germany, :name => "Triepkendorf", :area_code => "39820") + AreaCode.create(:country => germany, :name => "Carpin", :area_code => "39821") + AreaCode.create(:country => germany, :name => "Kratzeburg", :area_code => "39822") + AreaCode.create(:country => germany, :name => "Rechlin", :area_code => "39823") + AreaCode.create(:country => germany, :name => "Hohenzieritz", :area_code => "39824") + AreaCode.create(:country => germany, :name => "Wokuhl", :area_code => "39825") + AreaCode.create(:country => germany, :name => "Blankensee b Neustrelitz", :area_code => "39826") + AreaCode.create(:country => germany, :name => "Schwarz b Neustrelitz", :area_code => "39827") + AreaCode.create(:country => germany, :name => "Wustrow Kr Mecklenburg-Strelitz", :area_code => "39828") + AreaCode.create(:country => germany, :name => "Blankenförde", :area_code => "39829") + AreaCode.create(:country => germany, :name => "Feldberg Meckl", :area_code => "39831") + AreaCode.create(:country => germany, :name => "Wesenberg Meckl", :area_code => "39832") + AreaCode.create(:country => germany, :name => "Mirow Kr Neustrelitz", :area_code => "39833") + AreaCode.create(:country => germany, :name => "Prenzlau", :area_code => "3984") + AreaCode.create(:country => germany, :name => "Göritz b Prenzlau", :area_code => "39851") + AreaCode.create(:country => germany, :name => "Schönermark b Prenzlau", :area_code => "39852") + AreaCode.create(:country => germany, :name => "Holzendorf b Prenzlau", :area_code => "39853") + AreaCode.create(:country => germany, :name => "Kleptow", :area_code => "39854") + AreaCode.create(:country => germany, :name => "Parmen-Weggun", :area_code => "39855") + AreaCode.create(:country => germany, :name => "Beenz b Prenzlau", :area_code => "39856") + AreaCode.create(:country => germany, :name => "Drense", :area_code => "39857") + AreaCode.create(:country => germany, :name => "Bietikow", :area_code => "39858") + AreaCode.create(:country => germany, :name => "Fürstenwerder", :area_code => "39859") + AreaCode.create(:country => germany, :name => "Gramzow b Prenzlau", :area_code => "39861") + AreaCode.create(:country => germany, :name => "Schmölln b Prenzlau", :area_code => "39862") + AreaCode.create(:country => germany, :name => "Seehausen b Prenzlau", :area_code => "39863") + AreaCode.create(:country => germany, :name => "Templin", :area_code => "3987") + AreaCode.create(:country => germany, :name => "Ringenwalde b Templin", :area_code => "39881") + AreaCode.create(:country => germany, :name => "Gollin", :area_code => "39882") + AreaCode.create(:country => germany, :name => "Groß Dölln", :area_code => "39883") + AreaCode.create(:country => germany, :name => "Hassleben b Prenzlau", :area_code => "39884") + AreaCode.create(:country => germany, :name => "Jakobshagen", :area_code => "39885") + AreaCode.create(:country => germany, :name => "Milmersdorf", :area_code => "39886") + AreaCode.create(:country => germany, :name => "Gerswalde", :area_code => "39887") + AreaCode.create(:country => germany, :name => "Lychen", :area_code => "39888") + AreaCode.create(:country => germany, :name => "Boitzenburg", :area_code => "39889") + AreaCode.create(:country => germany, :name => "Waren Müritz", :area_code => "3991") + AreaCode.create(:country => germany, :name => "Ankershagen", :area_code => "39921") + AreaCode.create(:country => germany, :name => "Dambeck b Röbel", :area_code => "39922") + AreaCode.create(:country => germany, :name => "Priborn", :area_code => "39923") + AreaCode.create(:country => germany, :name => "Stuer", :area_code => "39924") + AreaCode.create(:country => germany, :name => "Wredenhagen", :area_code => "39925") + AreaCode.create(:country => germany, :name => "Grabowhöfe", :area_code => "39926") + AreaCode.create(:country => germany, :name => "Nossentiner Hütte", :area_code => "39927") + AreaCode.create(:country => germany, :name => "Möllenhagen", :area_code => "39928") + AreaCode.create(:country => germany, :name => "Jabel b Waren", :area_code => "39929") + AreaCode.create(:country => germany, :name => "Röbel Müritz", :area_code => "39931") + AreaCode.create(:country => germany, :name => "Malchow b Waren", :area_code => "39932") + AreaCode.create(:country => germany, :name => "Vollrathsruhe", :area_code => "39933") + AreaCode.create(:country => germany, :name => "Groß Plasten", :area_code => "39934") + AreaCode.create(:country => germany, :name => "Malchin", :area_code => "3994") + AreaCode.create(:country => germany, :name => "Faulenrost", :area_code => "39951") + AreaCode.create(:country => germany, :name => "Grammentin", :area_code => "39952") + AreaCode.create(:country => germany, :name => "Schwinkendorf", :area_code => "39953") + AreaCode.create(:country => germany, :name => "Stavenhagen Reuterstadt", :area_code => "39954") + AreaCode.create(:country => germany, :name => "Jürgenstorf Meckl", :area_code => "39955") + AreaCode.create(:country => germany, :name => "Neukalen", :area_code => "39956") + AreaCode.create(:country => germany, :name => "Gielow", :area_code => "39957") + AreaCode.create(:country => germany, :name => "Dargun", :area_code => "39959") + AreaCode.create(:country => germany, :name => "Teterow", :area_code => "3996") + AreaCode.create(:country => germany, :name => "Gnoien", :area_code => "39971") + AreaCode.create(:country => germany, :name => "Walkendorf", :area_code => "39972") + AreaCode.create(:country => germany, :name => "Altkalen", :area_code => "39973") + AreaCode.create(:country => germany, :name => "Thürkow", :area_code => "39975") + AreaCode.create(:country => germany, :name => "Groß Bützin", :area_code => "39976") + AreaCode.create(:country => germany, :name => "Jördenstorf", :area_code => "39977") + AreaCode.create(:country => germany, :name => "Gross Roge", :area_code => "39978") + AreaCode.create(:country => germany, :name => "Demmin", :area_code => "3998") + AreaCode.create(:country => germany, :name => "Daberkow", :area_code => "39991") + AreaCode.create(:country => germany, :name => "Görmin", :area_code => "39992") + AreaCode.create(:country => germany, :name => "Hohenmocker", :area_code => "39993") + AreaCode.create(:country => germany, :name => "Metschow", :area_code => "39994") + AreaCode.create(:country => germany, :name => "Nossendorf", :area_code => "39995") + AreaCode.create(:country => germany, :name => "Törpin", :area_code => "39996") + AreaCode.create(:country => germany, :name => "Jarmen", :area_code => "39997") + AreaCode.create(:country => germany, :name => "Loitz b Demmin", :area_code => "39998") + AreaCode.create(:country => germany, :name => "Tutow", :area_code => "39999") + AreaCode.create(:country => germany, :name => "Hamburg", :area_code => "40") + AreaCode.create(:country => germany, :name => "Pinneberg", :area_code => "4101") + AreaCode.create(:country => germany, :name => "Ahrensburg", :area_code => "4102") + AreaCode.create(:country => germany, :name => "Wedel", :area_code => "4103") + AreaCode.create(:country => germany, :name => "Aumühle b Hamburg", :area_code => "4104") + AreaCode.create(:country => germany, :name => "Seevetal", :area_code => "4105") + AreaCode.create(:country => germany, :name => "Quickborn Kr Pinneberg", :area_code => "4106") + AreaCode.create(:country => germany, :name => "Siek Kr Stormarn", :area_code => "4107") + AreaCode.create(:country => germany, :name => "Rosengarten Kr Harburg", :area_code => "4108") + AreaCode.create(:country => germany, :name => "Tangstedt Bz Hamburg", :area_code => "4109") + AreaCode.create(:country => germany, :name => "Ellerhoop", :area_code => "4120") + AreaCode.create(:country => germany, :name => "Elmshorn", :area_code => "4121") + AreaCode.create(:country => germany, :name => "Uetersen", :area_code => "4122") + AreaCode.create(:country => germany, :name => "Barmstedt", :area_code => "4123") + AreaCode.create(:country => germany, :name => "Glückstadt", :area_code => "4124") + AreaCode.create(:country => germany, :name => "Seestermühe", :area_code => "4125") + AreaCode.create(:country => germany, :name => "Horst Holstein", :area_code => "4126") + AreaCode.create(:country => germany, :name => "Westerhorn", :area_code => "4127") + AreaCode.create(:country => germany, :name => "Kollmar", :area_code => "4128") + AreaCode.create(:country => germany, :name => "Haseldorf", :area_code => "4129") + AreaCode.create(:country => germany, :name => "Lüneburg", :area_code => "4131") + AreaCode.create(:country => germany, :name => "Amelinghausen", :area_code => "4132") + AreaCode.create(:country => germany, :name => "Wittorf Kr Lüneburg", :area_code => "4133") + AreaCode.create(:country => germany, :name => "Embsen Kr Lünebeburg", :area_code => "4134") + AreaCode.create(:country => germany, :name => "Kirchgellersen", :area_code => "4135") + AreaCode.create(:country => germany, :name => "Scharnebeck", :area_code => "4136") + AreaCode.create(:country => germany, :name => "Barendorf", :area_code => "4137") + AreaCode.create(:country => germany, :name => "Betzendorf Kr Lünebeburg", :area_code => "4138") + AreaCode.create(:country => germany, :name => "Hohnstorf Elbe", :area_code => "4139") + AreaCode.create(:country => germany, :name => "Estorf Kr Stade", :area_code => "4140") + AreaCode.create(:country => germany, :name => "Stade", :area_code => "4141") + AreaCode.create(:country => germany, :name => "Steinkirchen Kr Stade", :area_code => "4142") + AreaCode.create(:country => germany, :name => "Drochtersen", :area_code => "4143") + AreaCode.create(:country => germany, :name => "Himmelpforten", :area_code => "4144") + AreaCode.create(:country => germany, :name => "Stade-Bützfleth", :area_code => "4146") + AreaCode.create(:country => germany, :name => "Drochtersen-Assel", :area_code => "4148") + AreaCode.create(:country => germany, :name => "Fredenbeck", :area_code => "4149") + AreaCode.create(:country => germany, :name => "Schwarzenbek", :area_code => "4151") + AreaCode.create(:country => germany, :name => "Geesthacht", :area_code => "4152") + AreaCode.create(:country => germany, :name => "Lauenburg Elbe", :area_code => "4153") + AreaCode.create(:country => germany, :name => "Trittau", :area_code => "4154") + AreaCode.create(:country => germany, :name => "Büchen", :area_code => "4155") + AreaCode.create(:country => germany, :name => "Talkau", :area_code => "4156") + AreaCode.create(:country => germany, :name => "Roseburg", :area_code => "4158") + AreaCode.create(:country => germany, :name => "Basthorst", :area_code => "4159") + AreaCode.create(:country => germany, :name => "Buxtehude", :area_code => "4161") + AreaCode.create(:country => germany, :name => "Jork", :area_code => "4162") + AreaCode.create(:country => germany, :name => "Horneburg Niederelbe", :area_code => "4163") + AreaCode.create(:country => germany, :name => "Harsefeld", :area_code => "4164") + AreaCode.create(:country => germany, :name => "Hollenstedt Nordheide", :area_code => "4165") + AreaCode.create(:country => germany, :name => "Ahlerstedt", :area_code => "4166") + AreaCode.create(:country => germany, :name => "Apensen", :area_code => "4167") + AreaCode.create(:country => germany, :name => "Neu Wulmstorf-Elstorf", :area_code => "4168") + AreaCode.create(:country => germany, :name => "Sauensiek", :area_code => "4169") + AreaCode.create(:country => germany, :name => "Winsen Luhe", :area_code => "4171") + AreaCode.create(:country => germany, :name => "Salzhausen", :area_code => "4172") + AreaCode.create(:country => germany, :name => "Wulfsen", :area_code => "4173") + AreaCode.create(:country => germany, :name => "Stelle Kr Harburg", :area_code => "4174") + AreaCode.create(:country => germany, :name => "Egestorf Nordheide", :area_code => "4175") + AreaCode.create(:country => germany, :name => "Marschacht", :area_code => "4176") + AreaCode.create(:country => germany, :name => "Drage Elbe", :area_code => "4177") + AreaCode.create(:country => germany, :name => "Radbruch", :area_code => "4178") + AreaCode.create(:country => germany, :name => "Winsen-Tönnhausen", :area_code => "4179") + AreaCode.create(:country => germany, :name => "Königsmoor", :area_code => "4180") + AreaCode.create(:country => germany, :name => "Buchholz in der Nordheide", :area_code => "4181") + AreaCode.create(:country => germany, :name => "Tostedt", :area_code => "4182") + AreaCode.create(:country => germany, :name => "Jesteburg", :area_code => "4183") + AreaCode.create(:country => germany, :name => "Hanstedt Nordheide", :area_code => "4184") + AreaCode.create(:country => germany, :name => "Marxen Auetal", :area_code => "4185") + AreaCode.create(:country => germany, :name => "Buchholz-Trelde", :area_code => "4186") + AreaCode.create(:country => germany, :name => "Holm-Seppensen", :area_code => "4187") + AreaCode.create(:country => germany, :name => "Welle Nordheide", :area_code => "4188") + AreaCode.create(:country => germany, :name => "Undeloh", :area_code => "4189") + AreaCode.create(:country => germany, :name => "Kaltenkirchen Holst", :area_code => "4191") + AreaCode.create(:country => germany, :name => "Bad Bramstedt", :area_code => "4192") + AreaCode.create(:country => germany, :name => "Henstedt-Ulzburg", :area_code => "4193") + AreaCode.create(:country => germany, :name => "Sievershütten", :area_code => "4194") + AreaCode.create(:country => germany, :name => "Hartenholm", :area_code => "4195") + AreaCode.create(:country => germany, :name => "Achim b Bremen", :area_code => "4202") + AreaCode.create(:country => germany, :name => "Weyhe b Bremen", :area_code => "4203") + AreaCode.create(:country => germany, :name => "Thedinghausen", :area_code => "4204") + AreaCode.create(:country => germany, :name => "Ottersberg", :area_code => "4205") + AreaCode.create(:country => germany, :name => "Stuhr-Heiligenrode", :area_code => "4206") + AreaCode.create(:country => germany, :name => "Oyten", :area_code => "4207") + AreaCode.create(:country => germany, :name => "Grasberg", :area_code => "4208") + AreaCode.create(:country => germany, :name => "Schwanewede", :area_code => "4209") + AreaCode.create(:country => germany, :name => "Bremen", :area_code => "421") + AreaCode.create(:country => germany, :name => "Delmenhorst", :area_code => "4221") + AreaCode.create(:country => germany, :name => "Ganderkesee", :area_code => "4222") + AreaCode.create(:country => germany, :name => "Ganderkesee-Bookholzberg", :area_code => "4223") + AreaCode.create(:country => germany, :name => "Gross Ippener", :area_code => "4224") + AreaCode.create(:country => germany, :name => "Verden-Walle", :area_code => "4230") + AreaCode.create(:country => germany, :name => "Verden Aller", :area_code => "4231") + AreaCode.create(:country => germany, :name => "Langwedel Kr Verden", :area_code => "4232") + AreaCode.create(:country => germany, :name => "Blender", :area_code => "4233") + AreaCode.create(:country => germany, :name => "Dörverden", :area_code => "4234") + AreaCode.create(:country => germany, :name => "Langwedel-Etelsen", :area_code => "4235") + AreaCode.create(:country => germany, :name => "Kirchlinteln", :area_code => "4236") + AreaCode.create(:country => germany, :name => "Bendingbostel", :area_code => "4237") + AreaCode.create(:country => germany, :name => "Neddenaverbergen", :area_code => "4238") + AreaCode.create(:country => germany, :name => "Dörverden-Westen", :area_code => "4239") + AreaCode.create(:country => germany, :name => "Syke-Heiligenfelde", :area_code => "4240") + AreaCode.create(:country => germany, :name => "Bassum", :area_code => "4241") + AreaCode.create(:country => germany, :name => "Syke", :area_code => "4242") + AreaCode.create(:country => germany, :name => "Twistringen", :area_code => "4243") + AreaCode.create(:country => germany, :name => "Harpstedt", :area_code => "4244") + AreaCode.create(:country => germany, :name => "Neuenkirchen b Bassum", :area_code => "4245") + AreaCode.create(:country => germany, :name => "Twistringen-Heiligenloh", :area_code => "4246") + AreaCode.create(:country => germany, :name => "Affinghausen", :area_code => "4247") + AreaCode.create(:country => germany, :name => "Bassum-Neubruchhausen", :area_code => "4248") + AreaCode.create(:country => germany, :name => "Bassum-Nordwohlde", :area_code => "4249") + AreaCode.create(:country => germany, :name => "Hoya", :area_code => "4251") + AreaCode.create(:country => germany, :name => "Bruchhausen-Vilsen", :area_code => "4252") + AreaCode.create(:country => germany, :name => "Asendorf Kr Diepholz", :area_code => "4253") + AreaCode.create(:country => germany, :name => "Eystrup", :area_code => "4254") + AreaCode.create(:country => germany, :name => "Martfeld", :area_code => "4255") + AreaCode.create(:country => germany, :name => "Hilgermissen", :area_code => "4256") + AreaCode.create(:country => germany, :name => "Schweringen", :area_code => "4257") + AreaCode.create(:country => germany, :name => "Schwarme", :area_code => "4258") + AreaCode.create(:country => germany, :name => "Visselhövede-Wittorf", :area_code => "4260") + AreaCode.create(:country => germany, :name => "Rotenburg Wümme", :area_code => "4261") + AreaCode.create(:country => germany, :name => "Visselhövede", :area_code => "4262") + AreaCode.create(:country => germany, :name => "Scheessel", :area_code => "4263") + AreaCode.create(:country => germany, :name => "Sottrum Kr Rotenburg", :area_code => "4264") + AreaCode.create(:country => germany, :name => "Fintel", :area_code => "4265") + AreaCode.create(:country => germany, :name => "Brockel", :area_code => "4266") + AreaCode.create(:country => germany, :name => "Lauenbrück", :area_code => "4267") + AreaCode.create(:country => germany, :name => "Bötersen", :area_code => "4268") + AreaCode.create(:country => germany, :name => "Ahausen-Kirchwalsede", :area_code => "4269") + AreaCode.create(:country => germany, :name => "Sulingen", :area_code => "4271") + AreaCode.create(:country => germany, :name => "Siedenburg", :area_code => "4272") + AreaCode.create(:country => germany, :name => "Kirchdorf b Sulingen", :area_code => "4273") + AreaCode.create(:country => germany, :name => "Varrel b Sulingen", :area_code => "4274") + AreaCode.create(:country => germany, :name => "Ehrenburg", :area_code => "4275") + AreaCode.create(:country => germany, :name => "Borstel b Sulingen", :area_code => "4276") + AreaCode.create(:country => germany, :name => "Schwaförden", :area_code => "4277") + AreaCode.create(:country => germany, :name => "Zeven", :area_code => "4281") + AreaCode.create(:country => germany, :name => "Sittensen", :area_code => "4282") + AreaCode.create(:country => germany, :name => "Tarmstedt", :area_code => "4283") + AreaCode.create(:country => germany, :name => "Selsingen", :area_code => "4284") + AreaCode.create(:country => germany, :name => "Rhade b Zeven", :area_code => "4285") + AreaCode.create(:country => germany, :name => "Gyhum", :area_code => "4286") + AreaCode.create(:country => germany, :name => "Heeslingen-Boitzen", :area_code => "4287") + AreaCode.create(:country => germany, :name => "Horstedt Kr Rotenburg", :area_code => "4288") + AreaCode.create(:country => germany, :name => "Kirchtimke", :area_code => "4289") + AreaCode.create(:country => germany, :name => "Ritterhude", :area_code => "4292") + AreaCode.create(:country => germany, :name => "Ottersberg-Fischerhude", :area_code => "4293") + AreaCode.create(:country => germany, :name => "Riede Kr Verden", :area_code => "4294") + AreaCode.create(:country => germany, :name => "Emtinghausen", :area_code => "4295") + AreaCode.create(:country => germany, :name => "Schwanewede-Aschwarden", :area_code => "4296") + AreaCode.create(:country => germany, :name => "Ottersberg-Posthausen", :area_code => "4297") + AreaCode.create(:country => germany, :name => "Lilienthal", :area_code => "4298") + AreaCode.create(:country => germany, :name => "Kirchbarkau", :area_code => "4302") + AreaCode.create(:country => germany, :name => "Schlesen", :area_code => "4303") + AreaCode.create(:country => germany, :name => "Westensee", :area_code => "4305") + AreaCode.create(:country => germany, :name => "Raisdorf", :area_code => "4307") + AreaCode.create(:country => germany, :name => "Schwedeneck", :area_code => "4308") + AreaCode.create(:country => germany, :name => "Kiel", :area_code => "431") + AreaCode.create(:country => germany, :name => "Heidmühlen", :area_code => "4320") + AreaCode.create(:country => germany, :name => "Neumünster", :area_code => "4321") + AreaCode.create(:country => germany, :name => "Bordesholm", :area_code => "4322") + AreaCode.create(:country => germany, :name => "Bornhöved", :area_code => "4323") + AreaCode.create(:country => germany, :name => "Brokstedt", :area_code => "4324") + AreaCode.create(:country => germany, :name => "Wankendorf", :area_code => "4326") + AreaCode.create(:country => germany, :name => "Grossenaspe", :area_code => "4327") + AreaCode.create(:country => germany, :name => "Rickling", :area_code => "4328") + AreaCode.create(:country => germany, :name => "Langwedel Holst", :area_code => "4329") + AreaCode.create(:country => germany, :name => "Emkendorf", :area_code => "4330") + AreaCode.create(:country => germany, :name => "Rendsburg", :area_code => "4331") + AreaCode.create(:country => germany, :name => "Hamdorf b Rendsburg", :area_code => "4332") + AreaCode.create(:country => germany, :name => "Erfde", :area_code => "4333") + AreaCode.create(:country => germany, :name => "Bredenbek b Rendsburg", :area_code => "4334") + AreaCode.create(:country => germany, :name => "Hohn b Rendsburg", :area_code => "4335") + AreaCode.create(:country => germany, :name => "Owschlag", :area_code => "4336") + AreaCode.create(:country => germany, :name => "Jevenstedt", :area_code => "4337") + AreaCode.create(:country => germany, :name => "Alt Duvenstedt", :area_code => "4338") + AreaCode.create(:country => germany, :name => "Christiansholm", :area_code => "4339") + AreaCode.create(:country => germany, :name => "Achterwehr", :area_code => "4340") + AreaCode.create(:country => germany, :name => "Preetz Kr Plön", :area_code => "4342") + AreaCode.create(:country => germany, :name => "Laboe", :area_code => "4343") + AreaCode.create(:country => germany, :name => "Schönberg Holstein", :area_code => "4344") + AreaCode.create(:country => germany, :name => "Gettorf", :area_code => "4346") + AreaCode.create(:country => germany, :name => "Flintbek", :area_code => "4347") + AreaCode.create(:country => germany, :name => "Schönkirchen", :area_code => "4348") + AreaCode.create(:country => germany, :name => "Dänischenhagen", :area_code => "4349") + AreaCode.create(:country => germany, :name => "Eckernförde", :area_code => "4351") + AreaCode.create(:country => germany, :name => "Damp", :area_code => "4352") + AreaCode.create(:country => germany, :name => "Ascheffel", :area_code => "4353") + AreaCode.create(:country => germany, :name => "Fleckeby", :area_code => "4354") + AreaCode.create(:country => germany, :name => "Rieseby", :area_code => "4355") + AreaCode.create(:country => germany, :name => "Gross Wittensee", :area_code => "4356") + AreaCode.create(:country => germany, :name => "Sehestedt Eider", :area_code => "4357") + AreaCode.create(:country => germany, :name => "Loose b Eckernförde", :area_code => "4358") + AreaCode.create(:country => germany, :name => "Oldenburg in Holstein", :area_code => "4361") + AreaCode.create(:country => germany, :name => "Heiligenhafen", :area_code => "4362") + AreaCode.create(:country => germany, :name => "Lensahn", :area_code => "4363") + AreaCode.create(:country => germany, :name => "Dahme Kr Ostholstein", :area_code => "4364") + AreaCode.create(:country => germany, :name => "Heringsdorf Holst", :area_code => "4365") + AreaCode.create(:country => germany, :name => "Grömitz-Cismar", :area_code => "4366") + AreaCode.create(:country => germany, :name => "Grossenbrode", :area_code => "4367") + AreaCode.create(:country => germany, :name => "Burg auf Fehmarn", :area_code => "4371") + AreaCode.create(:country => germany, :name => "Westfehmarn", :area_code => "4372") + AreaCode.create(:country => germany, :name => "Lütjenburg", :area_code => "4381") + AreaCode.create(:country => germany, :name => "Wangels", :area_code => "4382") + AreaCode.create(:country => germany, :name => "Grebin", :area_code => "4383") + AreaCode.create(:country => germany, :name => "Selent", :area_code => "4384") + AreaCode.create(:country => germany, :name => "Hohenfelde b Kiel", :area_code => "4385") + AreaCode.create(:country => germany, :name => "Nortorf b Neumünster", :area_code => "4392") + AreaCode.create(:country => germany, :name => "Boostedt", :area_code => "4393") + AreaCode.create(:country => germany, :name => "Bokhorst", :area_code => "4394") + AreaCode.create(:country => germany, :name => "Brake Unterweser", :area_code => "4401") + AreaCode.create(:country => germany, :name => "Rastede", :area_code => "4402") + AreaCode.create(:country => germany, :name => "Bad Zwischenahn", :area_code => "4403") + AreaCode.create(:country => germany, :name => "Elsfleth", :area_code => "4404") + AreaCode.create(:country => germany, :name => "Edewecht", :area_code => "4405") + AreaCode.create(:country => germany, :name => "Berne", :area_code => "4406") + AreaCode.create(:country => germany, :name => "Wardenburg", :area_code => "4407") + AreaCode.create(:country => germany, :name => "Hude Oldenburg", :area_code => "4408") + AreaCode.create(:country => germany, :name => "Westerstede-Ocholt", :area_code => "4409") + AreaCode.create(:country => germany, :name => "Oldenburg (Oldb)", :area_code => "441") + AreaCode.create(:country => germany, :name => "Wilhelmshaven", :area_code => "4421") + AreaCode.create(:country => germany, :name => "Sande Kr Friesl", :area_code => "4422") + AreaCode.create(:country => germany, :name => "Fedderwarden", :area_code => "4423") + AreaCode.create(:country => germany, :name => "Wangerland-Hooksiel", :area_code => "4425") + AreaCode.create(:country => germany, :name => "Wangerland-Horumersiel", :area_code => "4426") + AreaCode.create(:country => germany, :name => "Wildeshausen", :area_code => "4431") + AreaCode.create(:country => germany, :name => "Dötlingen-Brettorf", :area_code => "4432") + AreaCode.create(:country => germany, :name => "Dötlingen", :area_code => "4433") + AreaCode.create(:country => germany, :name => "Colnrade", :area_code => "4434") + AreaCode.create(:country => germany, :name => "Grossenkneten", :area_code => "4435") + AreaCode.create(:country => germany, :name => "Vechta", :area_code => "4441") + AreaCode.create(:country => germany, :name => "Lohne Oldenburg", :area_code => "4442") + AreaCode.create(:country => germany, :name => "Dinklage", :area_code => "4443") + AreaCode.create(:country => germany, :name => "Goldenstedt", :area_code => "4444") + AreaCode.create(:country => germany, :name => "Visbek Kr Vechta", :area_code => "4445") + AreaCode.create(:country => germany, :name => "Bakum Kr Vechta", :area_code => "4446") + AreaCode.create(:country => germany, :name => "Vechta-Langförden", :area_code => "4447") + AreaCode.create(:country => germany, :name => "Varel Jadebusen", :area_code => "4451") + AreaCode.create(:country => germany, :name => "Zetel-Neuenburg", :area_code => "4452") + AreaCode.create(:country => germany, :name => "Zetel", :area_code => "4453") + AreaCode.create(:country => germany, :name => "Jade", :area_code => "4454") + AreaCode.create(:country => germany, :name => "Jade-Schweiburg", :area_code => "4455") + AreaCode.create(:country => germany, :name => "Varel-Altjührden", :area_code => "4456") + AreaCode.create(:country => germany, :name => "Wiefelstede-Spohle", :area_code => "4458") + AreaCode.create(:country => germany, :name => "Jever", :area_code => "4461") + AreaCode.create(:country => germany, :name => "Wittmund", :area_code => "4462") + AreaCode.create(:country => germany, :name => "Wangerland", :area_code => "4463") + AreaCode.create(:country => germany, :name => "Wittmund-Carolinensiel", :area_code => "4464") + AreaCode.create(:country => germany, :name => "Friedeburg Ostfriesl", :area_code => "4465") + AreaCode.create(:country => germany, :name => "Wittmund-Ardorf", :area_code => "4466") + AreaCode.create(:country => germany, :name => "Wittmund-Funnix", :area_code => "4467") + AreaCode.create(:country => germany, :name => "Friedeburg-Reepsholt", :area_code => "4468") + AreaCode.create(:country => germany, :name => "Wangerooge", :area_code => "4469") + AreaCode.create(:country => germany, :name => "Cloppenburg", :area_code => "4471") + AreaCode.create(:country => germany, :name => "Lastrup", :area_code => "4472") + AreaCode.create(:country => germany, :name => "Emstek", :area_code => "4473") + AreaCode.create(:country => germany, :name => "Garrel", :area_code => "4474") + AreaCode.create(:country => germany, :name => "Molbergen", :area_code => "4475") + AreaCode.create(:country => germany, :name => "Lastrup-Hemmelte", :area_code => "4477") + AreaCode.create(:country => germany, :name => "Cappeln Oldenburg", :area_code => "4478") + AreaCode.create(:country => germany, :name => "Molbergen-Peheim", :area_code => "4479") + AreaCode.create(:country => germany, :name => "Ovelgönne-Strückhausen", :area_code => "4480") + AreaCode.create(:country => germany, :name => "Hatten-Sandkrug", :area_code => "4481") + AreaCode.create(:country => germany, :name => "Hatten", :area_code => "4482") + AreaCode.create(:country => germany, :name => "Ovelgönne-Großenmeer", :area_code => "4483") + AreaCode.create(:country => germany, :name => "Hude-Wüsting", :area_code => "4484") + AreaCode.create(:country => germany, :name => "Elsfleth-Huntorf", :area_code => "4485") + AreaCode.create(:country => germany, :name => "Edewecht-Friedrichsfehn", :area_code => "4486") + AreaCode.create(:country => germany, :name => "Grossenkneten-Huntlosen", :area_code => "4487") + AreaCode.create(:country => germany, :name => "Westerstede", :area_code => "4488") + AreaCode.create(:country => germany, :name => "Apen", :area_code => "4489") + AreaCode.create(:country => germany, :name => "Friesoythe", :area_code => "4491") + AreaCode.create(:country => germany, :name => "Saterland", :area_code => "4492") + AreaCode.create(:country => germany, :name => "Friesoythe-Gehlenberg", :area_code => "4493") + AreaCode.create(:country => germany, :name => "Bösel Oldenburg", :area_code => "4494") + AreaCode.create(:country => germany, :name => "Friesoythe-Thüle", :area_code => "4495") + AreaCode.create(:country => germany, :name => "Friesoythe-Markhausen", :area_code => "4496") + AreaCode.create(:country => germany, :name => "Barßel-Harkebrügge", :area_code => "4497") + AreaCode.create(:country => germany, :name => "Saterland-Ramsloh", :area_code => "4498") + AreaCode.create(:country => germany, :name => "Barssel", :area_code => "4499") + AreaCode.create(:country => germany, :name => "Kastorf Holst", :area_code => "4501") + AreaCode.create(:country => germany, :name => "Lübeck-Travemünde", :area_code => "4502") + AreaCode.create(:country => germany, :name => "Timmendorfer Strand", :area_code => "4503") + AreaCode.create(:country => germany, :name => "Ratekau", :area_code => "4504") + AreaCode.create(:country => germany, :name => "Stockelsdorf-Curau", :area_code => "4505") + AreaCode.create(:country => germany, :name => "Stockelsdorf-Krumbeck", :area_code => "4506") + AreaCode.create(:country => germany, :name => "Krummesse", :area_code => "4508") + AreaCode.create(:country => germany, :name => "Groß Grönau", :area_code => "4509") + AreaCode.create(:country => germany, :name => "Lübeck", :area_code => "451") + AreaCode.create(:country => germany, :name => "Eutin", :area_code => "4521") + AreaCode.create(:country => germany, :name => "Plön", :area_code => "4522") + AreaCode.create(:country => germany, :name => "Malente", :area_code => "4523") + AreaCode.create(:country => germany, :name => "Scharbeutz-Pönitz", :area_code => "4524") + AreaCode.create(:country => germany, :name => "Ahrensbök", :area_code => "4525") + AreaCode.create(:country => germany, :name => "Ascheberg Holstein", :area_code => "4526") + AreaCode.create(:country => germany, :name => "Bosau", :area_code => "4527") + AreaCode.create(:country => germany, :name => "Schönwalde am Bungsberg", :area_code => "4528") + AreaCode.create(:country => germany, :name => "Süsel-Bujendorf", :area_code => "4529") + AreaCode.create(:country => germany, :name => "Bad Oldesloe", :area_code => "4531") + AreaCode.create(:country => germany, :name => "Bargteheide", :area_code => "4532") + AreaCode.create(:country => germany, :name => "Reinfeld Holstein", :area_code => "4533") + AreaCode.create(:country => germany, :name => "Steinburg Kr Storman", :area_code => "4534") + AreaCode.create(:country => germany, :name => "Nahe", :area_code => "4535") + AreaCode.create(:country => germany, :name => "Steinhorst Lauenb", :area_code => "4536") + AreaCode.create(:country => germany, :name => "Sülfeld Holst", :area_code => "4537") + AreaCode.create(:country => germany, :name => "Westerau", :area_code => "4539") + AreaCode.create(:country => germany, :name => "Ratzeburg", :area_code => "4541") + AreaCode.create(:country => germany, :name => "Mölln Lauenb", :area_code => "4542") + AreaCode.create(:country => germany, :name => "Nusse", :area_code => "4543") + AreaCode.create(:country => germany, :name => "Berkenthin", :area_code => "4544") + AreaCode.create(:country => germany, :name => "Seedorf Lauenb", :area_code => "4545") + AreaCode.create(:country => germany, :name => "Mustin Lauenburg", :area_code => "4546") + AreaCode.create(:country => germany, :name => "Gudow Lauenb", :area_code => "4547") + AreaCode.create(:country => germany, :name => "Bühnsdorf", :area_code => "4550") + AreaCode.create(:country => germany, :name => "Bad Segeberg", :area_code => "4551") + AreaCode.create(:country => germany, :name => "Leezen", :area_code => "4552") + AreaCode.create(:country => germany, :name => "Geschendorf", :area_code => "4553") + AreaCode.create(:country => germany, :name => "Wahlstedt", :area_code => "4554") + AreaCode.create(:country => germany, :name => "Seedorf b Bad Segeberg", :area_code => "4555") + AreaCode.create(:country => germany, :name => "Ahrensbök-Gnissau", :area_code => "4556") + AreaCode.create(:country => germany, :name => "Blunk", :area_code => "4557") + AreaCode.create(:country => germany, :name => "Todesfelde", :area_code => "4558") + AreaCode.create(:country => germany, :name => "Wensin", :area_code => "4559") + AreaCode.create(:country => germany, :name => "Neustadt in Holstein", :area_code => "4561") + AreaCode.create(:country => germany, :name => "Grömitz", :area_code => "4562") + AreaCode.create(:country => germany, :name => "Scharbeutz-Haffkrug", :area_code => "4563") + AreaCode.create(:country => germany, :name => "Schashagen", :area_code => "4564") + AreaCode.create(:country => germany, :name => "Freienwill", :area_code => "4602") + AreaCode.create(:country => germany, :name => "Havetoft", :area_code => "4603") + AreaCode.create(:country => germany, :name => "Grossenwiehe", :area_code => "4604") + AreaCode.create(:country => germany, :name => "Medelby", :area_code => "4605") + AreaCode.create(:country => germany, :name => "Wanderup", :area_code => "4606") + AreaCode.create(:country => germany, :name => "Janneby", :area_code => "4607") + AreaCode.create(:country => germany, :name => "Handewitt", :area_code => "4608") + AreaCode.create(:country => germany, :name => "Eggebek", :area_code => "4609") + AreaCode.create(:country => germany, :name => "Flensburg", :area_code => "461") + AreaCode.create(:country => germany, :name => "Schleswig", :area_code => "4621") + AreaCode.create(:country => germany, :name => "Taarstedt", :area_code => "4622") + AreaCode.create(:country => germany, :name => "Böklund", :area_code => "4623") + AreaCode.create(:country => germany, :name => "Kropp", :area_code => "4624") + AreaCode.create(:country => germany, :name => "Jübek", :area_code => "4625") + AreaCode.create(:country => germany, :name => "Treia", :area_code => "4626") + AreaCode.create(:country => germany, :name => "Dörpstedt", :area_code => "4627") + AreaCode.create(:country => germany, :name => "Barderup", :area_code => "4630") + AreaCode.create(:country => germany, :name => "Glücksburg Ostsee", :area_code => "4631") + AreaCode.create(:country => germany, :name => "Steinbergkirche", :area_code => "4632") + AreaCode.create(:country => germany, :name => "Satrup", :area_code => "4633") + AreaCode.create(:country => germany, :name => "Husby", :area_code => "4634") + AreaCode.create(:country => germany, :name => "Sörup", :area_code => "4635") + AreaCode.create(:country => germany, :name => "Langballig", :area_code => "4636") + AreaCode.create(:country => germany, :name => "Sterup", :area_code => "4637") + AreaCode.create(:country => germany, :name => "Tarp", :area_code => "4638") + AreaCode.create(:country => germany, :name => "Schafflund", :area_code => "4639") + AreaCode.create(:country => germany, :name => "Süderbrarup", :area_code => "4641") + AreaCode.create(:country => germany, :name => "Kappeln Schlei", :area_code => "4642") + AreaCode.create(:country => germany, :name => "Gelting Angeln", :area_code => "4643") + AreaCode.create(:country => germany, :name => "Karby", :area_code => "4644") + AreaCode.create(:country => germany, :name => "Mohrkirch", :area_code => "4646") + AreaCode.create(:country => germany, :name => "Sylt", :area_code => "4651") + AreaCode.create(:country => germany, :name => "Niebüll", :area_code => "4661") + AreaCode.create(:country => germany, :name => "Leck", :area_code => "4662") + AreaCode.create(:country => germany, :name => "Süderlügum", :area_code => "4663") + AreaCode.create(:country => germany, :name => "Neukirchen b Niebüll", :area_code => "4664") + AreaCode.create(:country => germany, :name => "Emmelsbüll-Horsbüll", :area_code => "4665") + AreaCode.create(:country => germany, :name => "Ladelund", :area_code => "4666") + AreaCode.create(:country => germany, :name => "Dagebüll", :area_code => "4667") + AreaCode.create(:country => germany, :name => "Klanxbüll", :area_code => "4668") + AreaCode.create(:country => germany, :name => "Bredstedt", :area_code => "4671") + AreaCode.create(:country => germany, :name => "Langenhorn", :area_code => "4672") + AreaCode.create(:country => germany, :name => "Joldelund", :area_code => "4673") + AreaCode.create(:country => germany, :name => "Ockholm", :area_code => "4674") + AreaCode.create(:country => germany, :name => "Wyk auf Föhr", :area_code => "4681") + AreaCode.create(:country => germany, :name => "Amrum", :area_code => "4682") + AreaCode.create(:country => germany, :name => "Oldsum", :area_code => "4683") + AreaCode.create(:country => germany, :name => "Langeneß Hallig", :area_code => "4684") + AreaCode.create(:country => germany, :name => "Sandstedt", :area_code => "4702") + AreaCode.create(:country => germany, :name => "Loxstedt-Donnern", :area_code => "4703") + AreaCode.create(:country => germany, :name => "Drangstedt", :area_code => "4704") + AreaCode.create(:country => germany, :name => "Wremen", :area_code => "4705") + AreaCode.create(:country => germany, :name => "Schiffdorf", :area_code => "4706") + AreaCode.create(:country => germany, :name => "Langen-Neuenwalde", :area_code => "4707") + AreaCode.create(:country => germany, :name => "Ringstedt", :area_code => "4708") + AreaCode.create(:country => germany, :name => "Bremerhaven", :area_code => "471") + AreaCode.create(:country => germany, :name => "Cuxhaven", :area_code => "4721") + AreaCode.create(:country => germany, :name => "Cuxhaven-Altenbruch", :area_code => "4722") + AreaCode.create(:country => germany, :name => "Cuxhaven-Altenwalde", :area_code => "4723") + AreaCode.create(:country => germany, :name => "Cuxhaven-Lüdingworth", :area_code => "4724") + AreaCode.create(:country => germany, :name => "Helgoland", :area_code => "4725") + AreaCode.create(:country => germany, :name => "Nordenham", :area_code => "4731") + AreaCode.create(:country => germany, :name => "Stadland-Rodenkirchen", :area_code => "4732") + AreaCode.create(:country => germany, :name => "Butjadingen-Burhave", :area_code => "4733") + AreaCode.create(:country => germany, :name => "Stadland-Seefeld", :area_code => "4734") + AreaCode.create(:country => germany, :name => "Butjadingen-Stollhamm", :area_code => "4735") + AreaCode.create(:country => germany, :name => "Butjadingen-Tossens", :area_code => "4736") + AreaCode.create(:country => germany, :name => "Stadland-Schwei", :area_code => "4737") + AreaCode.create(:country => germany, :name => "Loxstedt-Dedesdorf", :area_code => "4740") + AreaCode.create(:country => germany, :name => "Nordholz b Bremerhaven", :area_code => "4741") + AreaCode.create(:country => germany, :name => "Dorum", :area_code => "4742") + AreaCode.create(:country => germany, :name => "Langen b Bremerhaven", :area_code => "4743") + AreaCode.create(:country => germany, :name => "Loxstedt", :area_code => "4744") + AreaCode.create(:country => germany, :name => "Bad Bederkesa", :area_code => "4745") + AreaCode.create(:country => germany, :name => "Hagen b Bremerhaven", :area_code => "4746") + AreaCode.create(:country => germany, :name => "Beverstedt", :area_code => "4747") + AreaCode.create(:country => germany, :name => "Stubben b Bremerhaven", :area_code => "4748") + AreaCode.create(:country => germany, :name => "Schiffdorf-Geestenseth", :area_code => "4749") + AreaCode.create(:country => germany, :name => "Otterndorf", :area_code => "4751") + AreaCode.create(:country => germany, :name => "Neuhaus Oste", :area_code => "4752") + AreaCode.create(:country => germany, :name => "Balje", :area_code => "4753") + AreaCode.create(:country => germany, :name => "Bülkau", :area_code => "4754") + AreaCode.create(:country => germany, :name => "Ihlienworth", :area_code => "4755") + AreaCode.create(:country => germany, :name => "Odisheim", :area_code => "4756") + AreaCode.create(:country => germany, :name => "Wanna", :area_code => "4757") + AreaCode.create(:country => germany, :name => "Nordleda", :area_code => "4758") + AreaCode.create(:country => germany, :name => "Bremervörde", :area_code => "4761") + AreaCode.create(:country => germany, :name => "Kutenholz", :area_code => "4762") + AreaCode.create(:country => germany, :name => "Gnarrenburg", :area_code => "4763") + AreaCode.create(:country => germany, :name => "Gnarrenburg-Klenkendorf", :area_code => "4764") + AreaCode.create(:country => germany, :name => "Ebersdorf b Bremervörde", :area_code => "4765") + AreaCode.create(:country => germany, :name => "Basdahl", :area_code => "4766") + AreaCode.create(:country => germany, :name => "Bremervörde-Bevern", :area_code => "4767") + AreaCode.create(:country => germany, :name => "Hipstedt", :area_code => "4768") + AreaCode.create(:country => germany, :name => "Bremervörde-Iselersheim", :area_code => "4769") + AreaCode.create(:country => germany, :name => "Wischhafen", :area_code => "4770") + AreaCode.create(:country => germany, :name => "Hemmoor", :area_code => "4771") + AreaCode.create(:country => germany, :name => "Oberndorf Oste", :area_code => "4772") + AreaCode.create(:country => germany, :name => "Lamstedt", :area_code => "4773") + AreaCode.create(:country => germany, :name => "Hechthausen", :area_code => "4774") + AreaCode.create(:country => germany, :name => "Grossenwörden", :area_code => "4775") + AreaCode.create(:country => germany, :name => "Osten-Altendorf", :area_code => "4776") + AreaCode.create(:country => germany, :name => "Cadenberge", :area_code => "4777") + AreaCode.create(:country => germany, :name => "Wingst", :area_code => "4778") + AreaCode.create(:country => germany, :name => "Freiburg Elbe", :area_code => "4779") + AreaCode.create(:country => germany, :name => "Osterholz-Scharmbeck", :area_code => "4791") + AreaCode.create(:country => germany, :name => "Worpswede", :area_code => "4792") + AreaCode.create(:country => germany, :name => "Hambergen", :area_code => "4793") + AreaCode.create(:country => germany, :name => "Worpswede-Ostersode", :area_code => "4794") + AreaCode.create(:country => germany, :name => "Garlstedt", :area_code => "4795") + AreaCode.create(:country => germany, :name => "Teufelsmoor", :area_code => "4796") + AreaCode.create(:country => germany, :name => "Wrohm", :area_code => "4802") + AreaCode.create(:country => germany, :name => "Pahlen", :area_code => "4803") + AreaCode.create(:country => germany, :name => "Nordhastedt", :area_code => "4804") + AreaCode.create(:country => germany, :name => "Schafstedt", :area_code => "4805") + AreaCode.create(:country => germany, :name => "Sarzbüttel", :area_code => "4806") + AreaCode.create(:country => germany, :name => "Heide Holst", :area_code => "481") + AreaCode.create(:country => germany, :name => "Itzehoe", :area_code => "4821") + AreaCode.create(:country => germany, :name => "Kellinghusen", :area_code => "4822") + AreaCode.create(:country => germany, :name => "Wilster", :area_code => "4823") + AreaCode.create(:country => germany, :name => "Krempe", :area_code => "4824") + AreaCode.create(:country => germany, :name => "Burg Dithmarschen", :area_code => "4825") + AreaCode.create(:country => germany, :name => "Hohenlockstedt", :area_code => "4826") + AreaCode.create(:country => germany, :name => "Wacken", :area_code => "4827") + AreaCode.create(:country => germany, :name => "Lägerdorf", :area_code => "4828") + AreaCode.create(:country => germany, :name => "Wewelsfleth", :area_code => "4829") + AreaCode.create(:country => germany, :name => "Süderhastedt", :area_code => "4830") + AreaCode.create(:country => germany, :name => "Meldorf", :area_code => "4832") + AreaCode.create(:country => germany, :name => "Wesselburen", :area_code => "4833") + AreaCode.create(:country => germany, :name => "Büsum", :area_code => "4834") + AreaCode.create(:country => germany, :name => "Albersdorf Holst", :area_code => "4835") + AreaCode.create(:country => germany, :name => "Hennstedt Dithm", :area_code => "4836") + AreaCode.create(:country => germany, :name => "Neuenkirchen Dithm", :area_code => "4837") + AreaCode.create(:country => germany, :name => "Tellingstedt", :area_code => "4838") + AreaCode.create(:country => germany, :name => "Wöhrden Dithm", :area_code => "4839") + AreaCode.create(:country => germany, :name => "Husum Nordsee", :area_code => "4841") + AreaCode.create(:country => germany, :name => "Nordstrand", :area_code => "4842") + AreaCode.create(:country => germany, :name => "Viöl", :area_code => "4843") + AreaCode.create(:country => germany, :name => "Pellworm", :area_code => "4844") + AreaCode.create(:country => germany, :name => "Ostenfeld Husum", :area_code => "4845") + AreaCode.create(:country => germany, :name => "Hattstedt", :area_code => "4846") + AreaCode.create(:country => germany, :name => "Oster-Ohrstedt", :area_code => "4847") + AreaCode.create(:country => germany, :name => "Rantrum", :area_code => "4848") + AreaCode.create(:country => germany, :name => "Hooge", :area_code => "4849") + AreaCode.create(:country => germany, :name => "Marne", :area_code => "4851") + AreaCode.create(:country => germany, :name => "Brunsbüttel", :area_code => "4852") + AreaCode.create(:country => germany, :name => "Sankt Michaelisdonn", :area_code => "4853") + AreaCode.create(:country => germany, :name => "Friedrichskoog", :area_code => "4854") + AreaCode.create(:country => germany, :name => "Eddelak", :area_code => "4855") + AreaCode.create(:country => germany, :name => "Kronprinzenkoog", :area_code => "4856") + AreaCode.create(:country => germany, :name => "Barlt", :area_code => "4857") + AreaCode.create(:country => germany, :name => "Sankt Margarethen Holst", :area_code => "4858") + AreaCode.create(:country => germany, :name => "Windbergen", :area_code => "4859") + AreaCode.create(:country => germany, :name => "Tönning", :area_code => "4861") + AreaCode.create(:country => germany, :name => "Garding", :area_code => "4862") + AreaCode.create(:country => germany, :name => "Sankt Peter-Ording", :area_code => "4863") + AreaCode.create(:country => germany, :name => "Oldenswort", :area_code => "4864") + AreaCode.create(:country => germany, :name => "Osterhever", :area_code => "4865") + AreaCode.create(:country => germany, :name => "Hohenwestedt", :area_code => "4871") + AreaCode.create(:country => germany, :name => "Hanerau-Hademarschen", :area_code => "4872") + AreaCode.create(:country => germany, :name => "Aukrug", :area_code => "4873") + AreaCode.create(:country => germany, :name => "Todenbüttel", :area_code => "4874") + AreaCode.create(:country => germany, :name => "Stafstedt", :area_code => "4875") + AreaCode.create(:country => germany, :name => "Reher Holst", :area_code => "4876") + AreaCode.create(:country => germany, :name => "Hennstedt b Itzehoe", :area_code => "4877") + AreaCode.create(:country => germany, :name => "Friedrichstadt", :area_code => "4881") + AreaCode.create(:country => germany, :name => "Lunden", :area_code => "4882") + AreaCode.create(:country => germany, :name => "Süderstapel", :area_code => "4883") + AreaCode.create(:country => germany, :name => "Schwabstedt", :area_code => "4884") + AreaCode.create(:country => germany, :name => "Bergenhusen", :area_code => "4885") + AreaCode.create(:country => germany, :name => "Schenefeld Mittelholst", :area_code => "4892") + AreaCode.create(:country => germany, :name => "Hohenaspe", :area_code => "4893") + AreaCode.create(:country => germany, :name => "Jemgum-Ditzum", :area_code => "4902") + AreaCode.create(:country => germany, :name => "Wymeer", :area_code => "4903") + AreaCode.create(:country => germany, :name => "Leer Ostfriesland", :area_code => "491") + AreaCode.create(:country => germany, :name => "Wirdum", :area_code => "4920") + AreaCode.create(:country => germany, :name => "Emden Stadt", :area_code => "4921") + AreaCode.create(:country => germany, :name => "Borkum", :area_code => "4922") + AreaCode.create(:country => germany, :name => "Krummhörn-Pewsum", :area_code => "4923") + AreaCode.create(:country => germany, :name => "Moormerland-Oldersum", :area_code => "4924") + AreaCode.create(:country => germany, :name => "Hinte", :area_code => "4925") + AreaCode.create(:country => germany, :name => "Krummhörn-Greetsiel", :area_code => "4926") + AreaCode.create(:country => germany, :name => "Krummhörn-Loquard", :area_code => "4927") + AreaCode.create(:country => germany, :name => "Ihlow-Riepe", :area_code => "4928") + AreaCode.create(:country => germany, :name => "Ihlow Kr Aurich", :area_code => "4929") + AreaCode.create(:country => germany, :name => "Norden", :area_code => "4931") + AreaCode.create(:country => germany, :name => "Norderney", :area_code => "4932") + AreaCode.create(:country => germany, :name => "Dornum Ostfriesl", :area_code => "4933") + AreaCode.create(:country => germany, :name => "Marienhafe", :area_code => "4934") + AreaCode.create(:country => germany, :name => "Juist", :area_code => "4935") + AreaCode.create(:country => germany, :name => "Grossheide", :area_code => "4936") + AreaCode.create(:country => germany, :name => "Hagermarsch", :area_code => "4938") + AreaCode.create(:country => germany, :name => "Baltrum", :area_code => "4939") + AreaCode.create(:country => germany, :name => "Aurich", :area_code => "4941") + AreaCode.create(:country => germany, :name => "Südbrookmerland", :area_code => "4942") + AreaCode.create(:country => germany, :name => "Grossefehn", :area_code => "4943") + AreaCode.create(:country => germany, :name => "Wiesmoor", :area_code => "4944") + AreaCode.create(:country => germany, :name => "Grossefehn-Timmel", :area_code => "4945") + AreaCode.create(:country => germany, :name => "Grossefehn-Bagband", :area_code => "4946") + AreaCode.create(:country => germany, :name => "Aurich-Ogenbargen", :area_code => "4947") + AreaCode.create(:country => germany, :name => "Wiesmoor-Marcardsmoor", :area_code => "4948") + AreaCode.create(:country => germany, :name => "Holtland", :area_code => "4950") + AreaCode.create(:country => germany, :name => "Weener", :area_code => "4951") + AreaCode.create(:country => germany, :name => "Rhauderfehn", :area_code => "4952") + AreaCode.create(:country => germany, :name => "Bunde", :area_code => "4953") + AreaCode.create(:country => germany, :name => "Moormerland", :area_code => "4954") + AreaCode.create(:country => germany, :name => "Westoverledingen", :area_code => "4955") + AreaCode.create(:country => germany, :name => "Uplengen", :area_code => "4956") + AreaCode.create(:country => germany, :name => "Detern", :area_code => "4957") + AreaCode.create(:country => germany, :name => "Jemgum", :area_code => "4958") + AreaCode.create(:country => germany, :name => "Dollart", :area_code => "4959") + AreaCode.create(:country => germany, :name => "Papenburg", :area_code => "4961") + AreaCode.create(:country => germany, :name => "Papenburg-Aschendorf", :area_code => "4962") + AreaCode.create(:country => germany, :name => "Dörpen", :area_code => "4963") + AreaCode.create(:country => germany, :name => "Rhede Ems", :area_code => "4964") + AreaCode.create(:country => germany, :name => "Surwold", :area_code => "4965") + AreaCode.create(:country => germany, :name => "Neubörger", :area_code => "4966") + AreaCode.create(:country => germany, :name => "Rhauderfehn-Burlage", :area_code => "4967") + AreaCode.create(:country => germany, :name => "Neulehe", :area_code => "4968") + AreaCode.create(:country => germany, :name => "Esens", :area_code => "4971") + AreaCode.create(:country => germany, :name => "Langeoog", :area_code => "4972") + AreaCode.create(:country => germany, :name => "Wittmund-Burhafe", :area_code => "4973") + AreaCode.create(:country => germany, :name => "Neuharlingersiel", :area_code => "4974") + AreaCode.create(:country => germany, :name => "Westerholt Ostfriesl", :area_code => "4975") + AreaCode.create(:country => germany, :name => "Spiekeroog", :area_code => "4976") + AreaCode.create(:country => germany, :name => "Blomberg Ostfriesl", :area_code => "4977") + AreaCode.create(:country => germany, :name => "Nienburg Weser", :area_code => "5021") + AreaCode.create(:country => germany, :name => "Wietzen", :area_code => "5022") + AreaCode.create(:country => germany, :name => "Liebenau Kr Nienburg Weser", :area_code => "5023") + AreaCode.create(:country => germany, :name => "Rohrsen Kr Nienburg Weser", :area_code => "5024") + AreaCode.create(:country => germany, :name => "Estorf Weser", :area_code => "5025") + AreaCode.create(:country => germany, :name => "Steimbke", :area_code => "5026") + AreaCode.create(:country => germany, :name => "Linsburg", :area_code => "5027") + AreaCode.create(:country => germany, :name => "Pennigsehl", :area_code => "5028") + AreaCode.create(:country => germany, :name => "Wunstorf", :area_code => "5031") + AreaCode.create(:country => germany, :name => "Neustadt am Rübenberge", :area_code => "5032") + AreaCode.create(:country => germany, :name => "Wunstorf-Grossenheidorn", :area_code => "5033") + AreaCode.create(:country => germany, :name => "Neustadt-Hagen", :area_code => "5034") + AreaCode.create(:country => germany, :name => "Gross Munzel", :area_code => "5035") + AreaCode.create(:country => germany, :name => "Neustadt-Schneeren", :area_code => "5036") + AreaCode.create(:country => germany, :name => "Bad Rehburg", :area_code => "5037") + AreaCode.create(:country => germany, :name => "Springe Deister", :area_code => "5041") + AreaCode.create(:country => germany, :name => "Bad Münder am Deister", :area_code => "5042") + AreaCode.create(:country => germany, :name => "Lauenau", :area_code => "5043") + AreaCode.create(:country => germany, :name => "Springe-Eldagsen", :area_code => "5044") + AreaCode.create(:country => germany, :name => "Springe-Bennigsen", :area_code => "5045") + AreaCode.create(:country => germany, :name => "Bergen Kr Celle", :area_code => "5051") + AreaCode.create(:country => germany, :name => "Hermannsburg", :area_code => "5052") + AreaCode.create(:country => germany, :name => "Faßberg-Müden", :area_code => "5053") + AreaCode.create(:country => germany, :name => "Bergen-Sülze", :area_code => "5054") + AreaCode.create(:country => germany, :name => "Fassberg", :area_code => "5055") + AreaCode.create(:country => germany, :name => "Winsen-Meissendorf", :area_code => "5056") + AreaCode.create(:country => germany, :name => "Bodenburg", :area_code => "5060") + AreaCode.create(:country => germany, :name => "Holle b Hildesheim", :area_code => "5062") + AreaCode.create(:country => germany, :name => "Bad Salzdetfurth", :area_code => "5063") + AreaCode.create(:country => germany, :name => "Groß Düngen", :area_code => "5064") + AreaCode.create(:country => germany, :name => "Sibbesse", :area_code => "5065") + AreaCode.create(:country => germany, :name => "Sarstedt", :area_code => "5066") + AreaCode.create(:country => germany, :name => "Bockenem", :area_code => "5067") + AreaCode.create(:country => germany, :name => "Elze Leine", :area_code => "5068") + AreaCode.create(:country => germany, :name => "Nordstemmen", :area_code => "5069") + AreaCode.create(:country => germany, :name => "Schwarmstedt", :area_code => "5071") + AreaCode.create(:country => germany, :name => "Neustadt-Mandelsloh", :area_code => "5072") + AreaCode.create(:country => germany, :name => "Neustadt-Esperke", :area_code => "5073") + AreaCode.create(:country => germany, :name => "Rodewald", :area_code => "5074") + AreaCode.create(:country => germany, :name => "Langlingen", :area_code => "5082") + AreaCode.create(:country => germany, :name => "Hohne b Celle", :area_code => "5083") + AreaCode.create(:country => germany, :name => "Hambühren", :area_code => "5084") + AreaCode.create(:country => germany, :name => "Burgdorf-Ehlershausen", :area_code => "5085") + AreaCode.create(:country => germany, :name => "Celle-Scheuen", :area_code => "5086") + AreaCode.create(:country => germany, :name => "Pattensen", :area_code => "5101") + AreaCode.create(:country => germany, :name => "Laatzen", :area_code => "5102") + AreaCode.create(:country => germany, :name => "Wennigsen Deister", :area_code => "5103") + AreaCode.create(:country => germany, :name => "Barsinghausen", :area_code => "5105") + AreaCode.create(:country => germany, :name => "Gehrden Han", :area_code => "5108") + AreaCode.create(:country => germany, :name => "Ronnenberg", :area_code => "5109") + AreaCode.create(:country => germany, :name => "Hannover", :area_code => "511") + AreaCode.create(:country => germany, :name => "Hildesheim", :area_code => "5121") + AreaCode.create(:country => germany, :name => "Schellerten", :area_code => "5123") + AreaCode.create(:country => germany, :name => "Algermissen", :area_code => "5126") + AreaCode.create(:country => germany, :name => "Harsum", :area_code => "5127") + AreaCode.create(:country => germany, :name => "Hohenhameln", :area_code => "5128") + AreaCode.create(:country => germany, :name => "Söhlde", :area_code => "5129") + AreaCode.create(:country => germany, :name => "Wedemark", :area_code => "5130") + AreaCode.create(:country => germany, :name => "Garbsen", :area_code => "5131") + AreaCode.create(:country => germany, :name => "Lehrte", :area_code => "5132") + AreaCode.create(:country => germany, :name => "Burgwedel-Fuhrberg", :area_code => "5135") + AreaCode.create(:country => germany, :name => "Burgdorf Kr Hannover", :area_code => "5136") + AreaCode.create(:country => germany, :name => "Seelze", :area_code => "5137") + AreaCode.create(:country => germany, :name => "Sehnde", :area_code => "5138") + AreaCode.create(:country => germany, :name => "Burgwedel", :area_code => "5139") + AreaCode.create(:country => germany, :name => "Celle", :area_code => "5141") + AreaCode.create(:country => germany, :name => "Eschede", :area_code => "5142") + AreaCode.create(:country => germany, :name => "Winsen Aller", :area_code => "5143") + AreaCode.create(:country => germany, :name => "Wathlingen", :area_code => "5144") + AreaCode.create(:country => germany, :name => "Beedenbostel", :area_code => "5145") + AreaCode.create(:country => germany, :name => "Wietze", :area_code => "5146") + AreaCode.create(:country => germany, :name => "Uetze-Hänigsen", :area_code => "5147") + AreaCode.create(:country => germany, :name => "Steinhorst Niedersachs", :area_code => "5148") + AreaCode.create(:country => germany, :name => "Wienhausen", :area_code => "5149") + AreaCode.create(:country => germany, :name => "Hameln", :area_code => "5151") + AreaCode.create(:country => germany, :name => "Hessisch Oldendorf", :area_code => "5152") + AreaCode.create(:country => germany, :name => "Salzhemmendorf", :area_code => "5153") + AreaCode.create(:country => germany, :name => "Aerzen", :area_code => "5154") + AreaCode.create(:country => germany, :name => "Emmerthal", :area_code => "5155") + AreaCode.create(:country => germany, :name => "Coppenbrügge", :area_code => "5156") + AreaCode.create(:country => germany, :name => "Emmerthal-Börry", :area_code => "5157") + AreaCode.create(:country => germany, :name => "Hemeringen", :area_code => "5158") + AreaCode.create(:country => germany, :name => "Coppenbrügge-Bisperode", :area_code => "5159") + AreaCode.create(:country => germany, :name => "Walsrode", :area_code => "5161") + AreaCode.create(:country => germany, :name => "Fallingbostel", :area_code => "5162") + AreaCode.create(:country => germany, :name => "Fallingbostel-Dorfmark", :area_code => "5163") + AreaCode.create(:country => germany, :name => "Hodenhagen", :area_code => "5164") + AreaCode.create(:country => germany, :name => "Rethem Aller", :area_code => "5165") + AreaCode.create(:country => germany, :name => "Walsrode-Kirchboitzen", :area_code => "5166") + AreaCode.create(:country => germany, :name => "Walsrode-Westenholz", :area_code => "5167") + AreaCode.create(:country => germany, :name => "Walsrode-Stellichte", :area_code => "5168") + AreaCode.create(:country => germany, :name => "Peine", :area_code => "5171") + AreaCode.create(:country => germany, :name => "Ilsede", :area_code => "5172") + AreaCode.create(:country => germany, :name => "Uetze", :area_code => "5173") + AreaCode.create(:country => germany, :name => "Lahstedt", :area_code => "5174") + AreaCode.create(:country => germany, :name => "Lehrte-Arpke", :area_code => "5175") + AreaCode.create(:country => germany, :name => "Edemissen", :area_code => "5176") + AreaCode.create(:country => germany, :name => "Edemissen-Abbensen", :area_code => "5177") + AreaCode.create(:country => germany, :name => "Alfeld Leine", :area_code => "5181") + AreaCode.create(:country => germany, :name => "Gronau Leine", :area_code => "5182") + AreaCode.create(:country => germany, :name => "Lamspringe", :area_code => "5183") + AreaCode.create(:country => germany, :name => "Freden Leine", :area_code => "5184") + AreaCode.create(:country => germany, :name => "Duingen", :area_code => "5185") + AreaCode.create(:country => germany, :name => "Salzhemmendorf-Wallensen", :area_code => "5186") + AreaCode.create(:country => germany, :name => "Delligsen", :area_code => "5187") + AreaCode.create(:country => germany, :name => "Soltau-Emmingen", :area_code => "5190") + AreaCode.create(:country => germany, :name => "Soltau", :area_code => "5191") + AreaCode.create(:country => germany, :name => "Munster", :area_code => "5192") + AreaCode.create(:country => germany, :name => "Schneverdingen", :area_code => "5193") + AreaCode.create(:country => germany, :name => "Bispingen", :area_code => "5194") + AreaCode.create(:country => germany, :name => "Neuenkirchen b Soltau", :area_code => "5195") + AreaCode.create(:country => germany, :name => "Wietzendorf", :area_code => "5196") + AreaCode.create(:country => germany, :name => "Soltau-Frielingen", :area_code => "5197") + AreaCode.create(:country => germany, :name => "Schneverdingen-Wintermoor", :area_code => "5198") + AreaCode.create(:country => germany, :name => "Schneverdingen-Heber", :area_code => "5199") + AreaCode.create(:country => germany, :name => "Halle Westf", :area_code => "5201") + AreaCode.create(:country => germany, :name => "Oerlinghausen", :area_code => "5202") + AreaCode.create(:country => germany, :name => "Werther Westf", :area_code => "5203") + AreaCode.create(:country => germany, :name => "Steinhagen Westf", :area_code => "5204") + AreaCode.create(:country => germany, :name => "Bielefeld-Sennestadt", :area_code => "5205") + AreaCode.create(:country => germany, :name => "Bielefeld-Jöllenbeck", :area_code => "5206") + AreaCode.create(:country => germany, :name => "Schloss Holte-Stukenbrock", :area_code => "5207") + AreaCode.create(:country => germany, :name => "Leopoldshöhe", :area_code => "5208") + AreaCode.create(:country => germany, :name => "Gütersloh-Friedrichsdorf", :area_code => "5209") + AreaCode.create(:country => germany, :name => "Bielefeld", :area_code => "521") + AreaCode.create(:country => germany, :name => "Herford", :area_code => "5221") + AreaCode.create(:country => germany, :name => "Bad Salzuflen", :area_code => "5222") + AreaCode.create(:country => germany, :name => "Bünde", :area_code => "5223") + AreaCode.create(:country => germany, :name => "Enger Westf", :area_code => "5224") + AreaCode.create(:country => germany, :name => "Spenge", :area_code => "5225") + AreaCode.create(:country => germany, :name => "Bruchmühlen Westf", :area_code => "5226") + AreaCode.create(:country => germany, :name => "Vlotho-Exter", :area_code => "5228") + AreaCode.create(:country => germany, :name => "Detmold", :area_code => "5231") + AreaCode.create(:country => germany, :name => "Lage Lippe", :area_code => "5232") + AreaCode.create(:country => germany, :name => "Steinheim Westf", :area_code => "5233") + AreaCode.create(:country => germany, :name => "Horn-Bad Meinberg", :area_code => "5234") + AreaCode.create(:country => germany, :name => "Blomberg Lippe", :area_code => "5235") + AreaCode.create(:country => germany, :name => "Blomberg-Grossenmarpe", :area_code => "5236") + AreaCode.create(:country => germany, :name => "Augustdorf", :area_code => "5237") + AreaCode.create(:country => germany, :name => "Nieheim-Himmighausen", :area_code => "5238") + AreaCode.create(:country => germany, :name => "Gütersloh", :area_code => "5241") + AreaCode.create(:country => germany, :name => "Rheda-Wiedenbrück", :area_code => "5242") + AreaCode.create(:country => germany, :name => "Rietberg", :area_code => "5244") + AreaCode.create(:country => germany, :name => "Herzebrock-Clarholz", :area_code => "5245") + AreaCode.create(:country => germany, :name => "Verl", :area_code => "5246") + AreaCode.create(:country => germany, :name => "Harsewinkel", :area_code => "5247") + AreaCode.create(:country => germany, :name => "Langenberg Kr Gütersloh", :area_code => "5248") + AreaCode.create(:country => germany, :name => "Delbrück Westf", :area_code => "5250") + AreaCode.create(:country => germany, :name => "Paderborn", :area_code => "5251") + AreaCode.create(:country => germany, :name => "Bad Lippspringe", :area_code => "5252") + AreaCode.create(:country => germany, :name => "Bad Driburg", :area_code => "5253") + AreaCode.create(:country => germany, :name => "Paderborn-Schloss Neuhaus", :area_code => "5254") + AreaCode.create(:country => germany, :name => "Altenbeken", :area_code => "5255") + AreaCode.create(:country => germany, :name => "Hövelhof", :area_code => "5257") + AreaCode.create(:country => germany, :name => "Salzkotten", :area_code => "5258") + AreaCode.create(:country => germany, :name => "Bad Driburg-Neuenheerse", :area_code => "5259") + AreaCode.create(:country => germany, :name => "Lemgo", :area_code => "5261") + AreaCode.create(:country => germany, :name => "Extertal", :area_code => "5262") + AreaCode.create(:country => germany, :name => "Barntrup", :area_code => "5263") + AreaCode.create(:country => germany, :name => "Kalletal", :area_code => "5264") + AreaCode.create(:country => germany, :name => "Dörentrup", :area_code => "5265") + AreaCode.create(:country => germany, :name => "Lemgo-Kirchheide", :area_code => "5266") + AreaCode.create(:country => germany, :name => "Höxter", :area_code => "5271") + AreaCode.create(:country => germany, :name => "Brakel Westf", :area_code => "5272") + AreaCode.create(:country => germany, :name => "Beverungen", :area_code => "5273") + AreaCode.create(:country => germany, :name => "Nieheim", :area_code => "5274") + AreaCode.create(:country => germany, :name => "Höxter-Ottbergen", :area_code => "5275") + AreaCode.create(:country => germany, :name => "Marienmünster", :area_code => "5276") + AreaCode.create(:country => germany, :name => "Höxter-Fürstenau", :area_code => "5277") + AreaCode.create(:country => germany, :name => "Höxter-Ovenhausen", :area_code => "5278") + AreaCode.create(:country => germany, :name => "Bad Pyrmont", :area_code => "5281") + AreaCode.create(:country => germany, :name => "Schieder-Schwalenberg", :area_code => "5282") + AreaCode.create(:country => germany, :name => "Lügde-Rischenau", :area_code => "5283") + AreaCode.create(:country => germany, :name => "Schwalenberg", :area_code => "5284") + AreaCode.create(:country => germany, :name => "Bad Pyrmont-Kleinenberg", :area_code => "5285") + AreaCode.create(:country => germany, :name => "Ottenstein Niedersachs", :area_code => "5286") + AreaCode.create(:country => germany, :name => "Lichtenau-Atteln", :area_code => "5292") + AreaCode.create(:country => germany, :name => "Paderborn-Dahl", :area_code => "5293") + AreaCode.create(:country => germany, :name => "Hövelhof-Espeln", :area_code => "5294") + AreaCode.create(:country => germany, :name => "Lichtenau Westf", :area_code => "5295") + AreaCode.create(:country => germany, :name => "Salzgitter-Üfingen", :area_code => "5300") + AreaCode.create(:country => germany, :name => "Lehre-Essenrode", :area_code => "5301") + AreaCode.create(:country => germany, :name => "Vechelde", :area_code => "5302") + AreaCode.create(:country => germany, :name => "Wendeburg", :area_code => "5303") + AreaCode.create(:country => germany, :name => "Meine", :area_code => "5304") + AreaCode.create(:country => germany, :name => "Sickte", :area_code => "5305") + AreaCode.create(:country => germany, :name => "Cremlingen", :area_code => "5306") + AreaCode.create(:country => germany, :name => "Braunschweig-Wenden", :area_code => "5307") + AreaCode.create(:country => germany, :name => "Lehre", :area_code => "5308") + AreaCode.create(:country => germany, :name => "Lehre-Wendhausen", :area_code => "5309") + AreaCode.create(:country => germany, :name => "Braunschweig", :area_code => "531") + AreaCode.create(:country => germany, :name => "Torfhaus", :area_code => "5320") + AreaCode.create(:country => germany, :name => "Goslar", :area_code => "5321") + AreaCode.create(:country => germany, :name => "Bad Harzburg", :area_code => "5322") + AreaCode.create(:country => germany, :name => "Clausthal-Zellerfeld", :area_code => "5323") + AreaCode.create(:country => germany, :name => "Vienenburg", :area_code => "5324") + AreaCode.create(:country => germany, :name => "Goslar-Hahnenklee", :area_code => "5325") + AreaCode.create(:country => germany, :name => "Langelsheim", :area_code => "5326") + AreaCode.create(:country => germany, :name => "Bad Grund Harz", :area_code => "5327") + AreaCode.create(:country => germany, :name => "Altenau Harz", :area_code => "5328") + AreaCode.create(:country => germany, :name => "Schulenberg im Oberharz", :area_code => "5329") + AreaCode.create(:country => germany, :name => "Wolfenbüttel", :area_code => "5331") + AreaCode.create(:country => germany, :name => "Schöppenstedt", :area_code => "5332") + AreaCode.create(:country => germany, :name => "Dettum", :area_code => "5333") + AreaCode.create(:country => germany, :name => "Hornburg Kr Wolfenbüttel", :area_code => "5334") + AreaCode.create(:country => germany, :name => "Schladen", :area_code => "5335") + AreaCode.create(:country => germany, :name => "Semmenstedt", :area_code => "5336") + AreaCode.create(:country => germany, :name => "Kissenbrück", :area_code => "5337") + AreaCode.create(:country => germany, :name => "Gielde", :area_code => "5339") + AreaCode.create(:country => germany, :name => "Salzgitter", :area_code => "5341") + AreaCode.create(:country => germany, :name => "Lengede", :area_code => "5344") + AreaCode.create(:country => germany, :name => "Baddeckenstedt", :area_code => "5345") + AreaCode.create(:country => germany, :name => "Liebenburg", :area_code => "5346") + AreaCode.create(:country => germany, :name => "Burgdorf b Salzgitter", :area_code => "5347") + AreaCode.create(:country => germany, :name => "Helmstedt", :area_code => "5351") + AreaCode.create(:country => germany, :name => "Schöningen", :area_code => "5352") + AreaCode.create(:country => germany, :name => "Königslutter am Elm", :area_code => "5353") + AreaCode.create(:country => germany, :name => "Jerxheim", :area_code => "5354") + AreaCode.create(:country => germany, :name => "Frellstedt", :area_code => "5355") + AreaCode.create(:country => germany, :name => "Helmstedt-Barmke", :area_code => "5356") + AreaCode.create(:country => germany, :name => "Grasleben", :area_code => "5357") + AreaCode.create(:country => germany, :name => "Bahrdorf-Mackendorf", :area_code => "5358") + AreaCode.create(:country => germany, :name => "Wolfsburg", :area_code => "5361") + AreaCode.create(:country => germany, :name => "Wolfsburg-Fallersleben", :area_code => "5362") + AreaCode.create(:country => germany, :name => "Wolfsburg-Vorsfelde", :area_code => "5363") + AreaCode.create(:country => germany, :name => "Velpke", :area_code => "5364") + AreaCode.create(:country => germany, :name => "Wolfsburg-Neindorf", :area_code => "5365") + AreaCode.create(:country => germany, :name => "Jembke", :area_code => "5366") + AreaCode.create(:country => germany, :name => "Rühen", :area_code => "5367") + AreaCode.create(:country => germany, :name => "Parsau", :area_code => "5368") + AreaCode.create(:country => germany, :name => "Gifhorn", :area_code => "5371") + AreaCode.create(:country => germany, :name => "Meinersen", :area_code => "5372") + AreaCode.create(:country => germany, :name => "Hillerse Kr Gifhorn", :area_code => "5373") + AreaCode.create(:country => germany, :name => "Isenbüttel", :area_code => "5374") + AreaCode.create(:country => germany, :name => "Müden Aller", :area_code => "5375") + AreaCode.create(:country => germany, :name => "Wesendorf Kr Gifhorn", :area_code => "5376") + AreaCode.create(:country => germany, :name => "Ehra-Lessien", :area_code => "5377") + AreaCode.create(:country => germany, :name => "Sassenburg-Platendorf", :area_code => "5378") + AreaCode.create(:country => germany, :name => "Sassenburg-Grussendorf", :area_code => "5379") + AreaCode.create(:country => germany, :name => "Seesen", :area_code => "5381") + AreaCode.create(:country => germany, :name => "Bad Gandersheim", :area_code => "5382") + AreaCode.create(:country => germany, :name => "Lutter am Barenberge", :area_code => "5383") + AreaCode.create(:country => germany, :name => "Seesen-Groß Rhüden", :area_code => "5384") + AreaCode.create(:country => germany, :name => "Georgsmarienhütte", :area_code => "5401") + AreaCode.create(:country => germany, :name => "Bissendorf Kr Osnabrück", :area_code => "5402") + AreaCode.create(:country => germany, :name => "Bad Iburg", :area_code => "5403") + AreaCode.create(:country => germany, :name => "Westerkappeln", :area_code => "5404") + AreaCode.create(:country => germany, :name => "Hasbergen Kr Osnabrück", :area_code => "5405") + AreaCode.create(:country => germany, :name => "Belm", :area_code => "5406") + AreaCode.create(:country => germany, :name => "Wallenhorst", :area_code => "5407") + AreaCode.create(:country => germany, :name => "Hilter am Teutoburger Wald", :area_code => "5409") + AreaCode.create(:country => germany, :name => "Osnabrück", :area_code => "541") + AreaCode.create(:country => germany, :name => "Dissen am Teutoburger Wald", :area_code => "5421") + AreaCode.create(:country => germany, :name => "Melle", :area_code => "5422") + AreaCode.create(:country => germany, :name => "Versmold", :area_code => "5423") + AreaCode.create(:country => germany, :name => "Bad Rothenfelde", :area_code => "5424") + AreaCode.create(:country => germany, :name => "Borgholzhausen", :area_code => "5425") + AreaCode.create(:country => germany, :name => "Glandorf", :area_code => "5426") + AreaCode.create(:country => germany, :name => "Melle-Buer", :area_code => "5427") + AreaCode.create(:country => germany, :name => "Melle-Neuenkirchen", :area_code => "5428") + AreaCode.create(:country => germany, :name => "Melle-Wellingholzhausen", :area_code => "5429") + AreaCode.create(:country => germany, :name => "Quakenbrück", :area_code => "5431") + AreaCode.create(:country => germany, :name => "Löningen", :area_code => "5432") + AreaCode.create(:country => germany, :name => "Badbergen", :area_code => "5433") + AreaCode.create(:country => germany, :name => "Essen Oldenburg", :area_code => "5434") + AreaCode.create(:country => germany, :name => "Berge b Quakenbrück", :area_code => "5435") + AreaCode.create(:country => germany, :name => "Nortrup", :area_code => "5436") + AreaCode.create(:country => germany, :name => "Menslage", :area_code => "5437") + AreaCode.create(:country => germany, :name => "Bakum-Lüsche", :area_code => "5438") + AreaCode.create(:country => germany, :name => "Bersenbrück", :area_code => "5439") + AreaCode.create(:country => germany, :name => "Diepholz", :area_code => "5441") + AreaCode.create(:country => germany, :name => "Barnstorf Kr Diepholz", :area_code => "5442") + AreaCode.create(:country => germany, :name => "Lemförde", :area_code => "5443") + AreaCode.create(:country => germany, :name => "Wagenfeld", :area_code => "5444") + AreaCode.create(:country => germany, :name => "Drebber", :area_code => "5445") + AreaCode.create(:country => germany, :name => "Rehden", :area_code => "5446") + AreaCode.create(:country => germany, :name => "Lembruch", :area_code => "5447") + AreaCode.create(:country => germany, :name => "Barver", :area_code => "5448") + AreaCode.create(:country => germany, :name => "Ibbenbüren", :area_code => "5451") + AreaCode.create(:country => germany, :name => "Mettingen Westf", :area_code => "5452") + AreaCode.create(:country => germany, :name => "Recke", :area_code => "5453") + AreaCode.create(:country => germany, :name => "Hörstel-Riesenbeck", :area_code => "5454") + AreaCode.create(:country => germany, :name => "Tecklenburg-Brochterbeck", :area_code => "5455") + AreaCode.create(:country => germany, :name => "Westerkappeln-Velpe", :area_code => "5456") + AreaCode.create(:country => germany, :name => "Hopsten-Schale", :area_code => "5457") + AreaCode.create(:country => germany, :name => "Hopsten", :area_code => "5458") + AreaCode.create(:country => germany, :name => "Hörstel", :area_code => "5459") + AreaCode.create(:country => germany, :name => "Bramsche Hase", :area_code => "5461") + AreaCode.create(:country => germany, :name => "Ankum", :area_code => "5462") + AreaCode.create(:country => germany, :name => "Alfhausen", :area_code => "5464") + AreaCode.create(:country => germany, :name => "Neuenkirchen b Bramsche", :area_code => "5465") + AreaCode.create(:country => germany, :name => "Merzen", :area_code => "5466") + AreaCode.create(:country => germany, :name => "Voltlage", :area_code => "5467") + AreaCode.create(:country => germany, :name => "Bramsche-Engter", :area_code => "5468") + AreaCode.create(:country => germany, :name => "Bohmte", :area_code => "5471") + AreaCode.create(:country => germany, :name => "Bad Essen", :area_code => "5472") + AreaCode.create(:country => germany, :name => "Ostercappeln", :area_code => "5473") + AreaCode.create(:country => germany, :name => "Stemwede-Dielingen", :area_code => "5474") + AreaCode.create(:country => germany, :name => "Bohmte-Hunteburg", :area_code => "5475") + AreaCode.create(:country => germany, :name => "Ostercappeln-Venne", :area_code => "5476") + AreaCode.create(:country => germany, :name => "Lengerich Westf", :area_code => "5481") + AreaCode.create(:country => germany, :name => "Tecklenburg", :area_code => "5482") + AreaCode.create(:country => germany, :name => "Lienen", :area_code => "5483") + AreaCode.create(:country => germany, :name => "Lienen-Kattenvenne", :area_code => "5484") + AreaCode.create(:country => germany, :name => "Ladbergen", :area_code => "5485") + AreaCode.create(:country => germany, :name => "Damme Dümmer", :area_code => "5491") + AreaCode.create(:country => germany, :name => "Steinfeld Oldenburg", :area_code => "5492") + AreaCode.create(:country => germany, :name => "Neuenkirchen Kr Vechta", :area_code => "5493") + AreaCode.create(:country => germany, :name => "Holdorf Niedersachs", :area_code => "5494") + AreaCode.create(:country => germany, :name => "Vörden Kr Vechta", :area_code => "5495") + AreaCode.create(:country => germany, :name => "Dransfeld", :area_code => "5502") + AreaCode.create(:country => germany, :name => "Nörten-Hardenberg", :area_code => "5503") + AreaCode.create(:country => germany, :name => "Friedland Kr Göttingen", :area_code => "5504") + AreaCode.create(:country => germany, :name => "Hardegsen", :area_code => "5505") + AreaCode.create(:country => germany, :name => "Adelebsen", :area_code => "5506") + AreaCode.create(:country => germany, :name => "Ebergötzen", :area_code => "5507") + AreaCode.create(:country => germany, :name => "Gleichen-Rittmarshausen", :area_code => "5508") + AreaCode.create(:country => germany, :name => "Rosdorf Kr Göttingen", :area_code => "5509") + AreaCode.create(:country => germany, :name => "Göttingen", :area_code => "551") + AreaCode.create(:country => germany, :name => "Braunlage", :area_code => "5520") + AreaCode.create(:country => germany, :name => "Herzberg am Harz", :area_code => "5521") + AreaCode.create(:country => germany, :name => "Osterode am Harz", :area_code => "5522") + AreaCode.create(:country => germany, :name => "Bad Sachsa", :area_code => "5523") + AreaCode.create(:country => germany, :name => "Bad Lauterberg im Harz", :area_code => "5524") + AreaCode.create(:country => germany, :name => "Walkenried", :area_code => "5525") + AreaCode.create(:country => germany, :name => "Duderstadt", :area_code => "5527") + AreaCode.create(:country => germany, :name => "Gieboldehausen", :area_code => "5528") + AreaCode.create(:country => germany, :name => "Rhumspringe", :area_code => "5529") + AreaCode.create(:country => germany, :name => "Holzminden", :area_code => "5531") + AreaCode.create(:country => germany, :name => "Stadtoldendorf", :area_code => "5532") + AreaCode.create(:country => germany, :name => "Bodenwerder", :area_code => "5533") + AreaCode.create(:country => germany, :name => "Eschershausen a d Lenne", :area_code => "5534") + AreaCode.create(:country => germany, :name => "Polle", :area_code => "5535") + AreaCode.create(:country => germany, :name => "Holzminden-Neuhaus", :area_code => "5536") + AreaCode.create(:country => germany, :name => "Hann. Münden", :area_code => "5541") + AreaCode.create(:country => germany, :name => "Witzenhausen", :area_code => "5542") + AreaCode.create(:country => germany, :name => "Staufenberg Niedersachs", :area_code => "5543") + AreaCode.create(:country => germany, :name => "Reinhardshagen", :area_code => "5544") + AreaCode.create(:country => germany, :name => "Hedemünden", :area_code => "5545") + AreaCode.create(:country => germany, :name => "Scheden", :area_code => "5546") + AreaCode.create(:country => germany, :name => "Northeim", :area_code => "5551") + AreaCode.create(:country => germany, :name => "Katlenburg", :area_code => "5552") + AreaCode.create(:country => germany, :name => "Kalefeld", :area_code => "5553") + AreaCode.create(:country => germany, :name => "Moringen", :area_code => "5554") + AreaCode.create(:country => germany, :name => "Moringen-Fredelsloh", :area_code => "5555") + AreaCode.create(:country => germany, :name => "Lindau Harz", :area_code => "5556") + AreaCode.create(:country => germany, :name => "Einbeck", :area_code => "5561") + AreaCode.create(:country => germany, :name => "Dassel-Markoldendorf", :area_code => "5562") + AreaCode.create(:country => germany, :name => "Kreiensen", :area_code => "5563") + AreaCode.create(:country => germany, :name => "Dassel", :area_code => "5564") + AreaCode.create(:country => germany, :name => "Einbeck-Wenzen", :area_code => "5565") + AreaCode.create(:country => germany, :name => "Uslar", :area_code => "5571") + AreaCode.create(:country => germany, :name => "Bodenfelde", :area_code => "5572") + AreaCode.create(:country => germany, :name => "Uslar-Volpriehausen", :area_code => "5573") + AreaCode.create(:country => germany, :name => "Oberweser", :area_code => "5574") + AreaCode.create(:country => germany, :name => "Sankt Andreasberg", :area_code => "5582") + AreaCode.create(:country => germany, :name => "Braunlage-Hohegeiss", :area_code => "5583") + AreaCode.create(:country => germany, :name => "Hattorf am Harz", :area_code => "5584") + AreaCode.create(:country => germany, :name => "Herzberg-Sieber", :area_code => "5585") + AreaCode.create(:country => germany, :name => "Wieda", :area_code => "5586") + AreaCode.create(:country => germany, :name => "Gleichen-Bremke", :area_code => "5592") + AreaCode.create(:country => germany, :name => "Bovenden-Lenglern", :area_code => "5593") + AreaCode.create(:country => germany, :name => "Bovenden-Reyershausen", :area_code => "5594") + AreaCode.create(:country => germany, :name => "Schauenburg", :area_code => "5601") + AreaCode.create(:country => germany, :name => "Hessisch Lichtenau", :area_code => "5602") + AreaCode.create(:country => germany, :name => "Gudensberg", :area_code => "5603") + AreaCode.create(:country => germany, :name => "Grossalmerode", :area_code => "5604") + AreaCode.create(:country => germany, :name => "Kaufungen Hess", :area_code => "5605") + AreaCode.create(:country => germany, :name => "Zierenberg", :area_code => "5606") + AreaCode.create(:country => germany, :name => "Fuldatal", :area_code => "5607") + AreaCode.create(:country => germany, :name => "Söhrewald", :area_code => "5608") + AreaCode.create(:country => germany, :name => "Ahnatal", :area_code => "5609") + AreaCode.create(:country => germany, :name => "Kassel", :area_code => "561") + AreaCode.create(:country => germany, :name => "Bad Wildungen", :area_code => "5621") + AreaCode.create(:country => germany, :name => "Fritzlar", :area_code => "5622") + AreaCode.create(:country => germany, :name => "Edertal", :area_code => "5623") + AreaCode.create(:country => germany, :name => "Bad Emstal", :area_code => "5624") + AreaCode.create(:country => germany, :name => "Naumburg Hess", :area_code => "5625") + AreaCode.create(:country => germany, :name => "Bad Zwesten", :area_code => "5626") + AreaCode.create(:country => germany, :name => "Korbach", :area_code => "5631") + AreaCode.create(:country => germany, :name => "Willingen Upland", :area_code => "5632") + AreaCode.create(:country => germany, :name => "Diemelsee", :area_code => "5633") + AreaCode.create(:country => germany, :name => "Waldeck-Sachsenhausen", :area_code => "5634") + AreaCode.create(:country => germany, :name => "Vöhl", :area_code => "5635") + AreaCode.create(:country => germany, :name => "Lichtenfels-Goddelsheim", :area_code => "5636") + AreaCode.create(:country => germany, :name => "Warburg", :area_code => "5641") + AreaCode.create(:country => germany, :name => "Warburg-Scherfede", :area_code => "5642") + AreaCode.create(:country => germany, :name => "Borgentreich", :area_code => "5643") + AreaCode.create(:country => germany, :name => "Willebadessen-Peckelsheim", :area_code => "5644") + AreaCode.create(:country => germany, :name => "Borgentreich-Borgholz", :area_code => "5645") + AreaCode.create(:country => germany, :name => "Willebadessen", :area_code => "5646") + AreaCode.create(:country => germany, :name => "Lichtenau-Kleinenberg", :area_code => "5647") + AreaCode.create(:country => germany, :name => "Brakel-Gehrden", :area_code => "5648") + AreaCode.create(:country => germany, :name => "Cornberg", :area_code => "5650") + AreaCode.create(:country => germany, :name => "Eschwege", :area_code => "5651") + AreaCode.create(:country => germany, :name => "Bad Sooden-Allendorf", :area_code => "5652") + AreaCode.create(:country => germany, :name => "Sontra", :area_code => "5653") + AreaCode.create(:country => germany, :name => "Herleshausen", :area_code => "5654") + AreaCode.create(:country => germany, :name => "Wanfried", :area_code => "5655") + AreaCode.create(:country => germany, :name => "Waldkappel", :area_code => "5656") + AreaCode.create(:country => germany, :name => "Meissner", :area_code => "5657") + AreaCode.create(:country => germany, :name => "Wehretal", :area_code => "5658") + AreaCode.create(:country => germany, :name => "Ringgau", :area_code => "5659") + AreaCode.create(:country => germany, :name => "Melsungen", :area_code => "5661") + AreaCode.create(:country => germany, :name => "Felsberg Hess", :area_code => "5662") + AreaCode.create(:country => germany, :name => "Spangenberg", :area_code => "5663") + AreaCode.create(:country => germany, :name => "Morschen", :area_code => "5664") + AreaCode.create(:country => germany, :name => "Guxhagen", :area_code => "5665") + AreaCode.create(:country => germany, :name => "Hofgeismar", :area_code => "5671") + AreaCode.create(:country => germany, :name => "Bad Karlshafen", :area_code => "5672") + AreaCode.create(:country => germany, :name => "Immenhausen Hess", :area_code => "5673") + AreaCode.create(:country => germany, :name => "Grebenstein", :area_code => "5674") + AreaCode.create(:country => germany, :name => "Trendelburg", :area_code => "5675") + AreaCode.create(:country => germany, :name => "Liebenau Hess", :area_code => "5676") + AreaCode.create(:country => germany, :name => "Calden-Westuffeln", :area_code => "5677") + AreaCode.create(:country => germany, :name => "Homberg Efze", :area_code => "5681") + AreaCode.create(:country => germany, :name => "Borken Hessen", :area_code => "5682") + AreaCode.create(:country => germany, :name => "Wabern Hess", :area_code => "5683") + AreaCode.create(:country => germany, :name => "Frielendorf", :area_code => "5684") + AreaCode.create(:country => germany, :name => "Knüllwald", :area_code => "5685") + AreaCode.create(:country => germany, :name => "Schwarzenborn Knüll", :area_code => "5686") + AreaCode.create(:country => germany, :name => "Bad Arolsen", :area_code => "5691") + AreaCode.create(:country => germany, :name => "Wolfhagen", :area_code => "5692") + AreaCode.create(:country => germany, :name => "Volkmarsen", :area_code => "5693") + AreaCode.create(:country => germany, :name => "Diemelstadt", :area_code => "5694") + AreaCode.create(:country => germany, :name => "Twistetal", :area_code => "5695") + AreaCode.create(:country => germany, :name => "Bad Arolsen-Landau", :area_code => "5696") + AreaCode.create(:country => germany, :name => "Petershagen-Lahde", :area_code => "5702") + AreaCode.create(:country => germany, :name => "Hille", :area_code => "5703") + AreaCode.create(:country => germany, :name => "Petershagen-Friedewalde", :area_code => "5704") + AreaCode.create(:country => germany, :name => "Petershagen-Windheim", :area_code => "5705") + AreaCode.create(:country => germany, :name => "Porta Westfalica", :area_code => "5706") + AreaCode.create(:country => germany, :name => "Petershagen Weser", :area_code => "5707") + AreaCode.create(:country => germany, :name => "Minden Westf", :area_code => "571") + AreaCode.create(:country => germany, :name => "Stadthagen", :area_code => "5721") + AreaCode.create(:country => germany, :name => "Bückeburg", :area_code => "5722") + AreaCode.create(:country => germany, :name => "Bad Nenndorf", :area_code => "5723") + AreaCode.create(:country => germany, :name => "Obernkirchen", :area_code => "5724") + AreaCode.create(:country => germany, :name => "Lindhorst b Stadthagen", :area_code => "5725") + AreaCode.create(:country => germany, :name => "Wiedensahl", :area_code => "5726") + AreaCode.create(:country => germany, :name => "Bad Oeynhausen", :area_code => "5731") + AreaCode.create(:country => germany, :name => "Löhne", :area_code => "5732") + AreaCode.create(:country => germany, :name => "Vlotho", :area_code => "5733") + AreaCode.create(:country => germany, :name => "Bergkirchen Westf", :area_code => "5734") + AreaCode.create(:country => germany, :name => "Lübbecke", :area_code => "5741") + AreaCode.create(:country => germany, :name => "Preussisch Oldendorf", :area_code => "5742") + AreaCode.create(:country => germany, :name => "Espelkamp-Gestringen", :area_code => "5743") + AreaCode.create(:country => germany, :name => "Hüllhorst", :area_code => "5744") + AreaCode.create(:country => germany, :name => "Stemwede-Levern", :area_code => "5745") + AreaCode.create(:country => germany, :name => "Rödinghausen", :area_code => "5746") + AreaCode.create(:country => germany, :name => "Rinteln", :area_code => "5751") + AreaCode.create(:country => germany, :name => "Auetal-Hattendorf", :area_code => "5752") + AreaCode.create(:country => germany, :name => "Auetal-Bernsen", :area_code => "5753") + AreaCode.create(:country => germany, :name => "Extertal-Bremke", :area_code => "5754") + AreaCode.create(:country => germany, :name => "Kalletal-Varenholz", :area_code => "5755") + AreaCode.create(:country => germany, :name => "Stolzenau", :area_code => "5761") + AreaCode.create(:country => germany, :name => "Uchte", :area_code => "5763") + AreaCode.create(:country => germany, :name => "Steyerberg", :area_code => "5764") + AreaCode.create(:country => germany, :name => "Raddestorf", :area_code => "5765") + AreaCode.create(:country => germany, :name => "Rehburg-Loccum", :area_code => "5766") + AreaCode.create(:country => germany, :name => "Warmsen", :area_code => "5767") + AreaCode.create(:country => germany, :name => "Petershagen-Heimsen", :area_code => "5768") + AreaCode.create(:country => germany, :name => "Steyerberg-Voigtei", :area_code => "5769") + AreaCode.create(:country => germany, :name => "Rahden Westf", :area_code => "5771") + AreaCode.create(:country => germany, :name => "Espelkamp", :area_code => "5772") + AreaCode.create(:country => germany, :name => "Stemwede-Wehdem", :area_code => "5773") + AreaCode.create(:country => germany, :name => "Wagenfeld-Ströhen", :area_code => "5774") + AreaCode.create(:country => germany, :name => "Diepenau", :area_code => "5775") + AreaCode.create(:country => germany, :name => "Preussisch Ströhen", :area_code => "5776") + AreaCode.create(:country => germany, :name => "Diepenau-Essern", :area_code => "5777") + AreaCode.create(:country => germany, :name => "Wrestedt", :area_code => "5802") + AreaCode.create(:country => germany, :name => "Rosche", :area_code => "5803") + AreaCode.create(:country => germany, :name => "Rätzlingen Kr Uelzen", :area_code => "5804") + AreaCode.create(:country => germany, :name => "Oetzen", :area_code => "5805") + AreaCode.create(:country => germany, :name => "Barum b Bad Bevensen", :area_code => "5806") + AreaCode.create(:country => germany, :name => "Altenmedingen", :area_code => "5807") + AreaCode.create(:country => germany, :name => "Gerdau", :area_code => "5808") + AreaCode.create(:country => germany, :name => "Uelzen", :area_code => "581") + AreaCode.create(:country => germany, :name => "Suhlendorf", :area_code => "5820") + AreaCode.create(:country => germany, :name => "Bad Bevensen", :area_code => "5821") + AreaCode.create(:country => germany, :name => "Ebstorf", :area_code => "5822") + AreaCode.create(:country => germany, :name => "Bienenbüttel", :area_code => "5823") + AreaCode.create(:country => germany, :name => "Bad Bodenteich", :area_code => "5824") + AreaCode.create(:country => germany, :name => "Wieren", :area_code => "5825") + AreaCode.create(:country => germany, :name => "Suderburg", :area_code => "5826") + AreaCode.create(:country => germany, :name => "Unterlüß", :area_code => "5827") + AreaCode.create(:country => germany, :name => "Himbergen", :area_code => "5828") + AreaCode.create(:country => germany, :name => "Wriedel", :area_code => "5829") + AreaCode.create(:country => germany, :name => "Wittingen", :area_code => "5831") + AreaCode.create(:country => germany, :name => "Hankensbüttel", :area_code => "5832") + AreaCode.create(:country => germany, :name => "Brome", :area_code => "5833") + AreaCode.create(:country => germany, :name => "Wittingen-Knesebeck", :area_code => "5834") + AreaCode.create(:country => germany, :name => "Wahrenholz", :area_code => "5835") + AreaCode.create(:country => germany, :name => "Wittingen-Radenbeck", :area_code => "5836") + AreaCode.create(:country => germany, :name => "Sprakensehl", :area_code => "5837") + AreaCode.create(:country => germany, :name => "Gross Oesingen", :area_code => "5838") + AreaCode.create(:country => germany, :name => "Wittingen-Ohrdorf", :area_code => "5839") + AreaCode.create(:country => germany, :name => "Schnackenburg", :area_code => "5840") + AreaCode.create(:country => germany, :name => "Lüchow Wendland", :area_code => "5841") + AreaCode.create(:country => germany, :name => "Schnega", :area_code => "5842") + AreaCode.create(:country => germany, :name => "Wustrow", :area_code => "5843") + AreaCode.create(:country => germany, :name => "Clenze", :area_code => "5844") + AreaCode.create(:country => germany, :name => "Bergen Dumme", :area_code => "5845") + AreaCode.create(:country => germany, :name => "Gartow Niedersachs", :area_code => "5846") + AreaCode.create(:country => germany, :name => "Trebel", :area_code => "5848") + AreaCode.create(:country => germany, :name => "Waddeweitz", :area_code => "5849") + AreaCode.create(:country => germany, :name => "Neetze", :area_code => "5850") + AreaCode.create(:country => germany, :name => "Dahlenburg", :area_code => "5851") + AreaCode.create(:country => germany, :name => "Bleckede", :area_code => "5852") + AreaCode.create(:country => germany, :name => "Neu Darchau", :area_code => "5853") + AreaCode.create(:country => germany, :name => "Bleckede-Barskamp", :area_code => "5854") + AreaCode.create(:country => germany, :name => "Nahrendorf", :area_code => "5855") + AreaCode.create(:country => germany, :name => "Bleckede-Brackede", :area_code => "5857") + AreaCode.create(:country => germany, :name => "Hitzacker-Wietzetze", :area_code => "5858") + AreaCode.create(:country => germany, :name => "Thomasburg", :area_code => "5859") + AreaCode.create(:country => germany, :name => "Dannenberg Elbe", :area_code => "5861") + AreaCode.create(:country => germany, :name => "Hitzacker Elbe", :area_code => "5862") + AreaCode.create(:country => germany, :name => "Zernien", :area_code => "5863") + AreaCode.create(:country => germany, :name => "Jameln", :area_code => "5864") + AreaCode.create(:country => germany, :name => "Gusborn", :area_code => "5865") + AreaCode.create(:country => germany, :name => "Stoetze", :area_code => "5872") + AreaCode.create(:country => germany, :name => "Eimke", :area_code => "5873") + AreaCode.create(:country => germany, :name => "Soltendieck", :area_code => "5874") + AreaCode.create(:country => germany, :name => "Emmendorf", :area_code => "5875") + AreaCode.create(:country => germany, :name => "Gorleben", :area_code => "5882") + AreaCode.create(:country => germany, :name => "Lemgow", :area_code => "5883") + AreaCode.create(:country => germany, :name => "Fürstenau b Bramsche", :area_code => "5901") + AreaCode.create(:country => germany, :name => "Freren", :area_code => "5902") + AreaCode.create(:country => germany, :name => "Emsbüren", :area_code => "5903") + AreaCode.create(:country => germany, :name => "Lengerich Emsl", :area_code => "5904") + AreaCode.create(:country => germany, :name => "Beesten", :area_code => "5905") + AreaCode.create(:country => germany, :name => "Lünne", :area_code => "5906") + AreaCode.create(:country => germany, :name => "Geeste", :area_code => "5907") + AreaCode.create(:country => germany, :name => "Wietmarschen-Lohne", :area_code => "5908") + AreaCode.create(:country => germany, :name => "Wettrup", :area_code => "5909") + AreaCode.create(:country => germany, :name => "Lingen (Ems)", :area_code => "591") + AreaCode.create(:country => germany, :name => "Nordhorn", :area_code => "5921") + AreaCode.create(:country => germany, :name => "Bad Bentheim", :area_code => "5922") + AreaCode.create(:country => germany, :name => "Schüttorf", :area_code => "5923") + AreaCode.create(:country => germany, :name => "Bad Bentheim-Gildehaus", :area_code => "5924") + AreaCode.create(:country => germany, :name => "Wietmarschen", :area_code => "5925") + AreaCode.create(:country => germany, :name => "Engden", :area_code => "5926") + AreaCode.create(:country => germany, :name => "Meppen", :area_code => "5931") + AreaCode.create(:country => germany, :name => "Haren Ems", :area_code => "5932") + AreaCode.create(:country => germany, :name => "Lathen", :area_code => "5933") + AreaCode.create(:country => germany, :name => "Haren-Rütenbrock", :area_code => "5934") + AreaCode.create(:country => germany, :name => "Twist-Schöninghsdorf", :area_code => "5935") + AreaCode.create(:country => germany, :name => "Twist", :area_code => "5936") + AreaCode.create(:country => germany, :name => "Geeste-Gross Hesepe", :area_code => "5937") + AreaCode.create(:country => germany, :name => "Sustrum", :area_code => "5939") + AreaCode.create(:country => germany, :name => "Neuenhaus Dinkel", :area_code => "5941") + AreaCode.create(:country => germany, :name => "Uelsen", :area_code => "5942") + AreaCode.create(:country => germany, :name => "Emlichheim", :area_code => "5943") + AreaCode.create(:country => germany, :name => "Hoogstede", :area_code => "5944") + AreaCode.create(:country => germany, :name => "Wilsum", :area_code => "5945") + AreaCode.create(:country => germany, :name => "Georgsdorf", :area_code => "5946") + AreaCode.create(:country => germany, :name => "Laar Vechte", :area_code => "5947") + AreaCode.create(:country => germany, :name => "Itterbeck", :area_code => "5948") + AreaCode.create(:country => germany, :name => "Werlte", :area_code => "5951") + AreaCode.create(:country => germany, :name => "Sögel", :area_code => "5952") + AreaCode.create(:country => germany, :name => "Börger", :area_code => "5953") + AreaCode.create(:country => germany, :name => "Lorup", :area_code => "5954") + AreaCode.create(:country => germany, :name => "Esterwegen", :area_code => "5955") + AreaCode.create(:country => germany, :name => "Rastdorf", :area_code => "5956") + AreaCode.create(:country => germany, :name => "Lindern Oldenburg", :area_code => "5957") + AreaCode.create(:country => germany, :name => "Haselünne", :area_code => "5961") + AreaCode.create(:country => germany, :name => "Herzlake", :area_code => "5962") + AreaCode.create(:country => germany, :name => "Bawinkel", :area_code => "5963") + AreaCode.create(:country => germany, :name => "Lähden", :area_code => "5964") + AreaCode.create(:country => germany, :name => "Klein Berssen", :area_code => "5965") + AreaCode.create(:country => germany, :name => "Meppen-Apeldorn", :area_code => "5966") + AreaCode.create(:country => germany, :name => "Rheine", :area_code => "5971") + AreaCode.create(:country => germany, :name => "Neuenkirchen Kr Steinfurt", :area_code => "5973") + AreaCode.create(:country => germany, :name => "Rheine-Mesum", :area_code => "5975") + AreaCode.create(:country => germany, :name => "Salzbergen", :area_code => "5976") + AreaCode.create(:country => germany, :name => "Spelle", :area_code => "5977") + AreaCode.create(:country => germany, :name => "Hörstel-Dreierwalde", :area_code => "5978") + AreaCode.create(:country => germany, :name => "Ober-Mörlen", :area_code => "6002") + AreaCode.create(:country => germany, :name => "Rosbach v d Höhe", :area_code => "6003") + AreaCode.create(:country => germany, :name => "Lich-Eberstadt", :area_code => "6004") + AreaCode.create(:country => germany, :name => "Rosbach-Rodheim", :area_code => "6007") + AreaCode.create(:country => germany, :name => "Echzell", :area_code => "6008") + AreaCode.create(:country => germany, :name => "Heigenbrücken", :area_code => "6020") + AreaCode.create(:country => germany, :name => "Aschaffenburg", :area_code => "6021") + AreaCode.create(:country => germany, :name => "Obernburg a Main", :area_code => "6022") + AreaCode.create(:country => germany, :name => "Alzenau i Ufr", :area_code => "6023") + AreaCode.create(:country => germany, :name => "Schöllkrippen", :area_code => "6024") + AreaCode.create(:country => germany, :name => "Grossostheim", :area_code => "6026") + AreaCode.create(:country => germany, :name => "Stockstadt a Main", :area_code => "6027") + AreaCode.create(:country => germany, :name => "Sulzbach a Main", :area_code => "6028") + AreaCode.create(:country => germany, :name => "Mömbris", :area_code => "6029") + AreaCode.create(:country => germany, :name => "Friedberg Hess", :area_code => "6031") + AreaCode.create(:country => germany, :name => "Bad Nauheim", :area_code => "6032") + AreaCode.create(:country => germany, :name => "Butzbach", :area_code => "6033") + AreaCode.create(:country => germany, :name => "Wöllstadt", :area_code => "6034") + AreaCode.create(:country => germany, :name => "Reichelsheim Wetterau", :area_code => "6035") + AreaCode.create(:country => germany, :name => "Wölfersheim", :area_code => "6036") + AreaCode.create(:country => germany, :name => "Karben", :area_code => "6039") + AreaCode.create(:country => germany, :name => "Glauburg", :area_code => "6041") + AreaCode.create(:country => germany, :name => "Büdingen Hess", :area_code => "6042") + AreaCode.create(:country => germany, :name => "Nidda", :area_code => "6043") + AreaCode.create(:country => germany, :name => "Schotten Hess", :area_code => "6044") + AreaCode.create(:country => germany, :name => "Gedern", :area_code => "6045") + AreaCode.create(:country => germany, :name => "Ortenberg Hess", :area_code => "6046") + AreaCode.create(:country => germany, :name => "Altenstadt Hess", :area_code => "6047") + AreaCode.create(:country => germany, :name => "Büdingen-Eckartshausen", :area_code => "6048") + AreaCode.create(:country => germany, :name => "Kefenrod", :area_code => "6049") + AreaCode.create(:country => germany, :name => "Biebergemünd", :area_code => "6050") + AreaCode.create(:country => germany, :name => "Gelnhausen", :area_code => "6051") + AreaCode.create(:country => germany, :name => "Bad Orb", :area_code => "6052") + AreaCode.create(:country => germany, :name => "Wächtersbach", :area_code => "6053") + AreaCode.create(:country => germany, :name => "Birstein", :area_code => "6054") + AreaCode.create(:country => germany, :name => "Freigericht", :area_code => "6055") + AreaCode.create(:country => germany, :name => "Bad Soden-Salmünster", :area_code => "6056") + AreaCode.create(:country => germany, :name => "Flörsbachtal", :area_code => "6057") + AreaCode.create(:country => germany, :name => "Gründau", :area_code => "6058") + AreaCode.create(:country => germany, :name => "Jossgrund", :area_code => "6059") + AreaCode.create(:country => germany, :name => "Michelstadt", :area_code => "6061") + AreaCode.create(:country => germany, :name => "Erbach Odenw", :area_code => "6062") + AreaCode.create(:country => germany, :name => "Bad König", :area_code => "6063") + AreaCode.create(:country => germany, :name => "Michelstadt-Vielbrunn", :area_code => "6066") + AreaCode.create(:country => germany, :name => "Beerfelden", :area_code => "6068") + AreaCode.create(:country => germany, :name => "Dieburg", :area_code => "6071") + AreaCode.create(:country => germany, :name => "Babenhausen Hess", :area_code => "6073") + AreaCode.create(:country => germany, :name => "Rödermark", :area_code => "6074") + AreaCode.create(:country => germany, :name => "Gross-Umstadt", :area_code => "6078") + AreaCode.create(:country => germany, :name => "Usingen", :area_code => "6081") + AreaCode.create(:country => germany, :name => "Niederreifenberg", :area_code => "6082") + AreaCode.create(:country => germany, :name => "Weilrod", :area_code => "6083") + AreaCode.create(:country => germany, :name => "Schmitten Taunus", :area_code => "6084") + AreaCode.create(:country => germany, :name => "Waldsolms", :area_code => "6085") + AreaCode.create(:country => germany, :name => "Grävenwiesbach", :area_code => "6086") + AreaCode.create(:country => germany, :name => "Waldems", :area_code => "6087") + AreaCode.create(:country => germany, :name => "Heimbuchenthal", :area_code => "6092") + AreaCode.create(:country => germany, :name => "Laufach", :area_code => "6093") + AreaCode.create(:country => germany, :name => "Weibersbrunn", :area_code => "6094") + AreaCode.create(:country => germany, :name => "Bessenbach", :area_code => "6095") + AreaCode.create(:country => germany, :name => "Wiesen Unterfr", :area_code => "6096") + AreaCode.create(:country => germany, :name => "Bad Vilbel", :area_code => "6101") + AreaCode.create(:country => germany, :name => "Neu-Isenburg", :area_code => "6102") + AreaCode.create(:country => germany, :name => "Langen Hess", :area_code => "6103") + AreaCode.create(:country => germany, :name => "Heusenstamm", :area_code => "6104") + AreaCode.create(:country => germany, :name => "Mörfelden-Walldorf", :area_code => "6105") + AreaCode.create(:country => germany, :name => "Rodgau", :area_code => "6106") + AreaCode.create(:country => germany, :name => "Kelsterbach", :area_code => "6107") + AreaCode.create(:country => germany, :name => "Mühlheim am Main", :area_code => "6108") + AreaCode.create(:country => germany, :name => "Frankfurt-Bergen-Enkheim", :area_code => "6109") + AreaCode.create(:country => germany, :name => "Wiesbaden", :area_code => "611") + AreaCode.create(:country => germany, :name => "Aarbergen", :area_code => "6120") + AreaCode.create(:country => germany, :name => "Hofheim-Wallau", :area_code => "6122") + AreaCode.create(:country => germany, :name => "Eltville am Rhein", :area_code => "6123") + AreaCode.create(:country => germany, :name => "Bad Schwalbach", :area_code => "6124") + AreaCode.create(:country => germany, :name => "Idstein", :area_code => "6126") + AreaCode.create(:country => germany, :name => "Niedernhausen Taunus", :area_code => "6127") + AreaCode.create(:country => germany, :name => "Taunusstein", :area_code => "6128") + AreaCode.create(:country => germany, :name => "Schlangenbad", :area_code => "6129") + AreaCode.create(:country => germany, :name => "Schwabenheim an der Selz", :area_code => "6130") + AreaCode.create(:country => germany, :name => "Mainz", :area_code => "6131") + AreaCode.create(:country => germany, :name => "Ingelheim am Rhein", :area_code => "6132") + AreaCode.create(:country => germany, :name => "Oppenheim", :area_code => "6133") + AreaCode.create(:country => germany, :name => "Mainz-Kastel", :area_code => "6134") + AreaCode.create(:country => germany, :name => "Bodenheim Rhein", :area_code => "6135") + AreaCode.create(:country => germany, :name => "Nieder-Olm", :area_code => "6136") + AreaCode.create(:country => germany, :name => "Mommenheim", :area_code => "6138") + AreaCode.create(:country => germany, :name => "Budenheim", :area_code => "6139") + AreaCode.create(:country => germany, :name => "Rüsselsheim", :area_code => "6142") + AreaCode.create(:country => germany, :name => "Bischofsheim b Rüsselsheim", :area_code => "6144") + AreaCode.create(:country => germany, :name => "Flörsheim am Main", :area_code => "6145") + AreaCode.create(:country => germany, :name => "Hochheim am Main", :area_code => "6146") + AreaCode.create(:country => germany, :name => "Trebur", :area_code => "6147") + AreaCode.create(:country => germany, :name => "Weiterstadt", :area_code => "6150") + AreaCode.create(:country => germany, :name => "Darmstadt", :area_code => "6151") + AreaCode.create(:country => germany, :name => "Gross-Gerau", :area_code => "6152") + AreaCode.create(:country => germany, :name => "Ober-Ramstadt", :area_code => "6154") + AreaCode.create(:country => germany, :name => "Griesheim Hess", :area_code => "6155") + AreaCode.create(:country => germany, :name => "Pfungstadt", :area_code => "6157") + AreaCode.create(:country => germany, :name => "Riedstadt", :area_code => "6158") + AreaCode.create(:country => germany, :name => "Messel", :area_code => "6159") + AreaCode.create(:country => germany, :name => "Brensbach", :area_code => "6161") + AreaCode.create(:country => germany, :name => "Reinheim Odenw", :area_code => "6162") + AreaCode.create(:country => germany, :name => "Höchst i Odw", :area_code => "6163") + AreaCode.create(:country => germany, :name => "Reichelsheim Odenwald", :area_code => "6164") + AreaCode.create(:country => germany, :name => "Breuberg", :area_code => "6165") + AreaCode.create(:country => germany, :name => "Fischbachtal", :area_code => "6166") + AreaCode.create(:country => germany, :name => "Modautal", :area_code => "6167") + AreaCode.create(:country => germany, :name => "Oberursel Taunus", :area_code => "6171") + AreaCode.create(:country => germany, :name => "Bad Homburg v d Höhe", :area_code => "6172") + AreaCode.create(:country => germany, :name => "Kronberg im Taunus", :area_code => "6173") + AreaCode.create(:country => germany, :name => "Königstein im Taunus", :area_code => "6174") + AreaCode.create(:country => germany, :name => "Friedrichsdorf Taunus", :area_code => "6175") + AreaCode.create(:country => germany, :name => "Hanau", :area_code => "6181") + AreaCode.create(:country => germany, :name => "Seligenstadt", :area_code => "6182") + AreaCode.create(:country => germany, :name => "Erlensee", :area_code => "6183") + AreaCode.create(:country => germany, :name => "Langenselbold", :area_code => "6184") + AreaCode.create(:country => germany, :name => "Hammersbach Hess", :area_code => "6185") + AreaCode.create(:country => germany, :name => "Grosskrotzenburg", :area_code => "6186") + AreaCode.create(:country => germany, :name => "Schöneck", :area_code => "6187") + AreaCode.create(:country => germany, :name => "Kahl a Main", :area_code => "6188") + AreaCode.create(:country => germany, :name => "Hattersheim a Main", :area_code => "6190") + AreaCode.create(:country => germany, :name => "Hofheim am Taunus", :area_code => "6192") + AreaCode.create(:country => germany, :name => "Kelkheim Taunus", :area_code => "6195") + AreaCode.create(:country => germany, :name => "Bad Soden am Taunus", :area_code => "6196") + AreaCode.create(:country => germany, :name => "Eppstein", :area_code => "6198") + AreaCode.create(:country => germany, :name => "Weinheim Bergstr", :area_code => "6201") + AreaCode.create(:country => germany, :name => "Schwetzingen", :area_code => "6202") + AreaCode.create(:country => germany, :name => "Ladenburg", :area_code => "6203") + AreaCode.create(:country => germany, :name => "Viernheim", :area_code => "6204") + AreaCode.create(:country => germany, :name => "Hockenheim", :area_code => "6205") + AreaCode.create(:country => germany, :name => "Lampertheim", :area_code => "6206") + AreaCode.create(:country => germany, :name => "Wald-Michelbach", :area_code => "6207") + AreaCode.create(:country => germany, :name => "Mörlenbach", :area_code => "6209") + AreaCode.create(:country => germany, :name => "Mannheim", :area_code => "621") + AreaCode.create(:country => germany, :name => "Wilhelmsfeld", :area_code => "6220") + AreaCode.create(:country => germany, :name => "Heidelberg", :area_code => "6221") + AreaCode.create(:country => germany, :name => "Wiesloch", :area_code => "6222") + AreaCode.create(:country => germany, :name => "Neckargemünd", :area_code => "6223") + AreaCode.create(:country => germany, :name => "Sandhausen Baden", :area_code => "6224") + AreaCode.create(:country => germany, :name => "Meckesheim", :area_code => "6226") + AreaCode.create(:country => germany, :name => "Walldorf Baden", :area_code => "6227") + AreaCode.create(:country => germany, :name => "Schönau Odenw", :area_code => "6228") + AreaCode.create(:country => germany, :name => "Neckarsteinach", :area_code => "6229") + AreaCode.create(:country => germany, :name => "Hochdorf-Assenheim", :area_code => "6231") + AreaCode.create(:country => germany, :name => "Speyer", :area_code => "6232") + AreaCode.create(:country => germany, :name => "Frankenthal Pfalz", :area_code => "6233") + AreaCode.create(:country => germany, :name => "Mutterstadt", :area_code => "6234") + AreaCode.create(:country => germany, :name => "Schifferstadt", :area_code => "6235") + AreaCode.create(:country => germany, :name => "Neuhofen Pfalz", :area_code => "6236") + AreaCode.create(:country => germany, :name => "Maxdorf", :area_code => "6237") + AreaCode.create(:country => germany, :name => "Dirmstein", :area_code => "6238") + AreaCode.create(:country => germany, :name => "Bobenheim-Roxheim", :area_code => "6239") + AreaCode.create(:country => germany, :name => "Worms", :area_code => "6241") + AreaCode.create(:country => germany, :name => "Osthofen", :area_code => "6242") + AreaCode.create(:country => germany, :name => "Monsheim", :area_code => "6243") + AreaCode.create(:country => germany, :name => "Westhofen Rheinhess", :area_code => "6244") + AreaCode.create(:country => germany, :name => "Biblis", :area_code => "6245") + AreaCode.create(:country => germany, :name => "Eich Rheinhess", :area_code => "6246") + AreaCode.create(:country => germany, :name => "Worms-Pfeddersheim", :area_code => "6247") + AreaCode.create(:country => germany, :name => "Guntersblum", :area_code => "6249") + AreaCode.create(:country => germany, :name => "Bensheim", :area_code => "6251") + AreaCode.create(:country => germany, :name => "Heppenheim Bergstraße", :area_code => "6252") + AreaCode.create(:country => germany, :name => "Fürth Odenw", :area_code => "6253") + AreaCode.create(:country => germany, :name => "Lautertal Odenwald", :area_code => "6254") + AreaCode.create(:country => germany, :name => "Lindenfels", :area_code => "6255") + AreaCode.create(:country => germany, :name => "Lampertheim-Hüttenfeld", :area_code => "6256") + AreaCode.create(:country => germany, :name => "Seeheim-Jugenheim", :area_code => "6257") + AreaCode.create(:country => germany, :name => "Gernsheim", :area_code => "6258") + AreaCode.create(:country => germany, :name => "Mosbach Baden", :area_code => "6261") + AreaCode.create(:country => germany, :name => "Aglasterhausen", :area_code => "6262") + AreaCode.create(:country => germany, :name => "Neckargerach", :area_code => "6263") + AreaCode.create(:country => germany, :name => "Neudenau", :area_code => "6264") + AreaCode.create(:country => germany, :name => "Billigheim Baden", :area_code => "6265") + AreaCode.create(:country => germany, :name => "Hassmersheim", :area_code => "6266") + AreaCode.create(:country => germany, :name => "Fahrenbach Baden", :area_code => "6267") + AreaCode.create(:country => germany, :name => "Hüffenhardt", :area_code => "6268") + AreaCode.create(:country => germany, :name => "Gundelsheim Württ", :area_code => "6269") + AreaCode.create(:country => germany, :name => "Eberbach Baden", :area_code => "6271") + AreaCode.create(:country => germany, :name => "Hirschhorn Neckar", :area_code => "6272") + AreaCode.create(:country => germany, :name => "Waldbrunn Odenw", :area_code => "6274") + AreaCode.create(:country => germany, :name => "Rothenberg Odenw", :area_code => "6275") + AreaCode.create(:country => germany, :name => "Hesseneck", :area_code => "6276") + AreaCode.create(:country => germany, :name => "Buchen Odenwald", :area_code => "6281") + AreaCode.create(:country => germany, :name => "Walldürn", :area_code => "6282") + AreaCode.create(:country => germany, :name => "Hardheim Odenw", :area_code => "6283") + AreaCode.create(:country => germany, :name => "Mudau", :area_code => "6284") + AreaCode.create(:country => germany, :name => "Walldürn-Altheim", :area_code => "6285") + AreaCode.create(:country => germany, :name => "Walldürn-Rippberg", :area_code => "6286") + AreaCode.create(:country => germany, :name => "Limbach Baden", :area_code => "6287") + AreaCode.create(:country => germany, :name => "Adelsheim", :area_code => "6291") + AreaCode.create(:country => germany, :name => "Seckach", :area_code => "6292") + AreaCode.create(:country => germany, :name => "Schefflenz", :area_code => "6293") + AreaCode.create(:country => germany, :name => "Krautheim Jagst", :area_code => "6294") + AreaCode.create(:country => germany, :name => "RosenbergBaden", :area_code => "6295") + AreaCode.create(:country => germany, :name => "Ahorn Baden", :area_code => "6296") + AreaCode.create(:country => germany, :name => "Ravenstein Baden", :area_code => "6297") + AreaCode.create(:country => germany, :name => "Möckmühl", :area_code => "6298") + AreaCode.create(:country => germany, :name => "Otterbach Pfalz", :area_code => "6301") + AreaCode.create(:country => germany, :name => "Winnweiler", :area_code => "6302") + AreaCode.create(:country => germany, :name => "Enkenbach-Alsenborn", :area_code => "6303") + AreaCode.create(:country => germany, :name => "Wolfstein Pfalz", :area_code => "6304") + AreaCode.create(:country => germany, :name => "Hochspeyer", :area_code => "6305") + AreaCode.create(:country => germany, :name => "Trippstadt", :area_code => "6306") + AreaCode.create(:country => germany, :name => "Schopp", :area_code => "6307") + AreaCode.create(:country => germany, :name => "Olsbrücken", :area_code => "6308") + AreaCode.create(:country => germany, :name => "Kaiserslautern", :area_code => "631") + AreaCode.create(:country => germany, :name => "Neustadt an der Weinstraße", :area_code => "6321") + AreaCode.create(:country => germany, :name => "Bad Dürkheim", :area_code => "6322") + AreaCode.create(:country => germany, :name => "Edenkoben", :area_code => "6323") + AreaCode.create(:country => germany, :name => "Hassloch", :area_code => "6324") + AreaCode.create(:country => germany, :name => "Lambrecht Pfalz", :area_code => "6325") + AreaCode.create(:country => germany, :name => "Deidesheim", :area_code => "6326") + AreaCode.create(:country => germany, :name => "Neustadt-Lachen", :area_code => "6327") + AreaCode.create(:country => germany, :name => "Elmstein", :area_code => "6328") + AreaCode.create(:country => germany, :name => "Weidenthal Pfalz", :area_code => "6329") + AreaCode.create(:country => germany, :name => "Pirmasens", :area_code => "6331") + AreaCode.create(:country => germany, :name => "Zweibrücken", :area_code => "6332") + AreaCode.create(:country => germany, :name => "Waldfischbach-Burgalben", :area_code => "6333") + AreaCode.create(:country => germany, :name => "Thaleischweiler-Fröschen", :area_code => "6334") + AreaCode.create(:country => germany, :name => "Trulben", :area_code => "6335") + AreaCode.create(:country => germany, :name => "Dellfeld", :area_code => "6336") + AreaCode.create(:country => germany, :name => "Grossbundenbach", :area_code => "6337") + AreaCode.create(:country => germany, :name => "Hornbach Pfalz", :area_code => "6338") + AreaCode.create(:country => germany, :name => "Grosssteinhausen", :area_code => "6339") + AreaCode.create(:country => germany, :name => "Wörth-Schaidt", :area_code => "6340") + AreaCode.create(:country => germany, :name => "Landau in der Pfalz", :area_code => "6341") + AreaCode.create(:country => germany, :name => "Schweigen-Rechtenbach", :area_code => "6342") + AreaCode.create(:country => germany, :name => "Bad Bergzabern", :area_code => "6343") + AreaCode.create(:country => germany, :name => "Schwegenheim", :area_code => "6344") + AreaCode.create(:country => germany, :name => "Albersweiler", :area_code => "6345") + AreaCode.create(:country => germany, :name => "Annweiler am Trifels", :area_code => "6346") + AreaCode.create(:country => germany, :name => "Hochstadt Pfalz", :area_code => "6347") + AreaCode.create(:country => germany, :name => "Offenbach an der Queich", :area_code => "6348") + AreaCode.create(:country => germany, :name => "Billigheim-Ingenheim", :area_code => "6349") + AreaCode.create(:country => germany, :name => "Eisenberg Pfalz", :area_code => "6351") + AreaCode.create(:country => germany, :name => "Kirchheimbolanden", :area_code => "6352") + AreaCode.create(:country => germany, :name => "Freinsheim", :area_code => "6353") + AreaCode.create(:country => germany, :name => "Albisheim Pfrimm", :area_code => "6355") + AreaCode.create(:country => germany, :name => "Carlsberg Pfalz", :area_code => "6356") + AreaCode.create(:country => germany, :name => "Standenbühl", :area_code => "6357") + AreaCode.create(:country => germany, :name => "Kriegsfeld", :area_code => "6358") + AreaCode.create(:country => germany, :name => "Grünstadt", :area_code => "6359") + AreaCode.create(:country => germany, :name => "Rockenhausen", :area_code => "6361") + AreaCode.create(:country => germany, :name => "Alsenz", :area_code => "6362") + AreaCode.create(:country => germany, :name => "Niederkirchen", :area_code => "6363") + AreaCode.create(:country => germany, :name => "Nußbach Pfalz", :area_code => "6364") + AreaCode.create(:country => germany, :name => "Landstuhl", :area_code => "6371") + AreaCode.create(:country => germany, :name => "Bruchmühlbach-Miesau", :area_code => "6372") + AreaCode.create(:country => germany, :name => "Schönenberg-Kübelberg", :area_code => "6373") + AreaCode.create(:country => germany, :name => "Weilerbach", :area_code => "6374") + AreaCode.create(:country => germany, :name => "Wallhalben", :area_code => "6375") + AreaCode.create(:country => germany, :name => "Kusel", :area_code => "6381") + AreaCode.create(:country => germany, :name => "Lauterecken", :area_code => "6382") + AreaCode.create(:country => germany, :name => "Glan-Münchweiler", :area_code => "6383") + AreaCode.create(:country => germany, :name => "Konken", :area_code => "6384") + AreaCode.create(:country => germany, :name => "Reichenbach-Steegen", :area_code => "6385") + AreaCode.create(:country => germany, :name => "Altenkirchen Pfalz", :area_code => "6386") + AreaCode.create(:country => germany, :name => "Sankt Julian", :area_code => "6387") + AreaCode.create(:country => germany, :name => "Dahn", :area_code => "6391") + AreaCode.create(:country => germany, :name => "Hauenstein Pfalz", :area_code => "6392") + AreaCode.create(:country => germany, :name => "Fischbach bei Dahn", :area_code => "6393") + AreaCode.create(:country => germany, :name => "Bundenthal", :area_code => "6394") + AreaCode.create(:country => germany, :name => "Münchweiler an der Rodalb", :area_code => "6395") + AreaCode.create(:country => germany, :name => "Hinterweidenthal", :area_code => "6396") + AreaCode.create(:country => germany, :name => "Leimen Pfalz", :area_code => "6397") + AreaCode.create(:country => germany, :name => "Vorderweidenthal", :area_code => "6398") + AreaCode.create(:country => germany, :name => "Mücke", :area_code => "6400") + AreaCode.create(:country => germany, :name => "Grünberg Hess", :area_code => "6401") + AreaCode.create(:country => germany, :name => "Hungen", :area_code => "6402") + AreaCode.create(:country => germany, :name => "Linden Hess", :area_code => "6403") + AreaCode.create(:country => germany, :name => "Lich Hess", :area_code => "6404") + AreaCode.create(:country => germany, :name => "Laubach Hess", :area_code => "6405") + AreaCode.create(:country => germany, :name => "Lollar", :area_code => "6406") + AreaCode.create(:country => germany, :name => "Rabenau Hess", :area_code => "6407") + AreaCode.create(:country => germany, :name => "Buseck", :area_code => "6408") + AreaCode.create(:country => germany, :name => "Biebertal", :area_code => "6409") + AreaCode.create(:country => germany, :name => "Giessen", :area_code => "641") + AreaCode.create(:country => germany, :name => "Lahntal", :area_code => "6420") + AreaCode.create(:country => germany, :name => "Marburg", :area_code => "6421") + AreaCode.create(:country => germany, :name => "Kirchhain", :area_code => "6422") + AreaCode.create(:country => germany, :name => "Wetter Hessen", :area_code => "6423") + AreaCode.create(:country => germany, :name => "Ebsdorfergrund", :area_code => "6424") + AreaCode.create(:country => germany, :name => "Rauschenberg Hess", :area_code => "6425") + AreaCode.create(:country => germany, :name => "Fronhausen", :area_code => "6426") + AreaCode.create(:country => germany, :name => "Cölbe-Schönstadt", :area_code => "6427") + AreaCode.create(:country => germany, :name => "Stadtallendorf", :area_code => "6428") + AreaCode.create(:country => germany, :name => "Schweinsberg Hess", :area_code => "6429") + AreaCode.create(:country => germany, :name => "Hahnstätten", :area_code => "6430") + AreaCode.create(:country => germany, :name => "Limburg a d Lahn", :area_code => "6431") + AreaCode.create(:country => germany, :name => "Diez", :area_code => "6432") + AreaCode.create(:country => germany, :name => "Hadamar", :area_code => "6433") + AreaCode.create(:country => germany, :name => "Bad Camberg", :area_code => "6434") + AreaCode.create(:country => germany, :name => "Wallmerod", :area_code => "6435") + AreaCode.create(:country => germany, :name => "Dornburg Hess", :area_code => "6436") + AreaCode.create(:country => germany, :name => "Hünfelden", :area_code => "6438") + AreaCode.create(:country => germany, :name => "Holzappel", :area_code => "6439") + AreaCode.create(:country => germany, :name => "Kölschhausen", :area_code => "6440") + AreaCode.create(:country => germany, :name => "Wetzlar", :area_code => "6441") + AreaCode.create(:country => germany, :name => "Braunfels", :area_code => "6442") + AreaCode.create(:country => germany, :name => "Ehringshausen Dill", :area_code => "6443") + AreaCode.create(:country => germany, :name => "Bischoffen", :area_code => "6444") + AreaCode.create(:country => germany, :name => "Schöffengrund", :area_code => "6445") + AreaCode.create(:country => germany, :name => "Hohenahr", :area_code => "6446") + AreaCode.create(:country => germany, :name => "Langgöns-Niederkleen", :area_code => "6447") + AreaCode.create(:country => germany, :name => "Ehringshausen-Katzenfurt", :area_code => "6449") + AreaCode.create(:country => germany, :name => "Frankenberg Eder", :area_code => "6451") + AreaCode.create(:country => germany, :name => "Battenberg Eder", :area_code => "6452") + AreaCode.create(:country => germany, :name => "Gemünden Wohra", :area_code => "6453") + AreaCode.create(:country => germany, :name => "Lichtenfels-Sachsenberg", :area_code => "6454") + AreaCode.create(:country => germany, :name => "Frankenau Hess", :area_code => "6455") + AreaCode.create(:country => germany, :name => "Haina Kloster", :area_code => "6456") + AreaCode.create(:country => germany, :name => "Burgwald Eder", :area_code => "6457") + AreaCode.create(:country => germany, :name => "Rosenthal Hess", :area_code => "6458") + AreaCode.create(:country => germany, :name => "Biedenkopf", :area_code => "6461") + AreaCode.create(:country => germany, :name => "Gladenbach", :area_code => "6462") + AreaCode.create(:country => germany, :name => "Angelburg", :area_code => "6464") + AreaCode.create(:country => germany, :name => "Breidenbach b Biedenkopf", :area_code => "6465") + AreaCode.create(:country => germany, :name => "Dautphetal-Friedensdorf", :area_code => "6466") + AreaCode.create(:country => germany, :name => "Hatzfeld Eder", :area_code => "6467") + AreaCode.create(:country => germany, :name => "Dautphetal-Mornshausen", :area_code => "6468") + AreaCode.create(:country => germany, :name => "Weilburg", :area_code => "6471") + AreaCode.create(:country => germany, :name => "Weilmünster", :area_code => "6472") + AreaCode.create(:country => germany, :name => "Leun", :area_code => "6473") + AreaCode.create(:country => germany, :name => "Villmar-Aumenau", :area_code => "6474") + AreaCode.create(:country => germany, :name => "Weilmünster-Wolfenhausen", :area_code => "6475") + AreaCode.create(:country => germany, :name => "Mengerskirchen", :area_code => "6476") + AreaCode.create(:country => germany, :name => "Greifenstein-Nenderoth", :area_code => "6477") + AreaCode.create(:country => germany, :name => "Greifenstein-Ulm", :area_code => "6478") + AreaCode.create(:country => germany, :name => "Waldbrunn Westerwald", :area_code => "6479") + AreaCode.create(:country => germany, :name => "Runkel", :area_code => "6482") + AreaCode.create(:country => germany, :name => "Selters Taunus", :area_code => "6483") + AreaCode.create(:country => germany, :name => "Beselich", :area_code => "6484") + AreaCode.create(:country => germany, :name => "Nentershausen Westerw", :area_code => "6485") + AreaCode.create(:country => germany, :name => "Katzenelnbogen", :area_code => "6486") + AreaCode.create(:country => germany, :name => "Waldrach", :area_code => "6500") + AreaCode.create(:country => germany, :name => "Konz", :area_code => "6501") + AreaCode.create(:country => germany, :name => "Schweich", :area_code => "6502") + AreaCode.create(:country => germany, :name => "Hermeskeil", :area_code => "6503") + AreaCode.create(:country => germany, :name => "Thalfang", :area_code => "6504") + AreaCode.create(:country => germany, :name => "Kordel", :area_code => "6505") + AreaCode.create(:country => germany, :name => "Welschbillig", :area_code => "6506") + AreaCode.create(:country => germany, :name => "Neumagen-Dhron", :area_code => "6507") + AreaCode.create(:country => germany, :name => "Hetzerath Mosel", :area_code => "6508") + AreaCode.create(:country => germany, :name => "Büdlich", :area_code => "6509") + AreaCode.create(:country => germany, :name => "Trier", :area_code => "651") + AreaCode.create(:country => germany, :name => "Mettendorf", :area_code => "6522") + AreaCode.create(:country => germany, :name => "Holsthum", :area_code => "6523") + AreaCode.create(:country => germany, :name => "Rodershausen", :area_code => "6524") + AreaCode.create(:country => germany, :name => "Irrel", :area_code => "6525") + AreaCode.create(:country => germany, :name => "Bollendorf", :area_code => "6526") + AreaCode.create(:country => germany, :name => "Oberweis", :area_code => "6527") + AreaCode.create(:country => germany, :name => "Bernkastel-Kues", :area_code => "6531") + AreaCode.create(:country => germany, :name => "Zeltingen-Rachtig", :area_code => "6532") + AreaCode.create(:country => germany, :name => "Morbach Hunsrück", :area_code => "6533") + AreaCode.create(:country => germany, :name => "Mülheim Mosel", :area_code => "6534") + AreaCode.create(:country => germany, :name => "Osann-Monzel", :area_code => "6535") + AreaCode.create(:country => germany, :name => "Kleinich", :area_code => "6536") + AreaCode.create(:country => germany, :name => "Traben-Trarbach", :area_code => "6541") + AreaCode.create(:country => germany, :name => "Bullay", :area_code => "6542") + AreaCode.create(:country => germany, :name => "Büchenbeuren", :area_code => "6543") + AreaCode.create(:country => germany, :name => "Rhaunen", :area_code => "6544") + AreaCode.create(:country => germany, :name => "Blankenrath", :area_code => "6545") + AreaCode.create(:country => germany, :name => "Irrhausen", :area_code => "6550") + AreaCode.create(:country => germany, :name => "Prüm", :area_code => "6551") + AreaCode.create(:country => germany, :name => "Olzheim", :area_code => "6552") + AreaCode.create(:country => germany, :name => "Schönecken", :area_code => "6553") + AreaCode.create(:country => germany, :name => "Waxweiler", :area_code => "6554") + AreaCode.create(:country => germany, :name => "Bleialf", :area_code => "6555") + AreaCode.create(:country => germany, :name => "Pronsfeld", :area_code => "6556") + AreaCode.create(:country => germany, :name => "Hallschlag", :area_code => "6557") + AreaCode.create(:country => germany, :name => "Büdesheim Eifel", :area_code => "6558") + AreaCode.create(:country => germany, :name => "Leidenborn", :area_code => "6559") + AreaCode.create(:country => germany, :name => "Bitburg", :area_code => "6561") + AreaCode.create(:country => germany, :name => "Speicher", :area_code => "6562") + AreaCode.create(:country => germany, :name => "Kyllburg", :area_code => "6563") + AreaCode.create(:country => germany, :name => "Neuerburg Eifel", :area_code => "6564") + AreaCode.create(:country => germany, :name => "Dudeldorf", :area_code => "6565") + AreaCode.create(:country => germany, :name => "Körperich", :area_code => "6566") + AreaCode.create(:country => germany, :name => "Oberkail", :area_code => "6567") + AreaCode.create(:country => germany, :name => "Wolsfeld", :area_code => "6568") + AreaCode.create(:country => germany, :name => "Bickendorf", :area_code => "6569") + AreaCode.create(:country => germany, :name => "Wittlich", :area_code => "6571") + AreaCode.create(:country => germany, :name => "Manderscheid Eifel", :area_code => "6572") + AreaCode.create(:country => germany, :name => "Gillenfeld", :area_code => "6573") + AreaCode.create(:country => germany, :name => "Hasborn", :area_code => "6574") + AreaCode.create(:country => germany, :name => "Landscheid", :area_code => "6575") + AreaCode.create(:country => germany, :name => "Salmtal", :area_code => "6578") + AreaCode.create(:country => germany, :name => "Zemmer", :area_code => "6580") + AreaCode.create(:country => germany, :name => "Saarburg", :area_code => "6581") + AreaCode.create(:country => germany, :name => "Freudenburg", :area_code => "6582") + AreaCode.create(:country => germany, :name => "Palzem", :area_code => "6583") + AreaCode.create(:country => germany, :name => "Wellen Mosel", :area_code => "6584") + AreaCode.create(:country => germany, :name => "Ralingen", :area_code => "6585") + AreaCode.create(:country => germany, :name => "Beuren Hochwald", :area_code => "6586") + AreaCode.create(:country => germany, :name => "Zerf", :area_code => "6587") + AreaCode.create(:country => germany, :name => "Pluwig", :area_code => "6588") + AreaCode.create(:country => germany, :name => "Kell am See", :area_code => "6589") + AreaCode.create(:country => germany, :name => "Gerolstein", :area_code => "6591") + AreaCode.create(:country => germany, :name => "Daun", :area_code => "6592") + AreaCode.create(:country => germany, :name => "Hillesheim Eifel", :area_code => "6593") + AreaCode.create(:country => germany, :name => "Birresborn", :area_code => "6594") + AreaCode.create(:country => germany, :name => "Dockweiler", :area_code => "6595") + AreaCode.create(:country => germany, :name => "Üdersdorf", :area_code => "6596") + AreaCode.create(:country => germany, :name => "Jünkerath", :area_code => "6597") + AreaCode.create(:country => germany, :name => "Weidenbach b Gerolstein", :area_code => "6599") + AreaCode.create(:country => germany, :name => "Fulda", :area_code => "661") + AreaCode.create(:country => germany, :name => "Philippsthal Werra", :area_code => "6620") + AreaCode.create(:country => germany, :name => "Bad Hersfeld", :area_code => "6621") + AreaCode.create(:country => germany, :name => "Bebra", :area_code => "6622") + AreaCode.create(:country => germany, :name => "Rotenburg a d Fulda", :area_code => "6623") + AreaCode.create(:country => germany, :name => "Heringen Werra", :area_code => "6624") + AreaCode.create(:country => germany, :name => "Niederaula", :area_code => "6625") + AreaCode.create(:country => germany, :name => "Wildeck-Obersuhl", :area_code => "6626") + AreaCode.create(:country => germany, :name => "Nentershausen Hess", :area_code => "6627") + AreaCode.create(:country => germany, :name => "Oberaula", :area_code => "6628") + AreaCode.create(:country => germany, :name => "Schenklengsfeld", :area_code => "6629") + AreaCode.create(:country => germany, :name => "Schwalmtal-Storndorf", :area_code => "6630") + AreaCode.create(:country => germany, :name => "Alsfeld", :area_code => "6631") + AreaCode.create(:country => germany, :name => "Homberg Ohm", :area_code => "6633") + AreaCode.create(:country => germany, :name => "Gemünden Felda", :area_code => "6634") + AreaCode.create(:country => germany, :name => "Kirtorf", :area_code => "6635") + AreaCode.create(:country => germany, :name => "Romrod", :area_code => "6636") + AreaCode.create(:country => germany, :name => "Feldatal", :area_code => "6637") + AreaCode.create(:country => germany, :name => "Schwalmtal-Renzendorf", :area_code => "6638") + AreaCode.create(:country => germany, :name => "Ottrau", :area_code => "6639") + AreaCode.create(:country => germany, :name => "Lauterbach Hessen", :area_code => "6641") + AreaCode.create(:country => germany, :name => "Schlitz", :area_code => "6642") + AreaCode.create(:country => germany, :name => "Herbstein", :area_code => "6643") + AreaCode.create(:country => germany, :name => "Grebenhain", :area_code => "6644") + AreaCode.create(:country => germany, :name => "Ulrichstein", :area_code => "6645") + AreaCode.create(:country => germany, :name => "Grebenau", :area_code => "6646") + AreaCode.create(:country => germany, :name => "Herbstein-Stockhausen", :area_code => "6647") + AreaCode.create(:country => germany, :name => "Bad Salzschlirf", :area_code => "6648") + AreaCode.create(:country => germany, :name => "Hosenfeld", :area_code => "6650") + AreaCode.create(:country => germany, :name => "Rasdorf", :area_code => "6651") + AreaCode.create(:country => germany, :name => "Hünfeld", :area_code => "6652") + AreaCode.create(:country => germany, :name => "Burghaun", :area_code => "6653") + AreaCode.create(:country => germany, :name => "Gersfeld Rhön", :area_code => "6654") + AreaCode.create(:country => germany, :name => "Neuhof Kr Fulda", :area_code => "6655") + AreaCode.create(:country => germany, :name => "Ebersburg", :area_code => "6656") + AreaCode.create(:country => germany, :name => "Hofbieber", :area_code => "6657") + AreaCode.create(:country => germany, :name => "Poppenhausen Wasserkuppe", :area_code => "6658") + AreaCode.create(:country => germany, :name => "Eichenzell", :area_code => "6659") + AreaCode.create(:country => germany, :name => "Steinau-Marjoss", :area_code => "6660") + AreaCode.create(:country => germany, :name => "Schlüchtern", :area_code => "6661") + AreaCode.create(:country => germany, :name => "Steinau an der Straße", :area_code => "6663") + AreaCode.create(:country => germany, :name => "Sinntal-Sterbfritz", :area_code => "6664") + AreaCode.create(:country => germany, :name => "Sinntal-Altengronau", :area_code => "6665") + AreaCode.create(:country => germany, :name => "Freiensteinau", :area_code => "6666") + AreaCode.create(:country => germany, :name => "Steinau-Ulmbach", :area_code => "6667") + AreaCode.create(:country => germany, :name => "Birstein-Lichenroth", :area_code => "6668") + AreaCode.create(:country => germany, :name => "Neuhof-Hauswurz", :area_code => "6669") + AreaCode.create(:country => germany, :name => "Ludwigsau Hess", :area_code => "6670") + AreaCode.create(:country => germany, :name => "Eiterfeld", :area_code => "6672") + AreaCode.create(:country => germany, :name => "Haunetal", :area_code => "6673") + AreaCode.create(:country => germany, :name => "Friedewald Hess", :area_code => "6674") + AreaCode.create(:country => germany, :name => "Breitenbach a Herzberg", :area_code => "6675") + AreaCode.create(:country => germany, :name => "Hohenroda Hess", :area_code => "6676") + AreaCode.create(:country => germany, :name => "Neuenstein Hess", :area_code => "6677") + AreaCode.create(:country => germany, :name => "Wildeck-Hönebach", :area_code => "6678") + AreaCode.create(:country => germany, :name => "Hilders", :area_code => "6681") + AreaCode.create(:country => germany, :name => "Tann Rhön", :area_code => "6682") + AreaCode.create(:country => germany, :name => "Ehrenberg Rhön", :area_code => "6683") + AreaCode.create(:country => germany, :name => "Hofbieber-Schwarzbach", :area_code => "6684") + AreaCode.create(:country => germany, :name => "Schwalmstadt", :area_code => "6691") + AreaCode.create(:country => germany, :name => "Neustadt Hessen", :area_code => "6692") + AreaCode.create(:country => germany, :name => "Neuental", :area_code => "6693") + AreaCode.create(:country => germany, :name => "Neukirchen Knüll", :area_code => "6694") + AreaCode.create(:country => germany, :name => "Jesberg", :area_code => "6695") + AreaCode.create(:country => germany, :name => "Gilserberg", :area_code => "6696") + AreaCode.create(:country => germany, :name => "Willingshausen", :area_code => "6697") + AreaCode.create(:country => germany, :name => "Schrecksbach", :area_code => "6698") + AreaCode.create(:country => germany, :name => "Sprendlingen Rheinhess", :area_code => "6701") + AreaCode.create(:country => germany, :name => "Wöllstein Rheinhess", :area_code => "6703") + AreaCode.create(:country => germany, :name => "Langenlonsheim", :area_code => "6704") + AreaCode.create(:country => germany, :name => "Wallhausen Nahe", :area_code => "6706") + AreaCode.create(:country => germany, :name => "Windesheim", :area_code => "6707") + AreaCode.create(:country => germany, :name => "Bad Münster am Stein-Ebernburg", :area_code => "6708") + AreaCode.create(:country => germany, :name => "Fürfeld Kr Bad Kreuznach", :area_code => "6709") + AreaCode.create(:country => germany, :name => "Bad Kreuznach", :area_code => "671") + AreaCode.create(:country => germany, :name => "Bingen am Rhein", :area_code => "6721") + AreaCode.create(:country => germany, :name => "Rüdesheim am Rhein", :area_code => "6722") + AreaCode.create(:country => germany, :name => "Oestrich-Winkel", :area_code => "6723") + AreaCode.create(:country => germany, :name => "Stromberg Hunsrück", :area_code => "6724") + AreaCode.create(:country => germany, :name => "Gau-Algesheim", :area_code => "6725") + AreaCode.create(:country => germany, :name => "Lorch Rheingau", :area_code => "6726") + AreaCode.create(:country => germany, :name => "Gensingen", :area_code => "6727") + AreaCode.create(:country => germany, :name => "Ober-Hilbersheim", :area_code => "6728") + AreaCode.create(:country => germany, :name => "Alzey", :area_code => "6731") + AreaCode.create(:country => germany, :name => "Wörrstadt", :area_code => "6732") + AreaCode.create(:country => germany, :name => "Gau-Odernheim", :area_code => "6733") + AreaCode.create(:country => germany, :name => "Flonheim", :area_code => "6734") + AreaCode.create(:country => germany, :name => "Eppelsheim", :area_code => "6735") + AreaCode.create(:country => germany, :name => "Bechenheim", :area_code => "6736") + AreaCode.create(:country => germany, :name => "Köngernheim", :area_code => "6737") + AreaCode.create(:country => germany, :name => "St Goar", :area_code => "6741") + AreaCode.create(:country => germany, :name => "Boppard", :area_code => "6742") + AreaCode.create(:country => germany, :name => "Bacharach", :area_code => "6743") + AreaCode.create(:country => germany, :name => "Oberwesel", :area_code => "6744") + AreaCode.create(:country => germany, :name => "Gondershausen", :area_code => "6745") + AreaCode.create(:country => germany, :name => "Pfalzfeld", :area_code => "6746") + AreaCode.create(:country => germany, :name => "Emmelshausen", :area_code => "6747") + AreaCode.create(:country => germany, :name => "Bad Sobernheim", :area_code => "6751") + AreaCode.create(:country => germany, :name => "Kirn Nahe", :area_code => "6752") + AreaCode.create(:country => germany, :name => "Meisenheim", :area_code => "6753") + AreaCode.create(:country => germany, :name => "Martinstein", :area_code => "6754") + AreaCode.create(:country => germany, :name => "Odernheim am Glan", :area_code => "6755") + AreaCode.create(:country => germany, :name => "Winterbach Soonwald", :area_code => "6756") + AreaCode.create(:country => germany, :name => "Becherbach bei Kirn", :area_code => "6757") + AreaCode.create(:country => germany, :name => "Waldböckelheim", :area_code => "6758") + AreaCode.create(:country => germany, :name => "Simmern Hunsrück", :area_code => "6761") + AreaCode.create(:country => germany, :name => "Kastellaun", :area_code => "6762") + AreaCode.create(:country => germany, :name => "Kirchberg Hunsrück", :area_code => "6763") + AreaCode.create(:country => germany, :name => "Rheinböllen", :area_code => "6764") + AreaCode.create(:country => germany, :name => "Gemünden Hunsrück", :area_code => "6765") + AreaCode.create(:country => germany, :name => "Kisselbach", :area_code => "6766") + AreaCode.create(:country => germany, :name => "St Goarshausen", :area_code => "6771") + AreaCode.create(:country => germany, :name => "Nastätten", :area_code => "6772") + AreaCode.create(:country => germany, :name => "Kamp-Bornhofen", :area_code => "6773") + AreaCode.create(:country => germany, :name => "Kaub", :area_code => "6774") + AreaCode.create(:country => germany, :name => "Strüth Taunus", :area_code => "6775") + AreaCode.create(:country => germany, :name => "Dachsenhausen", :area_code => "6776") + AreaCode.create(:country => germany, :name => "Idar-Oberstein", :area_code => "6781") + AreaCode.create(:country => germany, :name => "Birkenfeld Nahe", :area_code => "6782") + AreaCode.create(:country => germany, :name => "Baumholder", :area_code => "6783") + AreaCode.create(:country => germany, :name => "Weierbach", :area_code => "6784") + AreaCode.create(:country => germany, :name => "Herrstein", :area_code => "6785") + AreaCode.create(:country => germany, :name => "Kempfeld", :area_code => "6786") + AreaCode.create(:country => germany, :name => "Niederbrombach", :area_code => "6787") + AreaCode.create(:country => germany, :name => "Sien", :area_code => "6788") + AreaCode.create(:country => germany, :name => "Heimbach Nahe", :area_code => "6789") + AreaCode.create(:country => germany, :name => "Völklingen-Lauterbach", :area_code => "6802") + AreaCode.create(:country => germany, :name => "Mandelbachtal-Ommersheim", :area_code => "6803") + AreaCode.create(:country => germany, :name => "Mandelbachtal", :area_code => "6804") + AreaCode.create(:country => germany, :name => "Kleinblittersdorf", :area_code => "6805") + AreaCode.create(:country => germany, :name => "Heusweiler", :area_code => "6806") + AreaCode.create(:country => germany, :name => "Grossrosseln", :area_code => "6809") + AreaCode.create(:country => germany, :name => "Saarbrücken", :area_code => "681") + AreaCode.create(:country => germany, :name => "Neunkirchen Saar", :area_code => "6821") + AreaCode.create(:country => germany, :name => "Ottweiler", :area_code => "6824") + AreaCode.create(:country => germany, :name => "Illingen Saar", :area_code => "6825") + AreaCode.create(:country => germany, :name => "Bexbach", :area_code => "6826") + AreaCode.create(:country => germany, :name => "Eppelborn", :area_code => "6827") + AreaCode.create(:country => germany, :name => "Saarlouis", :area_code => "6831") + AreaCode.create(:country => germany, :name => "Beckingen-Reimsbach", :area_code => "6832") + AreaCode.create(:country => germany, :name => "Rehlingen-Siersburg", :area_code => "6833") + AreaCode.create(:country => germany, :name => "Bous", :area_code => "6834") + AreaCode.create(:country => germany, :name => "Beckingen", :area_code => "6835") + AreaCode.create(:country => germany, :name => "Überherrn", :area_code => "6836") + AreaCode.create(:country => germany, :name => "Wallerfangen", :area_code => "6837") + AreaCode.create(:country => germany, :name => "Saarwellingen", :area_code => "6838") + AreaCode.create(:country => germany, :name => "Homburg Saar", :area_code => "6841") + AreaCode.create(:country => germany, :name => "Blieskastel", :area_code => "6842") + AreaCode.create(:country => germany, :name => "Gersheim", :area_code => "6843") + AreaCode.create(:country => germany, :name => "Blieskastel-Altheim", :area_code => "6844") + AreaCode.create(:country => germany, :name => "Homburg-Einöd", :area_code => "6848") + AreaCode.create(:country => germany, :name => "Kirkel", :area_code => "6849") + AreaCode.create(:country => germany, :name => "St Wendel", :area_code => "6851") + AreaCode.create(:country => germany, :name => "Nohfelden", :area_code => "6852") + AreaCode.create(:country => germany, :name => "Marpingen", :area_code => "6853") + AreaCode.create(:country => germany, :name => "Oberthal Saar", :area_code => "6854") + AreaCode.create(:country => germany, :name => "Freisen", :area_code => "6855") + AreaCode.create(:country => germany, :name => "St Wendel-Niederkirchen", :area_code => "6856") + AreaCode.create(:country => germany, :name => "Namborn", :area_code => "6857") + AreaCode.create(:country => germany, :name => "Ottweiler-Fürth", :area_code => "6858") + AreaCode.create(:country => germany, :name => "Merzig", :area_code => "6861") + AreaCode.create(:country => germany, :name => "Mettlach", :area_code => "6864") + AreaCode.create(:country => germany, :name => "Mettlach-Orscholz", :area_code => "6865") + AreaCode.create(:country => germany, :name => "Perl-Nennig", :area_code => "6866") + AreaCode.create(:country => germany, :name => "Perl", :area_code => "6867") + AreaCode.create(:country => germany, :name => "Mettlach-Tünsdorf", :area_code => "6868") + AreaCode.create(:country => germany, :name => "Merzig-Silwingen", :area_code => "6869") + AreaCode.create(:country => germany, :name => "Wadern", :area_code => "6871") + AreaCode.create(:country => germany, :name => "Losheim am See", :area_code => "6872") + AreaCode.create(:country => germany, :name => "Nonnweiler", :area_code => "6873") + AreaCode.create(:country => germany, :name => "Wadern-Nunkirchen", :area_code => "6874") + AreaCode.create(:country => germany, :name => "Nonnweiler-Primstal", :area_code => "6875") + AreaCode.create(:country => germany, :name => "Weiskirchen Saar", :area_code => "6876") + AreaCode.create(:country => germany, :name => "Lebach", :area_code => "6881") + AreaCode.create(:country => germany, :name => "Schmelz Saar", :area_code => "6887") + AreaCode.create(:country => germany, :name => "Lebach-Steinbach", :area_code => "6888") + AreaCode.create(:country => germany, :name => "Saarbrücken-Ensheim", :area_code => "6893") + AreaCode.create(:country => germany, :name => "St Ingbert", :area_code => "6894") + AreaCode.create(:country => germany, :name => "Sulzbach Saar", :area_code => "6897") + AreaCode.create(:country => germany, :name => "Völklingen", :area_code => "6898") + AreaCode.create(:country => germany, :name => "Frankfurt am Main", :area_code => "69") + AreaCode.create(:country => germany, :name => "Kirchheim unter Teck", :area_code => "7021") + AreaCode.create(:country => germany, :name => "Nürtingen", :area_code => "7022") + AreaCode.create(:country => germany, :name => "Weilheim an der Teck", :area_code => "7023") + AreaCode.create(:country => germany, :name => "Wendlingen am Neckar", :area_code => "7024") + AreaCode.create(:country => germany, :name => "Neuffen", :area_code => "7025") + AreaCode.create(:country => germany, :name => "Lenningen", :area_code => "7026") + AreaCode.create(:country => germany, :name => "Böblingen", :area_code => "7031") + AreaCode.create(:country => germany, :name => "Herrenberg", :area_code => "7032") + AreaCode.create(:country => germany, :name => "Weil Der Stadt", :area_code => "7033") + AreaCode.create(:country => germany, :name => "Ehningen", :area_code => "7034") + AreaCode.create(:country => germany, :name => "Mühlacker", :area_code => "7041") + AreaCode.create(:country => germany, :name => "Vaihingen an der Enz", :area_code => "7042") + AreaCode.create(:country => germany, :name => "Maulbronn", :area_code => "7043") + AreaCode.create(:country => germany, :name => "Mönsheim", :area_code => "7044") + AreaCode.create(:country => germany, :name => "Oberderdingen", :area_code => "7045") + AreaCode.create(:country => germany, :name => "Zaberfeld", :area_code => "7046") + AreaCode.create(:country => germany, :name => "Calw", :area_code => "7051") + AreaCode.create(:country => germany, :name => "Bad Liebenzell", :area_code => "7052") + AreaCode.create(:country => germany, :name => "Bad Teinach-Zavelstein", :area_code => "7053") + AreaCode.create(:country => germany, :name => "Wildberg Württ", :area_code => "7054") + AreaCode.create(:country => germany, :name => "Neuweiler Kr Calw", :area_code => "7055") + AreaCode.create(:country => germany, :name => "Gechingen", :area_code => "7056") + AreaCode.create(:country => germany, :name => "Beilstein Württ", :area_code => "7062") + AreaCode.create(:country => germany, :name => "Bad Wimpfen", :area_code => "7063") + AreaCode.create(:country => germany, :name => "Bad Rappenau-Bonfeld", :area_code => "7066") + AreaCode.create(:country => germany, :name => "Tübingen", :area_code => "7071") + AreaCode.create(:country => germany, :name => "Gomaringen", :area_code => "7072") + AreaCode.create(:country => germany, :name => "Ammerbuch", :area_code => "7073") + AreaCode.create(:country => germany, :name => "Bad Wildbad", :area_code => "7081") + AreaCode.create(:country => germany, :name => "Neuenbürg Württ", :area_code => "7082") + AreaCode.create(:country => germany, :name => "Bad Herrenalb", :area_code => "7083") + AreaCode.create(:country => germany, :name => "Schömberg b Neuenbürg", :area_code => "7084") + AreaCode.create(:country => germany, :name => "Enzklösterle", :area_code => "7085") + AreaCode.create(:country => germany, :name => "Stuttgart", :area_code => "711") + AreaCode.create(:country => germany, :name => "Reutlingen", :area_code => "7121") + AreaCode.create(:country => germany, :name => "St Johann Württ", :area_code => "7122") + AreaCode.create(:country => germany, :name => "Metzingen Württ", :area_code => "7123") + AreaCode.create(:country => germany, :name => "Trochtelfingen Hohenz", :area_code => "7124") + AreaCode.create(:country => germany, :name => "Bad Urach", :area_code => "7125") + AreaCode.create(:country => germany, :name => "Burladingen-Melchingen", :area_code => "7126") + AreaCode.create(:country => germany, :name => "Neckartenzlingen", :area_code => "7127") + AreaCode.create(:country => germany, :name => "Sonnenbühl", :area_code => "7128") + AreaCode.create(:country => germany, :name => "Lichtenstein Württ", :area_code => "7129") + AreaCode.create(:country => germany, :name => "Löwenstein Württ", :area_code => "7130") + AreaCode.create(:country => germany, :name => "Heilbronn Neckar", :area_code => "7131") + AreaCode.create(:country => germany, :name => "Neckarsulm", :area_code => "7132") + AreaCode.create(:country => germany, :name => "Lauffen am Neckar", :area_code => "7133") + AreaCode.create(:country => germany, :name => "Weinsberg", :area_code => "7134") + AreaCode.create(:country => germany, :name => "Brackenheim", :area_code => "7135") + AreaCode.create(:country => germany, :name => "Bad Friedrichshall", :area_code => "7136") + AreaCode.create(:country => germany, :name => "Schwaigern", :area_code => "7138") + AreaCode.create(:country => germany, :name => "Neuenstadt am Kocher", :area_code => "7139") + AreaCode.create(:country => germany, :name => "Ludwigsburg Württ", :area_code => "7141") + AreaCode.create(:country => germany, :name => "Bietigheim-Bissingen", :area_code => "7142") + AreaCode.create(:country => germany, :name => "Besigheim", :area_code => "7143") + AreaCode.create(:country => germany, :name => "Marbach am Neckar", :area_code => "7144") + AreaCode.create(:country => germany, :name => "Markgröningen", :area_code => "7145") + AreaCode.create(:country => germany, :name => "Remseck am Neckar", :area_code => "7146") + AreaCode.create(:country => germany, :name => "Sachsenheim Württ", :area_code => "7147") + AreaCode.create(:country => germany, :name => "Grossbottwar", :area_code => "7148") + AreaCode.create(:country => germany, :name => "Korntal-Münchingen", :area_code => "7150") + AreaCode.create(:country => germany, :name => "Waiblingen", :area_code => "7151") + AreaCode.create(:country => germany, :name => "Leonberg Württ", :area_code => "7152") + AreaCode.create(:country => germany, :name => "Plochingen", :area_code => "7153") + AreaCode.create(:country => germany, :name => "Kornwestheim", :area_code => "7154") + AreaCode.create(:country => germany, :name => "Ditzingen", :area_code => "7156") + AreaCode.create(:country => germany, :name => "Waldenbuch", :area_code => "7157") + AreaCode.create(:country => germany, :name => "Neuhausen auf den Fildern", :area_code => "7158") + AreaCode.create(:country => germany, :name => "Renningen", :area_code => "7159") + AreaCode.create(:country => germany, :name => "Göppingen", :area_code => "7161") + AreaCode.create(:country => germany, :name => "Süßen", :area_code => "7162") + AreaCode.create(:country => germany, :name => "Ebersbach an der Fils", :area_code => "7163") + AreaCode.create(:country => germany, :name => "Boll Kr Göppingen", :area_code => "7164") + AreaCode.create(:country => germany, :name => "Göppingen-Hohenstaufen", :area_code => "7165") + AreaCode.create(:country => germany, :name => "Adelberg", :area_code => "7166") + AreaCode.create(:country => germany, :name => "Schwäbisch Gmünd", :area_code => "7171") + AreaCode.create(:country => germany, :name => "Lorch Württ", :area_code => "7172") + AreaCode.create(:country => germany, :name => "Heubach", :area_code => "7173") + AreaCode.create(:country => germany, :name => "Mögglingen", :area_code => "7174") + AreaCode.create(:country => germany, :name => "Leinzell", :area_code => "7175") + AreaCode.create(:country => germany, :name => "Spraitbach", :area_code => "7176") + AreaCode.create(:country => germany, :name => "Schorndorf Württ", :area_code => "7181") + AreaCode.create(:country => germany, :name => "Welzheim", :area_code => "7182") + AreaCode.create(:country => germany, :name => "Rudersberg Württ", :area_code => "7183") + AreaCode.create(:country => germany, :name => "Kaisersbach", :area_code => "7184") + AreaCode.create(:country => germany, :name => "Backnang", :area_code => "7191") + AreaCode.create(:country => germany, :name => "Murrhardt", :area_code => "7192") + AreaCode.create(:country => germany, :name => "Sulzbach an der Murr", :area_code => "7193") + AreaCode.create(:country => germany, :name => "Spiegelberg", :area_code => "7194") + AreaCode.create(:country => germany, :name => "Winnenden", :area_code => "7195") + AreaCode.create(:country => germany, :name => "Karlsbad", :area_code => "7202") + AreaCode.create(:country => germany, :name => "Walzbachtal", :area_code => "7203") + AreaCode.create(:country => germany, :name => "Malsch-Völkersbach", :area_code => "7204") + AreaCode.create(:country => germany, :name => "Karlsruhe", :area_code => "721") + AreaCode.create(:country => germany, :name => "Forbach-Hundsbach", :area_code => "7220") + AreaCode.create(:country => germany, :name => "Baden-Baden", :area_code => "7221") + AreaCode.create(:country => germany, :name => "Rastatt", :area_code => "7222") + AreaCode.create(:country => germany, :name => "Bühl Baden", :area_code => "7223") + AreaCode.create(:country => germany, :name => "Gernsbach", :area_code => "7224") + AreaCode.create(:country => germany, :name => "Gaggenau", :area_code => "7225") + AreaCode.create(:country => germany, :name => "Bühl-Sand", :area_code => "7226") + AreaCode.create(:country => germany, :name => "Lichtenau Baden", :area_code => "7227") + AreaCode.create(:country => germany, :name => "Forbach", :area_code => "7228") + AreaCode.create(:country => germany, :name => "Iffezheim", :area_code => "7229") + AreaCode.create(:country => germany, :name => "Pforzheim", :area_code => "7231") + AreaCode.create(:country => germany, :name => "Königsbach-Stein", :area_code => "7232") + AreaCode.create(:country => germany, :name => "Niefern-Öschelbronn", :area_code => "7233") + AreaCode.create(:country => germany, :name => "Tiefenbronn", :area_code => "7234") + AreaCode.create(:country => germany, :name => "Unterreichenbach Kr Calw", :area_code => "7235") + AreaCode.create(:country => germany, :name => "Keltern", :area_code => "7236") + AreaCode.create(:country => germany, :name => "Neulingen Enzkreis", :area_code => "7237") + AreaCode.create(:country => germany, :name => "Pfinztal", :area_code => "7240") + AreaCode.create(:country => germany, :name => "Rheinstetten", :area_code => "7242") + AreaCode.create(:country => germany, :name => "Ettlingen", :area_code => "7243") + AreaCode.create(:country => germany, :name => "Weingarten Baden", :area_code => "7244") + AreaCode.create(:country => germany, :name => "Durmersheim", :area_code => "7245") + AreaCode.create(:country => germany, :name => "Malsch Kr Karlsruhe", :area_code => "7246") + AreaCode.create(:country => germany, :name => "Linkenheim-Hochstetten", :area_code => "7247") + AreaCode.create(:country => germany, :name => "Marxzell", :area_code => "7248") + AreaCode.create(:country => germany, :name => "Stutensee", :area_code => "7249") + AreaCode.create(:country => germany, :name => "Kraichtal", :area_code => "7250") + AreaCode.create(:country => germany, :name => "Bruchsal", :area_code => "7251") + AreaCode.create(:country => germany, :name => "Bretten", :area_code => "7252") + AreaCode.create(:country => germany, :name => "Bad Schönborn", :area_code => "7253") + AreaCode.create(:country => germany, :name => "Waghäusel", :area_code => "7254") + AreaCode.create(:country => germany, :name => "Graben-Neudorf", :area_code => "7255") + AreaCode.create(:country => germany, :name => "Philippsburg", :area_code => "7256") + AreaCode.create(:country => germany, :name => "Bruchsal-Untergrombach", :area_code => "7257") + AreaCode.create(:country => germany, :name => "Oberderdingen-Flehingen", :area_code => "7258") + AreaCode.create(:country => germany, :name => "Östringen-Odenheim", :area_code => "7259") + AreaCode.create(:country => germany, :name => "Sinsheim-Hilsbach", :area_code => "7260") + AreaCode.create(:country => germany, :name => "Sinsheim", :area_code => "7261") + AreaCode.create(:country => germany, :name => "Eppingen", :area_code => "7262") + AreaCode.create(:country => germany, :name => "Waibstadt", :area_code => "7263") + AreaCode.create(:country => germany, :name => "Bad Rappenau", :area_code => "7264") + AreaCode.create(:country => germany, :name => "Angelbachtal", :area_code => "7265") + AreaCode.create(:country => germany, :name => "Kirchardt", :area_code => "7266") + AreaCode.create(:country => germany, :name => "Gemmingen", :area_code => "7267") + AreaCode.create(:country => germany, :name => "Bad Rappenau-Obergimpern", :area_code => "7268") + AreaCode.create(:country => germany, :name => "Sulzfeld Baden", :area_code => "7269") + AreaCode.create(:country => germany, :name => "Wörth am Rhein", :area_code => "7271") + AreaCode.create(:country => germany, :name => "Rülzheim", :area_code => "7272") + AreaCode.create(:country => germany, :name => "Hagenbach Pfalz", :area_code => "7273") + AreaCode.create(:country => germany, :name => "Germersheim", :area_code => "7274") + AreaCode.create(:country => germany, :name => "Kandel", :area_code => "7275") + AreaCode.create(:country => germany, :name => "Herxheim bei Landau Pfalz", :area_code => "7276") + AreaCode.create(:country => germany, :name => "Wörth-Büchelberg", :area_code => "7277") + AreaCode.create(:country => germany, :name => "Roggenburg", :area_code => "7300") + AreaCode.create(:country => germany, :name => "Pfaffenhofen a d Roth", :area_code => "7302") + AreaCode.create(:country => germany, :name => "Illertissen", :area_code => "7303") + AreaCode.create(:country => germany, :name => "Blaustein Württ", :area_code => "7304") + AreaCode.create(:country => germany, :name => "Erbach Donau", :area_code => "7305") + AreaCode.create(:country => germany, :name => "Vöhringen Iller", :area_code => "7306") + AreaCode.create(:country => germany, :name => "Senden Iller", :area_code => "7307") + AreaCode.create(:country => germany, :name => "Nersingen", :area_code => "7308") + AreaCode.create(:country => germany, :name => "Weissenhorn", :area_code => "7309") + AreaCode.create(:country => germany, :name => "Ulm Donau", :area_code => "731") + AreaCode.create(:country => germany, :name => "Heidenheim a d Brenz", :area_code => "7321") + AreaCode.create(:country => germany, :name => "Giengen a d Brenz", :area_code => "7322") + AreaCode.create(:country => germany, :name => "Gerstetten", :area_code => "7323") + AreaCode.create(:country => germany, :name => "Herbrechtingen", :area_code => "7324") + AreaCode.create(:country => germany, :name => "Sontheim a d Brenz", :area_code => "7325") + AreaCode.create(:country => germany, :name => "Neresheim", :area_code => "7326") + AreaCode.create(:country => germany, :name => "Dischingen", :area_code => "7327") + AreaCode.create(:country => germany, :name => "Königsbronn", :area_code => "7328") + AreaCode.create(:country => germany, :name => "Steinheim am Albuch", :area_code => "7329") + AreaCode.create(:country => germany, :name => "Geislingen an der Steige", :area_code => "7331") + AreaCode.create(:country => germany, :name => "Lauterstein", :area_code => "7332") + AreaCode.create(:country => germany, :name => "Laichingen", :area_code => "7333") + AreaCode.create(:country => germany, :name => "Deggingen", :area_code => "7334") + AreaCode.create(:country => germany, :name => "Wiesensteig", :area_code => "7335") + AreaCode.create(:country => germany, :name => "Lonsee", :area_code => "7336") + AreaCode.create(:country => germany, :name => "Nellingen Alb", :area_code => "7337") + AreaCode.create(:country => germany, :name => "Neenstetten", :area_code => "7340") + AreaCode.create(:country => germany, :name => "Buch b Illertissen", :area_code => "7343") + AreaCode.create(:country => germany, :name => "Blaubeuren", :area_code => "7344") + AreaCode.create(:country => germany, :name => "Langenau Württ", :area_code => "7345") + AreaCode.create(:country => germany, :name => "Illerkirchberg", :area_code => "7346") + AreaCode.create(:country => germany, :name => "Dietenheim", :area_code => "7347") + AreaCode.create(:country => germany, :name => "Beimerstetten", :area_code => "7348") + AreaCode.create(:country => germany, :name => "Biberach an der Riß", :area_code => "7351") + AreaCode.create(:country => germany, :name => "Ochsenhausen", :area_code => "7352") + AreaCode.create(:country => germany, :name => "Schwendi", :area_code => "7353") + AreaCode.create(:country => germany, :name => "Erolzheim", :area_code => "7354") + AreaCode.create(:country => germany, :name => "Hochdorf Riß", :area_code => "7355") + AreaCode.create(:country => germany, :name => "Schemmerhofen", :area_code => "7356") + AreaCode.create(:country => germany, :name => "Attenweiler", :area_code => "7357") + AreaCode.create(:country => germany, :name => "Eberhardzell-Füramoos", :area_code => "7358") + AreaCode.create(:country => germany, :name => "Aalen", :area_code => "7361") + AreaCode.create(:country => germany, :name => "Bopfingen", :area_code => "7362") + AreaCode.create(:country => germany, :name => "Lauchheim", :area_code => "7363") + AreaCode.create(:country => germany, :name => "Oberkochen", :area_code => "7364") + AreaCode.create(:country => germany, :name => "Essingen Württ", :area_code => "7365") + AreaCode.create(:country => germany, :name => "Abtsgmünd", :area_code => "7366") + AreaCode.create(:country => germany, :name => "Aalen-Ebnat", :area_code => "7367") + AreaCode.create(:country => germany, :name => "Riedlingen Württ", :area_code => "7371") + AreaCode.create(:country => germany, :name => "Zwiefalten", :area_code => "7373") + AreaCode.create(:country => germany, :name => "Uttenweiler", :area_code => "7374") + AreaCode.create(:country => germany, :name => "Obermarchtal", :area_code => "7375") + AreaCode.create(:country => germany, :name => "Langenenslingen", :area_code => "7376") + AreaCode.create(:country => germany, :name => "Münsingen", :area_code => "7381") + AreaCode.create(:country => germany, :name => "Römerstein", :area_code => "7382") + AreaCode.create(:country => germany, :name => "Münsingen-Buttenhausen", :area_code => "7383") + AreaCode.create(:country => germany, :name => "Schelklingen-Hütten", :area_code => "7384") + AreaCode.create(:country => germany, :name => "Gomadingen", :area_code => "7385") + AreaCode.create(:country => germany, :name => "Hayingen", :area_code => "7386") + AreaCode.create(:country => germany, :name => "Hohenstein Württ", :area_code => "7387") + AreaCode.create(:country => germany, :name => "Pfronstetten", :area_code => "7388") + AreaCode.create(:country => germany, :name => "Heroldstatt", :area_code => "7389") + AreaCode.create(:country => germany, :name => "Ehingen Donau", :area_code => "7391") + AreaCode.create(:country => germany, :name => "Laupheim", :area_code => "7392") + AreaCode.create(:country => germany, :name => "Munderkingen", :area_code => "7393") + AreaCode.create(:country => germany, :name => "Schelklingen", :area_code => "7394") + AreaCode.create(:country => germany, :name => "Ehingen-Dächingen", :area_code => "7395") + AreaCode.create(:country => germany, :name => "Fluorn-Winzeln", :area_code => "7402") + AreaCode.create(:country => germany, :name => "Dunningen", :area_code => "7403") + AreaCode.create(:country => germany, :name => "Epfendorf", :area_code => "7404") + AreaCode.create(:country => germany, :name => "Rottweil", :area_code => "741") + AreaCode.create(:country => germany, :name => "Deisslingen", :area_code => "7420") + AreaCode.create(:country => germany, :name => "Schramberg", :area_code => "7422") + AreaCode.create(:country => germany, :name => "Oberndorf am Neckar", :area_code => "7423") + AreaCode.create(:country => germany, :name => "Spaichingen", :area_code => "7424") + AreaCode.create(:country => germany, :name => "Trossingen", :area_code => "7425") + AreaCode.create(:country => germany, :name => "Gosheim", :area_code => "7426") + AreaCode.create(:country => germany, :name => "Schömberg b Balingen", :area_code => "7427") + AreaCode.create(:country => germany, :name => "Rosenfeld", :area_code => "7428") + AreaCode.create(:country => germany, :name => "Egesheim", :area_code => "7429") + AreaCode.create(:country => germany, :name => "Albstadt-Ebingen", :area_code => "7431") + AreaCode.create(:country => germany, :name => "Albstadt-Tailfingen", :area_code => "7432") + AreaCode.create(:country => germany, :name => "Balingen", :area_code => "7433") + AreaCode.create(:country => germany, :name => "Winterlingen", :area_code => "7434") + AreaCode.create(:country => germany, :name => "Albstadt-Laufen", :area_code => "7435") + AreaCode.create(:country => germany, :name => "Messstetten-Oberdigisheim", :area_code => "7436") + AreaCode.create(:country => germany, :name => "Bad Rippoldsau", :area_code => "7440") + AreaCode.create(:country => germany, :name => "Freudenstadt", :area_code => "7441") + AreaCode.create(:country => germany, :name => "Baiersbronn", :area_code => "7442") + AreaCode.create(:country => germany, :name => "Dornstetten", :area_code => "7443") + AreaCode.create(:country => germany, :name => "Alpirsbach", :area_code => "7444") + AreaCode.create(:country => germany, :name => "Pfalzgrafenweiler", :area_code => "7445") + AreaCode.create(:country => germany, :name => "Lossburg", :area_code => "7446") + AreaCode.create(:country => germany, :name => "Baiersbronn-Schwarzenberg", :area_code => "7447") + AreaCode.create(:country => germany, :name => "Seewald", :area_code => "7448") + AreaCode.create(:country => germany, :name => "Baiersbronn-Obertal", :area_code => "7449") + AreaCode.create(:country => germany, :name => "Horb am Neckar", :area_code => "7451") + AreaCode.create(:country => germany, :name => "Nagold", :area_code => "7452") + AreaCode.create(:country => germany, :name => "Altensteig Württ", :area_code => "7453") + AreaCode.create(:country => germany, :name => "Sulz am Neckar", :area_code => "7454") + AreaCode.create(:country => germany, :name => "Dornhan", :area_code => "7455") + AreaCode.create(:country => germany, :name => "Haiterbach", :area_code => "7456") + AreaCode.create(:country => germany, :name => "Rottenburg-Ergenzingen", :area_code => "7457") + AreaCode.create(:country => germany, :name => "Ebhausen", :area_code => "7458") + AreaCode.create(:country => germany, :name => "Nagold-Hochdorf", :area_code => "7459") + AreaCode.create(:country => germany, :name => "Tuttlingen", :area_code => "7461") + AreaCode.create(:country => germany, :name => "Immendingen", :area_code => "7462") + AreaCode.create(:country => germany, :name => "Mühlheim an der Donau", :area_code => "7463") + AreaCode.create(:country => germany, :name => "Talheim Kr Tuttlingen", :area_code => "7464") + AreaCode.create(:country => germany, :name => "Emmingen-Liptingen", :area_code => "7465") + AreaCode.create(:country => germany, :name => "Beuron", :area_code => "7466") + AreaCode.create(:country => germany, :name => "Neuhausen ob Eck", :area_code => "7467") + AreaCode.create(:country => germany, :name => "Hechingen", :area_code => "7471") + AreaCode.create(:country => germany, :name => "Rottenburg am Neckar", :area_code => "7472") + AreaCode.create(:country => germany, :name => "Mössingen", :area_code => "7473") + AreaCode.create(:country => germany, :name => "Haigerloch", :area_code => "7474") + AreaCode.create(:country => germany, :name => "Burladingen", :area_code => "7475") + AreaCode.create(:country => germany, :name => "Bisingen", :area_code => "7476") + AreaCode.create(:country => germany, :name => "Jungingen b Hechingen", :area_code => "7477") + AreaCode.create(:country => germany, :name => "Hirrlingen", :area_code => "7478") + AreaCode.create(:country => germany, :name => "Horb-Dettingen", :area_code => "7482") + AreaCode.create(:country => germany, :name => "Horb-Mühringen", :area_code => "7483") + AreaCode.create(:country => germany, :name => "Simmersfeld", :area_code => "7484") + AreaCode.create(:country => germany, :name => "Empfingen", :area_code => "7485") + AreaCode.create(:country => germany, :name => "Horb-Altheim", :area_code => "7486") + AreaCode.create(:country => germany, :name => "Wolpertswende", :area_code => "7502") + AreaCode.create(:country => germany, :name => "Wilhelmsdorf Württ", :area_code => "7503") + AreaCode.create(:country => germany, :name => "Horgenzell", :area_code => "7504") + AreaCode.create(:country => germany, :name => "Fronreute", :area_code => "7505") + AreaCode.create(:country => germany, :name => "Wangen-Leupolz", :area_code => "7506") + AreaCode.create(:country => germany, :name => "Ravensburg", :area_code => "751") + AreaCode.create(:country => germany, :name => "Bodnegg", :area_code => "7520") + AreaCode.create(:country => germany, :name => "Wangen im Allgäu", :area_code => "7522") + AreaCode.create(:country => germany, :name => "Bad Waldsee", :area_code => "7524") + AreaCode.create(:country => germany, :name => "Aulendorf", :area_code => "7525") + AreaCode.create(:country => germany, :name => "Wolfegg", :area_code => "7527") + AreaCode.create(:country => germany, :name => "Neukirch b Tettnang", :area_code => "7528") + AreaCode.create(:country => germany, :name => "Waldburg Württ", :area_code => "7529") + AreaCode.create(:country => germany, :name => "Konstanz", :area_code => "7531") + AreaCode.create(:country => germany, :name => "Meersburg", :area_code => "7532") + AreaCode.create(:country => germany, :name => "Allensbach", :area_code => "7533") + AreaCode.create(:country => germany, :name => "Reichenau Baden", :area_code => "7534") + AreaCode.create(:country => germany, :name => "Friedrichshafen", :area_code => "7541") + AreaCode.create(:country => germany, :name => "Tettnang", :area_code => "7542") + AreaCode.create(:country => germany, :name => "Kressbronn am Bodensee", :area_code => "7543") + AreaCode.create(:country => germany, :name => "Markdorf", :area_code => "7544") + AreaCode.create(:country => germany, :name => "Immenstaad am Bodensee", :area_code => "7545") + AreaCode.create(:country => germany, :name => "Oberteuringen", :area_code => "7546") + AreaCode.create(:country => germany, :name => "Überlingen Bodensee", :area_code => "7551") + AreaCode.create(:country => germany, :name => "Pfullendorf", :area_code => "7552") + AreaCode.create(:country => germany, :name => "Salem Baden", :area_code => "7553") + AreaCode.create(:country => germany, :name => "Heiligenberg Baden", :area_code => "7554") + AreaCode.create(:country => germany, :name => "Deggenhausertal", :area_code => "7555") + AreaCode.create(:country => germany, :name => "Uhldingen-Mühlhofen", :area_code => "7556") + AreaCode.create(:country => germany, :name => "Herdwangen-Schönach", :area_code => "7557") + AreaCode.create(:country => germany, :name => "Illmensee", :area_code => "7558") + AreaCode.create(:country => germany, :name => "Leutkirch im Allgäu", :area_code => "7561") + AreaCode.create(:country => germany, :name => "Isny im Allgäu", :area_code => "7562") + AreaCode.create(:country => germany, :name => "Kisslegg", :area_code => "7563") + AreaCode.create(:country => germany, :name => "Bad Wurzach", :area_code => "7564") + AreaCode.create(:country => germany, :name => "Aichstetten Kr Ravensburg", :area_code => "7565") + AreaCode.create(:country => germany, :name => "Argenbühl", :area_code => "7566") + AreaCode.create(:country => germany, :name => "Leutkirch-Friesenhofen", :area_code => "7567") + AreaCode.create(:country => germany, :name => "Bad Wurzach-Hauerz", :area_code => "7568") + AreaCode.create(:country => germany, :name => "Isny-Eisenbach", :area_code => "7569") + AreaCode.create(:country => germany, :name => "Sigmaringen-Gutenstein", :area_code => "7570") + AreaCode.create(:country => germany, :name => "Sigmaringen", :area_code => "7571") + AreaCode.create(:country => germany, :name => "Mengen Württ", :area_code => "7572") + AreaCode.create(:country => germany, :name => "Stetten am kalten Markt", :area_code => "7573") + AreaCode.create(:country => germany, :name => "Gammertingen", :area_code => "7574") + AreaCode.create(:country => germany, :name => "Messkirch", :area_code => "7575") + AreaCode.create(:country => germany, :name => "Krauchenwies", :area_code => "7576") + AreaCode.create(:country => germany, :name => "Veringenstadt", :area_code => "7577") + AreaCode.create(:country => germany, :name => "Wald Hohenz", :area_code => "7578") + AreaCode.create(:country => germany, :name => "Schwenningen Baden", :area_code => "7579") + AreaCode.create(:country => germany, :name => "Saulgau", :area_code => "7581") + AreaCode.create(:country => germany, :name => "Bad Buchau", :area_code => "7582") + AreaCode.create(:country => germany, :name => "Bad Schussenried", :area_code => "7583") + AreaCode.create(:country => germany, :name => "Altshausen", :area_code => "7584") + AreaCode.create(:country => germany, :name => "Ostrach", :area_code => "7585") + AreaCode.create(:country => germany, :name => "Herbertingen", :area_code => "7586") + AreaCode.create(:country => germany, :name => "Hosskirch", :area_code => "7587") + AreaCode.create(:country => germany, :name => "Oberried Breisgau", :area_code => "7602") + AreaCode.create(:country => germany, :name => "Freiburg im Breisgau", :area_code => "761") + AreaCode.create(:country => germany, :name => "Schopfheim-Gersbach", :area_code => "7620") + AreaCode.create(:country => germany, :name => "Lörrach", :area_code => "7621") + AreaCode.create(:country => germany, :name => "Schopfheim", :area_code => "7622") + AreaCode.create(:country => germany, :name => "Rheinfelden Baden", :area_code => "7623") + AreaCode.create(:country => germany, :name => "Grenzach-Wyhlen", :area_code => "7624") + AreaCode.create(:country => germany, :name => "Zell im Wiesental", :area_code => "7625") + AreaCode.create(:country => germany, :name => "Kandern", :area_code => "7626") + AreaCode.create(:country => germany, :name => "Steinen Kr Lörrach", :area_code => "7627") + AreaCode.create(:country => germany, :name => "Efringen-Kirchen", :area_code => "7628") + AreaCode.create(:country => germany, :name => "Tegernau Baden", :area_code => "7629") + AreaCode.create(:country => germany, :name => "Müllheim Baden", :area_code => "7631") + AreaCode.create(:country => germany, :name => "Badenweiler", :area_code => "7632") + AreaCode.create(:country => germany, :name => "Staufen im Breisgau", :area_code => "7633") + AreaCode.create(:country => germany, :name => "Sulzburg", :area_code => "7634") + AreaCode.create(:country => germany, :name => "Schliengen", :area_code => "7635") + AreaCode.create(:country => germany, :name => "Münstertal Schwarzwald", :area_code => "7636") + AreaCode.create(:country => germany, :name => "Emmendingen", :area_code => "7641") + AreaCode.create(:country => germany, :name => "Endingen Kaiserstuh", :area_code => "7642") + AreaCode.create(:country => germany, :name => "Herbolzheim Breisgau", :area_code => "7643") + AreaCode.create(:country => germany, :name => "Kenzingen", :area_code => "7644") + AreaCode.create(:country => germany, :name => "Freiamt", :area_code => "7645") + AreaCode.create(:country => germany, :name => "Weisweil Breisgau", :area_code => "7646") + AreaCode.create(:country => germany, :name => "Titisee-Neustadt", :area_code => "7651") + AreaCode.create(:country => germany, :name => "Hinterzarten", :area_code => "7652") + AreaCode.create(:country => germany, :name => "Lenzkirch", :area_code => "7653") + AreaCode.create(:country => germany, :name => "Löffingen", :area_code => "7654") + AreaCode.create(:country => germany, :name => "Feldberg-Altglashütten", :area_code => "7655") + AreaCode.create(:country => germany, :name => "Schluchsee", :area_code => "7656") + AreaCode.create(:country => germany, :name => "Eisenbach Hochschwarzwald", :area_code => "7657") + AreaCode.create(:country => germany, :name => "St Peter Schwarzw", :area_code => "7660") + AreaCode.create(:country => germany, :name => "Kirchzarten", :area_code => "7661") + AreaCode.create(:country => germany, :name => "Vogtsburg im Kaiserstuh", :area_code => "7662") + AreaCode.create(:country => germany, :name => "Eichstetten", :area_code => "7663") + AreaCode.create(:country => germany, :name => "Freiburg-Tiengen", :area_code => "7664") + AreaCode.create(:country => germany, :name => "March Breisgau", :area_code => "7665") + AreaCode.create(:country => germany, :name => "Denzlingen", :area_code => "7666") + AreaCode.create(:country => germany, :name => "Breisach am Rhein", :area_code => "7667") + AreaCode.create(:country => germany, :name => "Ihringen", :area_code => "7668") + AreaCode.create(:country => germany, :name => "St Märgen", :area_code => "7669") + AreaCode.create(:country => germany, :name => "Todtnau", :area_code => "7671") + AreaCode.create(:country => germany, :name => "St Blasien", :area_code => "7672") + AreaCode.create(:country => germany, :name => "Schönau im Schwarzwald", :area_code => "7673") + AreaCode.create(:country => germany, :name => "Todtmoos", :area_code => "7674") + AreaCode.create(:country => germany, :name => "Bernau Baden", :area_code => "7675") + AreaCode.create(:country => germany, :name => "Feldberg Schwarzwald", :area_code => "7676") + AreaCode.create(:country => germany, :name => "Waldkirch Breisgau", :area_code => "7681") + AreaCode.create(:country => germany, :name => "Elzach", :area_code => "7682") + AreaCode.create(:country => germany, :name => "Simonswald", :area_code => "7683") + AreaCode.create(:country => germany, :name => "Glottertal", :area_code => "7684") + AreaCode.create(:country => germany, :name => "Gutach-Bleibach", :area_code => "7685") + AreaCode.create(:country => germany, :name => "Blumberg Baden", :area_code => "7702") + AreaCode.create(:country => germany, :name => "Bonndorf im Schwarzwald", :area_code => "7703") + AreaCode.create(:country => germany, :name => "Geisingen Baden", :area_code => "7704") + AreaCode.create(:country => germany, :name => "Wolterdingen Schwarzw", :area_code => "7705") + AreaCode.create(:country => germany, :name => "Oberbaldingen", :area_code => "7706") + AreaCode.create(:country => germany, :name => "Bräunlingen", :area_code => "7707") + AreaCode.create(:country => germany, :name => "Geisingen-Leipferdingen", :area_code => "7708") + AreaCode.create(:country => germany, :name => "Wutach", :area_code => "7709") + AreaCode.create(:country => germany, :name => "Donaueschingen", :area_code => "771") + AreaCode.create(:country => germany, :name => "Schwenningen a Neckar", :area_code => "7720") + AreaCode.create(:country => germany, :name => "Villingen i Schwarzw", :area_code => "7721") + AreaCode.create(:country => germany, :name => "Triberg im Schwarzwald", :area_code => "7722") + AreaCode.create(:country => germany, :name => "Furtwangen im Schwarzwald", :area_code => "7723") + AreaCode.create(:country => germany, :name => "St Georgen im Schwarzwald", :area_code => "7724") + AreaCode.create(:country => germany, :name => "Königsfeld im Schwarzwald", :area_code => "7725") + AreaCode.create(:country => germany, :name => "Bad Dürrheim", :area_code => "7726") + AreaCode.create(:country => germany, :name => "Vöhrenbach", :area_code => "7727") + AreaCode.create(:country => germany, :name => "Niedereschach", :area_code => "7728") + AreaCode.create(:country => germany, :name => "Tennenbronn", :area_code => "7729") + AreaCode.create(:country => germany, :name => "Singen Hohentwiel", :area_code => "7731") + AreaCode.create(:country => germany, :name => "Radolfzell am Bodensee", :area_code => "7732") + AreaCode.create(:country => germany, :name => "Engen Hegau", :area_code => "7733") + AreaCode.create(:country => germany, :name => "Gailingen", :area_code => "7734") + AreaCode.create(:country => germany, :name => "Öhningen", :area_code => "7735") + AreaCode.create(:country => germany, :name => "Tengen", :area_code => "7736") + AreaCode.create(:country => germany, :name => "Steisslingen", :area_code => "7738") + AreaCode.create(:country => germany, :name => "Hilzingen", :area_code => "7739") + AreaCode.create(:country => germany, :name => "Tiengen Hochrhein", :area_code => "7741") + AreaCode.create(:country => germany, :name => "Klettgau", :area_code => "7742") + AreaCode.create(:country => germany, :name => "Ühlingen-Birkendorf", :area_code => "7743") + AreaCode.create(:country => germany, :name => "Stühlingen", :area_code => "7744") + AreaCode.create(:country => germany, :name => "Jestetten", :area_code => "7745") + AreaCode.create(:country => germany, :name => "Wutöschingen", :area_code => "7746") + AreaCode.create(:country => germany, :name => "Berau", :area_code => "7747") + AreaCode.create(:country => germany, :name => "Grafenhausen Hochschwarzw", :area_code => "7748") + AreaCode.create(:country => germany, :name => "Waldshut", :area_code => "7751") + AreaCode.create(:country => germany, :name => "Albbruck", :area_code => "7753") + AreaCode.create(:country => germany, :name => "Görwihl", :area_code => "7754") + AreaCode.create(:country => germany, :name => "Weilheim Kr Waldshut", :area_code => "7755") + AreaCode.create(:country => germany, :name => "Bad Säckingen", :area_code => "7761") + AreaCode.create(:country => germany, :name => "Wehr Baden", :area_code => "7762") + AreaCode.create(:country => germany, :name => "Murg", :area_code => "7763") + AreaCode.create(:country => germany, :name => "Herrischried", :area_code => "7764") + AreaCode.create(:country => germany, :name => "Rickenbach Hotzenw", :area_code => "7765") + AreaCode.create(:country => germany, :name => "Stockach", :area_code => "7771") + AreaCode.create(:country => germany, :name => "Bodman-Ludwigshafen", :area_code => "7773") + AreaCode.create(:country => germany, :name => "Eigeltingen", :area_code => "7774") + AreaCode.create(:country => germany, :name => "Mühlingen", :area_code => "7775") + AreaCode.create(:country => germany, :name => "Sauldorf", :area_code => "7777") + AreaCode.create(:country => germany, :name => "Oberkirch Baden", :area_code => "7802") + AreaCode.create(:country => germany, :name => "Gengenbach", :area_code => "7803") + AreaCode.create(:country => germany, :name => "Oppenau", :area_code => "7804") + AreaCode.create(:country => germany, :name => "Appenweier", :area_code => "7805") + AreaCode.create(:country => germany, :name => "Bad Peterstal-Griesbach", :area_code => "7806") + AreaCode.create(:country => germany, :name => "Neuried Ortenaukreis", :area_code => "7807") + AreaCode.create(:country => germany, :name => "Hohberg b Offenburg", :area_code => "7808") + AreaCode.create(:country => germany, :name => "Offenburg", :area_code => "781") + AreaCode.create(:country => germany, :name => "Lahr Schwarzwald", :area_code => "7821") + AreaCode.create(:country => germany, :name => "Ettenheim", :area_code => "7822") + AreaCode.create(:country => germany, :name => "Seelbach Schutter", :area_code => "7823") + AreaCode.create(:country => germany, :name => "Schwanau", :area_code => "7824") + AreaCode.create(:country => germany, :name => "Kippenheim", :area_code => "7825") + AreaCode.create(:country => germany, :name => "Schuttertal", :area_code => "7826") + AreaCode.create(:country => germany, :name => "Hausach", :area_code => "7831") + AreaCode.create(:country => germany, :name => "Haslach im Kinzigtal", :area_code => "7832") + AreaCode.create(:country => germany, :name => "Hornberg Schwarzwaldbahn", :area_code => "7833") + AreaCode.create(:country => germany, :name => "Wolfach", :area_code => "7834") + AreaCode.create(:country => germany, :name => "Zell am Harmersbach", :area_code => "7835") + AreaCode.create(:country => germany, :name => "Schiltach", :area_code => "7836") + AreaCode.create(:country => germany, :name => "Oberharmersbach", :area_code => "7837") + AreaCode.create(:country => germany, :name => "Nordrach", :area_code => "7838") + AreaCode.create(:country => germany, :name => "Schapbach", :area_code => "7839") + AreaCode.create(:country => germany, :name => "Achern", :area_code => "7841") + AreaCode.create(:country => germany, :name => "Kappelrodeck", :area_code => "7842") + AreaCode.create(:country => germany, :name => "Renchen", :area_code => "7843") + AreaCode.create(:country => germany, :name => "Rheinau", :area_code => "7844") + AreaCode.create(:country => germany, :name => "Kehl", :area_code => "7851") + AreaCode.create(:country => germany, :name => "Willstätt", :area_code => "7852") + AreaCode.create(:country => germany, :name => "Kehl-Bodersweier", :area_code => "7853") + AreaCode.create(:country => germany, :name => "Kehl-Goldscheuer", :area_code => "7854") + AreaCode.create(:country => germany, :name => "Mainhardt", :area_code => "7903") + AreaCode.create(:country => germany, :name => "Ilshofen", :area_code => "7904") + AreaCode.create(:country => germany, :name => "Langenburg", :area_code => "7905") + AreaCode.create(:country => germany, :name => "Braunsbach", :area_code => "7906") + AreaCode.create(:country => germany, :name => "Schwäbisch Hall-Sulzdorf", :area_code => "7907") + AreaCode.create(:country => germany, :name => "Schwäbisch Hall", :area_code => "791") + AreaCode.create(:country => germany, :name => "Boxberg Baden", :area_code => "7930") + AreaCode.create(:country => germany, :name => "Bad Mergentheim", :area_code => "7931") + AreaCode.create(:country => germany, :name => "Niederstetten Württ", :area_code => "7932") + AreaCode.create(:country => germany, :name => "Creglingen", :area_code => "7933") + AreaCode.create(:country => germany, :name => "Weikersheim", :area_code => "7934") + AreaCode.create(:country => germany, :name => "Schrozberg", :area_code => "7935") + AreaCode.create(:country => germany, :name => "Schrozberg-Bartenstein", :area_code => "7936") + AreaCode.create(:country => germany, :name => "Dörzbach", :area_code => "7937") + AreaCode.create(:country => germany, :name => "Mulfingen Jagst", :area_code => "7938") + AreaCode.create(:country => germany, :name => "Schrozberg-Spielbach", :area_code => "7939") + AreaCode.create(:country => germany, :name => "Künzelsau", :area_code => "7940") + AreaCode.create(:country => germany, :name => "Öhringen", :area_code => "7941") + AreaCode.create(:country => germany, :name => "Neuenstein Württ", :area_code => "7942") + AreaCode.create(:country => germany, :name => "Schöntal Jagst", :area_code => "7943") + AreaCode.create(:country => germany, :name => "Kupferzell", :area_code => "7944") + AreaCode.create(:country => germany, :name => "Wüstenrot", :area_code => "7945") + AreaCode.create(:country => germany, :name => "Bretzfeld", :area_code => "7946") + AreaCode.create(:country => germany, :name => "Forchtenberg", :area_code => "7947") + AreaCode.create(:country => germany, :name => "Öhringen-Ohrnberg", :area_code => "7948") + AreaCode.create(:country => germany, :name => "Pfedelbach-Untersteinbach", :area_code => "7949") + AreaCode.create(:country => germany, :name => "Schnelldorf", :area_code => "7950") + AreaCode.create(:country => germany, :name => "Crailsheim", :area_code => "7951") + AreaCode.create(:country => germany, :name => "Gerabronn", :area_code => "7952") + AreaCode.create(:country => germany, :name => "Blaufelden", :area_code => "7953") + AreaCode.create(:country => germany, :name => "Kirchberg an der Jagst", :area_code => "7954") + AreaCode.create(:country => germany, :name => "Wallhausen Württ", :area_code => "7955") + AreaCode.create(:country => germany, :name => "Kressberg", :area_code => "7957") + AreaCode.create(:country => germany, :name => "Rot Am See-Brettheim", :area_code => "7958") + AreaCode.create(:country => germany, :name => "Frankenhardt", :area_code => "7959") + AreaCode.create(:country => germany, :name => "Ellwangen Jagst", :area_code => "7961") + AreaCode.create(:country => germany, :name => "Fichtenau", :area_code => "7962") + AreaCode.create(:country => germany, :name => "Adelmannsfelden", :area_code => "7963") + AreaCode.create(:country => germany, :name => "Stödtlen", :area_code => "7964") + AreaCode.create(:country => germany, :name => "Ellwangen-Röhlingen", :area_code => "7965") + AreaCode.create(:country => germany, :name => "Unterschneidheim", :area_code => "7966") + AreaCode.create(:country => germany, :name => "Jagstzell", :area_code => "7967") + AreaCode.create(:country => germany, :name => "Gaildorf", :area_code => "7971") + AreaCode.create(:country => germany, :name => "Gschwend b Gaildorf", :area_code => "7972") + AreaCode.create(:country => germany, :name => "Obersontheim", :area_code => "7973") + AreaCode.create(:country => germany, :name => "Bühlerzell", :area_code => "7974") + AreaCode.create(:country => germany, :name => "Untergröningen", :area_code => "7975") + AreaCode.create(:country => germany, :name => "Sulzbach-Laufen", :area_code => "7976") + AreaCode.create(:country => germany, :name => "Oberrot b Gaildorf", :area_code => "7977") + AreaCode.create(:country => germany, :name => "Weyarn", :area_code => "8020") + AreaCode.create(:country => germany, :name => "Waakirchen", :area_code => "8021") + AreaCode.create(:country => germany, :name => "Tegernsee", :area_code => "8022") + AreaCode.create(:country => germany, :name => "Bayrischzell", :area_code => "8023") + AreaCode.create(:country => germany, :name => "Holzkirchen", :area_code => "8024") + AreaCode.create(:country => germany, :name => "Miesbach", :area_code => "8025") + AreaCode.create(:country => germany, :name => "Hausham", :area_code => "8026") + AreaCode.create(:country => germany, :name => "Dietramszell", :area_code => "8027") + AreaCode.create(:country => germany, :name => "Fischbachau", :area_code => "8028") + AreaCode.create(:country => germany, :name => "Kreuth b Tegernsee", :area_code => "8029") + AreaCode.create(:country => germany, :name => "Rosenheim Oberbay", :area_code => "8031") + AreaCode.create(:country => germany, :name => "Rohrdorf Kr Rosenheim", :area_code => "8032") + AreaCode.create(:country => germany, :name => "Oberaudorf", :area_code => "8033") + AreaCode.create(:country => germany, :name => "Brannenburg", :area_code => "8034") + AreaCode.create(:country => germany, :name => "Raubling", :area_code => "8035") + AreaCode.create(:country => germany, :name => "Stephanskirchen Simssee", :area_code => "8036") + AreaCode.create(:country => germany, :name => "Vogtareuth", :area_code => "8038") + AreaCode.create(:country => germany, :name => "Rott a Inn", :area_code => "8039") + AreaCode.create(:country => germany, :name => "Bad Tölz", :area_code => "8041") + AreaCode.create(:country => germany, :name => "Lenggries", :area_code => "8042") + AreaCode.create(:country => germany, :name => "Jachenau", :area_code => "8043") + AreaCode.create(:country => germany, :name => "Lenggries-Fall", :area_code => "8045") + AreaCode.create(:country => germany, :name => "Bad Heilbrunn", :area_code => "8046") + AreaCode.create(:country => germany, :name => "Prien a Chiemsee", :area_code => "8051") + AreaCode.create(:country => germany, :name => "Aschau i Chiemgau", :area_code => "8052") + AreaCode.create(:country => germany, :name => "Bad Endorf", :area_code => "8053") + AreaCode.create(:country => germany, :name => "Breitbrunn a Chiemsee", :area_code => "8054") + AreaCode.create(:country => germany, :name => "Halfing", :area_code => "8055") + AreaCode.create(:country => germany, :name => "Eggstätt", :area_code => "8056") + AreaCode.create(:country => germany, :name => "Aschau-Sachrang", :area_code => "8057") + AreaCode.create(:country => germany, :name => "Bad Aibling", :area_code => "8061") + AreaCode.create(:country => germany, :name => "Bruckmühl Mangfall", :area_code => "8062") + AreaCode.create(:country => germany, :name => "Feldkirchen-Westerham", :area_code => "8063") + AreaCode.create(:country => germany, :name => "Au b Bad Aibling", :area_code => "8064") + AreaCode.create(:country => germany, :name => "Tuntenhausen-Schönau", :area_code => "8065") + AreaCode.create(:country => germany, :name => "Bad Feilnbach", :area_code => "8066") + AreaCode.create(:country => germany, :name => "Tuntenhausen", :area_code => "8067") + AreaCode.create(:country => germany, :name => "Wasserburg a Inn", :area_code => "8071") + AreaCode.create(:country => germany, :name => "Haag i OB", :area_code => "8072") + AreaCode.create(:country => germany, :name => "Gars a Inn", :area_code => "8073") + AreaCode.create(:country => germany, :name => "Schnaitsee", :area_code => "8074") + AreaCode.create(:country => germany, :name => "Amerang", :area_code => "8075") + AreaCode.create(:country => germany, :name => "Pfaffing", :area_code => "8076") + AreaCode.create(:country => germany, :name => "Dorfen Stadt", :area_code => "8081") + AreaCode.create(:country => germany, :name => "Schwindegg", :area_code => "8082") + AreaCode.create(:country => germany, :name => "Isen", :area_code => "8083") + AreaCode.create(:country => germany, :name => "Taufkirchen Vils", :area_code => "8084") + AreaCode.create(:country => germany, :name => "Sankt Wolfgang", :area_code => "8085") + AreaCode.create(:country => germany, :name => "Buchbach Oberbay", :area_code => "8086") + AreaCode.create(:country => germany, :name => "Kirchseeon", :area_code => "8091") + AreaCode.create(:country => germany, :name => "Grafing b München", :area_code => "8092") + AreaCode.create(:country => germany, :name => "Glonn Kr Ebersberg", :area_code => "8093") + AreaCode.create(:country => germany, :name => "Steinhöring", :area_code => "8094") + AreaCode.create(:country => germany, :name => "Aying", :area_code => "8095") + AreaCode.create(:country => germany, :name => "Höhenkirchen-Siegertsbrunn", :area_code => "8102") + AreaCode.create(:country => germany, :name => "Sauerlach", :area_code => "8104") + AreaCode.create(:country => germany, :name => "Gilching", :area_code => "8105") + AreaCode.create(:country => germany, :name => "Vaterstetten", :area_code => "8106") + AreaCode.create(:country => germany, :name => "Hallbergmoos", :area_code => "811") + AreaCode.create(:country => germany, :name => "Markt Schwaben", :area_code => "8121") + AreaCode.create(:country => germany, :name => "Erding", :area_code => "8122") + AreaCode.create(:country => germany, :name => "Moosinning", :area_code => "8123") + AreaCode.create(:country => germany, :name => "Forstern Oberbay", :area_code => "8124") + AreaCode.create(:country => germany, :name => "Dachau", :area_code => "8131") + AreaCode.create(:country => germany, :name => "Haimhausen Oberbay", :area_code => "8133") + AreaCode.create(:country => germany, :name => "Odelzhausen", :area_code => "8134") + AreaCode.create(:country => germany, :name => "Sulzemoos", :area_code => "8135") + AreaCode.create(:country => germany, :name => "Markt Indersdorf", :area_code => "8136") + AreaCode.create(:country => germany, :name => "Petershausen", :area_code => "8137") + AreaCode.create(:country => germany, :name => "Schwabhausen b Dachau", :area_code => "8138") + AreaCode.create(:country => germany, :name => "Röhrmoos", :area_code => "8139") + AreaCode.create(:country => germany, :name => "Fürstenfeldbruck", :area_code => "8141") + AreaCode.create(:country => germany, :name => "Olching", :area_code => "8142") + AreaCode.create(:country => germany, :name => "Inning a Ammersee", :area_code => "8143") + AreaCode.create(:country => germany, :name => "Grafrath", :area_code => "8144") + AreaCode.create(:country => germany, :name => "Mammendorf", :area_code => "8145") + AreaCode.create(:country => germany, :name => "Moorenweis", :area_code => "8146") + AreaCode.create(:country => germany, :name => "Starnberg", :area_code => "8151") + AreaCode.create(:country => germany, :name => "Herrsching a Ammersee", :area_code => "8152") + AreaCode.create(:country => germany, :name => "Wessling", :area_code => "8153") + AreaCode.create(:country => germany, :name => "Feldafing", :area_code => "8157") + AreaCode.create(:country => germany, :name => "Tutzing", :area_code => "8158") + AreaCode.create(:country => germany, :name => "Freising", :area_code => "8161") + AreaCode.create(:country => germany, :name => "Neufahrn b Freising", :area_code => "8165") + AreaCode.create(:country => germany, :name => "Allershausen Oberbay", :area_code => "8166") + AreaCode.create(:country => germany, :name => "Zolling", :area_code => "8167") + AreaCode.create(:country => germany, :name => "Attenkirchen", :area_code => "8168") + AreaCode.create(:country => germany, :name => "Straßlach-Dingharting", :area_code => "8170") + AreaCode.create(:country => germany, :name => "Wolfratshausen", :area_code => "8171") + AreaCode.create(:country => germany, :name => "Egling b Wolfratshausen", :area_code => "8176") + AreaCode.create(:country => germany, :name => "Münsing Starnberger See", :area_code => "8177") + AreaCode.create(:country => germany, :name => "Icking", :area_code => "8178") + AreaCode.create(:country => germany, :name => "Eurasburg a d Loisach", :area_code => "8179") + AreaCode.create(:country => germany, :name => "Landsberg a Lech", :area_code => "8191") + AreaCode.create(:country => germany, :name => "Schondorf a Ammersee", :area_code => "8192") + AreaCode.create(:country => germany, :name => "Geltendorf", :area_code => "8193") + AreaCode.create(:country => germany, :name => "Vilgertshofen", :area_code => "8194") + AreaCode.create(:country => germany, :name => "Weil Kr Landsberg a Lech", :area_code => "8195") + AreaCode.create(:country => germany, :name => "Pürgen", :area_code => "8196") + AreaCode.create(:country => germany, :name => "Althegnenberg", :area_code => "8202") + AreaCode.create(:country => germany, :name => "Grossaitingen", :area_code => "8203") + AreaCode.create(:country => germany, :name => "Mickhausen", :area_code => "8204") + AreaCode.create(:country => germany, :name => "Dasing", :area_code => "8205") + AreaCode.create(:country => germany, :name => "Egling a d Paar", :area_code => "8206") + AreaCode.create(:country => germany, :name => "Affing", :area_code => "8207") + AreaCode.create(:country => germany, :name => "Eurasburg b Augsburg", :area_code => "8208") + AreaCode.create(:country => germany, :name => "Augsburg", :area_code => "821") + AreaCode.create(:country => germany, :name => "Günzburg", :area_code => "8221") + AreaCode.create(:country => germany, :name => "Burgau Schwab", :area_code => "8222") + AreaCode.create(:country => germany, :name => "Ichenhausen", :area_code => "8223") + AreaCode.create(:country => germany, :name => "Offingen Donau", :area_code => "8224") + AreaCode.create(:country => germany, :name => "Jettingen-Scheppach", :area_code => "8225") + AreaCode.create(:country => germany, :name => "Bibertal", :area_code => "8226") + AreaCode.create(:country => germany, :name => "Gablingen", :area_code => "8230") + AreaCode.create(:country => germany, :name => "Königsbrunn b Augsburg", :area_code => "8231") + AreaCode.create(:country => germany, :name => "Schwabmünchen", :area_code => "8232") + AreaCode.create(:country => germany, :name => "Kissing", :area_code => "8233") + AreaCode.create(:country => germany, :name => "Bobingen", :area_code => "8234") + AreaCode.create(:country => germany, :name => "Fischach", :area_code => "8236") + AreaCode.create(:country => germany, :name => "Aindling", :area_code => "8237") + AreaCode.create(:country => germany, :name => "Gessertshausen", :area_code => "8238") + AreaCode.create(:country => germany, :name => "Langenneufnach", :area_code => "8239") + AreaCode.create(:country => germany, :name => "Buchloe", :area_code => "8241") + AreaCode.create(:country => germany, :name => "Fuchstal", :area_code => "8243") + AreaCode.create(:country => germany, :name => "Türkheim Wertach", :area_code => "8245") + AreaCode.create(:country => germany, :name => "Waal", :area_code => "8246") + AreaCode.create(:country => germany, :name => "Bad Wörishofen", :area_code => "8247") + AreaCode.create(:country => germany, :name => "Lamerdingen", :area_code => "8248") + AreaCode.create(:country => germany, :name => "Ettringen Wertach", :area_code => "8249") + AreaCode.create(:country => germany, :name => "Hilgertshausen-Tandern", :area_code => "8250") + AreaCode.create(:country => germany, :name => "Aichach", :area_code => "8251") + AreaCode.create(:country => germany, :name => "Schrobenhausen", :area_code => "8252") + AreaCode.create(:country => germany, :name => "Pöttmes", :area_code => "8253") + AreaCode.create(:country => germany, :name => "Altomünster", :area_code => "8254") + AreaCode.create(:country => germany, :name => "Inchenhofen", :area_code => "8257") + AreaCode.create(:country => germany, :name => "Sielenbach", :area_code => "8258") + AreaCode.create(:country => germany, :name => "Schiltberg", :area_code => "8259") + AreaCode.create(:country => germany, :name => "Mindelheim", :area_code => "8261") + AreaCode.create(:country => germany, :name => "Mittelneufnach", :area_code => "8262") + AreaCode.create(:country => germany, :name => "Breitenbrunn Schwab", :area_code => "8263") + AreaCode.create(:country => germany, :name => "Pfaffenhausen Schwab", :area_code => "8265") + AreaCode.create(:country => germany, :name => "Kirchheim i Schw", :area_code => "8266") + AreaCode.create(:country => germany, :name => "Dirlewang", :area_code => "8267") + AreaCode.create(:country => germany, :name => "Tussenhausen", :area_code => "8268") + AreaCode.create(:country => germany, :name => "Unteregg b Mindelheim", :area_code => "8269") + AreaCode.create(:country => germany, :name => "Meitingen", :area_code => "8271") + AreaCode.create(:country => germany, :name => "Wertingen", :area_code => "8272") + AreaCode.create(:country => germany, :name => "Nordendorf", :area_code => "8273") + AreaCode.create(:country => germany, :name => "Buttenwiesen", :area_code => "8274") + AreaCode.create(:country => germany, :name => "Baar Schwaben", :area_code => "8276") + AreaCode.create(:country => germany, :name => "Thannhausen Schwab", :area_code => "8281") + AreaCode.create(:country => germany, :name => "Krumbach Schwaben", :area_code => "8282") + AreaCode.create(:country => germany, :name => "Neuburg a d Kammel", :area_code => "8283") + AreaCode.create(:country => germany, :name => "Ziemetshausen", :area_code => "8284") + AreaCode.create(:country => germany, :name => "Burtenbach", :area_code => "8285") + AreaCode.create(:country => germany, :name => "Zusmarshausen", :area_code => "8291") + AreaCode.create(:country => germany, :name => "Dinkelscherben", :area_code => "8292") + AreaCode.create(:country => germany, :name => "Welden b Augsburg", :area_code => "8293") + AreaCode.create(:country => germany, :name => "Horgau", :area_code => "8294") + AreaCode.create(:country => germany, :name => "Altenmünster Schwab", :area_code => "8295") + AreaCode.create(:country => germany, :name => "Villenbach", :area_code => "8296") + AreaCode.create(:country => germany, :name => "Görisried", :area_code => "8302") + AreaCode.create(:country => germany, :name => "Waltenhofen", :area_code => "8303") + AreaCode.create(:country => germany, :name => "Wildpoldsried", :area_code => "8304") + AreaCode.create(:country => germany, :name => "Ronsberg", :area_code => "8306") + AreaCode.create(:country => germany, :name => "Kempten Allgäu", :area_code => "831") + AreaCode.create(:country => germany, :name => "Missen-Wilhams", :area_code => "8320") + AreaCode.create(:country => germany, :name => "Sonthofen", :area_code => "8321") + AreaCode.create(:country => germany, :name => "Oberstdorf", :area_code => "8322") + AreaCode.create(:country => germany, :name => "Immenstadt i Allgäu", :area_code => "8323") + AreaCode.create(:country => germany, :name => "Hindelang", :area_code => "8324") + AreaCode.create(:country => germany, :name => "Oberstaufen-Thalkirchdorf", :area_code => "8325") + AreaCode.create(:country => germany, :name => "Fischen i Allgäu", :area_code => "8326") + AreaCode.create(:country => germany, :name => "Rettenberg", :area_code => "8327") + AreaCode.create(:country => germany, :name => "Balderschwang", :area_code => "8328") + AreaCode.create(:country => germany, :name => "Riezlern (Österreich)", :area_code => "8329") + AreaCode.create(:country => germany, :name => "Legau", :area_code => "8330") + AreaCode.create(:country => germany, :name => "Memmingen", :area_code => "8331") + AreaCode.create(:country => germany, :name => "Ottobeuren", :area_code => "8332") + AreaCode.create(:country => germany, :name => "Babenhausen Schwab", :area_code => "8333") + AreaCode.create(:country => germany, :name => "Bad Grönenbach", :area_code => "8334") + AreaCode.create(:country => germany, :name => "Fellheim", :area_code => "8335") + AreaCode.create(:country => germany, :name => "Erkheim", :area_code => "8336") + AreaCode.create(:country => germany, :name => "Altenstadt Iller", :area_code => "8337") + AreaCode.create(:country => germany, :name => "Böhen", :area_code => "8338") + AreaCode.create(:country => germany, :name => "Baisweil", :area_code => "8340") + AreaCode.create(:country => germany, :name => "Kaufbeuren", :area_code => "8341") + AreaCode.create(:country => germany, :name => "Marktoberdorf", :area_code => "8342") + AreaCode.create(:country => germany, :name => "Aitrang", :area_code => "8343") + AreaCode.create(:country => germany, :name => "Westendorf b Kaufbeuren", :area_code => "8344") + AreaCode.create(:country => germany, :name => "Stöttwang", :area_code => "8345") + AreaCode.create(:country => germany, :name => "Pforzen", :area_code => "8346") + AreaCode.create(:country => germany, :name => "Friesenried", :area_code => "8347") + AreaCode.create(:country => germany, :name => "Bidingen", :area_code => "8348") + AreaCode.create(:country => germany, :name => "Stötten a Auerberg", :area_code => "8349") + AreaCode.create(:country => germany, :name => "Nesselwang", :area_code => "8361") + AreaCode.create(:country => germany, :name => "Füssen", :area_code => "8362") + AreaCode.create(:country => germany, :name => "Pfronten", :area_code => "8363") + AreaCode.create(:country => germany, :name => "Seeg", :area_code => "8364") + AreaCode.create(:country => germany, :name => "Wertach", :area_code => "8365") + AreaCode.create(:country => germany, :name => "Oy-Mittelberg", :area_code => "8366") + AreaCode.create(:country => germany, :name => "Roßhaupten Forggensee", :area_code => "8367") + AreaCode.create(:country => germany, :name => "Halblech", :area_code => "8368") + AreaCode.create(:country => germany, :name => "Rückholz", :area_code => "8369") + AreaCode.create(:country => germany, :name => "Wiggensbach", :area_code => "8370") + AreaCode.create(:country => germany, :name => "Obergünzburg", :area_code => "8372") + AreaCode.create(:country => germany, :name => "Altusried", :area_code => "8373") + AreaCode.create(:country => germany, :name => "Dietmannsried", :area_code => "8374") + AreaCode.create(:country => germany, :name => "Weitnau", :area_code => "8375") + AreaCode.create(:country => germany, :name => "Sulzberg Allgäu", :area_code => "8376") + AreaCode.create(:country => germany, :name => "Unterthingau", :area_code => "8377") + AreaCode.create(:country => germany, :name => "Buchenberg b Kempten", :area_code => "8378") + AreaCode.create(:country => germany, :name => "Waltenhofen-Oberdorf", :area_code => "8379") + AreaCode.create(:country => germany, :name => "Achberg", :area_code => "8380") + AreaCode.create(:country => germany, :name => "Lindenberg i Allgäu", :area_code => "8381") + AreaCode.create(:country => germany, :name => "Lindau Bodensee", :area_code => "8382") + AreaCode.create(:country => germany, :name => "Grünenbach Allgäu", :area_code => "8383") + AreaCode.create(:country => germany, :name => "Röthenbach Allgäu", :area_code => "8384") + AreaCode.create(:country => germany, :name => "Hergatz", :area_code => "8385") + AreaCode.create(:country => germany, :name => "Oberstaufen", :area_code => "8386") + AreaCode.create(:country => germany, :name => "Weiler-Simmerberg", :area_code => "8387") + AreaCode.create(:country => germany, :name => "Hergensweiler", :area_code => "8388") + AreaCode.create(:country => germany, :name => "Weissensberg", :area_code => "8389") + AreaCode.create(:country => germany, :name => "Markt Rettenbach", :area_code => "8392") + AreaCode.create(:country => germany, :name => "Holzgünz", :area_code => "8393") + AreaCode.create(:country => germany, :name => "Lautrach", :area_code => "8394") + AreaCode.create(:country => germany, :name => "Tannheim Württ", :area_code => "8395") + AreaCode.create(:country => germany, :name => "Münchsmünster", :area_code => "8402") + AreaCode.create(:country => germany, :name => "Pförring", :area_code => "8403") + AreaCode.create(:country => germany, :name => "Oberdolling", :area_code => "8404") + AreaCode.create(:country => germany, :name => "Stammham b Ingolstadt", :area_code => "8405") + AreaCode.create(:country => germany, :name => "Böhmfeld", :area_code => "8406") + AreaCode.create(:country => germany, :name => "Grossmehring", :area_code => "8407") + AreaCode.create(:country => germany, :name => "Ingolstadt Donau", :area_code => "841") + AreaCode.create(:country => germany, :name => "Eichstätt Bay", :area_code => "8421") + AreaCode.create(:country => germany, :name => "Dollnstein", :area_code => "8422") + AreaCode.create(:country => germany, :name => "Titting", :area_code => "8423") + AreaCode.create(:country => germany, :name => "Nassenfels", :area_code => "8424") + AreaCode.create(:country => germany, :name => "Walting Kr Eichstätt", :area_code => "8426") + AreaCode.create(:country => germany, :name => "Wellheim", :area_code => "8427") + AreaCode.create(:country => germany, :name => "Neuburg a d Donau", :area_code => "8431") + AreaCode.create(:country => germany, :name => "Burgheim", :area_code => "8432") + AreaCode.create(:country => germany, :name => "Königsmoos", :area_code => "8433") + AreaCode.create(:country => germany, :name => "Rennertshofen", :area_code => "8434") + AreaCode.create(:country => germany, :name => "Ehekirchen", :area_code => "8435") + AreaCode.create(:country => germany, :name => "Pfaffenhofen a d Ilm", :area_code => "8441") + AreaCode.create(:country => germany, :name => "Wolnzach", :area_code => "8442") + AreaCode.create(:country => germany, :name => "Hohenwart Paar", :area_code => "8443") + AreaCode.create(:country => germany, :name => "Schweitenkirchen", :area_code => "8444") + AreaCode.create(:country => germany, :name => "Gerolsbach", :area_code => "8445") + AreaCode.create(:country => germany, :name => "Pörnbach", :area_code => "8446") + AreaCode.create(:country => germany, :name => "Ingolstadt-Zuchering", :area_code => "8450") + AreaCode.create(:country => germany, :name => "Geisenfeld", :area_code => "8452") + AreaCode.create(:country => germany, :name => "Reichertshofen Oberbay", :area_code => "8453") + AreaCode.create(:country => germany, :name => "Karlshuld", :area_code => "8454") + AreaCode.create(:country => germany, :name => "Lenting", :area_code => "8456") + AreaCode.create(:country => germany, :name => "Vohburg a d Donau", :area_code => "8457") + AreaCode.create(:country => germany, :name => "Gaimersheim", :area_code => "8458") + AreaCode.create(:country => germany, :name => "Manching", :area_code => "8459") + AreaCode.create(:country => germany, :name => "Berching-Holnstein", :area_code => "8460") + AreaCode.create(:country => germany, :name => "Beilngries", :area_code => "8461") + AreaCode.create(:country => germany, :name => "Berching", :area_code => "8462") + AreaCode.create(:country => germany, :name => "Greding", :area_code => "8463") + AreaCode.create(:country => germany, :name => "Dietfurt a d Altmühl", :area_code => "8464") + AreaCode.create(:country => germany, :name => "Kipfenberg", :area_code => "8465") + AreaCode.create(:country => germany, :name => "Denkendorf Oberbay", :area_code => "8466") + AreaCode.create(:country => germany, :name => "Kinding", :area_code => "8467") + AreaCode.create(:country => germany, :name => "Altmannstein-Pondorf", :area_code => "8468") + AreaCode.create(:country => germany, :name => "Freystadt-Burggriesbach", :area_code => "8469") + AreaCode.create(:country => germany, :name => "Thyrnau", :area_code => "8501") + AreaCode.create(:country => germany, :name => "Fürstenzell", :area_code => "8502") + AreaCode.create(:country => germany, :name => "Neuhaus a Inn", :area_code => "8503") + AreaCode.create(:country => germany, :name => "Tittling", :area_code => "8504") + AreaCode.create(:country => germany, :name => "Hutthurm", :area_code => "8505") + AreaCode.create(:country => germany, :name => "Bad Höhenstadt", :area_code => "8506") + AreaCode.create(:country => germany, :name => "Neuburg a Inn", :area_code => "8507") + AreaCode.create(:country => germany, :name => "Ruderting", :area_code => "8509") + AreaCode.create(:country => germany, :name => "Passau", :area_code => "851") + AreaCode.create(:country => germany, :name => "Pocking", :area_code => "8531") + AreaCode.create(:country => germany, :name => "Griesbach i Rottal", :area_code => "8532") + AreaCode.create(:country => germany, :name => "Rotthalmünster", :area_code => "8533") + AreaCode.create(:country => germany, :name => "Tettenweis", :area_code => "8534") + AreaCode.create(:country => germany, :name => "Haarbach", :area_code => "8535") + AreaCode.create(:country => germany, :name => "Kößlarn", :area_code => "8536") + AreaCode.create(:country => germany, :name => "Bad Füssing-Aigen", :area_code => "8537") + AreaCode.create(:country => germany, :name => "Pocking-Hartkirchen", :area_code => "8538") + AreaCode.create(:country => germany, :name => "Vilshofen Niederbay", :area_code => "8541") + AreaCode.create(:country => germany, :name => "Ortenburg", :area_code => "8542") + AreaCode.create(:country => germany, :name => "Aidenbach", :area_code => "8543") + AreaCode.create(:country => germany, :name => "Eging a See", :area_code => "8544") + AreaCode.create(:country => germany, :name => "Hofkirchen Bay", :area_code => "8545") + AreaCode.create(:country => germany, :name => "Windorf-Otterskirchen", :area_code => "8546") + AreaCode.create(:country => germany, :name => "Osterhofen-Gergweis", :area_code => "8547") + AreaCode.create(:country => germany, :name => "Vilshofen-Sandbach", :area_code => "8548") + AreaCode.create(:country => germany, :name => "Vilshofen-Pleinting", :area_code => "8549") + AreaCode.create(:country => germany, :name => "Philippsreut", :area_code => "8550") + AreaCode.create(:country => germany, :name => "Freyung", :area_code => "8551") + AreaCode.create(:country => germany, :name => "Grafenau Niederbay", :area_code => "8552") + AreaCode.create(:country => germany, :name => "Spiegelau", :area_code => "8553") + AreaCode.create(:country => germany, :name => "Schönberg Niederbay", :area_code => "8554") + AreaCode.create(:country => germany, :name => "Perlesreut", :area_code => "8555") + AreaCode.create(:country => germany, :name => "Haidmühle", :area_code => "8556") + AreaCode.create(:country => germany, :name => "Mauth", :area_code => "8557") + AreaCode.create(:country => germany, :name => "Hohenau Niederbay", :area_code => "8558") + AreaCode.create(:country => germany, :name => "Pfarrkirchen Niederbay", :area_code => "8561") + AreaCode.create(:country => germany, :name => "Triftern", :area_code => "8562") + AreaCode.create(:country => germany, :name => "Bad Birnbach Rottal", :area_code => "8563") + AreaCode.create(:country => germany, :name => "Johanniskirchen", :area_code => "8564") + AreaCode.create(:country => germany, :name => "Dietersburg-Baumgarten", :area_code => "8565") + AreaCode.create(:country => germany, :name => "Simbach a Inn", :area_code => "8571") + AreaCode.create(:country => germany, :name => "Tann Niederbay", :area_code => "8572") + AreaCode.create(:country => germany, :name => "Ering", :area_code => "8573") + AreaCode.create(:country => germany, :name => "Wittibreut", :area_code => "8574") + AreaCode.create(:country => germany, :name => "Waldkirchen Niederbay", :area_code => "8581") + AreaCode.create(:country => germany, :name => "Röhrnbach", :area_code => "8582") + AreaCode.create(:country => germany, :name => "Neureichenau", :area_code => "8583") + AreaCode.create(:country => germany, :name => "Breitenberg Niederbay", :area_code => "8584") + AreaCode.create(:country => germany, :name => "Grainet", :area_code => "8585") + AreaCode.create(:country => germany, :name => "Hauzenberg", :area_code => "8586") + AreaCode.create(:country => germany, :name => "Obernzell", :area_code => "8591") + AreaCode.create(:country => germany, :name => "Wegscheid Niederbay", :area_code => "8592") + AreaCode.create(:country => germany, :name => "Untergriesbach", :area_code => "8593") + AreaCode.create(:country => germany, :name => "Traunstein", :area_code => "861") + AreaCode.create(:country => germany, :name => "Trostberg", :area_code => "8621") + AreaCode.create(:country => germany, :name => "Tacherting- Peterskirchen", :area_code => "8622") + AreaCode.create(:country => germany, :name => "Kirchweidach", :area_code => "8623") + AreaCode.create(:country => germany, :name => "Obing", :area_code => "8624") + AreaCode.create(:country => germany, :name => "Kienberg Oberbay", :area_code => "8628") + AreaCode.create(:country => germany, :name => "Palling", :area_code => "8629") + AreaCode.create(:country => germany, :name => "Oberneukirchen", :area_code => "8630") + AreaCode.create(:country => germany, :name => "Mühldorf a Inn", :area_code => "8631") + AreaCode.create(:country => germany, :name => "Tüßling", :area_code => "8633") + AreaCode.create(:country => germany, :name => "Garching a d Alz", :area_code => "8634") + AreaCode.create(:country => germany, :name => "Pleiskirchen", :area_code => "8635") + AreaCode.create(:country => germany, :name => "Ampfing", :area_code => "8636") + AreaCode.create(:country => germany, :name => "Lohkirchen", :area_code => "8637") + AreaCode.create(:country => germany, :name => "Waldkraiburg", :area_code => "8638") + AreaCode.create(:country => germany, :name => "Neumarkt-Sankt Veit", :area_code => "8639") + AreaCode.create(:country => germany, :name => "Reit Im Winkl", :area_code => "8640") + AreaCode.create(:country => germany, :name => "Grassau Kr Traunstein", :area_code => "8641") + AreaCode.create(:country => germany, :name => "Übersee", :area_code => "8642") + AreaCode.create(:country => germany, :name => "Schleching", :area_code => "8649") + AreaCode.create(:country => germany, :name => "Marktschellenberg", :area_code => "8650") + AreaCode.create(:country => germany, :name => "Bad Reichenhall", :area_code => "8651") + AreaCode.create(:country => germany, :name => "Berchtesgaden", :area_code => "8652") + AreaCode.create(:country => germany, :name => "Freilassing", :area_code => "8654") + AreaCode.create(:country => germany, :name => "Anger", :area_code => "8656") + AreaCode.create(:country => germany, :name => "Ramsau b Berchtesgaden", :area_code => "8657") + AreaCode.create(:country => germany, :name => "Grabenstätt Chiemsee", :area_code => "8661") + AreaCode.create(:country => germany, :name => "Siegsdorf Kr Traunstein", :area_code => "8662") + AreaCode.create(:country => germany, :name => "Ruhpolding", :area_code => "8663") + AreaCode.create(:country => germany, :name => "Chieming", :area_code => "8664") + AreaCode.create(:country => germany, :name => "Inzell", :area_code => "8665") + AreaCode.create(:country => germany, :name => "Teisendorf", :area_code => "8666") + AreaCode.create(:country => germany, :name => "Seeon-Seebruck", :area_code => "8667") + AreaCode.create(:country => germany, :name => "Traunreut", :area_code => "8669") + AreaCode.create(:country => germany, :name => "Reischach Kr Altötting", :area_code => "8670") + AreaCode.create(:country => germany, :name => "Altötting", :area_code => "8671") + AreaCode.create(:country => germany, :name => "Burghausen Salzach", :area_code => "8677") + AreaCode.create(:country => germany, :name => "Marktl", :area_code => "8678") + AreaCode.create(:country => germany, :name => "Burgkirchen a d Alz", :area_code => "8679") + AreaCode.create(:country => germany, :name => "Waging a See", :area_code => "8681") + AreaCode.create(:country => germany, :name => "Laufen Salzach", :area_code => "8682") + AreaCode.create(:country => germany, :name => "Tittmoning", :area_code => "8683") + AreaCode.create(:country => germany, :name => "Fridolfing", :area_code => "8684") + AreaCode.create(:country => germany, :name => "Kirchanschöring", :area_code => "8685") + AreaCode.create(:country => germany, :name => "Petting", :area_code => "8686") + AreaCode.create(:country => germany, :name => "Taching-Tengling", :area_code => "8687") + AreaCode.create(:country => germany, :name => "Wörth a d Isar", :area_code => "8702") + AreaCode.create(:country => germany, :name => "Essenbach", :area_code => "8703") + AreaCode.create(:country => germany, :name => "Altdorf-Pfettrach", :area_code => "8704") + AreaCode.create(:country => germany, :name => "Altfraunhofen", :area_code => "8705") + AreaCode.create(:country => germany, :name => "Vilsheim", :area_code => "8706") + AreaCode.create(:country => germany, :name => "Adlkofen", :area_code => "8707") + AreaCode.create(:country => germany, :name => "Weihmichl-Unterneuhausen", :area_code => "8708") + AreaCode.create(:country => germany, :name => "Eching Niederbay", :area_code => "8709") + AreaCode.create(:country => germany, :name => "Landshut", :area_code => "871") + AreaCode.create(:country => germany, :name => "Eggenfelden", :area_code => "8721") + AreaCode.create(:country => germany, :name => "Gangkofen", :area_code => "8722") + AreaCode.create(:country => germany, :name => "Arnstorf", :area_code => "8723") + AreaCode.create(:country => germany, :name => "Massing", :area_code => "8724") + AreaCode.create(:country => germany, :name => "Wurmannsquick", :area_code => "8725") + AreaCode.create(:country => germany, :name => "Schönau Niederbay", :area_code => "8726") + AreaCode.create(:country => germany, :name => "Falkenberg Niederbay", :area_code => "8727") + AreaCode.create(:country => germany, :name => "Geratskirchen", :area_code => "8728") + AreaCode.create(:country => germany, :name => "Dingolfing", :area_code => "8731") + AreaCode.create(:country => germany, :name => "Frontenhausen", :area_code => "8732") + AreaCode.create(:country => germany, :name => "Mengkofen", :area_code => "8733") + AreaCode.create(:country => germany, :name => "Reisbach Niederbay", :area_code => "8734") + AreaCode.create(:country => germany, :name => "Gangkofen-Kollbach", :area_code => "8735") + AreaCode.create(:country => germany, :name => "Vilsbiburg", :area_code => "8741") + AreaCode.create(:country => germany, :name => "Velden Vils", :area_code => "8742") + AreaCode.create(:country => germany, :name => "Geisenhausen", :area_code => "8743") + AreaCode.create(:country => germany, :name => "Gerzen", :area_code => "8744") + AreaCode.create(:country => germany, :name => "Bodenkirchen", :area_code => "8745") + AreaCode.create(:country => germany, :name => "Mainburg", :area_code => "8751") + AreaCode.create(:country => germany, :name => "Au i d Hallertau", :area_code => "8752") + AreaCode.create(:country => germany, :name => "Elsendorf Niederbay", :area_code => "8753") + AreaCode.create(:country => germany, :name => "Volkenschwand", :area_code => "8754") + AreaCode.create(:country => germany, :name => "Nandlstadt", :area_code => "8756") + AreaCode.create(:country => germany, :name => "Moosburg a d Isar", :area_code => "8761") + AreaCode.create(:country => germany, :name => "Wartenberg Oberbay", :area_code => "8762") + AreaCode.create(:country => germany, :name => "Mauern Kr Freising", :area_code => "8764") + AreaCode.create(:country => germany, :name => "Bruckberg Niederbay", :area_code => "8765") + AreaCode.create(:country => germany, :name => "Gammelsdorf", :area_code => "8766") + AreaCode.create(:country => germany, :name => "Ergoldsbach", :area_code => "8771") + AreaCode.create(:country => germany, :name => "Mallersdorf-Pfaffenberg", :area_code => "8772") + AreaCode.create(:country => germany, :name => "Neufahrn i NB", :area_code => "8773") + AreaCode.create(:country => germany, :name => "Bayerbach b Ergoldsbach", :area_code => "8774") + AreaCode.create(:country => germany, :name => "Rottenburg a d Laaber", :area_code => "8781") + AreaCode.create(:country => germany, :name => "Pfeffenhausen", :area_code => "8782") + AreaCode.create(:country => germany, :name => "Rohr i NB", :area_code => "8783") + AreaCode.create(:country => germany, :name => "Hohenthann", :area_code => "8784") + AreaCode.create(:country => germany, :name => "Rottenburg-Oberroning", :area_code => "8785") + AreaCode.create(:country => germany, :name => "Seeshaupt", :area_code => "8801") + AreaCode.create(:country => germany, :name => "Huglfing", :area_code => "8802") + AreaCode.create(:country => germany, :name => "Peissenberg", :area_code => "8803") + AreaCode.create(:country => germany, :name => "Hohenpeissenberg", :area_code => "8805") + AreaCode.create(:country => germany, :name => "Utting a Ammersee", :area_code => "8806") + AreaCode.create(:country => germany, :name => "Dießen a Ammersee", :area_code => "8807") + AreaCode.create(:country => germany, :name => "Pähl", :area_code => "8808") + AreaCode.create(:country => germany, :name => "Wessobrunn", :area_code => "8809") + AreaCode.create(:country => germany, :name => "Weilheim i OB", :area_code => "881") + AreaCode.create(:country => germany, :name => "Garmisch-Partenkirchen", :area_code => "8821") + AreaCode.create(:country => germany, :name => "Oberammergau", :area_code => "8822") + AreaCode.create(:country => germany, :name => "Mittenwald", :area_code => "8823") + AreaCode.create(:country => germany, :name => "Oberau Loisach", :area_code => "8824") + AreaCode.create(:country => germany, :name => "Krün", :area_code => "8825") + AreaCode.create(:country => germany, :name => "Murnau a Staffelsee", :area_code => "8841") + AreaCode.create(:country => germany, :name => "Bad Kohlgrub", :area_code => "8845") + AreaCode.create(:country => germany, :name => "Uffing a Staffelsee", :area_code => "8846") + AreaCode.create(:country => germany, :name => "Obersöchering", :area_code => "8847") + AreaCode.create(:country => germany, :name => "Kochel a See", :area_code => "8851") + AreaCode.create(:country => germany, :name => "Penzberg", :area_code => "8856") + AreaCode.create(:country => germany, :name => "Benediktbeuern", :area_code => "8857") + AreaCode.create(:country => germany, :name => "Kochel-Walchensee", :area_code => "8858") + AreaCode.create(:country => germany, :name => "Bernbeuren", :area_code => "8860") + AreaCode.create(:country => germany, :name => "Schongau", :area_code => "8861") + AreaCode.create(:country => germany, :name => "Steingaden Oberbay", :area_code => "8862") + AreaCode.create(:country => germany, :name => "Rottenbuch Oberbay", :area_code => "8867") + AreaCode.create(:country => germany, :name => "Schwabsoien", :area_code => "8868") + AreaCode.create(:country => germany, :name => "Kinsau", :area_code => "8869") + AreaCode.create(:country => germany, :name => "München", :area_code => "89") + AreaCode.create(:country => germany, :name => "Donauwörth", :area_code => "906") + AreaCode.create(:country => germany, :name => "Tapfheim", :area_code => "9070") + AreaCode.create(:country => germany, :name => "Dillingen a d Donau", :area_code => "9071") + AreaCode.create(:country => germany, :name => "Lauingen Donau", :area_code => "9072") + AreaCode.create(:country => germany, :name => "Gundelfingen a d Donau", :area_code => "9073") + AreaCode.create(:country => germany, :name => "Höchstädt a d Donau", :area_code => "9074") + AreaCode.create(:country => germany, :name => "Glött", :area_code => "9075") + AreaCode.create(:country => germany, :name => "Wittislingen", :area_code => "9076") + AreaCode.create(:country => germany, :name => "Bachhagel", :area_code => "9077") + AreaCode.create(:country => germany, :name => "Mertingen", :area_code => "9078") + AreaCode.create(:country => germany, :name => "Harburg Schwaben", :area_code => "9080") + AreaCode.create(:country => germany, :name => "Nördlingen", :area_code => "9081") + AreaCode.create(:country => germany, :name => "Oettingen i Bay", :area_code => "9082") + AreaCode.create(:country => germany, :name => "Möttingen", :area_code => "9083") + AreaCode.create(:country => germany, :name => "Bissingen Schwab", :area_code => "9084") + AreaCode.create(:country => germany, :name => "Alerheim", :area_code => "9085") + AreaCode.create(:country => germany, :name => "Fremdingen", :area_code => "9086") + AreaCode.create(:country => germany, :name => "Marktoffingen", :area_code => "9087") + AreaCode.create(:country => germany, :name => "Mönchsdeggingen", :area_code => "9088") + AreaCode.create(:country => germany, :name => "Bissingen-Unterringingen", :area_code => "9089") + AreaCode.create(:country => germany, :name => "Rain Lech", :area_code => "9090") + AreaCode.create(:country => germany, :name => "Monheim Schwab", :area_code => "9091") + AreaCode.create(:country => germany, :name => "Wemding", :area_code => "9092") + AreaCode.create(:country => germany, :name => "Polsingen", :area_code => "9093") + AreaCode.create(:country => germany, :name => "Tagmersheim", :area_code => "9094") + AreaCode.create(:country => germany, :name => "Marxheim", :area_code => "9097") + AreaCode.create(:country => germany, :name => "Kaisheim", :area_code => "9099") + AreaCode.create(:country => germany, :name => "Langenzenn", :area_code => "9101") + AreaCode.create(:country => germany, :name => "Wilhermsdorf", :area_code => "9102") + AreaCode.create(:country => germany, :name => "Cadolzburg", :area_code => "9103") + AreaCode.create(:country => germany, :name => "Emskirchen", :area_code => "9104") + AreaCode.create(:country => germany, :name => "Grosshabersdorf", :area_code => "9105") + AreaCode.create(:country => germany, :name => "Markt Erlbach", :area_code => "9106") + AreaCode.create(:country => germany, :name => "Trautskirchen", :area_code => "9107") + AreaCode.create(:country => germany, :name => "Nürnberg", :area_code => "911") + AreaCode.create(:country => germany, :name => "Leinburg", :area_code => "9120") + AreaCode.create(:country => germany, :name => "Schwabach", :area_code => "9122") + AreaCode.create(:country => germany, :name => "Lauf a d Pegnitz", :area_code => "9123") + AreaCode.create(:country => germany, :name => "Eckental", :area_code => "9126") + AreaCode.create(:country => germany, :name => "Rosstal Mittelfr", :area_code => "9127") + AreaCode.create(:country => germany, :name => "Feucht", :area_code => "9128") + AreaCode.create(:country => germany, :name => "Wendelstein", :area_code => "9129") + AreaCode.create(:country => germany, :name => "Erlangen", :area_code => "9131") + AreaCode.create(:country => germany, :name => "Herzogenaurach", :area_code => "9132") + AreaCode.create(:country => germany, :name => "Baiersdorf Mittelfr", :area_code => "9133") + AreaCode.create(:country => germany, :name => "Neunkirchen a Brand", :area_code => "9134") + AreaCode.create(:country => germany, :name => "Heßdorf Mittelfr", :area_code => "9135") + AreaCode.create(:country => germany, :name => "Weißenburg i Bay", :area_code => "9141") + AreaCode.create(:country => germany, :name => "Treuchtlingen", :area_code => "9142") + AreaCode.create(:country => germany, :name => "Pappenheim Mittelfr", :area_code => "9143") + AreaCode.create(:country => germany, :name => "Pleinfeld", :area_code => "9144") + AreaCode.create(:country => germany, :name => "Solnhofen", :area_code => "9145") + AreaCode.create(:country => germany, :name => "Markt Berolzheim", :area_code => "9146") + AreaCode.create(:country => germany, :name => "Nennslingen", :area_code => "9147") + AreaCode.create(:country => germany, :name => "Ettenstatt", :area_code => "9148") + AreaCode.create(:country => germany, :name => "Weissenburg-Suffersheim", :area_code => "9149") + AreaCode.create(:country => germany, :name => "Hersbruck", :area_code => "9151") + AreaCode.create(:country => germany, :name => "Hartenstein Mittelfr", :area_code => "9152") + AreaCode.create(:country => germany, :name => "Schnaittach", :area_code => "9153") + AreaCode.create(:country => germany, :name => "Pommelsbrunn", :area_code => "9154") + AreaCode.create(:country => germany, :name => "Simmelsdorf", :area_code => "9155") + AreaCode.create(:country => germany, :name => "Neuhaus a d Pegnitz", :area_code => "9156") + AreaCode.create(:country => germany, :name => "Alfeld Mittelfr", :area_code => "9157") + AreaCode.create(:country => germany, :name => "Offenhausen Mittelfr", :area_code => "9158") + AreaCode.create(:country => germany, :name => "Neustadt a d Aisch", :area_code => "9161") + AreaCode.create(:country => germany, :name => "Scheinfeld", :area_code => "9162") + AreaCode.create(:country => germany, :name => "Dachsbach", :area_code => "9163") + AreaCode.create(:country => germany, :name => "Langenfeld Mittelfr", :area_code => "9164") + AreaCode.create(:country => germany, :name => "Sugenheim", :area_code => "9165") + AreaCode.create(:country => germany, :name => "Münchsteinach", :area_code => "9166") + AreaCode.create(:country => germany, :name => "Oberscheinfeld", :area_code => "9167") + AreaCode.create(:country => germany, :name => "Schwanstetten", :area_code => "9170") + AreaCode.create(:country => germany, :name => "Roth Mittelfr", :area_code => "9171") + AreaCode.create(:country => germany, :name => "Georgensgmünd", :area_code => "9172") + AreaCode.create(:country => germany, :name => "Thalmässing", :area_code => "9173") + AreaCode.create(:country => germany, :name => "Hilpoltstein", :area_code => "9174") + AreaCode.create(:country => germany, :name => "Spalt", :area_code => "9175") + AreaCode.create(:country => germany, :name => "Allersberg", :area_code => "9176") + AreaCode.create(:country => germany, :name => "Heideck", :area_code => "9177") + AreaCode.create(:country => germany, :name => "Abenberg Mittelfr", :area_code => "9178") + AreaCode.create(:country => germany, :name => "Freystadt", :area_code => "9179") + AreaCode.create(:country => germany, :name => "Pyrbaum", :area_code => "9180") + AreaCode.create(:country => germany, :name => "Neumarkt i d Opf", :area_code => "9181") + AreaCode.create(:country => germany, :name => "Velburg", :area_code => "9182") + AreaCode.create(:country => germany, :name => "Burgthann", :area_code => "9183") + AreaCode.create(:country => germany, :name => "Deining Oberpf", :area_code => "9184") + AreaCode.create(:country => germany, :name => "Mühlhausen Oberpf", :area_code => "9185") + AreaCode.create(:country => germany, :name => "Lauterhofen Oberpf", :area_code => "9186") + AreaCode.create(:country => germany, :name => "Altdorf b Nürnberg", :area_code => "9187") + AreaCode.create(:country => germany, :name => "Postbauer-Heng", :area_code => "9188") + AreaCode.create(:country => germany, :name => "Berg b Neumarkt i d Opf", :area_code => "9189") + AreaCode.create(:country => germany, :name => "Heroldsbach", :area_code => "9190") + AreaCode.create(:country => germany, :name => "Forchheim Oberfr", :area_code => "9191") + AreaCode.create(:country => germany, :name => "Gräfenberg", :area_code => "9192") + AreaCode.create(:country => germany, :name => "Höchstadt a d Aisch", :area_code => "9193") + AreaCode.create(:country => germany, :name => "Ebermannstadt", :area_code => "9194") + AreaCode.create(:country => germany, :name => "Adelsdorf Mittelfr", :area_code => "9195") + AreaCode.create(:country => germany, :name => "Wiesenttal", :area_code => "9196") + AreaCode.create(:country => germany, :name => "Egloffstein", :area_code => "9197") + AreaCode.create(:country => germany, :name => "Heiligenstadt i Ofr", :area_code => "9198") + AreaCode.create(:country => germany, :name => "Kunreuth", :area_code => "9199") + AreaCode.create(:country => germany, :name => "Gesees", :area_code => "9201") + AreaCode.create(:country => germany, :name => "Waischenfeld", :area_code => "9202") + AreaCode.create(:country => germany, :name => "Neudrossenfeld", :area_code => "9203") + AreaCode.create(:country => germany, :name => "Plankenfels", :area_code => "9204") + AreaCode.create(:country => germany, :name => "Vorbach", :area_code => "9205") + AreaCode.create(:country => germany, :name => "Mistelgau-Obernsees", :area_code => "9206") + AreaCode.create(:country => germany, :name => "Königsfeld Oberfr", :area_code => "9207") + AreaCode.create(:country => germany, :name => "Bindlach", :area_code => "9208") + AreaCode.create(:country => germany, :name => "Emtmannsberg", :area_code => "9209") + AreaCode.create(:country => germany, :name => "Bayreuth", :area_code => "921") + AreaCode.create(:country => germany, :name => "Kasendorf-Azendorf", :area_code => "9220") + AreaCode.create(:country => germany, :name => "Kulmbach", :area_code => "9221") + AreaCode.create(:country => germany, :name => "Presseck", :area_code => "9222") + AreaCode.create(:country => germany, :name => "Rugendorf", :area_code => "9223") + AreaCode.create(:country => germany, :name => "Stadtsteinach", :area_code => "9225") + AreaCode.create(:country => germany, :name => "Neuenmarkt", :area_code => "9227") + AreaCode.create(:country => germany, :name => "Thurnau", :area_code => "9228") + AreaCode.create(:country => germany, :name => "Mainleus", :area_code => "9229") + AreaCode.create(:country => germany, :name => "Marktredwitz", :area_code => "9231") + AreaCode.create(:country => germany, :name => "Wunsiedel", :area_code => "9232") + AreaCode.create(:country => germany, :name => "Arzberg Oberfr", :area_code => "9233") + AreaCode.create(:country => germany, :name => "Neusorg", :area_code => "9234") + AreaCode.create(:country => germany, :name => "Thierstein", :area_code => "9235") + AreaCode.create(:country => germany, :name => "Nagel", :area_code => "9236") + AreaCode.create(:country => germany, :name => "Röslau", :area_code => "9238") + AreaCode.create(:country => germany, :name => "Pegnitz", :area_code => "9241") + AreaCode.create(:country => germany, :name => "Gößweinstein", :area_code => "9242") + AreaCode.create(:country => germany, :name => "Pottenstein", :area_code => "9243") + AreaCode.create(:country => germany, :name => "Betzenstein", :area_code => "9244") + AreaCode.create(:country => germany, :name => "Obertrubach", :area_code => "9245") + AreaCode.create(:country => germany, :name => "Pegnitz-Trockau", :area_code => "9246") + AreaCode.create(:country => germany, :name => "Münchberg", :area_code => "9251") + AreaCode.create(:country => germany, :name => "Helmbrechts", :area_code => "9252") + AreaCode.create(:country => germany, :name => "Weissenstadt", :area_code => "9253") + AreaCode.create(:country => germany, :name => "Gefrees", :area_code => "9254") + AreaCode.create(:country => germany, :name => "Marktleugast", :area_code => "9255") + AreaCode.create(:country => germany, :name => "Stammbach", :area_code => "9256") + AreaCode.create(:country => germany, :name => "Zell Oberfr", :area_code => "9257") + AreaCode.create(:country => germany, :name => "Wilhelmsthal Oberfr", :area_code => "9260") + AreaCode.create(:country => germany, :name => "Kronach", :area_code => "9261") + AreaCode.create(:country => germany, :name => "Wallenfels", :area_code => "9262") + AreaCode.create(:country => germany, :name => "Ludwigsstadt", :area_code => "9263") + AreaCode.create(:country => germany, :name => "Küps", :area_code => "9264") + AreaCode.create(:country => germany, :name => "Pressig", :area_code => "9265") + AreaCode.create(:country => germany, :name => "Mitwitz", :area_code => "9266") + AreaCode.create(:country => germany, :name => "Nordhalben", :area_code => "9267") + AreaCode.create(:country => germany, :name => "Teuschnitz", :area_code => "9268") + AreaCode.create(:country => germany, :name => "Tettau Kr Kronach", :area_code => "9269") + AreaCode.create(:country => germany, :name => "Creussen", :area_code => "9270") + AreaCode.create(:country => germany, :name => "Thurnau-Alladorf", :area_code => "9271") + AreaCode.create(:country => germany, :name => "Fichtelberg", :area_code => "9272") + AreaCode.create(:country => germany, :name => "Bad Berneck i Fichtelgebirge", :area_code => "9273") + AreaCode.create(:country => germany, :name => "Hollfeld", :area_code => "9274") + AreaCode.create(:country => germany, :name => "Speichersdorf", :area_code => "9275") + AreaCode.create(:country => germany, :name => "Bischofsgrün", :area_code => "9276") + AreaCode.create(:country => germany, :name => "Warmensteinach", :area_code => "9277") + AreaCode.create(:country => germany, :name => "Weidenberg", :area_code => "9278") + AreaCode.create(:country => germany, :name => "Mistelgau", :area_code => "9279") + AreaCode.create(:country => germany, :name => "Selbitz Oberfr", :area_code => "9280") + AreaCode.create(:country => germany, :name => "Hof Saale", :area_code => "9281") + AreaCode.create(:country => germany, :name => "Naila", :area_code => "9282") + AreaCode.create(:country => germany, :name => "Rehau", :area_code => "9283") + AreaCode.create(:country => germany, :name => "Schwarzenbach a d Saale", :area_code => "9284") + AreaCode.create(:country => germany, :name => "Kirchenlamitz", :area_code => "9285") + AreaCode.create(:country => germany, :name => "Oberkotzau", :area_code => "9286") + AreaCode.create(:country => germany, :name => "Selb", :area_code => "9287") + AreaCode.create(:country => germany, :name => "Bad Steben", :area_code => "9288") + AreaCode.create(:country => germany, :name => "Schwarzenbach a Wald", :area_code => "9289") + AreaCode.create(:country => germany, :name => "Konradsreuth", :area_code => "9292") + AreaCode.create(:country => germany, :name => "Berg Oberfr", :area_code => "9293") + AreaCode.create(:country => germany, :name => "Regnitzlosau", :area_code => "9294") + AreaCode.create(:country => germany, :name => "Töpen", :area_code => "9295") + AreaCode.create(:country => germany, :name => "Rottendorf Unterfr", :area_code => "9302") + AreaCode.create(:country => germany, :name => "Eibelstadt", :area_code => "9303") + AreaCode.create(:country => germany, :name => "Estenfeld", :area_code => "9305") + AreaCode.create(:country => germany, :name => "Kist", :area_code => "9306") + AreaCode.create(:country => germany, :name => "Altertheim", :area_code => "9307") + AreaCode.create(:country => germany, :name => "Würzburg", :area_code => "931") + AreaCode.create(:country => germany, :name => "Kitzingen", :area_code => "9321") + AreaCode.create(:country => germany, :name => "Iphofen", :area_code => "9323") + AreaCode.create(:country => germany, :name => "Dettelbach", :area_code => "9324") + AreaCode.create(:country => germany, :name => "Kleinlangheim", :area_code => "9325") + AreaCode.create(:country => germany, :name => "Markt Einersheim", :area_code => "9326") + AreaCode.create(:country => germany, :name => "Ochsenfurt", :area_code => "9331") + AreaCode.create(:country => germany, :name => "Marktbreit", :area_code => "9332") + AreaCode.create(:country => germany, :name => "Sommerhausen", :area_code => "9333") + AreaCode.create(:country => germany, :name => "Giebelstadt", :area_code => "9334") + AreaCode.create(:country => germany, :name => "Aub Kr Würzburg", :area_code => "9335") + AreaCode.create(:country => germany, :name => "Bütthard", :area_code => "9336") + AreaCode.create(:country => germany, :name => "Gaukönigshofen", :area_code => "9337") + AreaCode.create(:country => germany, :name => "Röttingen Unterfr", :area_code => "9338") + AreaCode.create(:country => germany, :name => "Ippesheim", :area_code => "9339") + AreaCode.create(:country => germany, :name => "Königheim-Brehmen", :area_code => "9340") + AreaCode.create(:country => germany, :name => "Tauberbischofsheim", :area_code => "9341") + AreaCode.create(:country => germany, :name => "Wertheim", :area_code => "9342") + AreaCode.create(:country => germany, :name => "Lauda-Königshofen", :area_code => "9343") + AreaCode.create(:country => germany, :name => "Gerchsheim", :area_code => "9344") + AreaCode.create(:country => germany, :name => "Külsheim Baden", :area_code => "9345") + AreaCode.create(:country => germany, :name => "Grünsfeld", :area_code => "9346") + AreaCode.create(:country => germany, :name => "Wittighausen", :area_code => "9347") + AreaCode.create(:country => germany, :name => "Werbach-Gamburg", :area_code => "9348") + AreaCode.create(:country => germany, :name => "Werbach-Wenkheim", :area_code => "9349") + AreaCode.create(:country => germany, :name => "Eussenheim-Hundsbach", :area_code => "9350") + AreaCode.create(:country => germany, :name => "Gemünden a Main", :area_code => "9351") + AreaCode.create(:country => germany, :name => "Lohr a Main", :area_code => "9352") + AreaCode.create(:country => germany, :name => "Karlstadt", :area_code => "9353") + AreaCode.create(:country => germany, :name => "Rieneck", :area_code => "9354") + AreaCode.create(:country => germany, :name => "Frammersbach", :area_code => "9355") + AreaCode.create(:country => germany, :name => "Burgsinn", :area_code => "9356") + AreaCode.create(:country => germany, :name => "Gräfendorf Bay", :area_code => "9357") + AreaCode.create(:country => germany, :name => "Gössenheim", :area_code => "9358") + AreaCode.create(:country => germany, :name => "Karlstadt-Wiesenfeld", :area_code => "9359") + AreaCode.create(:country => germany, :name => "Thüngen", :area_code => "9360") + AreaCode.create(:country => germany, :name => "Arnstein Unterfr", :area_code => "9363") + AreaCode.create(:country => germany, :name => "Zellingen", :area_code => "9364") + AreaCode.create(:country => germany, :name => "Rimpar", :area_code => "9365") + AreaCode.create(:country => germany, :name => "Geroldshausen Unterfr", :area_code => "9366") + AreaCode.create(:country => germany, :name => "Unterpleichfeld", :area_code => "9367") + AreaCode.create(:country => germany, :name => "Uettingen", :area_code => "9369") + AreaCode.create(:country => germany, :name => "Miltenberg", :area_code => "9371") + AreaCode.create(:country => germany, :name => "Klingenberg a Main", :area_code => "9372") + AreaCode.create(:country => germany, :name => "Amorbach", :area_code => "9373") + AreaCode.create(:country => germany, :name => "Eschau", :area_code => "9374") + AreaCode.create(:country => germany, :name => "Freudenberg Baden", :area_code => "9375") + AreaCode.create(:country => germany, :name => "Collenberg", :area_code => "9376") + AreaCode.create(:country => germany, :name => "Freudenberg-Boxtal", :area_code => "9377") + AreaCode.create(:country => germany, :name => "Eichenbühl-Riedern", :area_code => "9378") + AreaCode.create(:country => germany, :name => "Volkach", :area_code => "9381") + AreaCode.create(:country => germany, :name => "Gerolzhofen", :area_code => "9382") + AreaCode.create(:country => germany, :name => "Wiesentheid", :area_code => "9383") + AreaCode.create(:country => germany, :name => "Schwanfeld", :area_code => "9384") + AreaCode.create(:country => germany, :name => "Kolitzheim", :area_code => "9385") + AreaCode.create(:country => germany, :name => "Prosselsheim", :area_code => "9386") + AreaCode.create(:country => germany, :name => "Marktheidenfeld", :area_code => "9391") + AreaCode.create(:country => germany, :name => "Faulbach Unterfr", :area_code => "9392") + AreaCode.create(:country => germany, :name => "Rothenfels Unterfr", :area_code => "9393") + AreaCode.create(:country => germany, :name => "Esselbach", :area_code => "9394") + AreaCode.create(:country => germany, :name => "Triefenstein", :area_code => "9395") + AreaCode.create(:country => germany, :name => "Urspringen b Lohr", :area_code => "9396") + AreaCode.create(:country => germany, :name => "Wertheim-Dertingen", :area_code => "9397") + AreaCode.create(:country => germany, :name => "Birkenfeld b Würzburg", :area_code => "9398") + AreaCode.create(:country => germany, :name => "Neutraubling", :area_code => "9401") + AreaCode.create(:country => germany, :name => "Regenstauf", :area_code => "9402") + AreaCode.create(:country => germany, :name => "Donaustauf", :area_code => "9403") + AreaCode.create(:country => germany, :name => "Nittendorf", :area_code => "9404") + AreaCode.create(:country => germany, :name => "Bad Abbach", :area_code => "9405") + AreaCode.create(:country => germany, :name => "Mintraching", :area_code => "9406") + AreaCode.create(:country => germany, :name => "Wenzenbach", :area_code => "9407") + AreaCode.create(:country => germany, :name => "Altenthann", :area_code => "9408") + AreaCode.create(:country => germany, :name => "Pielenhofen", :area_code => "9409") + AreaCode.create(:country => germany, :name => "Regensburg", :area_code => "941") + AreaCode.create(:country => germany, :name => "Feldkirchen Niederbay", :area_code => "9420") + AreaCode.create(:country => germany, :name => "Straubing", :area_code => "9421") + AreaCode.create(:country => germany, :name => "Bogen Niederbay", :area_code => "9422") + AreaCode.create(:country => germany, :name => "Geiselhöring", :area_code => "9423") + AreaCode.create(:country => germany, :name => "Strasskirchen", :area_code => "9424") + AreaCode.create(:country => germany, :name => "Oberschneiding", :area_code => "9426") + AreaCode.create(:country => germany, :name => "Leiblfing", :area_code => "9427") + AreaCode.create(:country => germany, :name => "Kirchroth", :area_code => "9428") + AreaCode.create(:country => germany, :name => "Rain Niederbay", :area_code => "9429") + AreaCode.create(:country => germany, :name => "Schwandorf", :area_code => "9431") + AreaCode.create(:country => germany, :name => "Nabburg", :area_code => "9433") + AreaCode.create(:country => germany, :name => "Bodenwöhr", :area_code => "9434") + AreaCode.create(:country => germany, :name => "Schwarzenfeld", :area_code => "9435") + AreaCode.create(:country => germany, :name => "Nittenau", :area_code => "9436") + AreaCode.create(:country => germany, :name => "Fensterbach", :area_code => "9438") + AreaCode.create(:country => germany, :name => "Neunburg-Kemnath", :area_code => "9439") + AreaCode.create(:country => germany, :name => "Kelheim", :area_code => "9441") + AreaCode.create(:country => germany, :name => "Riedenburg", :area_code => "9442") + AreaCode.create(:country => germany, :name => "Abensberg", :area_code => "9443") + AreaCode.create(:country => germany, :name => "Siegenburg", :area_code => "9444") + AreaCode.create(:country => germany, :name => "Neustadt a d Donau", :area_code => "9445") + AreaCode.create(:country => germany, :name => "Altmannstein", :area_code => "9446") + AreaCode.create(:country => germany, :name => "Essing", :area_code => "9447") + AreaCode.create(:country => germany, :name => "Hausen Niederbay", :area_code => "9448") + AreaCode.create(:country => germany, :name => "Schierling", :area_code => "9451") + AreaCode.create(:country => germany, :name => "Langquaid", :area_code => "9452") + AreaCode.create(:country => germany, :name => "Thalmassing", :area_code => "9453") + AreaCode.create(:country => germany, :name => "Aufhausen Oberpf", :area_code => "9454") + AreaCode.create(:country => germany, :name => "Roding", :area_code => "9461") + AreaCode.create(:country => germany, :name => "Falkenstein Oberpf", :area_code => "9462") + AreaCode.create(:country => germany, :name => "Wald Oberpf", :area_code => "9463") + AreaCode.create(:country => germany, :name => "Walderbach", :area_code => "9464") + AreaCode.create(:country => germany, :name => "Neukirchen-Balbini", :area_code => "9465") + AreaCode.create(:country => germany, :name => "Stamsried", :area_code => "9466") + AreaCode.create(:country => germany, :name => "Michelsneukirchen", :area_code => "9467") + AreaCode.create(:country => germany, :name => "Zell Oberpf", :area_code => "9468") + AreaCode.create(:country => germany, :name => "Roding-Neubäu", :area_code => "9469") + AreaCode.create(:country => germany, :name => "Burglengenfeld", :area_code => "9471") + AreaCode.create(:country => germany, :name => "Hohenfels Oberpf", :area_code => "9472") + AreaCode.create(:country => germany, :name => "Kallmünz", :area_code => "9473") + AreaCode.create(:country => germany, :name => "Schmidmühlen", :area_code => "9474") + AreaCode.create(:country => germany, :name => "Sünching", :area_code => "9480") + AreaCode.create(:country => germany, :name => "Pfatter", :area_code => "9481") + AreaCode.create(:country => germany, :name => "Wörth a d Donau", :area_code => "9482") + AreaCode.create(:country => germany, :name => "Brennberg", :area_code => "9484") + AreaCode.create(:country => germany, :name => "Hemau", :area_code => "9491") + AreaCode.create(:country => germany, :name => "Parsberg", :area_code => "9492") + AreaCode.create(:country => germany, :name => "Beratzhausen", :area_code => "9493") + AreaCode.create(:country => germany, :name => "Breitenbrunn Oberpf", :area_code => "9495") + AreaCode.create(:country => germany, :name => "Seubersdorf i d Opf", :area_code => "9497") + AreaCode.create(:country => germany, :name => "Laaber", :area_code => "9498") + AreaCode.create(:country => germany, :name => "Painten", :area_code => "9499") + AreaCode.create(:country => germany, :name => "Frensdorf", :area_code => "9502") + AreaCode.create(:country => germany, :name => "Oberhaid Oberfr", :area_code => "9503") + AreaCode.create(:country => germany, :name => "Stadelhofen", :area_code => "9504") + AreaCode.create(:country => germany, :name => "Litzendorf", :area_code => "9505") + AreaCode.create(:country => germany, :name => "Bamberg", :area_code => "951") + AreaCode.create(:country => germany, :name => "Hassfurt", :area_code => "9521") + AreaCode.create(:country => germany, :name => "Eltmann", :area_code => "9522") + AreaCode.create(:country => germany, :name => "Hofheim i Ufr", :area_code => "9523") + AreaCode.create(:country => germany, :name => "Zeil a Main", :area_code => "9524") + AreaCode.create(:country => germany, :name => "Königsberg i Bay", :area_code => "9525") + AreaCode.create(:country => germany, :name => "Riedbach", :area_code => "9526") + AreaCode.create(:country => germany, :name => "Knetzgau", :area_code => "9527") + AreaCode.create(:country => germany, :name => "Donnersdorf", :area_code => "9528") + AreaCode.create(:country => germany, :name => "Oberaurach", :area_code => "9529") + AreaCode.create(:country => germany, :name => "Ebern", :area_code => "9531") + AreaCode.create(:country => germany, :name => "Maroldsweisach", :area_code => "9532") + AreaCode.create(:country => germany, :name => "Untermerzbach", :area_code => "9533") + AreaCode.create(:country => germany, :name => "Burgpreppach", :area_code => "9534") + AreaCode.create(:country => germany, :name => "Pfarrweisach", :area_code => "9535") + AreaCode.create(:country => germany, :name => "Kirchlauter", :area_code => "9536") + AreaCode.create(:country => germany, :name => "Schesslitz", :area_code => "9542") + AreaCode.create(:country => germany, :name => "Hirschaid", :area_code => "9543") + AreaCode.create(:country => germany, :name => "Baunach", :area_code => "9544") + AreaCode.create(:country => germany, :name => "Buttenheim", :area_code => "9545") + AreaCode.create(:country => germany, :name => "Burgebrach", :area_code => "9546") + AreaCode.create(:country => germany, :name => "Zapfendorf", :area_code => "9547") + AreaCode.create(:country => germany, :name => "Mühlhausen Mittelfr", :area_code => "9548") + AreaCode.create(:country => germany, :name => "Lisberg", :area_code => "9549") + AreaCode.create(:country => germany, :name => "Burgwindheim", :area_code => "9551") + AreaCode.create(:country => germany, :name => "Burghaslach", :area_code => "9552") + AreaCode.create(:country => germany, :name => "Ebrach Oberfr", :area_code => "9553") + AreaCode.create(:country => germany, :name => "Untersteinbach Unterfr", :area_code => "9554") + AreaCode.create(:country => germany, :name => "Schlüsselfeld-Aschbach", :area_code => "9555") + AreaCode.create(:country => germany, :name => "Geiselwind", :area_code => "9556") + AreaCode.create(:country => germany, :name => "Grub a Forst", :area_code => "9560") + AreaCode.create(:country => germany, :name => "Coburg", :area_code => "9561") + AreaCode.create(:country => germany, :name => "Sonnefeld", :area_code => "9562") + AreaCode.create(:country => germany, :name => "Rödental", :area_code => "9563") + AreaCode.create(:country => germany, :name => "Bad Rodach", :area_code => "9564") + AreaCode.create(:country => germany, :name => "Untersiemau", :area_code => "9565") + AreaCode.create(:country => germany, :name => "Meeder", :area_code => "9566") + AreaCode.create(:country => germany, :name => "Seßlach-Gemünda", :area_code => "9567") + AreaCode.create(:country => germany, :name => "Neustadt b Coburg", :area_code => "9568") + AreaCode.create(:country => germany, :name => "Sesslach", :area_code => "9569") + AreaCode.create(:country => germany, :name => "Lichtenfels Bay", :area_code => "9571") + AreaCode.create(:country => germany, :name => "Burgkunstadt", :area_code => "9572") + AreaCode.create(:country => germany, :name => "Staffelstein Oberfr", :area_code => "9573") + AreaCode.create(:country => germany, :name => "Marktzeuln", :area_code => "9574") + AreaCode.create(:country => germany, :name => "Weismain", :area_code => "9575") + AreaCode.create(:country => germany, :name => "Lichtenfels-Isling", :area_code => "9576") + AreaCode.create(:country => germany, :name => "Neustadt a d Waldnaab", :area_code => "9602") + AreaCode.create(:country => germany, :name => "Floss", :area_code => "9603") + AreaCode.create(:country => germany, :name => "Wernberg-Köblitz", :area_code => "9604") + AreaCode.create(:country => germany, :name => "Weiherhammer", :area_code => "9605") + AreaCode.create(:country => germany, :name => "Pfreimd", :area_code => "9606") + AreaCode.create(:country => germany, :name => "Luhe-Wildenau", :area_code => "9607") + AreaCode.create(:country => germany, :name => "Kohlberg Oberpf", :area_code => "9608") + AreaCode.create(:country => germany, :name => "Weiden i d Opf", :area_code => "961") + AreaCode.create(:country => germany, :name => "Amberg Oberpf", :area_code => "9621") + AreaCode.create(:country => germany, :name => "Hirschau Oberpf", :area_code => "9622") + AreaCode.create(:country => germany, :name => "Ensdorf Oberpf", :area_code => "9624") + AreaCode.create(:country => germany, :name => "Kastl b Amberg", :area_code => "9625") + AreaCode.create(:country => germany, :name => "Hohenburg", :area_code => "9626") + AreaCode.create(:country => germany, :name => "Freudenberg Oberpf", :area_code => "9627") + AreaCode.create(:country => germany, :name => "Ursensollen", :area_code => "9628") + AreaCode.create(:country => germany, :name => "Tirschenreuth", :area_code => "9631") + AreaCode.create(:country => germany, :name => "Waldsassen", :area_code => "9632") + AreaCode.create(:country => germany, :name => "Mitterteich", :area_code => "9633") + AreaCode.create(:country => germany, :name => "Wiesau", :area_code => "9634") + AreaCode.create(:country => germany, :name => "Bärnau", :area_code => "9635") + AreaCode.create(:country => germany, :name => "Plößberg", :area_code => "9636") + AreaCode.create(:country => germany, :name => "Falkenberg Oberpf", :area_code => "9637") + AreaCode.create(:country => germany, :name => "Neualbenreuth", :area_code => "9638") + AreaCode.create(:country => germany, :name => "Mähring", :area_code => "9639") + AreaCode.create(:country => germany, :name => "Grafenwöhr", :area_code => "9641") + AreaCode.create(:country => germany, :name => "Kemnath Stadt", :area_code => "9642") + AreaCode.create(:country => germany, :name => "Auerbach i d Opf", :area_code => "9643") + AreaCode.create(:country => germany, :name => "Pressath", :area_code => "9644") + AreaCode.create(:country => germany, :name => "Eschenbach i d Opf", :area_code => "9645") + AreaCode.create(:country => germany, :name => "Freihung", :area_code => "9646") + AreaCode.create(:country => germany, :name => "Kirchenthumbach", :area_code => "9647") + AreaCode.create(:country => germany, :name => "Neustadt a Kulm", :area_code => "9648") + AreaCode.create(:country => germany, :name => "Vohenstrauss", :area_code => "9651") + AreaCode.create(:country => germany, :name => "Waidhaus", :area_code => "9652") + AreaCode.create(:country => germany, :name => "Eslarn", :area_code => "9653") + AreaCode.create(:country => germany, :name => "Pleystein", :area_code => "9654") + AreaCode.create(:country => germany, :name => "Tännesberg", :area_code => "9655") + AreaCode.create(:country => germany, :name => "Moosbach b Vohenstrauß", :area_code => "9656") + AreaCode.create(:country => germany, :name => "Waldthurn", :area_code => "9657") + AreaCode.create(:country => germany, :name => "Georgenberg", :area_code => "9658") + AreaCode.create(:country => germany, :name => "Leuchtenberg", :area_code => "9659") + AreaCode.create(:country => germany, :name => "Sulzbach-Rosenberg", :area_code => "9661") + AreaCode.create(:country => germany, :name => "Vilseck", :area_code => "9662") + AreaCode.create(:country => germany, :name => "Neukirchen b Sulzbach-Rosenberg", :area_code => "9663") + AreaCode.create(:country => germany, :name => "Hahnbach", :area_code => "9664") + AreaCode.create(:country => germany, :name => "Königstein Oberpf", :area_code => "9665") + AreaCode.create(:country => germany, :name => "Illschwang", :area_code => "9666") + AreaCode.create(:country => germany, :name => "Oberviechtach", :area_code => "9671") + AreaCode.create(:country => germany, :name => "Neunburg vorm Wald", :area_code => "9672") + AreaCode.create(:country => germany, :name => "Tiefenbach Oberpf", :area_code => "9673") + AreaCode.create(:country => germany, :name => "Schönsee", :area_code => "9674") + AreaCode.create(:country => germany, :name => "Altendorf a Nabburg", :area_code => "9675") + AreaCode.create(:country => germany, :name => "Winklarn", :area_code => "9676") + AreaCode.create(:country => germany, :name => "Oberviechtach-Pullenried", :area_code => "9677") + AreaCode.create(:country => germany, :name => "Windischeschenbach", :area_code => "9681") + AreaCode.create(:country => germany, :name => "Erbendorf", :area_code => "9682") + AreaCode.create(:country => germany, :name => "Friedenfels", :area_code => "9683") + AreaCode.create(:country => germany, :name => "Sandberg Unterfr", :area_code => "9701") + AreaCode.create(:country => germany, :name => "Euerdorf", :area_code => "9704") + AreaCode.create(:country => germany, :name => "Bad Bocklet", :area_code => "9708") + AreaCode.create(:country => germany, :name => "Bad Kissingen", :area_code => "971") + AreaCode.create(:country => germany, :name => "Üchtelhausen", :area_code => "9720") + AreaCode.create(:country => germany, :name => "Schweinfurt", :area_code => "9721") + AreaCode.create(:country => germany, :name => "Werneck", :area_code => "9722") + AreaCode.create(:country => germany, :name => "Röthlein", :area_code => "9723") + AreaCode.create(:country => germany, :name => "Stadtlauringen", :area_code => "9724") + AreaCode.create(:country => germany, :name => "Poppenhausen Unterfr", :area_code => "9725") + AreaCode.create(:country => germany, :name => "Euerbach", :area_code => "9726") + AreaCode.create(:country => germany, :name => "Schonungen-Marktsteinach", :area_code => "9727") + AreaCode.create(:country => germany, :name => "Wülfershausen Unterfr", :area_code => "9728") + AreaCode.create(:country => germany, :name => "Grettstadt", :area_code => "9729") + AreaCode.create(:country => germany, :name => "Hammelburg", :area_code => "9732") + AreaCode.create(:country => germany, :name => "Münnerstadt", :area_code => "9733") + AreaCode.create(:country => germany, :name => "Burkardroth", :area_code => "9734") + AreaCode.create(:country => germany, :name => "Massbach", :area_code => "9735") + AreaCode.create(:country => germany, :name => "Oberthulba", :area_code => "9736") + AreaCode.create(:country => germany, :name => "Wartmannsroth", :area_code => "9737") + AreaCode.create(:country => germany, :name => "Rottershausen", :area_code => "9738") + AreaCode.create(:country => germany, :name => "Bad Brückenau", :area_code => "9741") + AreaCode.create(:country => germany, :name => "Kalbach Rhön", :area_code => "9742") + AreaCode.create(:country => germany, :name => "Zeitlofs-Detter", :area_code => "9744") + AreaCode.create(:country => germany, :name => "Wildflecken", :area_code => "9745") + AreaCode.create(:country => germany, :name => "Zeitlofs", :area_code => "9746") + AreaCode.create(:country => germany, :name => "Geroda Bay", :area_code => "9747") + AreaCode.create(:country => germany, :name => "Motten", :area_code => "9748") + AreaCode.create(:country => germany, :name => "Oberbach Unterfr", :area_code => "9749") + AreaCode.create(:country => germany, :name => "Bad Königshofen i Grabfeld", :area_code => "9761") + AreaCode.create(:country => germany, :name => "Saal a d Saale", :area_code => "9762") + AreaCode.create(:country => germany, :name => "Sulzdorf a d Lederhecke", :area_code => "9763") + AreaCode.create(:country => germany, :name => "Höchheim", :area_code => "9764") + AreaCode.create(:country => germany, :name => "Trappstadt", :area_code => "9765") + AreaCode.create(:country => germany, :name => "Grosswenkheim", :area_code => "9766") + AreaCode.create(:country => germany, :name => "Bad Neustadt a d Saale", :area_code => "9771") + AreaCode.create(:country => germany, :name => "Bischofsheim a d Rhön", :area_code => "9772") + AreaCode.create(:country => germany, :name => "Unsleben", :area_code => "9773") + AreaCode.create(:country => germany, :name => "Oberelsbach", :area_code => "9774") + AreaCode.create(:country => germany, :name => "Schönau a d Brend", :area_code => "9775") + AreaCode.create(:country => germany, :name => "Mellrichstadt", :area_code => "9776") + AreaCode.create(:country => germany, :name => "Ostheim v d Rhön", :area_code => "9777") + AreaCode.create(:country => germany, :name => "Fladungen", :area_code => "9778") + AreaCode.create(:country => germany, :name => "Nordheim v d Rhön", :area_code => "9779") + AreaCode.create(:country => germany, :name => "Ansbach-Katterbach", :area_code => "9802") + AreaCode.create(:country => germany, :name => "Colmberg", :area_code => "9803") + AreaCode.create(:country => germany, :name => "Aurach", :area_code => "9804") + AreaCode.create(:country => germany, :name => "Burgoberbach", :area_code => "9805") + AreaCode.create(:country => germany, :name => "Ansbach", :area_code => "981") + AreaCode.create(:country => germany, :name => "Lehrberg", :area_code => "9820") + AreaCode.create(:country => germany, :name => "Bechhofen a d Heide", :area_code => "9822") + AreaCode.create(:country => germany, :name => "Leutershausen", :area_code => "9823") + AreaCode.create(:country => germany, :name => "Dietenhofen", :area_code => "9824") + AreaCode.create(:country => germany, :name => "Herrieden", :area_code => "9825") + AreaCode.create(:country => germany, :name => "Weidenbach Mittelfr", :area_code => "9826") + AreaCode.create(:country => germany, :name => "Lichtenau Mittelfr", :area_code => "9827") + AreaCode.create(:country => germany, :name => "Rügland", :area_code => "9828") + AreaCode.create(:country => germany, :name => "Flachslanden", :area_code => "9829") + AreaCode.create(:country => germany, :name => "Gunzenhausen", :area_code => "9831") + AreaCode.create(:country => germany, :name => "Wassertrüdingen", :area_code => "9832") + AreaCode.create(:country => germany, :name => "Heidenheim Mittelfr", :area_code => "9833") + AreaCode.create(:country => germany, :name => "Theilenhofen", :area_code => "9834") + AreaCode.create(:country => germany, :name => "Ehingen Mittelfr", :area_code => "9835") + AreaCode.create(:country => germany, :name => "Gunzenhausen-Cronheim", :area_code => "9836") + AreaCode.create(:country => germany, :name => "Haundorf", :area_code => "9837") + AreaCode.create(:country => germany, :name => "Bad Windsheim", :area_code => "9841") + AreaCode.create(:country => germany, :name => "Uffenheim", :area_code => "9842") + AreaCode.create(:country => germany, :name => "Burgbernheim", :area_code => "9843") + AreaCode.create(:country => germany, :name => "Obernzenn", :area_code => "9844") + AreaCode.create(:country => germany, :name => "Oberdachstetten", :area_code => "9845") + AreaCode.create(:country => germany, :name => "Ipsheim", :area_code => "9846") + AreaCode.create(:country => germany, :name => "Ergersheim", :area_code => "9847") + AreaCode.create(:country => germany, :name => "Simmershofen", :area_code => "9848") + AreaCode.create(:country => germany, :name => "Dinkelsbühl", :area_code => "9851") + AreaCode.create(:country => germany, :name => "Feuchtwangen", :area_code => "9852") + AreaCode.create(:country => germany, :name => "Wilburgstetten", :area_code => "9853") + AreaCode.create(:country => germany, :name => "Wittelshofen", :area_code => "9854") + AreaCode.create(:country => germany, :name => "Dentlein a Forst", :area_code => "9855") + AreaCode.create(:country => germany, :name => "Dürrwangen", :area_code => "9856") + AreaCode.create(:country => germany, :name => "Schopfloch Mittelfr", :area_code => "9857") + AreaCode.create(:country => germany, :name => "Rothenburg ob der Tauber", :area_code => "9861") + AreaCode.create(:country => germany, :name => "Adelshofen Mittelfr", :area_code => "9865") + AreaCode.create(:country => germany, :name => "Geslau", :area_code => "9867") + AreaCode.create(:country => germany, :name => "Schillingsfürst", :area_code => "9868") + AreaCode.create(:country => germany, :name => "Wettringen Mittelfr", :area_code => "9869") + AreaCode.create(:country => germany, :name => "Windsbach", :area_code => "9871") + AreaCode.create(:country => germany, :name => "Heilsbronn", :area_code => "9872") + AreaCode.create(:country => germany, :name => "Abenberg-Wassermungenau", :area_code => "9873") + AreaCode.create(:country => germany, :name => "Neuendettelsau", :area_code => "9874") + AreaCode.create(:country => germany, :name => "Wolframs-Eschenbach", :area_code => "9875") + AreaCode.create(:country => germany, :name => "Rohr Mittelfr", :area_code => "9876") + AreaCode.create(:country => germany, :name => "Hengersberg Bay", :area_code => "9901") + AreaCode.create(:country => germany, :name => "Schöllnach", :area_code => "9903") + AreaCode.create(:country => germany, :name => "Lalling", :area_code => "9904") + AreaCode.create(:country => germany, :name => "Bernried Niederbay", :area_code => "9905") + AreaCode.create(:country => germany, :name => "Mariaposching", :area_code => "9906") + AreaCode.create(:country => germany, :name => "Zenting", :area_code => "9907") + AreaCode.create(:country => germany, :name => "Schöfweg", :area_code => "9908") + AreaCode.create(:country => germany, :name => "Deggendorf", :area_code => "991") + AreaCode.create(:country => germany, :name => "Bischofsmais", :area_code => "9920") + AreaCode.create(:country => germany, :name => "Regen", :area_code => "9921") + AreaCode.create(:country => germany, :name => "Zwiesel", :area_code => "9922") + AreaCode.create(:country => germany, :name => "Teisnach", :area_code => "9923") + AreaCode.create(:country => germany, :name => "Bodenmais", :area_code => "9924") + AreaCode.create(:country => germany, :name => "Bayerisch Eisenstein", :area_code => "9925") + AreaCode.create(:country => germany, :name => "Frauenau", :area_code => "9926") + AreaCode.create(:country => germany, :name => "Kirchberg Wald", :area_code => "9927") + AreaCode.create(:country => germany, :name => "Kirchdorf i Wald", :area_code => "9928") + AreaCode.create(:country => germany, :name => "Ruhmannsfelden", :area_code => "9929") + AreaCode.create(:country => germany, :name => "Plattling", :area_code => "9931") + AreaCode.create(:country => germany, :name => "Osterhofen", :area_code => "9932") + AreaCode.create(:country => germany, :name => "Wallersdorf", :area_code => "9933") + AreaCode.create(:country => germany, :name => "Stephansposching", :area_code => "9935") + AreaCode.create(:country => germany, :name => "Wallerfing", :area_code => "9936") + AreaCode.create(:country => germany, :name => "Oberpöring", :area_code => "9937") + AreaCode.create(:country => germany, :name => "Moos Niederbay", :area_code => "9938") + AreaCode.create(:country => germany, :name => "Kötzting", :area_code => "9941") + AreaCode.create(:country => germany, :name => "Viechtach", :area_code => "9942") + AreaCode.create(:country => germany, :name => "Lam Oberpf", :area_code => "9943") + AreaCode.create(:country => germany, :name => "Miltach", :area_code => "9944") + AreaCode.create(:country => germany, :name => "Arnbruck", :area_code => "9945") + AreaCode.create(:country => germany, :name => "Hohenwarth b Kötzing", :area_code => "9946") + AreaCode.create(:country => germany, :name => "Neukirchen b Hl Blut", :area_code => "9947") + AreaCode.create(:country => germany, :name => "Eschlkam", :area_code => "9948") + AreaCode.create(:country => germany, :name => "Landau a d Isar", :area_code => "9951") + AreaCode.create(:country => germany, :name => "Eichendorf", :area_code => "9952") + AreaCode.create(:country => germany, :name => "Pilsting", :area_code => "9953") + AreaCode.create(:country => germany, :name => "SimbachNiederbay", :area_code => "9954") + AreaCode.create(:country => germany, :name => "Mamming", :area_code => "9955") + AreaCode.create(:country => germany, :name => "Eichendorf-Aufhausen", :area_code => "9956") + AreaCode.create(:country => germany, :name => "Mitterfels", :area_code => "9961") + AreaCode.create(:country => germany, :name => "Schwarzach Niederbay", :area_code => "9962") + AreaCode.create(:country => germany, :name => "Konzell", :area_code => "9963") + AreaCode.create(:country => germany, :name => "Stallwang", :area_code => "9964") + AreaCode.create(:country => germany, :name => "Sankt Englmar", :area_code => "9965") + AreaCode.create(:country => germany, :name => "Wiesenfelden", :area_code => "9966") + AreaCode.create(:country => germany, :name => "Cham", :area_code => "9971") + AreaCode.create(:country => germany, :name => "Waldmünchen", :area_code => "9972") + AreaCode.create(:country => germany, :name => "Furth i Wald", :area_code => "9973") + AreaCode.create(:country => germany, :name => "Traitsching", :area_code => "9974") + AreaCode.create(:country => germany, :name => "Waldmünchen-Geigant", :area_code => "9975") + AreaCode.create(:country => germany, :name => "Rötz", :area_code => "9976") + AreaCode.create(:country => germany, :name => "Arnschwang", :area_code => "9977") + AreaCode.create(:country => germany, :name => "Schönthal Oberpf", :area_code => "9978") + + # Mobilfunknetze + # + '01511, 01512, 01514, 01515, 0160, 0170, 0171, 0175'.gsub(/[^0-9\,]/,'').split(/,/).each do |area_code| + AreaCode.create(:country => germany, :name => "D1 Mobilfunknetz (Telekom)", :area_code => area_code.gsub(/^0/,'')) + end + + '01520, 01522, 01525, 0162, 0172, 0173, 0174'.gsub(/[^0-9\,]/,'').split(/,/).each do |area_code| + AreaCode.create(:country => germany, :name => "Vodafone Mobilfunknetz", :area_code => area_code.gsub(/^0/,'')) + end + + '01577, 01578, 0163, 0177, 0178, 01570, 01575'.gsub(/[^0-9\,]/,'').split(/,/).each do |area_code| + AreaCode.create(:country => germany, :name => "E-Plus Mobilfunknetz", :area_code => area_code.gsub(/^0/,'')) + end + + '0176, 0179, 0159, 01505'.gsub(/[^0-9\,]/,'').split(/,/).each do |area_code| + AreaCode.create(:country => germany, :name => "O2 Mobilfunknetz", :area_code => area_code.gsub(/^0/,'')) + end + + # Sondervorwahlen + # + AreaCode.create(:country => germany, :name => "Service-Dienste", :area_code => "180") + AreaCode.create(:country => germany, :name => "Persönliche Rufnummern", :area_code => "700") + AreaCode.create(:country => germany, :name => "Entgeltfreie Telefondienste", :area_code => "800") + AreaCode.create(:country => germany, :name => "Premium Dienste", :area_code => "900") + end + end + + def down + germany = Country.find_by_name('Germany') + germany.area_codes.destroy_all + end +end diff --git a/db/migrate/20120119155619_area_codes_poland.rb b/db/migrate/20120119155619_area_codes_poland.rb new file mode 100644 index 0000000..fdf520b --- /dev/null +++ b/db/migrate/20120119155619_area_codes_poland.rb @@ -0,0 +1,69 @@ +# ruby encoding: utf-8 + +class AreaCodesPoland < ActiveRecord::Migration + def up + poland = Country.find_by_name('Poland') + + ################################################################ + # AreaCodes Poland + ################################################################ + + ActiveRecord::Base.transaction do + AreaCode.create(:country => poland, :name => "Biała Podlaska", :area_code => "83") + AreaCode.create(:country => poland, :name => "Białystok", :area_code => "85") + AreaCode.create(:country => poland, :name => "Bielsko-Biała", :area_code => "33") + AreaCode.create(:country => poland, :name => "Bydgoszcz", :area_code => "52") + AreaCode.create(:country => poland, :name => "Chełm", :area_code => "82") + AreaCode.create(:country => poland, :name => "Ciechanów", :area_code => "23") + AreaCode.create(:country => poland, :name => "Częstochowa", :area_code => "34") + AreaCode.create(:country => poland, :name => "Elbląg", :area_code => "55") + AreaCode.create(:country => poland, :name => "Gdańsk", :area_code => "58") + AreaCode.create(:country => poland, :name => "Gorzów Wielkopolski", :area_code => "95") + AreaCode.create(:country => poland, :name => "Jelenia Góra", :area_code => "75") + AreaCode.create(:country => poland, :name => "Kalisz", :area_code => "62") + AreaCode.create(:country => poland, :name => "Katowice", :area_code => "32") + AreaCode.create(:country => poland, :name => "Kielce", :area_code => "41") + AreaCode.create(:country => poland, :name => "Konin", :area_code => "63") + AreaCode.create(:country => poland, :name => "Koszalin", :area_code => "94") + AreaCode.create(:country => poland, :name => "Kraków", :area_code => "12") + AreaCode.create(:country => poland, :name => "Krosno", :area_code => "13") + AreaCode.create(:country => poland, :name => "Legnica", :area_code => "76") + AreaCode.create(:country => poland, :name => "Leszno", :area_code => "65") + AreaCode.create(:country => poland, :name => "Łódź", :area_code => "42") + AreaCode.create(:country => poland, :name => "Łomża", :area_code => "86") + AreaCode.create(:country => poland, :name => "Lublin", :area_code => "81") + AreaCode.create(:country => poland, :name => "Nowy Sącz", :area_code => "18") + AreaCode.create(:country => poland, :name => "Olsztyn", :area_code => "89") + AreaCode.create(:country => poland, :name => "Opole", :area_code => "77") + AreaCode.create(:country => poland, :name => "Ostrołęka", :area_code => "29") + AreaCode.create(:country => poland, :name => "Piła", :area_code => "67") + AreaCode.create(:country => poland, :name => "Piotrków Trybunalski", :area_code => "44") + AreaCode.create(:country => poland, :name => "Płock", :area_code => "24") + AreaCode.create(:country => poland, :name => "Poznań", :area_code => "61") + AreaCode.create(:country => poland, :name => "Przemyśl", :area_code => "16") + AreaCode.create(:country => poland, :name => "Radom", :area_code => "48") + AreaCode.create(:country => poland, :name => "Rzeszów", :area_code => "17") + AreaCode.create(:country => poland, :name => "Siedlce", :area_code => "25") + AreaCode.create(:country => poland, :name => "Sieradz", :area_code => "43") + AreaCode.create(:country => poland, :name => "Skierniewice", :area_code => "46") + AreaCode.create(:country => poland, :name => "Słupsk", :area_code => "59") + AreaCode.create(:country => poland, :name => "Suwałki", :area_code => "87") + AreaCode.create(:country => poland, :name => "Szczecin", :area_code => "91") + AreaCode.create(:country => poland, :name => "Tarnobrzeg", :area_code => "15") + AreaCode.create(:country => poland, :name => "Tarnów", :area_code => "14") + AreaCode.create(:country => poland, :name => "Toruń", :area_code => "56") + AreaCode.create(:country => poland, :name => "Wałbrzych", :area_code => "74") + AreaCode.create(:country => poland, :name => "Warszawa", :area_code => "22") + AreaCode.create(:country => poland, :name => "Włocławek", :area_code => "54") + AreaCode.create(:country => poland, :name => "Wrocław", :area_code => "71") + AreaCode.create(:country => poland, :name => "Zamość", :area_code => "84") + AreaCode.create(:country => poland, :name => "Zielona Góra", :area_code => "68") + end + + end + + def down + poland = Country.find_by_name('Poland') + poland.area_codes.destroy_all + end +end diff --git a/db/migrate/20120119161017_call_forward_cases.rb b/db/migrate/20120119161017_call_forward_cases.rb new file mode 100644 index 0000000..2f6466b --- /dev/null +++ b/db/migrate/20120119161017_call_forward_cases.rb @@ -0,0 +1,23 @@ +# ruby encoding: utf-8 + +class CallForwardCases < ActiveRecord::Migration + def up + ################################################################ + # Call forward cases + ################################################################ + + [ + 'always', + 'busy', + 'noanswer', + 'offline', + 'assistant', + ].each { |case_name| + CallForwardCase.create( :value => case_name ) + } + end + + def down + CallForwardCase.destroy_all + end +end diff --git a/db/migrate/20120119161152_snom_phones.rb b/db/migrate/20120119161152_snom_phones.rb new file mode 100644 index 0000000..88c35f9 --- /dev/null +++ b/db/migrate/20120119161152_snom_phones.rb @@ -0,0 +1,63 @@ +# ruby encoding: utf-8 + +class SnomPhones < ActiveRecord::Migration + def up + ################################################################ + # Manufacturers + ################################################################ + add_column :phone_models, :uuid, :string rescue puts "column already added" + snom = Manufacturer.find_or_create_by_ieee_name('SNOM Technology AG', + { + :name => "SNOM Technology AG", + :homepage_url => 'http://www.snom.com' + } + ) + + + ################################################################ + # OUIs + ################################################################ + + snom.ouis.find_or_create_by_value('000413') + + + ################################################################ + # Phone models + ################################################################ + + snom300 = snom.phone_models.create(:name => 'Snom 300', + :product_homepage_url => 'http://www.snom.com/en/products/ip-phones/snom-300/', + :product_manual_homepage_url => 'http://wiki.snom.com/Snom300/Documentation') + + snom320 = snom.phone_models.create(:name => 'Snom 320', + :product_homepage_url => 'http://www.snom.com/en/products/ip-phones/snom-320/', + :product_manual_homepage_url => 'http://wiki.snom.com/Snom320/Documentation') + + snom360 = snom.phone_models.create(:name => 'Snom 360', + :product_homepage_url => 'http://www.snom.com/en/products/ip-phones/snom-360/', + :product_manual_homepage_url => 'http://wiki.snom.com/Snom360/Documentation') + + snom370 = snom.phone_models.create(:name => 'Snom 370', + :product_homepage_url => 'http://www.snom.com/en/products/ip-phones/snom-370/', + :product_manual_homepage_url => 'http://wiki.snom.com/Snom370/Documentation') + + snom820 = snom.phone_models.create(:name => 'Snom 820', + :product_homepage_url => 'http://www.snom.com/en/products/ip-phones/snom-820/', + :product_manual_homepage_url => 'http://wiki.snom.com/Snom820/Documentation') + + snom821 = snom.phone_models.create(:name => 'Snom 821', + :product_homepage_url => 'http://www.snom.com/en/products/ip-phones/snom-821/', + :product_manual_homepage_url => 'http://wiki.snom.com/Snom821/Documentation') + + snom870 = snom.phone_models.create(:name => 'Snom 870', + :product_homepage_url => 'http://www.snom.com/en/products/ip-phones/snom-870/', + :product_manual_homepage_url => 'http://wiki.snom.com/Snom870/Documentation') + + end + + def down + Manufacturer.destroy_all + Oui.destroy_all + PhoneModel.destroy_all + end +end diff --git a/db/migrate/20120124131057_add_clip_number_to_sip_account.rb b/db/migrate/20120124131057_add_clip_number_to_sip_account.rb new file mode 100644 index 0000000..e981fb4 --- /dev/null +++ b/db/migrate/20120124131057_add_clip_number_to_sip_account.rb @@ -0,0 +1,6 @@ +class AddClipNumberToSipAccount < ActiveRecord::Migration + def change + add_column :sip_accounts, :clip, :string + remove_column :sip_accounts, :clip_phone_number_id + end +end diff --git a/db/migrate/20120124133950_add_clip_no_screening_to_sip_account.rb b/db/migrate/20120124133950_add_clip_no_screening_to_sip_account.rb new file mode 100644 index 0000000..ce2a7e9 --- /dev/null +++ b/db/migrate/20120124133950_add_clip_no_screening_to_sip_account.rb @@ -0,0 +1,6 @@ +class AddClipNoScreeningToSipAccount < ActiveRecord::Migration + def change + add_column :sip_accounts, :clip_no_screening, :string + remove_column :sip_accounts, :clip + end +end diff --git a/db/migrate/20120124135953_add_clip_to_sip_account.rb b/db/migrate/20120124135953_add_clip_to_sip_account.rb new file mode 100644 index 0000000..51d3243 --- /dev/null +++ b/db/migrate/20120124135953_add_clip_to_sip_account.rb @@ -0,0 +1,5 @@ +class AddClipToSipAccount < ActiveRecord::Migration + def change + add_column :sip_accounts, :clip, :boolean + end +end diff --git a/db/migrate/20120124142001_remove_name_from_softkey.rb b/db/migrate/20120124142001_remove_name_from_softkey.rb new file mode 100644 index 0000000..7fc17d5 --- /dev/null +++ b/db/migrate/20120124142001_remove_name_from_softkey.rb @@ -0,0 +1,9 @@ +class RemoveNameFromSoftkey < ActiveRecord::Migration + def up + remove_column :softkeys, :name + end + + def down + add_column :softkeys, :name, :string + end +end diff --git a/db/migrate/20120126090831_create_callthroughs.rb b/db/migrate/20120126090831_create_callthroughs.rb new file mode 100644 index 0000000..e7d146e --- /dev/null +++ b/db/migrate/20120126090831_create_callthroughs.rb @@ -0,0 +1,15 @@ +class CreateCallthroughs < ActiveRecord::Migration + def self.up + create_table :callthroughs do |t| + t.integer :tenant_id + t.string :name + t.integer :sip_account_id + t.string :clip_no_screening + t.timestamps + end + end + + def self.down + drop_table :callthroughs + end +end diff --git a/db/migrate/20120127101726_create_system_messages.rb b/db/migrate/20120127101726_create_system_messages.rb new file mode 100644 index 0000000..830f54a --- /dev/null +++ b/db/migrate/20120127101726_create_system_messages.rb @@ -0,0 +1,13 @@ +class CreateSystemMessages < ActiveRecord::Migration + def self.up + create_table :system_messages do |t| + t.integer :user_id + t.string :content + t.timestamps + end + end + + def self.down + drop_table :system_messages + end +end diff --git a/db/migrate/20120128143538_openstage_phones.rb b/db/migrate/20120128143538_openstage_phones.rb new file mode 100644 index 0000000..64d5cb0 --- /dev/null +++ b/db/migrate/20120128143538_openstage_phones.rb @@ -0,0 +1,25 @@ +class OpenstagePhones < ActiveRecord::Migration + def up + siemens = Manufacturer.find_or_create_by_ieee_name('Siemens Enterprise CommunicationsGmbH & Co. KG', + :name => 'Siemens Enterprise Communications', + :homepage_url => 'http://www.siemens-enterprise.com') + + siemens.phone_models.find_or_create_by_name('Openstage 40', + :product_homepage_url => 'http://www.siemens-enterprise.com/de/products/devices-and-clients/open-stage-desktop-phones.aspx', + :product_manual_homepage_url => 'http://www.siemens-enterprise.com/de/support/downloads-phones-devices/~/media/BOL%20Documents/BOL%20Internet/1%20DownloadFile_P31003S2000U120010019@NETINFO.ashx') + + siemens.phone_models.find_or_create_by_name('Openstage 60', + :product_homepage_url => 'http://www.siemens-enterprise.com/de/products/devices-and-clients/open-stage-desktop-phones.aspx', + :product_manual_homepage_url => 'http://www.siemens-enterprise.com/de/support/downloads-phones-devices/~/media/BOL%20Documents/BOL%20Internet/1%20DownloadFile_P31003S2000U119010019@NETINFO.ashx') + + + siemens.phone_models.find_or_create_by_name('Openstage 80', + :product_homepage_url => 'http://www.siemens-enterprise.com/de/products/devices-and-clients/open-stage-desktop-phones.aspx', + :product_manual_homepage_url => 'http://www.siemens-enterprise.com/de/support/downloads-phones-devices/~/media/BOL%20Documents/BOL%20Internet/1%20DownloadFile_P31003S2000U119010019@NETINFO.ashx') + end + + def down + siemens = Manufacturer.find_by_ieee_name('Siemens Enterprise CommunicationsGmbH & Co. KG') + siemens.destroy + end +end diff --git a/db/migrate/20120128191113_create_access_authorizations.rb b/db/migrate/20120128191113_create_access_authorizations.rb new file mode 100644 index 0000000..b05a288 --- /dev/null +++ b/db/migrate/20120128191113_create_access_authorizations.rb @@ -0,0 +1,17 @@ +class CreateAccessAuthorizations < ActiveRecord::Migration + def self.up + create_table :access_authorizations do |t| + t.string :access_authorizationable_type + t.integer :access_authorizationable_id + t.string :name + t.string :login + t.string :pin + t.integer :position + t.timestamps + end + end + + def self.down + drop_table :access_authorizations + end +end diff --git a/db/migrate/20120129094444_create_whitelists.rb b/db/migrate/20120129094444_create_whitelists.rb new file mode 100644 index 0000000..9e31632 --- /dev/null +++ b/db/migrate/20120129094444_create_whitelists.rb @@ -0,0 +1,15 @@ +class CreateWhitelists < ActiveRecord::Migration + def self.up + create_table :whitelists do |t| + t.string :name + t.string :whitelistable_type + t.integer :whitelistable_id + t.integer :position + t.timestamps + end + end + + def self.down + drop_table :whitelists + end +end diff --git a/db/migrate/20120130155801_add_sip_account_id_to_access_authorization.rb b/db/migrate/20120130155801_add_sip_account_id_to_access_authorization.rb new file mode 100644 index 0000000..6907791 --- /dev/null +++ b/db/migrate/20120130155801_add_sip_account_id_to_access_authorization.rb @@ -0,0 +1,6 @@ +class AddSipAccountIdToAccessAuthorization < ActiveRecord::Migration + def change + add_column :access_authorizations, :sip_account_id, :integer + remove_column :callthroughs, :sip_account_id + end +end diff --git a/db/migrate/20120203093048_create_hunt_groups.rb b/db/migrate/20120203093048_create_hunt_groups.rb new file mode 100644 index 0000000..1f2cfb6 --- /dev/null +++ b/db/migrate/20120203093048_create_hunt_groups.rb @@ -0,0 +1,15 @@ +class CreateHuntGroups < ActiveRecord::Migration + def self.up + create_table :hunt_groups do |t| + t.integer :tenant_id + t.string :name + t.string :strategy + t.integer :seconds_between_jumps + t.timestamps + end + end + + def self.down + drop_table :hunt_groups + end +end diff --git a/db/migrate/20120203120739_create_hunt_group_members.rb b/db/migrate/20120203120739_create_hunt_group_members.rb new file mode 100644 index 0000000..31eb620 --- /dev/null +++ b/db/migrate/20120203120739_create_hunt_group_members.rb @@ -0,0 +1,16 @@ +class CreateHuntGroupMembers < ActiveRecord::Migration + def self.up + create_table :hunt_group_members do |t| + t.integer :hunt_group_id + t.string :name + t.integer :position + t.boolean :active + t.boolean :can_switch_status_itself + t.timestamps + end + end + + def self.down + drop_table :hunt_group_members + end +end diff --git a/db/migrate/20120210121455_add_language_id_to_users.rb b/db/migrate/20120210121455_add_language_id_to_users.rb new file mode 100644 index 0000000..9d6765e --- /dev/null +++ b/db/migrate/20120210121455_add_language_id_to_users.rb @@ -0,0 +1,5 @@ +class AddLanguageIdToUsers < ActiveRecord::Migration + def change + add_column :users, :language_id, :integer + end +end diff --git a/db/migrate/20120215160448_create_softkey_functions.rb b/db/migrate/20120215160448_create_softkey_functions.rb new file mode 100644 index 0000000..569c50c --- /dev/null +++ b/db/migrate/20120215160448_create_softkey_functions.rb @@ -0,0 +1,14 @@ +class CreateSoftkeyFunctions < ActiveRecord::Migration + def up + create_table :softkey_functions do |t| + t.string :name + + t.timestamps + end + + end + + def down + drop_table :softkey_functions + end +end diff --git a/db/migrate/20120215160449_add_position_to_softkey_function.rb b/db/migrate/20120215160449_add_position_to_softkey_function.rb new file mode 100644 index 0000000..16f6b06 --- /dev/null +++ b/db/migrate/20120215160449_add_position_to_softkey_function.rb @@ -0,0 +1,7 @@ +class AddPositionToSoftkeyFunction < ActiveRecord::Migration + def change + add_column :softkey_functions, :position, :integer + add_index :softkey_functions, :position + add_index :softkey_functions, :name + end +end diff --git a/db/migrate/20120215161054_add_softkey_function_id_to_softkey.rb b/db/migrate/20120215161054_add_softkey_function_id_to_softkey.rb new file mode 100644 index 0000000..0f6600f --- /dev/null +++ b/db/migrate/20120215161054_add_softkey_function_id_to_softkey.rb @@ -0,0 +1,5 @@ +class AddSoftkeyFunctionIdToSoftkey < ActiveRecord::Migration + def change + add_column :softkeys, :softkey_function_id, :integer + end +end diff --git a/db/migrate/20120218182205_create_api_rows.rb b/db/migrate/20120218182205_create_api_rows.rb new file mode 100644 index 0000000..d949b3f --- /dev/null +++ b/db/migrate/20120218182205_create_api_rows.rb @@ -0,0 +1,21 @@ +class CreateApiRows < ActiveRecord::Migration + def change + create_table :api_rows do |t| + t.string :user_id + t.string :user_name + t.string :last_name + t.string :middle_name + t.string :first_name + t.string :office_phone_number + t.string :internal_extension + t.string :mobile_phone_number + t.string :fax_phone_number + t.string :email + t.string :pin + t.datetime :pin_updated_at + t.string :photo_file_name + + t.timestamps + end + end +end diff --git a/db/migrate/20120219210950_remove_state_from_user.rb b/db/migrate/20120219210950_remove_state_from_user.rb new file mode 100644 index 0000000..3bb8f59 --- /dev/null +++ b/db/migrate/20120219210950_remove_state_from_user.rb @@ -0,0 +1,9 @@ +class RemoveStateFromUser < ActiveRecord::Migration + def up + remove_column :users, :state + end + + def down + add_column :users, :state, :string + end +end diff --git a/db/migrate/20120228154913_create_cdrs.rb b/db/migrate/20120228154913_create_cdrs.rb new file mode 100644 index 0000000..f9f92b7 --- /dev/null +++ b/db/migrate/20120228154913_create_cdrs.rb @@ -0,0 +1,33 @@ +class CreateCdrs < ActiveRecord::Migration + def self.up + create_table :cdrs, :id => false do |t| + t.string :uuid, :limit => '256', :primary => true + t.integer :account_id + t.string :account_type, :limit => '256' + t.string :bleg_uuid, :limit => '256' + t.integer :bleg_account_id + t.string :bleg_account_type, :limit => '256' + t.string :dialed_number, :limit => '256' + t.string :destination_number, :limit => '256' + t.string :caller_id_number, :limit => '256' + t.string :caller_id_name, :limit => '256' + t.string :callee_id_number, :limit => '256' + t.string :callee_id_name, :limit => '256' + t.datetime :start_stamp + t.datetime :answer_stamp + t.datetime :end_stamp + t.integer :duration + t.integer :billsec + t.string :hangup_cause, :limit => '256' + t.string :dialstatus, :limit => '256' + t.string :forwarding_number, :limit => '256' + t.integer :forwarding_account_id + t.string :forwarding_account_type, :limit => '256' + t.string :forwarding_service, :limit => '256' + end + end + + def self.down + drop_table :cdrs + end +end diff --git a/db/migrate/20120301094049_add_voicemail_boolean_to_call_forward.rb b/db/migrate/20120301094049_add_voicemail_boolean_to_call_forward.rb new file mode 100644 index 0000000..a5ac2f0 --- /dev/null +++ b/db/migrate/20120301094049_add_voicemail_boolean_to_call_forward.rb @@ -0,0 +1,6 @@ +class AddVoicemailBooleanToCallForward < ActiveRecord::Migration + def change + add_column :call_forwards, :to_voicemail, :boolean + + end +end diff --git a/db/migrate/20120312175918_add_hunt_group_id_to_call_forward.rb b/db/migrate/20120312175918_add_hunt_group_id_to_call_forward.rb new file mode 100644 index 0000000..f5d3f79 --- /dev/null +++ b/db/migrate/20120312175918_add_hunt_group_id_to_call_forward.rb @@ -0,0 +1,6 @@ +class AddHuntGroupIdToCallForward < ActiveRecord::Migration + def change + add_column :call_forwards, :hunt_group_id, :integer + + end +end diff --git a/db/migrate/20120313121920_add_polymorphic_to_call_forward.rb b/db/migrate/20120313121920_add_polymorphic_to_call_forward.rb new file mode 100644 index 0000000..3f7bae7 --- /dev/null +++ b/db/migrate/20120313121920_add_polymorphic_to_call_forward.rb @@ -0,0 +1,9 @@ +class AddPolymorphicToCallForward < ActiveRecord::Migration + def change + add_column :call_forwards, :call_forwardable_type, :string + add_column :call_forwards, :call_forwardable_id, :integer + + remove_column :call_forwards, :hunt_group_id + remove_column :call_forwards, :to_voicemail + end +end diff --git a/db/migrate/20120314094720_add_send_voicemail_as_email_attachment_to_user.rb b/db/migrate/20120314094720_add_send_voicemail_as_email_attachment_to_user.rb new file mode 100644 index 0000000..7b74c4f --- /dev/null +++ b/db/migrate/20120314094720_add_send_voicemail_as_email_attachment_to_user.rb @@ -0,0 +1,6 @@ +class AddSendVoicemailAsEmailAttachmentToUser < ActiveRecord::Migration + def change + add_column :users, :send_voicemail_as_email_attachment, :boolean + + end +end diff --git a/db/migrate/20120329133930_add_bleg_read_time_to_cdrs.rb b/db/migrate/20120329133930_add_bleg_read_time_to_cdrs.rb new file mode 100644 index 0000000..c09eb6a --- /dev/null +++ b/db/migrate/20120329133930_add_bleg_read_time_to_cdrs.rb @@ -0,0 +1,6 @@ +class AddBlegReadTimeToCdrs < ActiveRecord::Migration + def change + add_column :cdrs, :bleg_read_time, :datetime + + end +end diff --git a/db/migrate/20120409092724_add_importer_checksum_to_user.rb b/db/migrate/20120409092724_add_importer_checksum_to_user.rb new file mode 100644 index 0000000..a457bcf --- /dev/null +++ b/db/migrate/20120409092724_add_importer_checksum_to_user.rb @@ -0,0 +1,6 @@ +class AddImporterChecksumToUser < ActiveRecord::Migration + def change + add_column :users, :importer_checksum, :string + + end +end diff --git a/db/migrate/20120409160614_add_description_to_sip_account.rb b/db/migrate/20120409160614_add_description_to_sip_account.rb new file mode 100644 index 0000000..7e848f0 --- /dev/null +++ b/db/migrate/20120409160614_add_description_to_sip_account.rb @@ -0,0 +1,6 @@ +class AddDescriptionToSipAccount < ActiveRecord::Migration + def change + add_column :sip_accounts, :description, :string + + end +end diff --git a/db/migrate/20120416074152_callforward_rules_act_per_sip_account_to_sip_account.rb b/db/migrate/20120416074152_callforward_rules_act_per_sip_account_to_sip_account.rb new file mode 100644 index 0000000..72cac09 --- /dev/null +++ b/db/migrate/20120416074152_callforward_rules_act_per_sip_account_to_sip_account.rb @@ -0,0 +1,5 @@ +class CallforwardRulesActPerSipAccountToSipAccount < ActiveRecord::Migration + def change + add_column :sip_accounts, :callforward_rules_act_per_sip_account, :boolean + end +end diff --git a/db/migrate/20120418194029_add_call_forward_id_to_softkeys.rb b/db/migrate/20120418194029_add_call_forward_id_to_softkeys.rb new file mode 100644 index 0000000..c9ad754 --- /dev/null +++ b/db/migrate/20120418194029_add_call_forward_id_to_softkeys.rb @@ -0,0 +1,6 @@ +class AddCallForwardIdToSoftkeys < ActiveRecord::Migration + def change + add_column :softkeys, :call_forward_id, :integer + + end +end diff --git a/db/migrate/20120421073538_add_position_to_call_forward.rb b/db/migrate/20120421073538_add_position_to_call_forward.rb new file mode 100644 index 0000000..e8bf4aa --- /dev/null +++ b/db/migrate/20120421073538_add_position_to_call_forward.rb @@ -0,0 +1,6 @@ +class AddPositionToCallForward < ActiveRecord::Migration + def change + add_column :call_forwards, :position, :integer + + end +end diff --git a/db/migrate/20120421075735_populate_softkey_functions.rb b/db/migrate/20120421075735_populate_softkey_functions.rb new file mode 100644 index 0000000..36eb02f --- /dev/null +++ b/db/migrate/20120421075735_populate_softkey_functions.rb @@ -0,0 +1,9 @@ +class PopulateSoftkeyFunctions < ActiveRecord::Migration + def up + SoftkeyFunction.create(:name => 'call_forwarding') + end + + def down + SoftkeyFunction.where(:name => 'call_forwarding').destroy_all + end +end diff --git a/db/migrate/20120422072551_populate_softkey_function.rb b/db/migrate/20120422072551_populate_softkey_function.rb new file mode 100644 index 0000000..91f5fd2 --- /dev/null +++ b/db/migrate/20120422072551_populate_softkey_function.rb @@ -0,0 +1,18 @@ +class PopulateSoftkeyFunction < ActiveRecord::Migration + def up + ['speed_dial', 'blf', 'dtmf', 'log_out', 'log_in', 'conference'].each do |function_name| + SoftkeyFunction.create(:name => function_name) + end + + SoftkeyFunction.where(:position => nil).order(:id).each do |softkey_function| + softkey_function.update_attributes(:position => softkey_function.id) if softkey_function.position.nil? + end + deactivated_softkey_function = SoftkeyFunction.create(:name => 'deactivated') + deactivated_softkey_function.move_to_top + end + + def down + SoftkeyFunction.where(:name => ['speed_dial', 'blf', 'dtmf', 'log_out', 'log_in', 'conference', 'deactivated'] ).destroy_all + end + +end diff --git a/db/migrate/20120424062951_add_hotdeskable_to_sip_account.rb b/db/migrate/20120424062951_add_hotdeskable_to_sip_account.rb new file mode 100644 index 0000000..3d917d6 --- /dev/null +++ b/db/migrate/20120424062951_add_hotdeskable_to_sip_account.rb @@ -0,0 +1,6 @@ +class AddHotdeskableToSipAccount < ActiveRecord::Migration + def change + add_column :sip_accounts, :hotdeskable, :boolean + + end +end diff --git a/db/migrate/20120425112414_add_nightly_reboot_to_phone.rb b/db/migrate/20120425112414_add_nightly_reboot_to_phone.rb new file mode 100644 index 0000000..46ddf37 --- /dev/null +++ b/db/migrate/20120425112414_add_nightly_reboot_to_phone.rb @@ -0,0 +1,6 @@ +class AddNightlyRebootToPhone < ActiveRecord::Migration + def change + add_column :phones, :nightly_reboot, :boolean + + end +end diff --git a/db/migrate/20120509071426_add_from_field_to_tenant.rb b/db/migrate/20120509071426_add_from_field_to_tenant.rb new file mode 100644 index 0000000..b99dc3e --- /dev/null +++ b/db/migrate/20120509071426_add_from_field_to_tenant.rb @@ -0,0 +1,8 @@ +class AddFromFieldToTenant < ActiveRecord::Migration + def change + add_column :tenants, :from_field_voicemail_email, :string + + add_column :tenants, :from_field_pin_change_email, :string + + end +end diff --git a/db/migrate/20120510110311_add_forwarding_read_time_to_cdrs.rb b/db/migrate/20120510110311_add_forwarding_read_time_to_cdrs.rb new file mode 100644 index 0000000..b152457 --- /dev/null +++ b/db/migrate/20120510110311_add_forwarding_read_time_to_cdrs.rb @@ -0,0 +1,6 @@ +class AddForwardingReadTimeToCdrs < ActiveRecord::Migration + def change + add_column :cdrs, :forwarding_read_time, :datetime + + end +end diff --git a/db/migrate/20120513154359_create_gui_functions.rb b/db/migrate/20120513154359_create_gui_functions.rb new file mode 100644 index 0000000..e1d814c --- /dev/null +++ b/db/migrate/20120513154359_create_gui_functions.rb @@ -0,0 +1,14 @@ +class CreateGuiFunctions < ActiveRecord::Migration + def self.up + create_table :gui_functions do |t| + t.string :category + t.string :name + t.string :description + t.timestamps + end + end + + def self.down + drop_table :gui_functions + end +end diff --git a/db/migrate/20120513155342_create_gui_function_memberships.rb b/db/migrate/20120513155342_create_gui_function_memberships.rb new file mode 100644 index 0000000..d271853 --- /dev/null +++ b/db/migrate/20120513155342_create_gui_function_memberships.rb @@ -0,0 +1,12 @@ +class CreateGuiFunctionMemberships < ActiveRecord::Migration + def change + create_table :gui_function_memberships do |t| + t.integer :gui_function_id + t.integer :user_group_id + t.boolean :activated + t.string :output + + t.timestamps + end + end +end diff --git a/db/migrate/20120513185233_add_gui_functions.rb b/db/migrate/20120513185233_add_gui_functions.rb new file mode 100644 index 0000000..c70d61d --- /dev/null +++ b/db/migrate/20120513185233_add_gui_functions.rb @@ -0,0 +1,47 @@ +class AddGuiFunctions < ActiveRecord::Migration + def up + GuiFunction.create(:category => 'Top navigation bar', :name => 'user_avatar_in_top_navigation_bar', + :description => 'Show the user avatar in the top navigaction bar.') + GuiFunction.create(:category => 'Top navigation bar', :name => 'search_field_in_top_navigation_bar', + :description => 'Show the search field for phone book entries in the top navigation bar.') + GuiFunction.create(:category => 'Top navigation bar', :name => 'navigation_items_in_top_navigation_bar', + :description => 'Show the navigation items in the top navigation bar.') + GuiFunction.create(:category => 'User show view', :name => 'show_phone_books_in_user_show_view', + :description => 'Show the available phone books in the user show view.') + GuiFunction.create(:category => 'Footer', :name => 'amooma_commercial_support_link_in_footer', + :description => 'Show a link to the AMOOMA commerical support page in the footer.') + GuiFunction.create(:category => 'Footer', :name => 'gemeinschaft_mailinglist_link_in_footer', + :description => 'Show a link to the Gemeinschaft Mailinglist in the footer.') + GuiFunction.create(:category => 'User edit view', :name => 'name_data_fields_in_user_edit_form', + :description => 'Show gender, first name, middle name, last name in the User edit form.') + GuiFunction.create(:category => 'User edit view', :name => 'user_name_field_in_user_edit_form', + :description => 'Show user name (login) field in the User edit form.') + GuiFunction.create(:category => 'User edit view', :name => 'email_field_in_user_edit_form', + :description => 'Show e-mail field in the User edit form.') + GuiFunction.create(:category => 'User edit view', :name => 'password_fields_in_user_edit_form', + :description => 'Show password fields in the User edit form.') + GuiFunction.create(:category => 'User edit view', :name => 'pin_fields_in_user_edit_form', + :description => 'Show PIN fields in the User edit form.') + GuiFunction.create(:category => 'Call Forward edit view', :name => 'depth_field_in_call_forward_form', + :description => 'Show depth field in the call forward form.') + GuiFunction.create(:category => 'Call Forward index view', :name => 'depth_field_value_in_index_table', + :description => 'Show depth field in the call forwards table.') + + CallForwardCase.all.each do |call_forward_case| + GuiFunction.create(:category => 'Call Forward edit view', :name => "call_forward_case_#{call_forward_case.value.downcase}_field_in_call_forward_form", + :description => "Show the call forward case '#{call_forward_case.value}' in the forward form.") + end + + GuiFunction.create(:category => 'Call Forward edit view', :name => 'huntgroup_in_destination_field_in_call_forward_form', + :description => 'Show huntgroups in the destination field of the call forward form.') + + SoftkeyFunction.all.each do |softkey_function| + GuiFunction.create(:category => 'Softkey edit view', :name => "softkey_function_#{softkey_function.name.downcase}_field_in_softkey_form", + :description => "Show the softkey function '#{softkey_function.name}' in the softkey form.") + end + end + + def down + GuiFunction.destroy_all + end +end diff --git a/db/migrate/20120515104749_add_hunt_group_function_key.rb b/db/migrate/20120515104749_add_hunt_group_function_key.rb new file mode 100644 index 0000000..02689d5 --- /dev/null +++ b/db/migrate/20120515104749_add_hunt_group_function_key.rb @@ -0,0 +1,14 @@ +class AddHuntGroupFunctionKey < ActiveRecord::Migration + def up + softkey_function = SoftkeyFunction.find_or_create_by_name('hunt_group_membership') + gui_function = GuiFunction.find_or_create_by_name("softkey_function_#{softkey_function.name.downcase}_field_in_softkey_form", + :category => 'Softkey edit view', + :description => "Show the softkey function '#{softkey_function.name}' in the softkey form.") + end + + def down + softkey_function = SoftkeyFunction.find_by_name('hunt_group_membership') + softkey_function.destroy + GuiFunction.find_by_name("softkey_function_#{softkey_function.name.downcase}_field_in_softkey_form").destroy + end +end diff --git a/db/migrate/20120515124103_add_hold_softkey_function.rb b/db/migrate/20120515124103_add_hold_softkey_function.rb new file mode 100644 index 0000000..4e16587 --- /dev/null +++ b/db/migrate/20120515124103_add_hold_softkey_function.rb @@ -0,0 +1,14 @@ +class AddHoldSoftkeyFunction < ActiveRecord::Migration + def up + softkey_function = SoftkeyFunction.find_or_create_by_name('hold') + gui_function = GuiFunction.find_or_create_by_name("softkey_function_#{softkey_function.name.downcase}_field_in_softkey_form", + :category => 'Softkey edit view', + :description => "Show the softkey function '#{softkey_function.name}' in the softkey form.") + end + + def down + softkey_function = SoftkeyFunction.find_by_name('hold') + softkey_function.destroy + GuiFunction.find_by_name("softkey_function_#{softkey_function.name.downcase}_field_in_softkey_form").destroy + end +end diff --git a/db/migrate/20120611093946_create_gs_nodes.rb b/db/migrate/20120611093946_create_gs_nodes.rb new file mode 100644 index 0000000..4aa167d --- /dev/null +++ b/db/migrate/20120611093946_create_gs_nodes.rb @@ -0,0 +1,14 @@ +class CreateGsNodes < ActiveRecord::Migration + def self.up + create_table :gs_nodes do |t| + t.string :name + t.string :ip_address + t.boolean :push_updates + t.timestamps + end + end + + def self.down + drop_table :gs_nodes + end +end diff --git a/db/migrate/20120611150245_add_gs_node_id_to_phone_number.rb b/db/migrate/20120611150245_add_gs_node_id_to_phone_number.rb new file mode 100644 index 0000000..d896e5d --- /dev/null +++ b/db/migrate/20120611150245_add_gs_node_id_to_phone_number.rb @@ -0,0 +1,8 @@ +class AddGsNodeIdToPhoneNumber < ActiveRecord::Migration + def change + add_column :phone_numbers, :gs_node_id, :integer + + add_column :phone_numbers, :gs_node_original_id, :integer + + end +end diff --git a/db/migrate/20120614113123_add_gs_node_information_to_user.rb b/db/migrate/20120614113123_add_gs_node_information_to_user.rb new file mode 100644 index 0000000..171958f --- /dev/null +++ b/db/migrate/20120614113123_add_gs_node_information_to_user.rb @@ -0,0 +1,8 @@ +class AddGsNodeInformationToUser < ActiveRecord::Migration + def change + add_column :users, :gs_node_id, :integer + + add_column :users, :gs_node_original_id, :integer + + end +end diff --git a/db/migrate/20120614113931_add_gs_node_information_to_sip_account.rb b/db/migrate/20120614113931_add_gs_node_information_to_sip_account.rb new file mode 100644 index 0000000..057f543 --- /dev/null +++ b/db/migrate/20120614113931_add_gs_node_information_to_sip_account.rb @@ -0,0 +1,8 @@ +class AddGsNodeInformationToSipAccount < ActiveRecord::Migration + def change + add_column :sip_accounts, :gs_node_id, :integer + + add_column :sip_accounts, :gs_node_original_id, :integer + + end +end diff --git a/db/migrate/20120614115938_add_gs_node_information_to_hunt_group.rb b/db/migrate/20120614115938_add_gs_node_information_to_hunt_group.rb new file mode 100644 index 0000000..0e5bdd3 --- /dev/null +++ b/db/migrate/20120614115938_add_gs_node_information_to_hunt_group.rb @@ -0,0 +1,8 @@ +class AddGsNodeInformationToHuntGroup < ActiveRecord::Migration + def change + add_column :hunt_groups, :gs_node_id, :integer + + add_column :hunt_groups, :gs_node_original_id, :integer + + end +end diff --git a/db/migrate/20120617065247_create_gs_cluster_sync_log_entries.rb b/db/migrate/20120617065247_create_gs_cluster_sync_log_entries.rb new file mode 100644 index 0000000..83d6a5b --- /dev/null +++ b/db/migrate/20120617065247_create_gs_cluster_sync_log_entries.rb @@ -0,0 +1,17 @@ +class CreateGsClusterSyncLogEntries < ActiveRecord::Migration + def self.up + create_table :gs_cluster_sync_log_entries do |t| + t.integer :gs_node_id + t.string :class_name + t.string :action + t.text :content + t.string :status + t.string :history + t.timestamps + end + end + + def self.down + drop_table :gs_cluster_sync_log_entries + end +end diff --git a/db/migrate/20120617193636_add_site_to_gs_node.rb b/db/migrate/20120617193636_add_site_to_gs_node.rb new file mode 100644 index 0000000..f2f6545 --- /dev/null +++ b/db/migrate/20120617193636_add_site_to_gs_node.rb @@ -0,0 +1,12 @@ +class AddSiteToGsNode < ActiveRecord::Migration + def change + add_column :gs_nodes, :site, :string + + add_column :gs_nodes, :element_name, :string + + rename_column :gs_nodes, :push_updates, :push_updates_to + + add_column :gs_nodes, :accepts_updates_from, :boolean + + end +end diff --git a/db/migrate/20120626094238_add_uuid_to_phone_number.rb b/db/migrate/20120626094238_add_uuid_to_phone_number.rb new file mode 100644 index 0000000..095981e --- /dev/null +++ b/db/migrate/20120626094238_add_uuid_to_phone_number.rb @@ -0,0 +1,11 @@ +class AddUuidToPhoneNumber < ActiveRecord::Migration + def change + add_column :phone_numbers, :uuid, :string rescue puts "column already added" + add_column :sip_accounts, :uuid, :string + add_column :hunt_groups, :uuid, :string + + add_index :phone_numbers, :uuid rescue puts "index already added" + add_index :sip_accounts, :uuid + add_index :hunt_groups, :uuid + end +end diff --git a/db/migrate/20120626095730_add_uuid_to_users.rb b/db/migrate/20120626095730_add_uuid_to_users.rb new file mode 100644 index 0000000..dbd5008 --- /dev/null +++ b/db/migrate/20120626095730_add_uuid_to_users.rb @@ -0,0 +1,6 @@ +class AddUuidToUsers < ActiveRecord::Migration + def change + add_column :users, :uuid, :string + add_index :users, :uuid + end +end diff --git a/db/migrate/20120715175419_add_homebase_ip_address_to_gs_cluster_sync_log_entry.rb b/db/migrate/20120715175419_add_homebase_ip_address_to_gs_cluster_sync_log_entry.rb new file mode 100644 index 0000000..318ff25 --- /dev/null +++ b/db/migrate/20120715175419_add_homebase_ip_address_to_gs_cluster_sync_log_entry.rb @@ -0,0 +1,6 @@ +class AddHomebaseIpAddressToGsClusterSyncLogEntry < ActiveRecord::Migration + def change + add_column :gs_cluster_sync_log_entries, :homebase_ip_address, :string + + end +end diff --git a/db/migrate/20120720070000_add_waiting_to_be_syned_to_gs_cluster_sync_log_entry.rb b/db/migrate/20120720070000_add_waiting_to_be_syned_to_gs_cluster_sync_log_entry.rb new file mode 100644 index 0000000..d0d67be --- /dev/null +++ b/db/migrate/20120720070000_add_waiting_to_be_syned_to_gs_cluster_sync_log_entry.rb @@ -0,0 +1,6 @@ +class AddWaitingToBeSynedToGsClusterSyncLogEntry < ActiveRecord::Migration + def change + add_column :gs_cluster_sync_log_entries, :waiting_to_be_synced, :boolean + + end +end diff --git a/db/migrate/20120722072517_add_association_to_gs_cluster_sync_log_entry.rb b/db/migrate/20120722072517_add_association_to_gs_cluster_sync_log_entry.rb new file mode 100644 index 0000000..6c9c050 --- /dev/null +++ b/db/migrate/20120722072517_add_association_to_gs_cluster_sync_log_entry.rb @@ -0,0 +1,8 @@ +class AddAssociationToGsClusterSyncLogEntry < ActiveRecord::Migration + def change + add_column :gs_cluster_sync_log_entries, :association_method, :string + + add_column :gs_cluster_sync_log_entries, :association_uuid, :string + + end +end diff --git a/db/migrate/20120723065038_add_uuid_to_tenants.rb b/db/migrate/20120723065038_add_uuid_to_tenants.rb new file mode 100644 index 0000000..14d6912 --- /dev/null +++ b/db/migrate/20120723065038_add_uuid_to_tenants.rb @@ -0,0 +1,6 @@ +class AddUuidToTenants < ActiveRecord::Migration + def change + add_column :tenants, :uuid, :string + + end +end diff --git a/db/migrate/20120724131815_add_uuid_to_conferences.rb b/db/migrate/20120724131815_add_uuid_to_conferences.rb new file mode 100644 index 0000000..17c26a5 --- /dev/null +++ b/db/migrate/20120724131815_add_uuid_to_conferences.rb @@ -0,0 +1,6 @@ +class AddUuidToConferences < ActiveRecord::Migration + def change + add_column :conferences, :uuid, :string + + end +end diff --git a/db/migrate/20120724131905_add_uuid_to_callthroughs.rb b/db/migrate/20120724131905_add_uuid_to_callthroughs.rb new file mode 100644 index 0000000..9ec067b --- /dev/null +++ b/db/migrate/20120724131905_add_uuid_to_callthroughs.rb @@ -0,0 +1,6 @@ +class AddUuidToCallthroughs < ActiveRecord::Migration + def change + add_column :callthroughs, :uuid, :string + + end +end diff --git a/db/migrate/20120724131956_add_uuid_to_fax_accounts.rb b/db/migrate/20120724131956_add_uuid_to_fax_accounts.rb new file mode 100644 index 0000000..177260f --- /dev/null +++ b/db/migrate/20120724131956_add_uuid_to_fax_accounts.rb @@ -0,0 +1,6 @@ +class AddUuidToFaxAccounts < ActiveRecord::Migration + def change + add_column :fax_accounts, :uuid, :string + + end +end diff --git a/db/migrate/20120727102518_add_uuid_to_phone_book_entry.rb b/db/migrate/20120727102518_add_uuid_to_phone_book_entry.rb new file mode 100644 index 0000000..920fe15 --- /dev/null +++ b/db/migrate/20120727102518_add_uuid_to_phone_book_entry.rb @@ -0,0 +1,7 @@ +class AddUuidToPhoneBookEntry < ActiveRecord::Migration + def change + add_column :phone_book_entries, :uuid, :string + add_index :phone_book_entries, :uuid + + end +end diff --git a/db/migrate/20120727105750_add_uuid_to_access_authorization.rb b/db/migrate/20120727105750_add_uuid_to_access_authorization.rb new file mode 100644 index 0000000..78f3197 --- /dev/null +++ b/db/migrate/20120727105750_add_uuid_to_access_authorization.rb @@ -0,0 +1,7 @@ +class AddUuidToAccessAuthorization < ActiveRecord::Migration + def change + add_column :access_authorizations, :uuid, :string + add_index :access_authorizations, :uuid + + end +end diff --git a/db/migrate/20120727110501_add_access_authorization_user_id_to_phone_number.rb b/db/migrate/20120727110501_add_access_authorization_user_id_to_phone_number.rb new file mode 100644 index 0000000..325952d --- /dev/null +++ b/db/migrate/20120727110501_add_access_authorization_user_id_to_phone_number.rb @@ -0,0 +1,6 @@ +class AddAccessAuthorizationUserIdToPhoneNumber < ActiveRecord::Migration + def change + add_column :phone_numbers, :access_authorization_user_id, :integer + + end +end diff --git a/db/migrate/20120728073802_add_is_native_to_user.rb b/db/migrate/20120728073802_add_is_native_to_user.rb new file mode 100644 index 0000000..6cfc160 --- /dev/null +++ b/db/migrate/20120728073802_add_is_native_to_user.rb @@ -0,0 +1,6 @@ +class AddIsNativeToUser < ActiveRecord::Migration + def change + add_column :users, :is_native, :boolean + + end +end diff --git a/db/migrate/20120728073904_add_is_native_to_phone_number.rb b/db/migrate/20120728073904_add_is_native_to_phone_number.rb new file mode 100644 index 0000000..6d4782d --- /dev/null +++ b/db/migrate/20120728073904_add_is_native_to_phone_number.rb @@ -0,0 +1,6 @@ +class AddIsNativeToPhoneNumber < ActiveRecord::Migration + def change + add_column :phone_numbers, :is_native, :boolean + + end +end diff --git a/db/migrate/20120728091842_add_is_native_to_sip_account.rb b/db/migrate/20120728091842_add_is_native_to_sip_account.rb new file mode 100644 index 0000000..de230d1 --- /dev/null +++ b/db/migrate/20120728091842_add_is_native_to_sip_account.rb @@ -0,0 +1,6 @@ +class AddIsNativeToSipAccount < ActiveRecord::Migration + def change + add_column :sip_accounts, :is_native, :boolean + + end +end diff --git a/db/migrate/20120728113705_add_uuid_to_hunt_group_member.rb b/db/migrate/20120728113705_add_uuid_to_hunt_group_member.rb new file mode 100644 index 0000000..fc2fb5c --- /dev/null +++ b/db/migrate/20120728113705_add_uuid_to_hunt_group_member.rb @@ -0,0 +1,7 @@ +class AddUuidToHuntGroupMember < ActiveRecord::Migration + def change + add_column :hunt_group_members, :uuid, :string + add_index :hunt_group_members, :uuid + + end +end diff --git a/db/migrate/20120728133144_add_uuid_to_phone_number_range.rb b/db/migrate/20120728133144_add_uuid_to_phone_number_range.rb new file mode 100644 index 0000000..1674ea0 --- /dev/null +++ b/db/migrate/20120728133144_add_uuid_to_phone_number_range.rb @@ -0,0 +1,7 @@ +class AddUuidToPhoneNumberRange < ActiveRecord::Migration + def change + add_column :phone_number_ranges, :uuid, :string + add_index :phone_number_ranges, :uuid + + end +end diff --git a/db/migrate/20120728135133_add_uuid_to_fax_documents.rb b/db/migrate/20120728135133_add_uuid_to_fax_documents.rb new file mode 100644 index 0000000..c1d96d1 --- /dev/null +++ b/db/migrate/20120728135133_add_uuid_to_fax_documents.rb @@ -0,0 +1,6 @@ +class AddUuidToFaxDocuments < ActiveRecord::Migration + def change + add_column :fax_documents, :uuid, :string + + end +end diff --git a/db/migrate/20120802132854_add_notification_to_voicemail_msgs.rb b/db/migrate/20120802132854_add_notification_to_voicemail_msgs.rb new file mode 100644 index 0000000..4ebc33e --- /dev/null +++ b/db/migrate/20120802132854_add_notification_to_voicemail_msgs.rb @@ -0,0 +1,6 @@ +class AddNotificationToVoicemailMsgs < ActiveRecord::Migration + def change + add_column :voicemail_msgs, :notification, :boolean + + end +end diff --git a/db/migrate/20120813085708_add_uuid_to_conference_invitee.rb b/db/migrate/20120813085708_add_uuid_to_conference_invitee.rb new file mode 100644 index 0000000..9017767 --- /dev/null +++ b/db/migrate/20120813085708_add_uuid_to_conference_invitee.rb @@ -0,0 +1,6 @@ +class AddUuidToConferenceInvitee < ActiveRecord::Migration + def change + add_column :conference_invitees, :uuid, :string + + end +end diff --git a/db/migrate/20120821105942_create_automatic_call_distributors.rb b/db/migrate/20120821105942_create_automatic_call_distributors.rb new file mode 100644 index 0000000..6bfa921 --- /dev/null +++ b/db/migrate/20120821105942_create_automatic_call_distributors.rb @@ -0,0 +1,22 @@ +class CreateAutomaticCallDistributors < ActiveRecord::Migration + def self.up + create_table :automatic_call_distributors do |t| + t.string :uuid + t.string :name + t.string :strategy + t.string :automatic_call_distributorable_type + t.integer :automatic_call_distributorable_id + t.integer :max_callers + t.integer :agent_timeout + t.integer :retry_timeout + t.string :join + t.string :leave + t.integer :gs_node_id + t.timestamps + end + end + + def self.down + drop_table :automatic_call_distributors + end +end diff --git a/db/migrate/20120822094609_create_acd_callers.rb b/db/migrate/20120822094609_create_acd_callers.rb new file mode 100644 index 0000000..fd1d30c --- /dev/null +++ b/db/migrate/20120822094609_create_acd_callers.rb @@ -0,0 +1,18 @@ +class CreateAcdCallers < ActiveRecord::Migration + def self.up + create_table :acd_callers do |t| + t.string :channel_uuid + t.integer :automatic_call_distributor_id + t.string :status + t.datetime :enter_time + t.datetime :agent_answer_time + t.string :callback_number + t.integer :callback_attempts + t.timestamps + end + end + + def self.down + drop_table :acd_callers + end +end diff --git a/db/migrate/20120822124716_create_acd_agents.rb b/db/migrate/20120822124716_create_acd_agents.rb new file mode 100644 index 0000000..bfd1ab6 --- /dev/null +++ b/db/migrate/20120822124716_create_acd_agents.rb @@ -0,0 +1,19 @@ +class CreateAcdAgents < ActiveRecord::Migration + def self.up + create_table :acd_agents do |t| + t.string :uuid + t.string :name + t.string :status + t.integer :automatic_call_distributor_id + t.datetime :last_call + t.integer :calls_answered + t.string :destination_type + t.integer :destination_id + t.timestamps + end + end + + def self.down + drop_table :acd_agents + end +end diff --git a/db/migrate/20120927101336_add_announce_position_to_automatic_call_distributors.rb b/db/migrate/20120927101336_add_announce_position_to_automatic_call_distributors.rb new file mode 100644 index 0000000..7b92cdb --- /dev/null +++ b/db/migrate/20120927101336_add_announce_position_to_automatic_call_distributors.rb @@ -0,0 +1,6 @@ +class AddAnnouncePositionToAutomaticCallDistributors < ActiveRecord::Migration + def change + add_column :automatic_call_distributors, :announce_position, :integer + + end +end diff --git a/db/migrate/20120927101507_add_announce_call_agents_to_automatic_call_distributors.rb b/db/migrate/20120927101507_add_announce_call_agents_to_automatic_call_distributors.rb new file mode 100644 index 0000000..7010ce7 --- /dev/null +++ b/db/migrate/20120927101507_add_announce_call_agents_to_automatic_call_distributors.rb @@ -0,0 +1,6 @@ +class AddAnnounceCallAgentsToAutomaticCallDistributors < ActiveRecord::Migration + def change + add_column :automatic_call_distributors, :announce_call_agents, :boolean + + end +end diff --git a/db/migrate/20120927101636_add_greeting_to_automatic_call_distributors.rb b/db/migrate/20120927101636_add_greeting_to_automatic_call_distributors.rb new file mode 100644 index 0000000..0eead96 --- /dev/null +++ b/db/migrate/20120927101636_add_greeting_to_automatic_call_distributors.rb @@ -0,0 +1,6 @@ +class AddGreetingToAutomaticCallDistributors < ActiveRecord::Migration + def change + add_column :automatic_call_distributors, :greeting, :string + + end +end diff --git a/db/migrate/20120927101800_add_goodbye_to_automatic_call_distributors.rb b/db/migrate/20120927101800_add_goodbye_to_automatic_call_distributors.rb new file mode 100644 index 0000000..5313bba --- /dev/null +++ b/db/migrate/20120927101800_add_goodbye_to_automatic_call_distributors.rb @@ -0,0 +1,6 @@ +class AddGoodbyeToAutomaticCallDistributors < ActiveRecord::Migration + def change + add_column :automatic_call_distributors, :goodbye, :string + + end +end diff --git a/db/migrate/20120927101908_add_music_to_automatic_call_distributors.rb b/db/migrate/20120927101908_add_music_to_automatic_call_distributors.rb new file mode 100644 index 0000000..3f39b38 --- /dev/null +++ b/db/migrate/20120927101908_add_music_to_automatic_call_distributors.rb @@ -0,0 +1,6 @@ +class AddMusicToAutomaticCallDistributors < ActiveRecord::Migration + def change + add_column :automatic_call_distributors, :music, :string + + end +end diff --git a/db/migrate/20120927110240_change_data_type_for_announce_call_agents.rb b/db/migrate/20120927110240_change_data_type_for_announce_call_agents.rb new file mode 100644 index 0000000..9ae0277 --- /dev/null +++ b/db/migrate/20120927110240_change_data_type_for_announce_call_agents.rb @@ -0,0 +1,13 @@ +class ChangeDataTypeForAnnounceCallAgents < ActiveRecord::Migration + def up + change_table :automatic_call_distributors do |t| + t.change :announce_call_agents, :string + end + end + + def down + change_table :automatic_call_distributors do |t| + t.change :announce_call_agents, :boolean + end + end +end diff --git a/db/migrate/20121009135700_add_automatic_call_distributor_function_key.rb b/db/migrate/20121009135700_add_automatic_call_distributor_function_key.rb new file mode 100644 index 0000000..b6fa561 --- /dev/null +++ b/db/migrate/20121009135700_add_automatic_call_distributor_function_key.rb @@ -0,0 +1,14 @@ +class AddAutomaticCallDistributorFunctionKey < ActiveRecord::Migration + def up + softkey_function = SoftkeyFunction.find_or_create_by_name('acd_membership') + gui_function = GuiFunction.find_or_create_by_name("softkey_function_#{softkey_function.name.downcase}_field_in_softkey_form", + :category => 'Softkey edit view', + :description => "Show the softkey function '#{softkey_function.name}' in the softkey form.") + end + + def down + softkey_function = SoftkeyFunction.find_by_name('acd_membership') + softkey_function.destroy + GuiFunction.find_by_name("softkey_function_#{softkey_function.name.downcase}_field_in_softkey_form").destroy + end +end diff --git a/db/migrate/20121012071908_create_call_histories.rb b/db/migrate/20121012071908_create_call_histories.rb new file mode 100644 index 0000000..d40e566 --- /dev/null +++ b/db/migrate/20121012071908_create_call_histories.rb @@ -0,0 +1,29 @@ +class CreateCallHistories < ActiveRecord::Migration + def change + create_table :call_histories do |t| + t.string :call_historyable_type + t.integer :call_historyable_id + t.string :entry_type + t.string :caller_account_type + t.integer :caller_account_id + t.string :caller_id_number + t.string :caller_id_name + t.string :caller_channel_uuid + t.string :callee_account_type + t.integer :callee_account_id + t.string :callee_id_number + t.string :callee_id_name + t.string :auth_account_type + t.integer :auth_account_id + t.string :forwarding_service + t.string :destination_number + t.datetime :start_stamp + t.integer :duration + t.string :result + t.boolean :read_flag + t.boolean :returned_flag + + t.timestamps + end + end +end diff --git a/db/migrate/20121105123841_add_uuid_to_phone_books.rb b/db/migrate/20121105123841_add_uuid_to_phone_books.rb new file mode 100644 index 0000000..cc51b3f --- /dev/null +++ b/db/migrate/20121105123841_add_uuid_to_phone_books.rb @@ -0,0 +1,6 @@ +class AddUuidToPhoneBooks < ActiveRecord::Migration + def change + add_column :phone_books, :uuid, :string + + end +end diff --git a/db/migrate/20121105123943_add_uuid_to_addresses.rb b/db/migrate/20121105123943_add_uuid_to_addresses.rb new file mode 100644 index 0000000..1d67c73 --- /dev/null +++ b/db/migrate/20121105123943_add_uuid_to_addresses.rb @@ -0,0 +1,6 @@ +class AddUuidToAddresses < ActiveRecord::Migration + def change + add_column :addresses, :uuid, :string + + end +end diff --git a/db/migrate/20121105124208_add_uuid_to_call_forwards.rb b/db/migrate/20121105124208_add_uuid_to_call_forwards.rb new file mode 100644 index 0000000..6689bec --- /dev/null +++ b/db/migrate/20121105124208_add_uuid_to_call_forwards.rb @@ -0,0 +1,6 @@ +class AddUuidToCallForwards < ActiveRecord::Migration + def change + add_column :call_forwards, :uuid, :string + + end +end diff --git a/db/migrate/20121105124343_add_uuid_to_phone_models.rb b/db/migrate/20121105124343_add_uuid_to_phone_models.rb new file mode 100644 index 0000000..49acc8b --- /dev/null +++ b/db/migrate/20121105124343_add_uuid_to_phone_models.rb @@ -0,0 +1,6 @@ +class AddUuidToPhoneModels < ActiveRecord::Migration + def change + add_column :phone_models, :uuid, :string rescue puts "column already added" + + end +end diff --git a/db/migrate/20121105124904_add_uuid_to_softkeys.rb b/db/migrate/20121105124904_add_uuid_to_softkeys.rb new file mode 100644 index 0000000..0ba13e8 --- /dev/null +++ b/db/migrate/20121105124904_add_uuid_to_softkeys.rb @@ -0,0 +1,6 @@ +class AddUuidToSoftkeys < ActiveRecord::Migration + def change + add_column :softkeys, :uuid, :string + + end +end diff --git a/db/migrate/20121105125043_add_uuid_to_whitelists.rb b/db/migrate/20121105125043_add_uuid_to_whitelists.rb new file mode 100644 index 0000000..11f1766 --- /dev/null +++ b/db/migrate/20121105125043_add_uuid_to_whitelists.rb @@ -0,0 +1,6 @@ +class AddUuidToWhitelists < ActiveRecord::Migration + def change + add_column :whitelists, :uuid, :string + + end +end diff --git a/db/migrate/20121105125232_populate_uuid_field.rb b/db/migrate/20121105125232_populate_uuid_field.rb new file mode 100644 index 0000000..4a83bc8 --- /dev/null +++ b/db/migrate/20121105125232_populate_uuid_field.rb @@ -0,0 +1,138 @@ +class PopulateUuidField < ActiveRecord::Migration + def up + AccessAuthorization.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + AcdAgent.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + AutomaticCallDistributor.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + Callthrough.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + ConferenceInvitee.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + Conference.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + FaxAccount.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + FaxDocument.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + HuntGroupMember.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + HuntGroup.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + PhoneBookEntry.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + PhoneNumberRange.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + PhoneNumber.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + SipAccount.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + Tenant.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + User.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + PhoneBook.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + Address.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + CallForward.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + PhoneModel.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + Softkey.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + + Whitelist.where('uuid IS NULL OR uuid = ""').each do |record| + uuid = UUID.new + record.uuid = uuid.generate + record.save + end + end + + def down + end +end diff --git a/db/migrate/20121105144944_add_last_sync_to_gs_nodes.rb b/db/migrate/20121105144944_add_last_sync_to_gs_nodes.rb new file mode 100644 index 0000000..aea4e64 --- /dev/null +++ b/db/migrate/20121105144944_add_last_sync_to_gs_nodes.rb @@ -0,0 +1,6 @@ +class AddLastSyncToGsNodes < ActiveRecord::Migration + def change + add_column :gs_nodes, :last_sync, :datetime + + end +end diff --git a/db/migrate/20121107072526_add_bridge_stamp_to_cdrs.rb b/db/migrate/20121107072526_add_bridge_stamp_to_cdrs.rb new file mode 100644 index 0000000..42cb949 --- /dev/null +++ b/db/migrate/20121107072526_add_bridge_stamp_to_cdrs.rb @@ -0,0 +1,6 @@ +class AddBridgeStampToCdrs < ActiveRecord::Migration + def change + add_column :cdrs, :bridge_stamp, :datetime + + end +end diff --git a/db/migrate/20121121080400_add_notify_to_voicemail_prefs.rb b/db/migrate/20121121080400_add_notify_to_voicemail_prefs.rb new file mode 100644 index 0000000..f09c3f6 --- /dev/null +++ b/db/migrate/20121121080400_add_notify_to_voicemail_prefs.rb @@ -0,0 +1,6 @@ +class AddNotifyToVoicemailPrefs < ActiveRecord::Migration + def change + add_column :voicemail_prefs, :notify, :boolean + + end +end diff --git a/db/migrate/20121121080548_add_attachment_to_voicemail_prefs.rb b/db/migrate/20121121080548_add_attachment_to_voicemail_prefs.rb new file mode 100644 index 0000000..27d9386 --- /dev/null +++ b/db/migrate/20121121080548_add_attachment_to_voicemail_prefs.rb @@ -0,0 +1,6 @@ +class AddAttachmentToVoicemailPrefs < ActiveRecord::Migration + def change + add_column :voicemail_prefs, :attachment, :boolean + + end +end diff --git a/db/migrate/20121121080649_add_mark_read_to_voicemail_prefs.rb b/db/migrate/20121121080649_add_mark_read_to_voicemail_prefs.rb new file mode 100644 index 0000000..52e6afe --- /dev/null +++ b/db/migrate/20121121080649_add_mark_read_to_voicemail_prefs.rb @@ -0,0 +1,6 @@ +class AddMarkReadToVoicemailPrefs < ActiveRecord::Migration + def change + add_column :voicemail_prefs, :mark_read, :boolean + + end +end diff --git a/db/migrate/20121121081552_add_purge_to_voicemail_prefs.rb b/db/migrate/20121121081552_add_purge_to_voicemail_prefs.rb new file mode 100644 index 0000000..6188849 --- /dev/null +++ b/db/migrate/20121121081552_add_purge_to_voicemail_prefs.rb @@ -0,0 +1,6 @@ +class AddPurgeToVoicemailPrefs < ActiveRecord::Migration + def change + add_column :voicemail_prefs, :purge, :boolean + + end +end diff --git a/db/migrate/20121125084332_add_provisioning_key_to_phones.rb b/db/migrate/20121125084332_add_provisioning_key_to_phones.rb new file mode 100644 index 0000000..4b11461 --- /dev/null +++ b/db/migrate/20121125084332_add_provisioning_key_to_phones.rb @@ -0,0 +1,6 @@ +class AddProvisioningKeyToPhones < ActiveRecord::Migration + def change + add_column :phones, :provisioning_key, :string + + end +end diff --git a/db/migrate/20121125084447_add_provisioning_key_active_to_phones.rb b/db/migrate/20121125084447_add_provisioning_key_active_to_phones.rb new file mode 100644 index 0000000..c304b79 --- /dev/null +++ b/db/migrate/20121125084447_add_provisioning_key_active_to_phones.rb @@ -0,0 +1,6 @@ +class AddProvisioningKeyActiveToPhones < ActiveRecord::Migration + def change + add_column :phones, :provisioning_key_active, :boolean + + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..1395e1b --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,967 @@ +# encoding: UTF-8 +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended to check this file into your version control system. + +ActiveRecord::Schema.define(:version => 20121125084447) do + + create_table "access_authorizations", :force => true do |t| + t.string "access_authorizationable_type" + t.integer "access_authorizationable_id" + t.string "name" + t.string "login" + t.string "pin" + t.integer "position" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "sip_account_id" + t.string "uuid" + end + + add_index "access_authorizations", ["uuid"], :name => "index_access_authorizations_on_uuid" + + create_table "acd_agents", :force => true do |t| + t.string "uuid" + t.string "name" + t.string "status" + t.integer "automatic_call_distributor_id" + t.datetime "last_call" + t.integer "calls_answered" + t.string "destination_type" + t.integer "destination_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "acd_callers", :force => true do |t| + t.string "channel_uuid" + t.integer "automatic_call_distributor_id" + t.string "status" + t.datetime "enter_time" + t.datetime "agent_answer_time" + t.string "callback_number" + t.integer "callback_attempts" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "addresses", :force => true do |t| + t.integer "phone_book_entry_id" + t.string "line1" + t.string "line2" + t.string "street" + t.string "zip_code" + t.string "city" + t.integer "country_id" + t.integer "position" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "uuid" + end + + create_table "aliases", :id => false, :force => true do |t| + t.integer "sticky" + t.string "alias", :limit => 128 + t.string "command", :limit => 4096 + t.string "hostname", :limit => 256 + end + + add_index "aliases", ["alias"], :name => "alias1" + + create_table "api_rows", :force => true do |t| + t.string "user_id" + t.string "user_name" + t.string "last_name" + t.string "middle_name" + t.string "first_name" + t.string "office_phone_number" + t.string "internal_extension" + t.string "mobile_phone_number" + t.string "fax_phone_number" + t.string "email" + t.string "pin" + t.datetime "pin_updated_at" + t.string "photo_file_name" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "area_codes", :force => true do |t| + t.integer "country_id" + t.string "name" + t.string "area_code" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "central_office_code" + end + + create_table "automatic_call_distributors", :force => true do |t| + t.string "uuid" + t.string "name" + t.string "strategy" + t.string "automatic_call_distributorable_type" + t.integer "automatic_call_distributorable_id" + t.integer "max_callers" + t.integer "agent_timeout" + t.integer "retry_timeout" + t.string "join" + t.string "leave" + t.integer "gs_node_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "announce_position" + t.string "announce_call_agents" + t.string "greeting" + t.string "goodbye" + t.string "music" + end + + create_table "call_forward_cases", :force => true do |t| + t.string "value" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + add_index "call_forward_cases", ["value"], :name => "call_forward_cases_value_index", :unique => true + + create_table "call_forwards", :force => true do |t| + t.integer "call_forward_case_id" + t.integer "timeout" + t.string "destination" + t.string "source" + t.boolean "active" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "phone_number_id" + t.integer "depth" + t.string "call_forwardable_type" + t.integer "call_forwardable_id" + t.integer "position" + t.string "uuid" + end + + add_index "call_forwards", ["phone_number_id"], :name => "index_call_forwards_on_phone_number_id" + + create_table "call_histories", :force => true do |t| + t.string "call_historyable_type" + t.integer "call_historyable_id" + t.string "entry_type" + t.string "caller_account_type" + t.integer "caller_account_id" + t.string "caller_id_number" + t.string "caller_id_name" + t.string "caller_channel_uuid" + t.string "callee_account_type" + t.integer "callee_account_id" + t.string "callee_id_number" + t.string "callee_id_name" + t.string "auth_account_type" + t.integer "auth_account_id" + t.string "forwarding_service" + t.string "destination_number" + t.datetime "start_stamp" + t.integer "duration" + t.string "result" + t.boolean "read_flag" + t.boolean "returned_flag" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "calls", :id => false, :force => true do |t| + t.string "call_uuid" + t.string "call_created", :limit => 128 + t.integer "call_created_epoch" + t.string "function", :limit => 1024 + t.string "caller_cid_name", :limit => 1024 + t.string "caller_cid_num", :limit => 256 + t.string "caller_dest_num", :limit => 256 + t.string "caller_chan_name", :limit => 1024 + t.string "caller_uuid", :limit => 256 + t.string "callee_cid_name", :limit => 1024 + t.string "callee_cid_numcallee_dest_num", :limit => 256 + t.string "callee_chan_name", :limit => 1024 + t.string "callee_uuid", :limit => 256 + t.string "hostname", :limit => 256 + end + + add_index "calls", ["call_uuid", "hostname"], :name => "eeuuindex2" + add_index "calls", ["callee_uuid", "hostname"], :name => "eeuuindex" + add_index "calls", ["caller_uuid", "hostname"], :name => "eruuindex" + add_index "calls", ["hostname"], :name => "calls1" + + create_table "callthroughs", :force => true do |t| + t.integer "tenant_id" + t.string "name" + t.string "clip_no_screening" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "uuid" + end + + create_table "cdrs", :id => false, :force => true do |t| + t.string "uuid", :limit => 256 + t.integer "account_id" + t.string "account_type", :limit => 256 + t.string "bleg_uuid", :limit => 256 + t.integer "bleg_account_id" + t.string "bleg_account_type", :limit => 256 + t.string "dialed_number", :limit => 256 + t.string "destination_number", :limit => 256 + t.string "caller_id_number", :limit => 256 + t.string "caller_id_name", :limit => 256 + t.string "callee_id_number", :limit => 256 + t.string "callee_id_name", :limit => 256 + t.datetime "start_stamp" + t.datetime "answer_stamp" + t.datetime "end_stamp" + t.integer "duration" + t.integer "billsec" + t.string "hangup_cause", :limit => 256 + t.string "dialstatus", :limit => 256 + t.string "forwarding_number", :limit => 256 + t.integer "forwarding_account_id" + t.string "forwarding_account_type", :limit => 256 + t.string "forwarding_service", :limit => 256 + t.datetime "bleg_read_time" + t.datetime "forwarding_read_time" + t.datetime "bridge_stamp" + end + + create_table "channels", :id => false, :force => true do |t| + t.string "uuid", :limit => 256 + t.string "direction", :limit => 32 + t.string "created", :limit => 128 + t.integer "created_epoch" + t.string "name", :limit => 1024 + t.string "state", :limit => 64 + t.string "cid_name", :limit => 1024 + t.string "cid_num", :limit => 256 + t.string "ip_addr", :limit => 256 + t.string "dest", :limit => 1024 + t.string "application", :limit => 128 + t.string "application_data", :limit => 4096 + t.string "dialplan", :limit => 128 + t.string "context", :limit => 128 + t.string "read_codec", :limit => 128 + t.string "read_rate", :limit => 32 + t.string "read_bit_rate", :limit => 32 + t.string "write_codec", :limit => 128 + t.string "write_rate", :limit => 32 + t.string "write_bit_rate", :limit => 32 + t.string "secure", :limit => 32 + t.string "hostname", :limit => 256 + t.string "presence_id", :limit => 4096 + t.string "presence_data", :limit => 4096 + t.string "callstate", :limit => 64 + t.string "callee_name", :limit => 1024 + t.string "callee_num", :limit => 256 + t.string "callee_direction", :limit => 5 + t.string "call_uuid", :limit => 256 + end + + add_index "channels", ["call_uuid", "hostname"], :name => "uuindex2" + add_index "channels", ["hostname"], :name => "channels1" + add_index "channels", ["uuid", "hostname"], :name => "uuindex", :unique => true + + create_table "complete", :id => false, :force => true do |t| + t.integer "sticky" + t.string "a1", :limit => 128 + t.string "a2", :limit => 128 + t.string "a3", :limit => 128 + t.string "a4", :limit => 128 + t.string "a5", :limit => 128 + t.string "a6", :limit => 128 + t.string "a7", :limit => 128 + t.string "a8", :limit => 128 + t.string "a9", :limit => 128 + t.string "a10", :limit => 128 + t.string "hostname", :limit => 256 + end + + add_index "complete", ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "hostname"], :name => "complete11" + add_index "complete", ["a1", "hostname"], :name => "complete1" + add_index "complete", ["a10", "hostname"], :name => "complete10" + add_index "complete", ["a2", "hostname"], :name => "complete2" + add_index "complete", ["a3", "hostname"], :name => "complete3" + add_index "complete", ["a4", "hostname"], :name => "complete4" + add_index "complete", ["a5", "hostname"], :name => "complete5" + add_index "complete", ["a6", "hostname"], :name => "complete6" + add_index "complete", ["a7", "hostname"], :name => "complete7" + add_index "complete", ["a8", "hostname"], :name => "complete8" + add_index "complete", ["a9", "hostname"], :name => "complete9" + + create_table "conference_invitees", :force => true do |t| + t.integer "conference_id" + t.integer "phone_book_entry_id" + t.string "pin" + t.boolean "speaker" + t.boolean "moderator" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "uuid" + end + + create_table "conferences", :force => true do |t| + t.string "name" + t.datetime "start" + t.datetime "end" + t.text "description" + t.string "pin" + t.text "state" + t.boolean "open_for_anybody" + t.string "conferenceable_type" + t.integer "conferenceable_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "max_members" + t.boolean "announce_new_member_by_name" + t.boolean "announce_left_member_by_name" + t.string "uuid" + end + + create_table "countries", :force => true do |t| + t.string "name" + t.string "country_code" + t.string "international_call_prefix" + t.string "trunk_prefix" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "delayed_jobs", :force => true do |t| + t.integer "priority", :default => 0 + t.integer "attempts", :default => 0 + t.text "handler" + t.text "last_error" + t.datetime "run_at" + t.datetime "locked_at" + t.datetime "failed_at" + t.string "locked_by" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + add_index "delayed_jobs", ["priority", "run_at"], :name => "delayed_jobs_priority" + + create_table "fax_accounts", :force => true do |t| + t.string "fax_accountable_type" + t.integer "fax_accountable_id" + t.string "name" + t.string "email" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "tenant_id" + t.string "station_id" + t.integer "days_till_auto_delete" + t.integer "retries" + t.string "uuid" + end + + create_table "fax_documents", :force => true do |t| + t.boolean "inbound" + t.string "state" + t.integer "transmission_time" + t.datetime "sent_at" + t.integer "document_total_pages" + t.integer "document_transferred_pages" + t.boolean "ecm_requested" + t.boolean "ecm_used" + t.string "image_resolution" + t.string "image_size" + t.string "local_station_id" + t.integer "result_code" + t.string "remote_station_id" + t.boolean "success" + t.integer "transfer_rate" + t.string "document" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "fax_account_id" + t.string "caller_id_number" + t.string "caller_id_name" + t.integer "retry_counter" + t.string "tiff" + t.integer "fax_resolution_id" + t.string "uuid" + end + + create_table "fax_pages", :force => true do |t| + t.integer "position" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "fax_page" + end + + create_table "fax_resolutions", :force => true do |t| + t.string "name" + t.string "resolution_value" + t.integer "position" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "fax_thumbnails", :force => true do |t| + t.integer "fax_document_id" + t.integer "position" + t.string "thumbnail" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "faxes", :force => true do |t| + t.boolean "inbound" + t.integer "faxable_id" + t.string "faxable_type" + t.string "state" + t.integer "transmission_time" + t.datetime "sent_at" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "document_total_pages" + t.integer "document_transferred_pages" + t.boolean "ecm_requested" + t.boolean "ecm_used" + t.string "image_resolution" + t.string "image_size" + t.string "local_station_id" + t.integer "result_code" + t.string "result_text" + t.string "remote_station_id" + t.boolean "success" + t.integer "transfer_rate" + t.string "t38_gateway_format" + t.string "t38_peer" + t.string "fax" + end + + create_table "fifo_bridge", :id => false, :force => true do |t| + t.string "fifo_name", :limit => 1024, :null => false + t.string "caller_uuid", :null => false + t.string "caller_caller_id_name", :null => false + t.string "caller_caller_id_number", :null => false + t.string "consumer_uuid", :null => false + t.string "consumer_outgoing_uuid" + t.integer "bridge_start" + end + + create_table "fifo_callers", :id => false, :force => true do |t| + t.string "fifo_name", :null => false + t.string "uuid", :null => false + t.string "caller_caller_id_name" + t.string "caller_caller_id_number" + t.integer "timestamp" + end + + create_table "fifo_outbound", :id => false, :force => true do |t| + t.string "uuid" + t.string "fifo_name" + t.string "originate_string" + t.integer "simo_count" + t.integer "use_count" + t.integer "timeout" + t.integer "lag" + t.integer "next_avail", :default => 0, :null => false + t.integer "expires", :default => 0, :null => false + t.integer "static", :default => 0, :null => false + t.integer "outbound_call_count", :default => 0, :null => false + t.integer "outbound_fail_count", :default => 0, :null => false + t.string "hostname" + t.integer "taking_calls", :default => 1, :null => false + t.string "status" + t.integer "outbound_call_total_count", :default => 0, :null => false + t.integer "outbound_fail_total_count", :default => 0, :null => false + t.integer "active_time", :default => 0, :null => false + t.integer "inactive_time", :default => 0, :null => false + t.integer "manual_calls_out_count", :default => 0, :null => false + t.integer "manual_calls_in_count", :default => 0, :null => false + t.integer "manual_calls_out_total_count", :default => 0, :null => false + t.integer "manual_calls_in_total_count", :default => 0, :null => false + t.integer "ring_count", :default => 0, :null => false + t.integer "start_time", :default => 0, :null => false + t.integer "stop_time", :default => 0, :null => false + end + + create_table "gemeinschaft_setups", :force => true do |t| + t.integer "user_id" + t.integer "sip_domain_id" + t.integer "country_id" + t.integer "language_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "gs_cluster_sync_log_entries", :force => true do |t| + t.integer "gs_node_id" + t.string "class_name" + t.string "action" + t.text "content" + t.string "status" + t.string "history" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "homebase_ip_address" + t.boolean "waiting_to_be_synced" + t.string "association_method" + t.string "association_uuid" + end + + create_table "gs_nodes", :force => true do |t| + t.string "name" + t.string "ip_address" + t.boolean "push_updates_to" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "site" + t.string "element_name" + t.boolean "accepts_updates_from" + t.datetime "last_sync" + end + + create_table "gui_function_memberships", :force => true do |t| + t.integer "gui_function_id" + t.integer "user_group_id" + t.boolean "activated" + t.string "output" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "gui_functions", :force => true do |t| + t.string "category" + t.string "name" + t.string "description" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "hunt_group_members", :force => true do |t| + t.integer "hunt_group_id" + t.string "name" + t.integer "position" + t.boolean "active" + t.boolean "can_switch_status_itself" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "uuid" + end + + add_index "hunt_group_members", ["uuid"], :name => "index_hunt_group_members_on_uuid" + + create_table "hunt_groups", :force => true do |t| + t.integer "tenant_id" + t.string "name" + t.string "strategy" + t.integer "seconds_between_jumps" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "gs_node_id" + t.integer "gs_node_original_id" + t.string "uuid" + end + + add_index "hunt_groups", ["uuid"], :name => "index_hunt_groups_on_uuid" + + create_table "interfaces", :id => false, :force => true do |t| + t.string "type", :limit => 128 + t.string "name", :limit => 1024 + t.string "description", :limit => 4096 + t.string "ikey", :limit => 1024 + t.string "filename", :limit => 4096 + t.string "syntax", :limit => 4096 + t.string "hostname", :limit => 256 + end + + create_table "languages", :force => true do |t| + t.string "name" + t.string "code" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "manufacturers", :force => true do |t| + t.string "name" + t.string "ieee_name" + t.string "homepage_url" + t.string "state" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "nat", :id => false, :force => true do |t| + t.integer "sticky" + t.integer "port" + t.integer "proto" + t.string "hostname", :limit => 256 + end + + add_index "nat", ["port", "proto", "hostname"], :name => "nat_map_port_proto" + + create_table "ouis", :force => true do |t| + t.integer "manufacturer_id" + t.string "value" + t.string "state" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "phone_book_entries", :force => true do |t| + t.integer "phone_book_id" + t.string "first_name" + t.string "middle_name" + t.string "last_name" + t.string "title" + t.string "nickname" + t.string "organization" + t.boolean "is_organization" + t.string "department" + t.string "job_title" + t.boolean "is_male" + t.date "birthday" + t.string "birth_name" + t.string "state" + t.text "description" + t.integer "position" + t.string "homepage_personal" + t.string "homepage_organization" + t.string "twitter_account" + t.string "facebook_account" + t.string "google_plus_account" + t.string "xing_account" + t.string "linkedin_account" + t.string "mobileme_account" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "image" + t.string "first_name_phonetic" + t.string "last_name_phonetic" + t.string "organization_phonetic" + t.string "value_of_to_s" + t.string "uuid" + end + + add_index "phone_book_entries", ["first_name"], :name => "index_phone_book_entries_on_first_name" + add_index "phone_book_entries", ["first_name_phonetic"], :name => "index_phone_book_entries_on_first_name_phonetic" + add_index "phone_book_entries", ["last_name"], :name => "index_phone_book_entries_on_last_name" + add_index "phone_book_entries", ["last_name_phonetic"], :name => "index_phone_book_entries_on_last_name_phonetic" + add_index "phone_book_entries", ["organization"], :name => "index_phone_book_entries_on_organization" + add_index "phone_book_entries", ["organization_phonetic"], :name => "index_phone_book_entries_on_organization_phonetic" + add_index "phone_book_entries", ["uuid"], :name => "index_phone_book_entries_on_uuid" + + create_table "phone_books", :force => true do |t| + t.string "name" + t.string "description" + t.integer "phone_bookable_id" + t.string "phone_bookable_type" + t.string "state" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "uuid" + end + + create_table "phone_models", :force => true do |t| + t.string "name" + t.string "manufacturer_id" + t.string "product_manual_homepage_url" + t.string "product_homepage_url" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "state" + t.string "uuid" + end + + create_table "phone_number_ranges", :force => true do |t| + t.string "name" + t.text "description" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "phone_number_rangeable_type" + t.integer "phone_number_rangeable_id" + t.string "uuid" + end + + add_index "phone_number_ranges", ["uuid"], :name => "index_phone_number_ranges_on_uuid" + + create_table "phone_numbers", :force => true do |t| + t.string "name" + t.string "number" + t.string "country_code" + t.string "area_code" + t.string "subscriber_number" + t.string "extension" + t.integer "position" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "central_office_code" + t.string "phone_numberable_type" + t.integer "phone_numberable_id" + t.string "state" + t.string "value_of_to_s" + t.integer "gs_node_id" + t.integer "gs_node_original_id" + t.string "uuid" + t.integer "access_authorization_user_id" + t.boolean "is_native" + end + + add_index "phone_numbers", ["uuid"], :name => "index_phone_numbers_on_uuid" + + create_table "phone_sip_accounts", :force => true do |t| + t.integer "phone_id" + t.integer "sip_account_id" + t.integer "position" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "phones", :force => true do |t| + t.string "mac_address" + t.integer "phone_model_id" + t.string "ip_address" + t.string "last_ip_address" + t.string "http_user" + t.string "http_password" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "state" + t.string "phoneable_type" + t.integer "phoneable_id" + t.boolean "hot_deskable" + t.boolean "nightly_reboot" + t.string "provisioning_key" + t.boolean "provisioning_key_active" + end + + create_table "registrations", :id => false, :force => true do |t| + t.string "reg_user" + t.string "realm", :limit => 256 + t.string "token", :limit => 256 + t.text "url" + t.integer "expires" + t.string "network_ip", :limit => 256 + t.string "network_port", :limit => 256 + t.string "network_proto", :limit => 256 + t.string "hostname", :limit => 256 + end + + add_index "registrations", ["reg_user", "realm", "hostname"], :name => "regindex1" + + create_table "ringtones", :force => true do |t| + t.string "ringtoneable_type" + t.integer "ringtoneable_id" + t.string "audio" + t.integer "bellcore_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "sessions", :force => true do |t| + t.string "session_id", :null => false + t.text "data" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id" + add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at" + + create_table "sip_accounts", :force => true do |t| + t.string "sip_accountable_type" + t.integer "sip_accountable_id" + t.string "auth_name" + t.string "caller_name" + t.string "password" + t.string "voicemail_pin" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "value_of_to_s" + t.integer "tenant_id" + t.integer "sip_domain_id" + t.boolean "call_waiting" + t.boolean "clir" + t.string "clip_no_screening" + t.boolean "clip" + t.string "description" + t.boolean "callforward_rules_act_per_sip_account" + t.boolean "hotdeskable" + t.integer "gs_node_id" + t.integer "gs_node_original_id" + t.string "uuid" + t.boolean "is_native" + end + + add_index "sip_accounts", ["uuid"], :name => "index_sip_accounts_on_uuid" + + create_table "sip_domains", :force => true do |t| + t.string "host" + t.string "realm" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "softkey_functions", :force => true do |t| + t.string "name" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "position" + end + + add_index "softkey_functions", ["name"], :name => "index_softkey_functions_on_name" + add_index "softkey_functions", ["position"], :name => "index_softkey_functions_on_position" + + create_table "softkeys", :force => true do |t| + t.string "function" + t.string "number" + t.string "label" + t.integer "position" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "sip_account_id" + t.integer "softkey_function_id" + t.integer "call_forward_id" + t.string "uuid" + end + + create_table "system_messages", :force => true do |t| + t.integer "user_id" + t.string "content" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "tasks", :id => false, :force => true do |t| + t.integer "task_id" + t.string "task_desc", :limit => 4096 + t.string "task_group", :limit => 1024 + t.integer "task_sql_manager" + t.string "hostname", :limit => 256 + end + + add_index "tasks", ["hostname", "task_id"], :name => "tasks1", :unique => true + + create_table "tenant_memberships", :force => true do |t| + t.integer "tenant_id" + t.integer "user_id" + t.string "state" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "tenants", :force => true do |t| + t.string "name" + t.text "description" + t.string "state" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "country_id" + t.integer "sip_domain_id" + t.integer "language_id" + t.string "internal_extension_ranges" + t.string "did_list" + t.string "from_field_voicemail_email" + t.string "from_field_pin_change_email" + t.string "uuid" + end + + create_table "user_group_memberships", :force => true do |t| + t.integer "user_group_id" + t.integer "user_id" + t.string "state" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "user_groups", :force => true do |t| + t.string "name" + t.text "description" + t.integer "tenant_id" + t.integer "position" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "users", :force => true do |t| + t.string "user_name" + t.string "email" + t.string "password_digest" + t.string "first_name" + t.string "middle_name" + t.string "last_name" + t.boolean "male" + t.string "gemeinschaft_unique_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "image" + t.integer "current_tenant_id" + t.string "pin_salt" + t.string "pin_hash" + t.integer "language_id" + t.boolean "send_voicemail_as_email_attachment" + t.string "importer_checksum" + t.integer "gs_node_id" + t.integer "gs_node_original_id" + t.string "uuid" + t.boolean "is_native" + end + + add_index "users", ["uuid"], :name => "index_users_on_uuid" + + create_table "voicemail_msgs", :id => false, :force => true do |t| + t.integer "created_epoch" + t.integer "read_epoch" + t.string "username" + t.string "domain" + t.string "uuid" + t.string "cid_name" + t.string "cid_number" + t.string "in_folder" + t.string "file_path" + t.integer "message_len" + t.string "flags" + t.string "read_flags" + t.string "forwarded_by" + t.boolean "notification" + end + + add_index "voicemail_msgs", ["created_epoch"], :name => "voicemail_msgs_idx1" + add_index "voicemail_msgs", ["domain"], :name => "voicemail_msgs_idx3" + add_index "voicemail_msgs", ["forwarded_by"], :name => "voicemail_msgs_idx7" + add_index "voicemail_msgs", ["in_folder"], :name => "voicemail_msgs_idx5" + add_index "voicemail_msgs", ["read_flags"], :name => "voicemail_msgs_idx6" + add_index "voicemail_msgs", ["username"], :name => "voicemail_msgs_idx2" + add_index "voicemail_msgs", ["uuid"], :name => "voicemail_msgs_idx4" + + create_table "voicemail_prefs", :id => false, :force => true do |t| + t.string "username" + t.string "domain" + t.string "name_path" + t.string "greeting_path" + t.string "password" + t.boolean "notify" + t.boolean "attachment" + t.boolean "mark_read" + t.boolean "purge" + end + + add_index "voicemail_prefs", ["domain"], :name => "voicemail_prefs_idx2" + add_index "voicemail_prefs", ["username"], :name => "voicemail_prefs_idx1" + + create_table "whitelists", :force => true do |t| + t.string "name" + t.string "whitelistable_type" + t.integer "whitelistable_id" + t.integer "position" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "uuid" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..d640036 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,5 @@ +# ruby encoding: utf-8 +# +# This file should contain all the record creation needed to seed the database with its default values. +# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). + diff --git a/db/to-dos/20120119160732_emergency_numbers_germany.rb b/db/to-dos/20120119160732_emergency_numbers_germany.rb new file mode 100644 index 0000000..9dd9131 --- /dev/null +++ b/db/to-dos/20120119160732_emergency_numbers_germany.rb @@ -0,0 +1,30 @@ +# ruby encoding: utf-8 + +class EmergencyNumbersGermany < ActiveRecord::Migration + + def up + # add_column :phone_numbers, :uuid, :string + # add_index :phone_numbers, :uuid + + germany = Country.find_by_name('Germany') + + ################################################################ + # Emergency numbers which shouldn't be used as extensions + ################################################################ + notruf_nummern = germany.phone_number_ranges.find_or_create_by_name(SERVICE_NUMBERS) + notruf_nummern.phone_numbers.find_or_create_by_name_and_number('Polizei', '110') + notruf_nummern.phone_numbers.find_or_create_by_name_and_number('Feuerwehr', '112') + notruf_nummern.phone_numbers.find_or_create_by_name_and_number('Zentrale Behördenrufnummer', '115') + notruf_nummern.phone_numbers.find_or_create_by_name_and_number('Krankenwagen', '19222') + notruf_nummern.phone_numbers.find_or_create_by_name_and_number('Weisser Ring e. V.', '116006') + notruf_nummern.phone_numbers.find_or_create_by_name_and_number('Nummer gegen Kummer e. V.', '116111') + notruf_nummern.phone_numbers.find_or_create_by_name_and_number('Zentrale Anlaufstelle zur Sperrung elektronischer Berechtigungen', '116116') + notruf_nummern.phone_numbers.find_or_create_by_name_and_number('Kassenärztliche Vereinigung: ärztliche Bereitschaftsdienste', '116117') + notruf_nummern.phone_numbers.find_or_create_by_name_and_number('Katholische Bundesarbeitsgemeinschaft für Ehe-, Familien- und Lebensberatung, Telefonseelsorge', '116123') + end + + def down + germany = Country.find_by_name('Germany') + germany.phone_number_ranges.where(:name => SERVICE_NUMBERS).destroy_all + end +end diff --git a/db/to-dos/20120223142004_add_more_german_area_codes.rb b/db/to-dos/20120223142004_add_more_german_area_codes.rb new file mode 100644 index 0000000..2eb2554 --- /dev/null +++ b/db/to-dos/20120223142004_add_more_german_area_codes.rb @@ -0,0 +1,58 @@ +# encoding: UTF-8 + +class AddMoreGermanAreaCodes < ActiveRecord::Migration + def up + # http://www.bundesnetzagentur.de/cln_1912/DE/Sachgebiete/Telekommunikation/RegulierungTelekommunikation/Nummernverwaltung/Nummernverwaltung_node.html + + germany = Country.find_by_name('Germany') + german_service_number_range = germany.phone_number_ranges.find_by_name('service_numbers') + + # Harmonisierte Dienste von sozialem Wert + # + (0..9).each do |x| + (0..9).each do |y| + (0..9).each do |z| + german_service_number_range.phone_numbers.create( + :name => "Harmonisierte Dienste von sozialem Wert", + :number => "116#{x}#{y}#{z}" + ) + end + end + end + + # Auskunftsdienste + # + (0..9).each do |x| + (0..9).each do |y| + german_service_number_range.phone_numbers.create( + :name => "Auskunftsdienste", + :number => "118#{x}#{y}" + ) + end + end + + # Online-Dienste + # + (0..9).each do |x| + (0..9).each do |y| + (0..9).each do |z| + AreaCode.create( + :country_id => germany.id, + :name => 'Online-Dienste', + :area_code => "19#{x}#{y}#{z}" + ) + end + end + end + + AreaCode.create(:country_id => germany.id, :name => 'Neuartige Dienste', :area_code => '12') + AreaCode.create(:country_id => germany.id, :name => 'Massenverkehrs-Dienste', :area_code => '137') + AreaCode.create(:country_id => germany.id, :name => 'Nutzergruppen', :area_code => '18') + AreaCode.create(:country_id => germany.id, :name => 'Internationale Virtuelle Private Netze', :area_code => '181') + AreaCode.create(:country_id => germany.id, :name => 'Nationale Teilnehmernummern', :area_code => '32') + AreaCode.create(:country_id => germany.id, :name => 'Anwählprogramme (Dialer)', :area_code => '9009') + end + + def down + end +end diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..b086f6f --- /dev/null +++ b/install.sh @@ -0,0 +1,214 @@ +#!/bin/bash + +echo -e "Gemeinschaft Version 5.0 Installation for Debian Linux\n" + +GS_DIR="/opt/GS5" + +aptitude update + +# Ask for the Github account data +# +echo -e "github username:\n" +read USERNAME + +echo -e "github password:\n" +read PASSWORD + +# Upgrade everything to be on the safe side. +# +echo "Upgrade the server ..." +aptitude upgrade + +# Install git +# +echo -e "Installing git ...\n" +aptitude install -y git + +# Install the mysql server without asking for a password +# +echo "Installing MySQL server ..." +apt-get install -y debconf-utils + +mysql_password= +export DEBIAN_FRONTEND=noninteractive +debconf-set-selections <<< 'mysql-server-5.1 mysql-server/root_password password '$mysql_password'' +debconf-set-selections <<< 'mysql-server-5.1 mysql-server/root_password_again password '$mysql_password'' +apt-get -y install mysql-server + +# Clone the git repository +# +echo -e "Downloading GS5 ...\n" + +cd /opt + +git clone "https://$USERNAME:$PASSWORD@github.com/amooma/GS5.git" "${GS_DIR}" + +if [ -f "${GS_DIR}/config/application.rb" ] +then + echo " OK" +else + echo " ERROR" + exit 1 +fi + +echo -e "Installing GS5 dependencies ...\n" + +aptitude install -y \ + sqlite3 \ + libsqlite3-dev \ + libjpeg62 \ + ghostscript \ + imagemagick \ + libtiff-tools \ + +cd /usr/local/src/ + +wget "http://65.23.153.46/GS5/freeswitch_1.1.beta2.1-1_i386.deb" +wget "http://65.23.153.46/GS5/freeswitch-lang-en_1.1.beta2.1-1_i386.deb" +wget "http://65.23.153.46/GS5/freeswitch-lang-de_1.1.beta2.1-1_i386.deb" +wget "http://65.23.153.46/GS5/freeswitch-lua_1.1.beta2.1-1_i386.deb" +wget "http://65.23.153.46/GS5/unixodbc_2.3.1-1_i386.deb" +wget "http://65.23.153.46/GS5/mysql-connector-odbc_5.1.11-1_i386.deb" +wget "http://65.23.153.46/GS5/luasql_2.1.1-1_i386.deb" +wget "http://files.freeswitch.org/freeswitch-sounds-en-us-callie-8000-1.0.16.tar.gz" +wget "http://files.freeswitch.org/freeswitch-sounds-en-us-callie-16000-1.0.16.tar.gz" +wget "http://files.freeswitch.org/freeswitch-sounds-music-8000-1.0.8.tar.gz" +wget "http://files.freeswitch.org/freeswitch-sounds-music-16000-1.0.8.tar.gz" + +echo -e "Installing FreeSWITCH dependencies ...\n" + +aptitude install -y \ + libasound2 \ + libcurl3 \ + libogg0 \ + libvorbis0a + +echo -e "Installing FreeSWITCH ...\n" + +DEBIAN_FRONTEND=noninteractive dpkg -i /usr/local/src/freeswitch_1.1.beta2.1-1_i386.deb +DEBIAN_FRONTEND=noninteractive dpkg -i /usr/local/src/freeswitch-lang-en_1.1.beta2.1-1_i386.deb +DEBIAN_FRONTEND=noninteractive dpkg -i /usr/local/src/freeswitch-freeswitch-lang-de_1.1.beta2.1-1_i386.deb +DEBIAN_FRONTEND=noninteractive dpkg -i /usr/local/src/freeswitch-lua_1.1.beta2.1-1_i386.deb +DEBIAN_FRONTEND=noninteractive dpkg -i /usr/local/src/unixodbc_2.3.1-1_i386.deb +DEBIAN_FRONTEND=noninteractive dpkg -i /usr/local/src/mysql-connector-odbc_5.1.11-1_i386.deb +DEBIAN_FRONTEND=noninteractive dpkg -i /usr/local/src/luasql_2.1.1-1_i386.deb + +aptitude -f install + +sed -i 's/FREESWITCH_ENABLED="false"/FREESWITCH_ENABLED="true"/' /etc/default/freeswitch +sed -i 's/^FREESWITCH_PARAMS.*/FREESWITCH_PARAMS="-nc"/' /etc/default/freeswitch + +echo -e "Installing Dependencies ...\n" + +aptitude -y install \ + curl \ + build-essential \ + libncurses5-dev \ + zlib1g-dev \ + libssl-dev \ + libreadline-dev \ + libcurl4-openssl-dev + +# Install RVM +# +bash < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer ) + +source /etc/profile.d/rvm.sh + +rvm install 1.9.2 +rvm use 1.9.2 --default + +# Install stuff which is needed to build specific gems +# +apt-get -y install libmysqlclient15-dev +apt-get -y install libxslt-dev libxml2-dev + +echo -e "Installing GS5 gems ...\n" +cd "${GS_DIR}" +bundle install + +echo -e "Setting up database ...\n" + +mysqladmin create gemeinschaft + +echo "[ODBC Drivers] +MyODBC = Installed +/usr/local/lib/libmyodbc5.so = Installed + +[gemeinschaft] +Description = MySQL database for Gemeinschaft +Driver = /usr/lib/libmyodbc5.so +" >/usr/local/etc/odbcinst.ini + +echo "[gemeinschaft] +Description = MySQL database for Gemeinschaft +Driver = /usr/local/lib/libmyodbc5.so +SERVER = localhost +PORT = 3306 +DATABASE = gemeinschaft +OPTION = 67108864 +USER = gemeinschaft +PASSWORD = gemeinschaft +" >/usr/local/etc/odbc.ini + +mysql -e "GRANT ALL PRIVILEGES ON gemeinschaft.* TO gemeinschaft @'%' IDENTIFIED BY 'gemeinschaft';" +mysql -e "FLUSH PRIVILEGES" + +bundle exec rake db:migrate RAILS_ENV="production" + +echo -e "Extracting FreeSWITCH sounds ...\n" + +mkdir -p /opt/freeswitch/sounds +cd /opt/freeswitch/sounds + +tar -xzf "/usr/local/src/freeswitch-sounds-en-us-callie-8000-1.0.16.tar.gz" +tar -xzf "/usr/local/src/freeswitch-sounds-en-us-callie-16000-1.0.16.tar.gz" +tar -xzf "/usr/local/src/freeswitch-sounds-music-8000-1.0.8.tar.gz" +tar -xzf "/usr/local/src/freeswitch-sounds-music-16000-1.0.8.tar.gz" + +echo -e "Creating FreeSWITCH configuration ...\n" + +rm -fr /opt/freeswitch/conf +rm -fr /opt/freeswitch/scripts + +ln -s "${GS_DIR}/misc/freeswitch/conf/" /opt/freeswitch/conf +ln -s "${GS_DIR}/misc/freeswitch/scripts/" /opt/freeswitch/scripts + +echo -e "Setting up permissions ...\n" + +addgroup gemeinschaft || true +adduser freeswitch gemeinschaft --quiet + +chgrp -R gemeinschaft "${GS_DIR}" +chmod -R g+w "${GS_DIR}" + +# Create FreeSWITCH log directory +mkdir /var/log/freeswitch/ +chown freeswitch:gemeinschaft /var/log/freeswitch/ + +# Installation of nginx and passenger +# +apt-get -y install libpcre3-dev +gem install passenger +passenger-install-nginx-module --auto --auto-download --prefix=/opt/nginx + +rm -f /opt/nginx/conf/nginx.conf +ln -s "${GS_DIR}/misc/nginx/nginx.conf" /opt/nginx/conf/nginx.conf + +adduser www-data gemeinschaft --quiet + +# Generate CSS +# +cd "${GS_DIR}" +RAILS_ENV=production bundle exec rake assets:precompile + +echo "Done!" + +echo "You can start the webserver with /opt/nginx/sbin/nginx" + + +# Ensure FreeSWITCH has permission to write to Fax directory +#chmod -R g+w /opt/gemeinschaft/public/uploads/fax_document/ +#chgrp -R gemeinschaft /opt/gemeinschaft/public/uploads/fax_document/ +#chmod -R g+w /tmp/GS-5.0/ +#chgrp -R gemeinschaft /tmp/GS-5.0/ diff --git a/lib/activerecord_extensions.rb b/lib/activerecord_extensions.rb new file mode 100644 index 0000000..50c44be --- /dev/null +++ b/lib/activerecord_extensions.rb @@ -0,0 +1,72 @@ +class ActiveRecord::Base + + before_validation :populate_uuid, :on => :create + before_validation :populate_gs_node_id, :on => :create + + # Set a UUID. + # + def populate_uuid + if self.attribute_names.include?('uuid') && self.uuid.blank? + uuid = UUID.new + self.uuid = uuid.generate + end + end + + # Set the gs_node_id if not already set. + # + def populate_gs_node_id + if self.attribute_names.include?('gs_node_id') && self.gs_node_id.blank? + self.gs_node_id = GsNode.where(:ip_address => HOMEBASE_IP_ADDRESS).first.try(:id) + end + end + + # Create a new GsClusterSyncLogEntry. + # This will be populated automatically to GsNode.all.where(...) + # + def create_on_other_gs_nodes(association_method = nil, association_uuid = nil) + action_on_other_gs_nodes('create', self.to_json, nil, association_method, association_uuid) + end + + def destroy_on_other_gs_nodes + action_on_other_gs_nodes('destroy', self.to_json) + end + + def update_on_other_gs_nodes(association_method = nil, association_uuid = nil) + action_on_other_gs_nodes('update', self.changes.to_json, 'Changed: ' + self.changed.to_json, association_method, association_uuid) + end + + def action_on_other_gs_nodes(action, content, history = nil, association_method = nil, association_uuid = nil) + # One doesn't make sense without the other. + # + if association_method.blank? || association_uuid.blank? + association_method = nil + association_uuid = nil + end + history = nil if history.blank? + if !self.attribute_names.include?('is_native') + logger.error "Couldn't #{action} #{self.class} with the ID #{self.id} on other GsNodes because #{self.class} doesn't have a is_native attribute." + else + if self.is_native != false + if defined? WRITE_GS_CLUSTER_SYNC_LOG && WRITE_GS_CLUSTER_SYNC_LOG == true + if !(defined? $gs_cluster_loop_protection) || $gs_cluster_loop_protection != true + begin + GsClusterSyncLogEntry.create( + :class_name => self.class.name, + :action => action, + :content => content, + :history => history, + :homebase_ip_address => HOMEBASE_IP_ADDRESS, + :waiting_to_be_synced => true, + :association_method => association_method, + :association_uuid => association_uuid + ) + rescue + logger.error "Couldn't add action: #{action} for #{self.class} with the ID #{self.id} to gs_cluster_log_entries." + end + end + end + end + end + end + +end \ No newline at end of file diff --git a/lib/agi_server.rb b/lib/agi_server.rb new file mode 100644 index 0000000..29c06c4 --- /dev/null +++ b/lib/agi_server.rb @@ -0,0 +1,123 @@ +module AGIServer + DEFAULT_AGI_SERVER_HOST = nil + DEFAULT_AGI_SERVER_PORT = 4573 + + def self.log_debug(message) + puts "DEBUG-AGI-Server: #{message.to_s}" + #Rails.logger.debug "AGI-Server: #{message}" + end + + def self.log_error(message) + puts "ERROR-AGI-Server: #{message.to_s}" + #Rails.logger.error "AGI-Server: #{message}" + end + + class Client + AGI_AVAILABLE_METHODS = ['directory_lookup'] + @client = nil + @options = nil + + def set_variable(variable_name, variable_value) + if !@client + return false + end + @client.puts "SET VARIABLE #{variable_name.to_s} \"#{variable_value.to_s}\"" + end + + def directory_lookup + number = @options['agi_arg_1'].to_s.gsub(/[^0-9A-Za-z\*_-]/, '') + number_type = @options['agi_arg_3'].to_s + client_id = @options['agi_arg_2'].to_i + + if number.blank? + number = @options['agi_dnid'].to_s.gsub(/[^0-9A-Za-z\*_-]/, '') + number_type = "unknown" + client_id = 1 + end + + if client_id > 0 + if number != "" + phone_number = PhoneNumber.where(:number => number, :phone_numberable_type => "SipAccount").first + if phone_number.blank? + set_variable(:directory_status, 'unknown') + set_variable(:directory_message, 'Number not found in directory') + return nil + end + + set_variable(:directory_status, 'exact_match') + set_variable(:directory_message, 'Exact match') + set_variable(:directory_number_type, phone_number.phone_numberable_type) + set_variable(:directory_number_destination, phone_number.phone_numberable.to_s) + set_variable(:directory_number_host, "1") + set_variable(:directory_number_name, phone_number.name) + set_variable(:directory_number_number, phone_number.number) + set_variable(:directory_number_country_code, phone_number.country_code) + set_variable(:directory_number_area_code, phone_number.area_code) + set_variable(:directory_number_central_office_code, phone_number.central_office_code) + set_variable(:directory_number_subscriber_number, phone_number.subscriber_number) + set_variable(:directory_number_extension, phone_number.extension) + + if phone_number.phone_numberable_type == "SipAccount" + set_variable(:directory_caller_name, phone_number.phone_numberable.caller_name) + end + else + set_variable(:directory_status, 'error') + set_variable(:directory_message, 'No number specified') + end + else + set_variable(:directory_status, 'error') + set_variable(:directory_message, 'No ID') + end + end + + def handler(client) + @client = client + @options = Hash.new + while @client + buffer = @client.gets().strip + if buffer == "" + if @options['agi_network_script'] && AGI_AVAILABLE_METHODS.include?(@options['agi_network_script'].to_s.downcase) + self.send(@options['agi_network_script'].to_s.downcase) + end + break + elsif buffer =~ /^.*:\s/ + key, value = buffer.split(': ') + @options[key]= value + end + end + @client.close + end + end + + def self.server( host = DEFAULT_AGI_SERVER_HOST, port = DEFAULT_AGI_SERVER_PORT ) + + log_debug("Starting server process.") + require 'socket' + server = TCPServer.open(4573) + if server + run_server = true + end + + client_handler_id = 0 + while run_server + log_debug("Server listening on: #{server.local_address.ip_address}:#{server.local_address.ip_port}") + + Thread.start(server.accept) do |client| + remote_ip = client.remote_address.ip_address + remote_port = client.remote_address.ip_port + + begin + client_handler = Client.new + client_handler_id = client_handler.object_id + log_debug("[#{client_handler_id}] Connection opened: #{remote_ip}:#{remote_port}") + client_handler.handler(client) + log_debug("[#{client_handler_id}] Connection closed: #{remote_ip}:#{remote_port}") + rescue => e + log_error("[#{client_handler_id}] #{e.class.to_s}: #{e.to_s}, closing connection: #{remote_ip}:#{remote_port}") + ensure + client.close() + end + end + end + end +end diff --git a/lib/assets/.gitkeep b/lib/assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/lib/freeswitch_event.rb b/lib/freeswitch_event.rb new file mode 100644 index 0000000..b6e5cbc --- /dev/null +++ b/lib/freeswitch_event.rb @@ -0,0 +1,133 @@ +class FreeswitchEventSocket + DEFAULT_HOST = "127.0.0.1" + DEFAULT_PORT = 8021 + DEFAULT_PASSWORD = "ClueCon" + DEFAULT_SOCKET_TIMEOUT = 20 + @socket = nil + + def auth(password) + self.command("auth #{password}") + result = self.result() + + if result && result["Reply-Text"] == "+OK accepted" + return true + end + return false + end + + def connect(password = DEFAULT_PASSWORD, event_host = DEFAULT_HOST, event_port = DEFAULT_PORT) + begin + @socket = TCPSocket.open(event_host, event_port) + rescue + return false + end + + if not @socket + return false + end + + result = self.result() + if result && result["Content-Type"] == "auth/request" then + if not self.auth(password) + return false + end + end + + return true + end + + def command(command) + @socket.puts("#{command}\n\n") + end + + def close() + @socket.close + end + + def read() + return @socket.recv(1024) + end + + def result() + reply = self.read() + if reply.class == String + message = Hash.new() + header, body = reply.split("\n\n", 2) + if ! body.blank? + message['_BODY'] = body + end + header.split("\n").each do |line| + key, value = line.split(/\: */, 2) + message[key] = value + end + return message + end + return nil + end +end + +class FreeswitchEvent + def initialize(event_type) + @event_type = event_type + @event_header = Array.new() + @event_body = nil + @event_header.push("sendevent #{@event_type}") + end + + def add_header(name, value) + @event_header.push("#{name}: #{value}") + end + + def add_body(body) + @event_body = body + end + + def fire() + if @event_body && @event_body.length > 0 + self.add_header("content-length", @event_body.length); + end + + event = FreeswitchEventSocket.new() + if event && event.connect() + event.command(@event_header.join("\n")) + event.command( @event_body) + result = event.result() + event.close() + + if result && result["Reply-Text"] == "+OK" + return true + end + end + return false + end +end + +class FreeswitchAPI + def self.execute(command, arguments, bgapi = false) + + event = FreeswitchEventSocket.new() + if event && event.connect() + api = bgapi ? 'bgapi' : 'api' + event.command( "#{api} #{command} #{arguments}") + result = event.result() + if result && result["Content-Type"] == 'api/response' && result["_BODY"].blank? + result = event.result() + end + event.close() + + if result + if result.has_key?('Reply-Text') && result['Reply-Text'] =~ /^\+OK/ + if result.has_key?('Job-UUID') && ! result['Job-UUID'].blank? + return result['Job-UUID']; + else + return true; + end + elsif result.has_key?('_BODY') && result['_BODY'] =~ /^\+OK/ + return true; + end + end + end + + return false + end +end diff --git a/lib/generators/nifty.rb b/lib/generators/nifty.rb new file mode 100644 index 0000000..1c3d6d7 --- /dev/null +++ b/lib/generators/nifty.rb @@ -0,0 +1,28 @@ +require 'rails/generators/base' + +module Nifty + module Generators + class Base < Rails::Generators::Base #:nodoc: + def self.source_root + @_nifty_source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'nifty', generator_name, 'templates')) + end + + def self.banner + "rails generate nifty:#{generator_name} #{self.arguments.map{ |a| a.usage }.join(' ')} [options]" + end + + private + + def add_gem(name, options = {}) + gemfile_content = File.read(destination_path("Gemfile")) + File.open(destination_path("Gemfile"), 'a') { |f| f.write("\n") } unless gemfile_content =~ /\n\Z/ + gem name, options unless gemfile_content.include? name + end + + def print_usage + self.class.help(Thor::Base.shell.new) + exit + end + end + end +end diff --git a/lib/generators/nifty/authentication/USAGE b/lib/generators/nifty/authentication/USAGE new file mode 100644 index 0000000..89f0a64 --- /dev/null +++ b/lib/generators/nifty/authentication/USAGE @@ -0,0 +1,50 @@ +Description: + Generates a user model, users controller, and sessions controller. The + users controller handles the registration and the sessions controller + handles authentication. This is similar to restful_authentication, but + simpler. + + IMPORTANT: This generator uses the "title" helper method which is generated + by the nifty_layout generator. You may want to run that generator first. + +Usage: + If you do not pass any arguments, the model name will default to "user", and + the authentication controller will default to "session". You can override + each of these respectively by passing one or two arguments. Either name can + be CamelCased or under_scored. + + Make sure to setup the authlogic gem if you are using that option. + + gem "authlogic" # in Gemfile + +Examples: + rails generate nifty:authentication + + Creates user model, users_controller, and sessions_controller. + + rails generate nifty:authentication account + + Creates account model, accounts_controller, and sessions_controller. + + rails generate nifty:authentication Account UserSession + + Creates account model, accounts_controller, and user_sessions_controller. + +Methods: + There are several methods generated which you can use in your application. + Here's a common example of what you might add to your layout. + + <% if logged_in? %> + Welcome <%= current_user.username %>! Not you? + <%= link_to "Log out", logout_path %> + <% else %> + <%= link_to "Sign up", signup_path %> or + <%= link_to "log in", login_path %>. + <% end %> + + You can also restrict unregistered users from accessing a controller using + a before filter. For example. + + before_filter :login_required, :except => [:index, :show] + + See the generated file lib/authentication.rb for details. \ No newline at end of file diff --git a/lib/generators/nifty/authentication/authentication_generator.rb b/lib/generators/nifty/authentication/authentication_generator.rb new file mode 100644 index 0000000..d4dcbde --- /dev/null +++ b/lib/generators/nifty/authentication/authentication_generator.rb @@ -0,0 +1,154 @@ +require 'generators/nifty' +require 'rails/generators/migration' + +module Nifty + module Generators + class AuthenticationGenerator < Base + include Rails::Generators::Migration + + argument :user_name, :type => :string, :default => 'user', :banner => 'user_name' + argument :session_name, :type => :string, :default => '[[DEFAULT]]', :banner => 'sessions_controller_name' + + class_option :testunit, :desc => 'Use test/unit for test files.', :group => 'Test framework', :type => :boolean + class_option :rspec, :desc => 'Use RSpec for test files.', :group => 'Test framework', :type => :boolean + class_option :shoulda, :desc => 'Use shoulda for test files.', :group => 'Test framework', :type => :boolean + + class_option :haml, :desc => 'Generate HAML views instead of ERB.', :type => :boolean + class_option :authlogic, :desc => 'Use Authlogic for authentication.', :type => :boolean + + def add_gems + add_gem "bcrypt-ruby", :require => "bcrypt" + add_gem "mocha", :group => :test + end + + def create_model_files + template 'user.rb', "app/models/#{user_singular_name}.rb" + template 'authlogic_session.rb', "app/models/#{user_singular_name}_session.rb" if options.authlogic? + end + + def create_controller_files + template 'users_controller.rb', "app/controllers/#{user_plural_name}_controller.rb" + template 'sessions_controller.rb', "app/controllers/#{session_plural_name}_controller.rb" + end + + def create_helper_files + template 'users_helper.rb', "app/helpers/#{user_plural_name}_helper.rb" + template 'sessions_helper.rb', "app/helpers/#{session_plural_name}_helper.rb" + end + + def create_view_files + template "views/#{view_language}/signup.html.#{view_language}", "app/views/#{user_plural_name}/new.html.#{view_language}" + template "views/#{view_language}/edit.html.#{view_language}", "app/views/#{user_plural_name}/edit.html.#{view_language}" + template "views/#{view_language}/_form.html.#{view_language}", "app/views/#{user_plural_name}/_form.html.#{view_language}" + template "views/#{view_language}/login.html.#{view_language}", "app/views/#{session_plural_name}/new.html.#{view_language}" + end + + def create_lib_files + template 'controller_authentication.rb', 'lib/controller_authentication.rb' + end + + def create_routes + route "resources #{user_plural_name.to_sym.inspect}" + route "resources #{session_plural_name.to_sym.inspect}" + route "match 'login' => '#{session_plural_name}#new', :as => :login" + route "match 'logout' => '#{session_plural_name}#destroy', :as => :logout" + route "match 'signup' => '#{user_plural_name}#new', :as => :signup" + route "match '#{user_singular_name}/edit' => '#{user_plural_name}#edit', :as => :edit_current_#{user_singular_name}" + end + + def create_migration + migration_template 'migration.rb', "db/migrate/create_#{user_plural_name}.rb" + end + + def load_and_include_authentication + inject_into_class "config/application.rb", "Application", " config.autoload_paths << \"\#{config.root}/lib\"" + inject_into_class "app/controllers/application_controller.rb", "ApplicationController", " include ControllerAuthentication\n" + end + + def create_test_files + if test_framework == :rspec + template 'fixtures.yml', "spec/fixtures/#{user_plural_name}.yml" + template 'tests/rspec/user.rb', "spec/models/#{user_singular_name}_spec.rb" + template 'tests/rspec/users_controller.rb', "spec/controllers/#{user_plural_name}_controller_spec.rb" + template 'tests/rspec/sessions_controller.rb', "spec/controllers/#{session_plural_name}_controller_spec.rb" + else + template 'fixtures.yml', "test/fixtures/#{user_plural_name}.yml" + template "tests/#{test_framework}/user.rb", "test/unit/#{user_singular_name}_test.rb" + template "tests/#{test_framework}/users_controller.rb", "test/functional/#{user_plural_name}_controller_test.rb" + template "tests/#{test_framework}/sessions_controller.rb", "test/functional/#{session_plural_name}_controller_test.rb" + end + end + + private + + def session_name + @_session_name ||= @session_name == '[[DEFAULT]]' ? + (options.authlogic? ? user_name + '_session' : 'session') : + @session_name + end + + def user_singular_name + user_name.underscore + end + + def user_plural_name + user_singular_name.pluralize + end + + def user_class_name + user_name.camelize + end + + def user_plural_class_name + user_plural_name.camelize + end + + def session_singular_name + session_name.underscore + end + + def session_plural_name + session_singular_name.pluralize + end + + def session_class_name + session_name.camelize + end + + def session_plural_class_name + session_plural_name.camelize + end + + def view_language + options.haml? ? 'haml' : 'erb' + end + + def test_framework + return @test_framework if defined?(@test_framework) + if options.testunit? + return @test_framework = :testunit + elsif options.rspec? + return @test_framework = :rspec + elsif options.shoulda? + return @test_framework = :shoulda + else + return @test_framework = File.exist?(destination_path('spec')) ? :rspec : :testunit + end + end + + def destination_path(path) + File.join(destination_root, path) + end + + # FIXME: Should be proxied to ActiveRecord::Generators::Base + # Implement the required interface for Rails::Generators::Migration. + def self.next_migration_number(dirname) #:nodoc: + if ActiveRecord::Base.timestamped_migrations + Time.now.utc.strftime("%Y%m%d%H%M%S") + else + "%.3d" % (current_migration_number(dirname) + 1) + end + end + end + end +end diff --git a/lib/generators/nifty/authentication/templates/authlogic_session.rb b/lib/generators/nifty/authentication/templates/authlogic_session.rb new file mode 100644 index 0000000..676cfd0 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/authlogic_session.rb @@ -0,0 +1,2 @@ +class <%= session_class_name %> < Authlogic::Session::Base +end diff --git a/lib/generators/nifty/authentication/templates/controller_authentication.rb b/lib/generators/nifty/authentication/templates/controller_authentication.rb new file mode 100644 index 0000000..6d34ab0 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/controller_authentication.rb @@ -0,0 +1,60 @@ +# This module is included in your application controller which makes +# several methods available to all controllers and views. Here's a +# common example you might add to your application layout file. +# +# <%% if logged_in? %> +# Welcome <%%= current_<%= user_singular_name %>.username %>. +# <%%= link_to "Edit profile", edit_current_<%= user_singular_name %>_path %> or +# <%%= link_to "Log out", logout_path %> +# <%% else %> +# <%%= link_to "Sign up", signup_path %> or +# <%%= link_to "log in", login_path %>. +# <%% end %> +# +# You can also restrict unregistered users from accessing a controller using +# a before filter. For example. +# +# before_filter :login_required, :except => [:index, :show] +module ControllerAuthentication + def self.included(controller) + controller.send :helper_method, :current_<%= user_singular_name %>, :logged_in?, :redirect_to_target_or_default + end + +<%- if options[:authlogic] -%> + def current_<%= session_singular_name %> + return @current_<%= session_singular_name %> if defined?(@current_<%= session_singular_name %>) + @current_<%= session_singular_name %> = <%= session_class_name %>.find + end + + def current_<%= user_singular_name %> + return @current_<%= user_singular_name %> if defined?(@current_<%= user_singular_name %>) + @current_<%= user_singular_name %> = current_<%= session_singular_name %> && current_<%= session_singular_name %>.record + end +<%- else -%> + def current_<%= user_singular_name %> + @current_<%= user_singular_name %> ||= <%= user_class_name %>.find(session[:<%= user_singular_name %>_id]) if session[:<%= user_singular_name %>_id] + end +<%- end -%> + + def logged_in? + current_<%= user_singular_name %> + end + + def login_required + unless logged_in? + store_target_location + redirect_to login_url, :alert => "You must first log in or sign up before accessing this page." + end + end + + def redirect_to_target_or_default(default, *args) + redirect_to(session[:return_to] || default, *args) + session[:return_to] = nil + end + + private + + def store_target_location + session[:return_to] = request.url + end +end diff --git a/lib/generators/nifty/authentication/templates/fixtures.yml b/lib/generators/nifty/authentication/templates/fixtures.yml new file mode 100644 index 0000000..c52532b --- /dev/null +++ b/lib/generators/nifty/authentication/templates/fixtures.yml @@ -0,0 +1,24 @@ +# password: "secret" +foo: + username: foo + email: foo@example.com +<%- if options[:authlogic] -%> + persistence_token: d5ddba13ed4408ea2b0a12ab18ed2d2eda086279736bdc121ca726a11f1e4b99217d9c534c2cc4ebb22729349c8c5fdbe1529e1f2c3c5859c62ef4dd9feea25c + crypted_password: 3d16c326648cccafe3d4b4cb024475c381dda92f430dfedf6f933e1f61203bacb6bae2437849bdb43b06be335e23790e4aa03902b3c28c3bbbbe27d501e521f3 + password_salt: n6z_wtpWoIsHgQb5IcFd +<%- else -%> + password_hash: 3488f5f7efecab14b91eb96169e5e1ee518a569f + password_salt: bef65e058905c379436d80d1a32e7374b139e7b0 +<%- end -%> + +bar: + username: bar + email: bar@example.com +<%- if options[:authlogic] -%> + persistence_token: 19e074bd7cb506ab3e7e53e41f24f0ab3221c8cb68111f4c1aa43965114ad734233979a50a9463537487cdca18c279ac91c4bc83693d589625d446493322394c + crypted_password: 3bc9f4113ca645a186765df3d31a9352d0067bf2304ba0cdd6b08a7f3d58c6668ab1762fa3e76aef466ea2ff188399d8e6c40244fa59312bb4112292dac9f7f0 + password_salt: UiAh9ejabnKRxqsiK0xO +<%- else -%> + password_hash: 3488f5f7efecab14b91eb96169e5e1ee518a569f + password_salt: bef65e058905c379436d80d1a32e7374b139e7b0 +<%- end -%> diff --git a/lib/generators/nifty/authentication/templates/migration.rb b/lib/generators/nifty/authentication/templates/migration.rb new file mode 100644 index 0000000..c945df3 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/migration.rb @@ -0,0 +1,20 @@ +class Create<%= user_plural_class_name %> < ActiveRecord::Migration + def self.up + create_table :<%= user_plural_name %> do |t| + t.string :username + t.string :email + <%- if options[:authlogic] -%> + t.string :persistence_token + t.string :crypted_password + <%- else -%> + t.string :password_hash + <%- end -%> + t.string :password_salt + t.timestamps + end + end + + def self.down + drop_table :<%= user_plural_name %> + end +end diff --git a/lib/generators/nifty/authentication/templates/sessions_controller.rb b/lib/generators/nifty/authentication/templates/sessions_controller.rb new file mode 100644 index 0000000..65e77c1 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/sessions_controller.rb @@ -0,0 +1,41 @@ +class <%= session_plural_class_name %>Controller < ApplicationController +<%- if options[:authlogic] -%> + def new + @<%= session_singular_name %> = <%= session_class_name %>.new + end + + def create + @<%= session_singular_name %> = <%= session_class_name %>.new(params[:<%= session_singular_name %>]) + if @<%= session_singular_name %>.save + redirect_to_target_or_default root_url, :notice => "Logged in successfully." + else + render :new + end + end + + def destroy + @<%= session_singular_name %> = <%= session_class_name %>.find + @<%= session_singular_name %>.destroy + redirect_to root_url, :notice => "You have been logged out." + end +<%- else -%> + def new + end + + def create + <%= user_singular_name %> = <%= user_class_name %>.authenticate(params[:login], params[:password]) + if <%= user_singular_name %> + session[:<%= user_singular_name %>_id] = <%= user_singular_name %>.id + redirect_to_target_or_default root_url, :notice => "Logged in successfully." + else + flash.now[:alert] = "Invalid login or password." + render :new + end + end + + def destroy + session[:<%= user_singular_name %>_id] = nil + redirect_to root_url, :notice => "You have been logged out." + end +<%- end -%> +end diff --git a/lib/generators/nifty/authentication/templates/sessions_helper.rb b/lib/generators/nifty/authentication/templates/sessions_helper.rb new file mode 100644 index 0000000..0958537 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/sessions_helper.rb @@ -0,0 +1,2 @@ +module <%= session_plural_class_name %>Helper +end diff --git a/lib/generators/nifty/authentication/templates/tests/rspec/sessions_controller.rb b/lib/generators/nifty/authentication/templates/tests/rspec/sessions_controller.rb new file mode 100644 index 0000000..e0953cc --- /dev/null +++ b/lib/generators/nifty/authentication/templates/tests/rspec/sessions_controller.rb @@ -0,0 +1,39 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe <%= session_plural_class_name %>Controller do + fixtures :all + render_views + + it "new action should render new template" do + get :new + response.should render_template(:new) + end + +<%- if options[:authlogic] -%> + it "create action should render new template when authentication is invalid" do + post :create, :<%= session_singular_name %> => { :username => "foo", :password => "badpassword" } + response.should render_template(:new) + <%= session_class_name %>.find.should be_nil + end + + it "create action should redirect when authentication is valid" do + post :create, :<%= session_singular_name %> => { :username => "foo", :password => "secret" } + response.should redirect_to(root_url) + <%= session_class_name %>.find.<%= user_singular_name %>.should == <%= user_plural_name %>(:foo) + end +<%- else -%> + it "create action should render new template when authentication is invalid" do + <%= user_class_name %>.stubs(:authenticate).returns(nil) + post :create + response.should render_template(:new) + session['<%= user_singular_name %>_id'].should be_nil + end + + it "create action should redirect when authentication is valid" do + <%= user_class_name %>.stubs(:authenticate).returns(<%= user_class_name %>.first) + post :create + response.should redirect_to(root_url) + session['<%= user_singular_name %>_id'].should == <%= user_class_name %>.first.id + end +<%- end -%> +end diff --git a/lib/generators/nifty/authentication/templates/tests/rspec/user.rb b/lib/generators/nifty/authentication/templates/tests/rspec/user.rb new file mode 100644 index 0000000..a3f7e92 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/tests/rspec/user.rb @@ -0,0 +1,83 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe <%= user_class_name %> do +<%- unless options[:authlogic] -%> + def new_<%= user_singular_name %>(attributes = {}) + attributes[:username] ||= 'foo' + attributes[:email] ||= 'foo@example.com' + attributes[:password] ||= 'abc123' + attributes[:password_confirmation] ||= attributes[:password] + <%= user_class_name %>.new(attributes) + end + + before(:each) do + <%= user_class_name %>.delete_all + end + + it "should be valid" do + new_<%= user_singular_name %>.should be_valid + end + + it "should require username" do + new_<%= user_singular_name %>(:username => '').should have(1).error_on(:username) + end + + it "should require password" do + new_<%= user_singular_name %>(:password => '').should have(1).error_on(:password) + end + + it "should require well formed email" do + new_<%= user_singular_name %>(:email => 'foo@bar@example.com').should have(1).error_on(:email) + end + + it "should validate uniqueness of email" do + new_<%= user_singular_name %>(:email => 'bar@example.com').save! + new_<%= user_singular_name %>(:email => 'bar@example.com').should have(1).error_on(:email) + end + + it "should validate uniqueness of username" do + new_<%= user_singular_name %>(:username => 'uniquename').save! + new_<%= user_singular_name %>(:username => 'uniquename').should have(1).error_on(:username) + end + + it "should not allow odd characters in username" do + new_<%= user_singular_name %>(:username => 'odd ^&(@)').should have(1).error_on(:username) + end + + it "should validate password is longer than 3 characters" do + new_<%= user_singular_name %>(:password => 'bad').should have(1).error_on(:password) + end + + it "should require matching password confirmation" do + new_<%= user_singular_name %>(:password_confirmation => 'nonmatching').should have(1).error_on(:password) + end + + it "should generate password hash and salt on create" do + <%= user_singular_name %> = new_<%= user_singular_name %> + <%= user_singular_name %>.save! + <%= user_singular_name %>.password_hash.should_not be_nil + <%= user_singular_name %>.password_salt.should_not be_nil + end + + it "should authenticate by username" do + <%= user_singular_name %> = new_<%= user_singular_name %>(:username => 'foobar', :password => 'secret') + <%= user_singular_name %>.save! + <%= user_class_name %>.authenticate('foobar', 'secret').should == <%= user_singular_name %> + end + + it "should authenticate by email" do + <%= user_singular_name %> = new_<%= user_singular_name %>(:email => 'foo@bar.com', :password => 'secret') + <%= user_singular_name %>.save! + <%= user_class_name %>.authenticate('foo@bar.com', 'secret').should == <%= user_singular_name %> + end + + it "should not authenticate bad username" do + <%= user_class_name %>.authenticate('nonexisting', 'secret').should be_nil + end + + it "should not authenticate bad password" do + new_<%= user_singular_name %>(:username => 'foobar', :password => 'secret').save! + <%= user_class_name %>.authenticate('foobar', 'badpassword').should be_nil + end +<%- end -%> +end diff --git a/lib/generators/nifty/authentication/templates/tests/rspec/users_controller.rb b/lib/generators/nifty/authentication/templates/tests/rspec/users_controller.rb new file mode 100644 index 0000000..60bcff9 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/tests/rspec/users_controller.rb @@ -0,0 +1,56 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe <%= user_plural_class_name %>Controller do + fixtures :all + render_views + + it "new action should render new template" do + get :new + response.should render_template(:new) + end + + it "create action should render new template when model is invalid" do + <%= user_class_name %>.any_instance.stubs(:valid?).returns(false) + post :create + response.should render_template(:new) + end + + it "create action should redirect when model is valid" do + <%= user_class_name %>.any_instance.stubs(:valid?).returns(true) + post :create + response.should redirect_to(root_url) + <%- unless options[:authlogic] -%> + session['<%= user_singular_name %>_id'].should == assigns['<%= user_singular_name %>'].id + <%- end -%> + end + + it "edit action should redirect when not logged in" do + get :edit, :id => "ignored" + response.should redirect_to(login_url) + end + + it "edit action should render edit template" do + @controller.stubs(:current_<%= user_singular_name %>).returns(<%= user_class_name %>.first) + get :edit, :id => "ignored" + response.should render_template(:edit) + end + + it "update action should redirect when not logged in" do + put :update, :id => "ignored" + response.should redirect_to(login_url) + end + + it "update action should render edit template when <%= user_singular_name %> is invalid" do + @controller.stubs(:current_<%= user_singular_name %>).returns(<%= user_class_name %>.first) + <%= user_class_name %>.any_instance.stubs(:valid?).returns(false) + put :update, :id => "ignored" + response.should render_template(:edit) + end + + it "update action should redirect when <%= user_singular_name %> is valid" do + @controller.stubs(:current_<%= user_singular_name %>).returns(<%= user_class_name %>.first) + <%= user_class_name %>.any_instance.stubs(:valid?).returns(true) + put :update, :id => "ignored" + response.should redirect_to(root_url) + end +end diff --git a/lib/generators/nifty/authentication/templates/tests/shoulda/sessions_controller.rb b/lib/generators/nifty/authentication/templates/tests/shoulda/sessions_controller.rb new file mode 100644 index 0000000..e2f9005 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/tests/shoulda/sessions_controller.rb @@ -0,0 +1,40 @@ +require 'test_helper' + +class <%= session_plural_class_name %>ControllerTest < ActionController::TestCase + context "new action" do + should "render new template" do + get :new + assert_template 'new' + end + end + + context "create action" do + <%- if options[:authlogic] -%> + should "render new template when authentication is invalid" do + post :create, :<%= session_singular_name %> => { :username => "foo", :password => "badpassword" } + assert_template 'new' + assert_nil <%= session_class_name %>.find + end + + should "redirect when authentication is valid" do + post :create, :<%= session_singular_name %> => { :username => "foo", :password => "secret" } + assert_redirected_to root_url + assert_equal <%= user_plural_name %>(:foo), <%= session_class_name %>.find.<%= user_singular_name %> + end + <%- else -%> + should "render new template when authentication is invalid" do + <%= user_class_name %>.stubs(:authenticate).returns(nil) + post :create + assert_template 'new' + assert_nil session['<%= user_singular_name %>_id'] + end + + should "redirect when authentication is valid" do + <%= user_class_name %>.stubs(:authenticate).returns(<%= user_class_name %>.first) + post :create + assert_redirected_to root_url + assert_equal <%= user_class_name %>.first.id, session['<%= user_singular_name %>_id'] + end + <%- end -%> + end +end diff --git a/lib/generators/nifty/authentication/templates/tests/shoulda/user.rb b/lib/generators/nifty/authentication/templates/tests/shoulda/user.rb new file mode 100644 index 0000000..beb8bf4 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/tests/shoulda/user.rb @@ -0,0 +1,85 @@ +require 'test_helper' + +class <%= user_class_name %>Test < ActiveSupport::TestCase +<%- unless options[:authlogic] -%> + def new_<%= user_singular_name %>(attributes = {}) + attributes[:username] ||= 'foo' + attributes[:email] ||= 'foo@example.com' + attributes[:password] ||= 'abc123' + attributes[:password_confirmation] ||= attributes[:password] + <%= user_singular_name %> = <%= user_class_name %>.new(attributes) + <%= user_singular_name %>.valid? # run validations + <%= user_singular_name %> + end + + def setup + <%= user_class_name %>.delete_all + end + + should "be valid" do + assert new_<%= user_singular_name %>.valid? + end + + should "require username" do + assert_equal ["can't be blank"], new_<%= user_singular_name %>(:username => '').errors[:username] + end + + should "require password" do + assert_equal ["can't be blank"], new_<%= user_singular_name %>(:password => '').errors[:password] + end + + should "require well formed email" do + assert_equal ["is invalid"], new_<%= user_singular_name %>(:email => 'foo@bar@example.com').errors[:email] + end + + should "validate uniqueness of email" do + new_<%= user_singular_name %>(:email => 'bar@example.com').save! + assert_equal ["has already been taken"], new_<%= user_singular_name %>(:email => 'bar@example.com').errors[:email] + end + + should "validate uniqueness of username" do + new_<%= user_singular_name %>(:username => 'uniquename').save! + assert_equal ["has already been taken"], new_<%= user_singular_name %>(:username => 'uniquename').errors[:username] + end + + should "not allow odd characters in username" do + assert_equal ["should only contain letters, numbers, or .-_@"], new_<%= user_singular_name %>(:username => 'odd ^&(@)').errors[:username] + end + + should "validate password is longer than 3 characters" do + assert_equal ["is too short (minimum is 4 characters)"], new_<%= user_singular_name %>(:password => 'bad').errors[:password] + end + + should "require matching password confirmation" do + assert_equal ["doesn't match confirmation"], new_<%= user_singular_name %>(:password_confirmation => 'nonmatching').errors[:password] + end + + should "generate password hash and salt on create" do + <%= user_singular_name %> = new_<%= user_singular_name %> + <%= user_singular_name %>.save! + assert <%= user_singular_name %>.password_hash + assert <%= user_singular_name %>.password_salt + end + + should "authenticate by username" do + <%= user_singular_name %> = new_<%= user_singular_name %>(:username => 'foobar', :password => 'secret') + <%= user_singular_name %>.save! + assert_equal <%= user_singular_name %>, <%= user_class_name %>.authenticate('foobar', 'secret') + end + + should "authenticate by email" do + <%= user_singular_name %> = new_<%= user_singular_name %>(:email => 'foo@bar.com', :password => 'secret') + <%= user_singular_name %>.save! + assert_equal <%= user_singular_name %>, <%= user_class_name %>.authenticate('foo@bar.com', 'secret') + end + + should "not authenticate bad username" do + assert_nil <%= user_class_name %>.authenticate('nonexisting', 'secret') + end + + should "not authenticate bad password" do + new_<%= user_singular_name %>(:username => 'foobar', :password => 'secret').save! + assert_nil <%= user_class_name %>.authenticate('foobar', 'badpassword') + end +<%- end -%> +end diff --git a/lib/generators/nifty/authentication/templates/tests/shoulda/users_controller.rb b/lib/generators/nifty/authentication/templates/tests/shoulda/users_controller.rb new file mode 100644 index 0000000..1728329 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/tests/shoulda/users_controller.rb @@ -0,0 +1,61 @@ +require 'test_helper' + +class <%= user_plural_class_name %>ControllerTest < ActionController::TestCase + context "new action" do + should "render new template" do + get :new + assert_template 'new' + end + end + + context "create action" do + should "render new template when <%= user_singular_name %> is invalid" do + <%= user_class_name %>.any_instance.stubs(:valid?).returns(false) + post :create + assert_template 'new' + end + + should "redirect when <%= user_singular_name %> is valid" do + <%= user_class_name %>.any_instance.stubs(:valid?).returns(true) + post :create + assert_redirected_to root_url + <%- unless options[:authlogic] -%> + assert_equal assigns['<%= user_singular_name %>'].id, session['<%= user_singular_name %>_id'] + <%- end -%> + end + end + + context "edit action" do + should "redirect when not logged in" do + get :edit, :id => "ignored" + assert_redirected_to login_url + end + + should "render edit template" do + @controller.stubs(:current_<%= user_singular_name %>).returns(<%= user_class_name %>.first) + get :edit, :id => "ignored" + assert_template 'edit' + end + end + + context "update action" do + should "redirect when not logged in" do + put :update, :id => "ignored" + assert_redirected_to login_url + end + + should "render edit template when <%= user_singular_name %> is invalid" do + @controller.stubs(:current_<%= user_singular_name %>).returns(<%= user_class_name %>.first) + <%= user_class_name %>.any_instance.stubs(:valid?).returns(false) + put :update, :id => "ignored" + assert_template 'edit' + end + + should "redirect when <%= user_singular_name %> is valid" do + @controller.stubs(:current_<%= user_singular_name %>).returns(<%= user_class_name %>.first) + <%= user_class_name %>.any_instance.stubs(:valid?).returns(true) + put :update, :id => "ignored" + assert_redirected_to root_url + end + end +end diff --git a/lib/generators/nifty/authentication/templates/tests/testunit/sessions_controller.rb b/lib/generators/nifty/authentication/templates/tests/testunit/sessions_controller.rb new file mode 100644 index 0000000..fe2a65b --- /dev/null +++ b/lib/generators/nifty/authentication/templates/tests/testunit/sessions_controller.rb @@ -0,0 +1,36 @@ +require 'test_helper' + +class <%= session_plural_class_name %>ControllerTest < ActionController::TestCase + def test_new + get :new + assert_template 'new' + end + +<%- if options[:authlogic] -%> + def test_create_invalid + post :create, :<%= session_singular_name %> => { :username => "foo", :password => "badpassword" } + assert_template 'new' + assert_nil <%= session_class_name %>.find + end + + def test_create_valid + post :create, :<%= session_singular_name %> => { :username => "foo", :password => "secret" } + assert_redirected_to root_url + assert_equal <%= user_plural_name %>(:foo), <%= session_class_name %>.find.<%= user_singular_name %> + end +<%- else -%> + def test_create_invalid + <%= user_class_name %>.stubs(:authenticate).returns(nil) + post :create + assert_template 'new' + assert_nil session['<%= user_singular_name %>_id'] + end + + def test_create_valid + <%= user_class_name %>.stubs(:authenticate).returns(<%= user_class_name %>.first) + post :create + assert_redirected_to root_url + assert_equal <%= user_class_name %>.first.id, session['<%= user_singular_name %>_id'] + end +<%- end -%> +end diff --git a/lib/generators/nifty/authentication/templates/tests/testunit/user.rb b/lib/generators/nifty/authentication/templates/tests/testunit/user.rb new file mode 100644 index 0000000..c036cf1 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/tests/testunit/user.rb @@ -0,0 +1,88 @@ +require 'test_helper' + +class <%= user_class_name %>Test < ActiveSupport::TestCase +<%- unless options[:authlogic] -%> + def new_<%= user_singular_name %>(attributes = {}) + attributes[:username] ||= 'foo' + attributes[:email] ||= 'foo@example.com' + attributes[:password] ||= 'abc123' + attributes[:password_confirmation] ||= attributes[:password] + <%= user_singular_name %> = <%= user_class_name %>.new(attributes) + <%= user_singular_name %>.valid? # run validations + <%= user_singular_name %> + end + + def setup + <%= user_class_name %>.delete_all + end + + def test_valid + assert new_<%= user_singular_name %>.valid? + end + + def test_require_username + assert_equal ["can't be blank"], new_<%= user_singular_name %>(:username => '').errors[:username] + end + + def test_require_password + assert_equal ["can't be blank"], new_<%= user_singular_name %>(:password => '').errors[:password] + end + + def test_require_well_formed_email + assert_equal ["is invalid"], new_<%= user_singular_name %>(:email => 'foo@bar@example.com').errors[:email] + end + + def test_validate_uniqueness_of_email + new_<%= user_singular_name %>(:email => 'bar@example.com').save! + assert_equal ["has already been taken"], new_<%= user_singular_name %>(:email => 'bar@example.com').errors[:email] + end + + def test_validate_uniqueness_of_username + new_<%= user_singular_name %>(:username => 'uniquename').save! + assert_equal ["has already been taken"], new_<%= user_singular_name %>(:username => 'uniquename').errors[:username] + end + + def test_validate_odd_characters_in_username + assert_equal ["should only contain letters, numbers, or .-_@"], new_<%= user_singular_name %>(:username => 'odd ^&(@)').errors[:username] + end + + def test_validate_password_length + assert_equal ["is too short (minimum is 4 characters)"], new_<%= user_singular_name %>(:password => 'bad').errors[:password] + end + + def test_require_matching_password_confirmation + assert_equal ["doesn't match confirmation"], new_<%= user_singular_name %>(:password_confirmation => 'nonmatching').errors[:password] + end + + def test_generate_password_hash_and_salt_on_create + <%= user_singular_name %> = new_<%= user_singular_name %> + <%= user_singular_name %>.save! + assert <%= user_singular_name %>.password_hash + assert <%= user_singular_name %>.password_salt + end + + def test_authenticate_by_username + <%= user_class_name %>.delete_all + <%= user_singular_name %> = new_<%= user_singular_name %>(:username => 'foobar', :password => 'secret') + <%= user_singular_name %>.save! + assert_equal <%= user_singular_name %>, <%= user_class_name %>.authenticate('foobar', 'secret') + end + + def test_authenticate_by_email + <%= user_class_name %>.delete_all + <%= user_singular_name %> = new_<%= user_singular_name %>(:email => 'foo@bar.com', :password => 'secret') + <%= user_singular_name %>.save! + assert_equal <%= user_singular_name %>, <%= user_class_name %>.authenticate('foo@bar.com', 'secret') + end + + def test_authenticate_bad_username + assert_nil <%= user_class_name %>.authenticate('nonexisting', 'secret') + end + + def test_authenticate_bad_password + <%= user_class_name %>.delete_all + new_<%= user_singular_name %>(:username => 'foobar', :password => 'secret').save! + assert_nil <%= user_class_name %>.authenticate('foobar', 'badpassword') + end +<%- end -%> +end diff --git a/lib/generators/nifty/authentication/templates/tests/testunit/users_controller.rb b/lib/generators/nifty/authentication/templates/tests/testunit/users_controller.rb new file mode 100644 index 0000000..ef8a3f7 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/tests/testunit/users_controller.rb @@ -0,0 +1,53 @@ +require 'test_helper' + +class <%= user_plural_class_name %>ControllerTest < ActionController::TestCase + def test_new + get :new + assert_template 'new' + end + + def test_create_invalid + <%= user_class_name %>.any_instance.stubs(:valid?).returns(false) + post :create + assert_template 'new' + end + + def test_create_valid + <%= user_class_name %>.any_instance.stubs(:valid?).returns(true) + post :create + assert_redirected_to root_url + <%- unless options[:authlogic] -%> + assert_equal assigns['<%= user_singular_name %>'].id, session['<%= user_singular_name %>_id'] + <%- end -%> + end + + def test_edit_without_user + get :edit, :id => "ignored" + assert_redirected_to login_url + end + + def test_edit + @controller.stubs(:current_<%= user_singular_name %>).returns(<%= user_class_name %>.first) + get :edit, :id => "ignored" + assert_template 'edit' + end + + def test_update_without_user + put :update, :id => "ignored" + assert_redirected_to login_url + end + + def test_update_invalid + @controller.stubs(:current_<%= user_singular_name %>).returns(<%= user_class_name %>.first) + <%= user_class_name %>.any_instance.stubs(:valid?).returns(false) + put :update, :id => "ignored" + assert_template 'edit' + end + + def test_update_valid + @controller.stubs(:current_<%= user_singular_name %>).returns(<%= user_class_name %>.first) + <%= user_class_name %>.any_instance.stubs(:valid?).returns(true) + put :update, :id => "ignored" + assert_redirected_to root_url + end +end diff --git a/lib/generators/nifty/authentication/templates/user.rb b/lib/generators/nifty/authentication/templates/user.rb new file mode 100644 index 0000000..ec18524 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/user.rb @@ -0,0 +1,38 @@ +class <%= user_class_name %> < ActiveRecord::Base +<%- if options[:authlogic] -%> + acts_as_authentic +<%- else -%> + # new columns need to be added here to be writable through mass assignment + attr_accessible :username, :email, :password, :password_confirmation + + attr_accessor :password + before_save :prepare_password + + validates_presence_of :username + validates_uniqueness_of :username, :email, :allow_blank => true + validates_format_of :username, :with => /^[-\w\._@]+$/i, :allow_blank => true, :message => "should only contain letters, numbers, or .-_@" + validates_format_of :email, :with => /^[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i + validates_presence_of :password, :on => :create + validates_confirmation_of :password + validates_length_of :password, :minimum => 4, :allow_blank => true + + # login can be either username or email address + def self.authenticate(login, pass) + <%= user_singular_name %> = find_by_username(login) || find_by_email(login) + return <%= user_singular_name %> if <%= user_singular_name %> && <%= user_singular_name %>.password_hash == <%= user_singular_name %>.encrypt_password(pass) + end + + def encrypt_password(pass) + BCrypt::Engine.hash_secret(pass, password_salt) + end + + private + + def prepare_password + unless password.blank? + self.password_salt = BCrypt::Engine.generate_salt + self.password_hash = encrypt_password(password) + end + end +<%- end -%> +end diff --git a/lib/generators/nifty/authentication/templates/users_controller.rb b/lib/generators/nifty/authentication/templates/users_controller.rb new file mode 100644 index 0000000..2faed00 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/users_controller.rb @@ -0,0 +1,32 @@ +class <%= user_plural_class_name %>Controller < ApplicationController + before_filter :login_required, :except => [:new, :create] + + def new + @<%= user_singular_name %> = <%= user_class_name %>.new + end + + def create + @<%= user_singular_name %> = <%= user_class_name %>.new(params[:<%= user_singular_name %>]) + if @<%= user_singular_name %>.save + <%- unless options[:authlogic] -%> + session[:<%= user_singular_name %>_id] = @<%= user_singular_name %>.id + <%- end -%> + redirect_to root_url, :notice => "Thank you for signing up! You are now logged in." + else + render :new + end + end + + def edit + @<%= user_singular_name %> = current_<%= user_singular_name %> + end + + def update + @<%= user_singular_name %> = current_<%= user_singular_name %> + if @<%= user_singular_name %>.update_attributes(params[:<%= user_singular_name %>]) + redirect_to root_url, :notice => "Your profile has been updated." + else + render :edit + end + end +end diff --git a/lib/generators/nifty/authentication/templates/users_helper.rb b/lib/generators/nifty/authentication/templates/users_helper.rb new file mode 100644 index 0000000..7eb9040 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/users_helper.rb @@ -0,0 +1,2 @@ +module <%= user_plural_class_name %>Helper +end diff --git a/lib/generators/nifty/authentication/templates/views/erb/_form.html.erb b/lib/generators/nifty/authentication/templates/views/erb/_form.html.erb new file mode 100644 index 0000000..4e1c47d --- /dev/null +++ b/lib/generators/nifty/authentication/templates/views/erb/_form.html.erb @@ -0,0 +1,20 @@ +<%%= form_for @<%= user_singular_name %> do |f| %> + <%%= f.error_messages %> +
    + <%%= f.label :username %> + <%%= f.text_field :username %> +
    +
    + <%%= f.label :email, "Email Address" %> + <%%= f.text_field :email %> +
    +
    + <%%= f.label :password %> + <%%= f.password_field :password %> +
    +
    + <%%= f.label :password_confirmation, "Confirm Password" %> + <%%= f.password_field :password_confirmation %> +
    +
    <%%= f.submit (@<%= user_singular_name %>.new_record? ? "Sign up" : "Update") %>
    +<%% end %> diff --git a/lib/generators/nifty/authentication/templates/views/erb/edit.html.erb b/lib/generators/nifty/authentication/templates/views/erb/edit.html.erb new file mode 100644 index 0000000..75de67e --- /dev/null +++ b/lib/generators/nifty/authentication/templates/views/erb/edit.html.erb @@ -0,0 +1,3 @@ +<%% title "Update Profile" %> + +<%%= render "form" %> diff --git a/lib/generators/nifty/authentication/templates/views/erb/login.html.erb b/lib/generators/nifty/authentication/templates/views/erb/login.html.erb new file mode 100644 index 0000000..1cbc428 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/views/erb/login.html.erb @@ -0,0 +1,30 @@ +<%% title "Log in" %> + +

    Don't have an account? <%%= link_to "Sign up!", signup_path %>

    + +<%- if options[:authlogic] -%> +<%%= form_for @<%= session_singular_name %> do |f| %> + <%%= f.error_messages %> +
    + <%%= f.label :username %> + <%%= f.text_field :username %> +
    +
    + <%%= f.label :password %> + <%%= f.password_field :password %> +
    +
    <%%= f.submit "Log in" %>
    +<%% end %> +<%- else -%> +<%%= form_tag <%= session_plural_name %>_path do %> +
    + <%%= label_tag :login, "Username or Email Address" %> + <%%= text_field_tag :login, params[:login] %> +
    +
    + <%%= label_tag :password %> + <%%= password_field_tag :password %> +
    +
    <%%= submit_tag "Log in" %>
    +<%% end %> +<%- end -%> diff --git a/lib/generators/nifty/authentication/templates/views/erb/signup.html.erb b/lib/generators/nifty/authentication/templates/views/erb/signup.html.erb new file mode 100644 index 0000000..6f282b5 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/views/erb/signup.html.erb @@ -0,0 +1,5 @@ +<%% title "Sign up" %> + +

    Already have an account? <%%= link_to "Log in", login_path %>.

    + +<%%= render "form" %> diff --git a/lib/generators/nifty/authentication/templates/views/haml/_form.html.haml b/lib/generators/nifty/authentication/templates/views/haml/_form.html.haml new file mode 100644 index 0000000..992ee9c --- /dev/null +++ b/lib/generators/nifty/authentication/templates/views/haml/_form.html.haml @@ -0,0 +1,16 @@ += form_for @<%= user_singular_name %> do |f| + = f.error_messages + .field + = f.label :username + = f.text_field :username + .field + = f.label :email, "Email Address" + = f.text_field :email + .field + = f.label :password + = f.password_field :password + .field + = f.label :password_confirmation, "Confirm Password" + = f.password_field :password_confirmation + .actions + = f.submit (@<%= user_singular_name %>.new_record? ? "Sign up" : "Update") diff --git a/lib/generators/nifty/authentication/templates/views/haml/edit.html.haml b/lib/generators/nifty/authentication/templates/views/haml/edit.html.haml new file mode 100644 index 0000000..4b43a3b --- /dev/null +++ b/lib/generators/nifty/authentication/templates/views/haml/edit.html.haml @@ -0,0 +1,3 @@ +- title "Sign up" + += render "form" diff --git a/lib/generators/nifty/authentication/templates/views/haml/login.html.haml b/lib/generators/nifty/authentication/templates/views/haml/login.html.haml new file mode 100644 index 0000000..22fc95b --- /dev/null +++ b/lib/generators/nifty/authentication/templates/views/haml/login.html.haml @@ -0,0 +1,26 @@ +- title "Log in" + +%p== Don't have an account? #{link_to "Sign up!", signup_path} + +<%- if options[:authlogic] -%> += form_for @<%= session_singular_name %> do |f| + = f.error_messages + .field + = f.label :username + = f.text_field :username + .field + = f.label :password + = f.password_field :password + .actions + = f.submit "Log in" +<%- else -%> +- form_tag <%= session_plural_name %>_path do + .field + = label_tag :login, "Username or Email Address" + = text_field_tag :login, params[:login] + .field + = label_tag :password + = password_field_tag :password + .actions + = submit_tag "Log in" +<%- end -%> diff --git a/lib/generators/nifty/authentication/templates/views/haml/signup.html.haml b/lib/generators/nifty/authentication/templates/views/haml/signup.html.haml new file mode 100644 index 0000000..dc75c13 --- /dev/null +++ b/lib/generators/nifty/authentication/templates/views/haml/signup.html.haml @@ -0,0 +1,5 @@ +- title "Sign up" + +%p== Already have an account? #{link_to "Log in", login_path}. + += render "form" diff --git a/lib/generators/nifty/config/USAGE b/lib/generators/nifty/config/USAGE new file mode 100644 index 0000000..f98972c --- /dev/null +++ b/lib/generators/nifty/config/USAGE @@ -0,0 +1,23 @@ +Description: + The nifty_config generator creates YAML file in your config + directory and an initializer to load this config. The config has a + separate section for each environment. This is a great place to put + any config settings you don't want in your app. + + The config is loaded into a constant called APP_CONFIG by default, + this changes depending on the name you choose to pass the generator. + Use this constant to access the config settings like this. + + APP_CONFIG[:some_setting] + + +Examples: + rails generate nifty:config + + Config: config/app_config.yml + Initializer: config/initializers/load_app_config.rb + + rails generate nifty:config passwords + + Config: config/passwords_config.yml + Initializer: config/initializers/load_passwords_config.rb diff --git a/lib/generators/nifty/config/config_generator.rb b/lib/generators/nifty/config/config_generator.rb new file mode 100644 index 0000000..811c80e --- /dev/null +++ b/lib/generators/nifty/config/config_generator.rb @@ -0,0 +1,24 @@ +require 'generators/nifty' + +module Nifty + module Generators + class ConfigGenerator < Base + argument :config_name, :type => :string, :default => 'app', :banner => 'config_name' + + def create_config + template "load_config.rb", "config/initializers/load_#{file_name}_config.rb" + copy_file "config.yml", "config/#{file_name}_config.yml" + end + + private + + def file_name + config_name.underscore + end + + def constant_name + config_name.underscore.upcase + end + end + end +end diff --git a/lib/generators/nifty/config/templates/config.yml b/lib/generators/nifty/config/templates/config.yml new file mode 100644 index 0000000..3a26ebc --- /dev/null +++ b/lib/generators/nifty/config/templates/config.yml @@ -0,0 +1,8 @@ +development: + domain: localhost:3000 + +test: + domain: test.host + +production: + domain: example.com diff --git a/lib/generators/nifty/config/templates/load_config.rb b/lib/generators/nifty/config/templates/load_config.rb new file mode 100644 index 0000000..06e6a52 --- /dev/null +++ b/lib/generators/nifty/config/templates/load_config.rb @@ -0,0 +1,2 @@ +raw_config = File.read("#{Rails.root}/config/<%= file_name %>_config.yml") +<%= constant_name %>_CONFIG = YAML.load(raw_config)[Rails.env].symbolize_keys diff --git a/lib/generators/nifty/layout/USAGE b/lib/generators/nifty/layout/USAGE new file mode 100644 index 0000000..f94af0d --- /dev/null +++ b/lib/generators/nifty/layout/USAGE @@ -0,0 +1,25 @@ +Description: + The nifty_layout generator creates a basic layout, stylesheet and + helper which will give some structure to a starting Rails app. + + The generator takes one argument which will be the name of the + layout and stylesheet files. If no argument is passed then it defaults + to "application". + + The helper module includes some methods which can be called in any + template or partial to set variables to be used in the layout, such as + page title and javascript/stylesheet includes. + +Examples: + rails generate nifty:layout + + Layout: app/views/layouts/application.html.erb + Stylesheet: public/stylesheets/application.css + Helper: app/helpers/layout_helper.rb + + + rails generate nifty:layout admin + + Layout: app/views/layouts/admin.html.erb + Stylesheet: public/stylesheets/admin.css + Helper: app/helpers/layout_helper.rb diff --git a/lib/generators/nifty/layout/layout_generator.rb b/lib/generators/nifty/layout/layout_generator.rb new file mode 100644 index 0000000..fb7f9f4 --- /dev/null +++ b/lib/generators/nifty/layout/layout_generator.rb @@ -0,0 +1,29 @@ +require 'generators/nifty' + +module Nifty + module Generators + class LayoutGenerator < Base + argument :layout_name, :type => :string, :default => 'application', :banner => 'layout_name' + + class_option :haml, :desc => 'Generate HAML for view, and SASS for stylesheet.', :type => :boolean, :default => true + + def create_layout + if options.haml? + template 'layout.html.haml', "app/views/layouts/#{file_name}.html.haml" + copy_file 'stylesheet.sass', "public/stylesheets/sass/#{file_name}.sass" + else + template 'layout.html.erb', "app/views/layouts/#{file_name}.html.erb" + copy_file 'stylesheet.css', "public/stylesheets/#{file_name}.css" + end + copy_file 'layout_helper.rb', 'app/helpers/layout_helper.rb' + copy_file 'error_messages_helper.rb', 'app/helpers/error_messages_helper.rb' + end + + private + + def file_name + layout_name.underscore + end + end + end +end diff --git a/lib/generators/nifty/layout/templates/error_messages_helper.rb b/lib/generators/nifty/layout/templates/error_messages_helper.rb new file mode 100644 index 0000000..8e9c4d3 --- /dev/null +++ b/lib/generators/nifty/layout/templates/error_messages_helper.rb @@ -0,0 +1,23 @@ +module ErrorMessagesHelper + # Render error messages for the given objects. The :message and :header_message options are allowed. + def error_messages_for(*objects) + options = objects.extract_options! + options[:header_message] ||= I18n.t(:"activerecord.errors.header", :default => "Invalid Fields") + options[:message] ||= I18n.t(:"activerecord.errors.message", :default => "Correct the following errors and try again.") + messages = objects.compact.map { |o| o.errors.full_messages }.flatten + unless messages.empty? + content_tag(:div, :class => "error_messages") do + list_items = messages.map { |msg| content_tag(:li, msg.html_safe) } + content_tag(:h2, options[:header_message].html_safe) + content_tag(:p, options[:message].html_safe) + content_tag(:ul, list_items.join.html_safe) + end + end + end + + module FormBuilderAdditions + def error_messages(options = {}) + @template.error_messages_for(@object, options) + end + end +end + +ActionView::Helpers::FormBuilder.send(:include, ErrorMessagesHelper::FormBuilderAdditions) diff --git a/lib/generators/nifty/layout/templates/layout.html.haml b/lib/generators/nifty/layout/templates/layout.html.haml new file mode 100644 index 0000000..24ec1d6 --- /dev/null +++ b/lib/generators/nifty/layout/templates/layout.html.haml @@ -0,0 +1,21 @@ +!!! +%html + + %head + %title + = content_for?(:title) ? yield(:title) : "Untitled" + %meta{"http-equiv"=>"Content-Type", :content=>"text/html; charset=utf-8"}/ + = stylesheet_link_tag "application" + = javascript_include_tag "application" + = csrf_meta_tag + = yield(:head) + + %body + #container + - flash.each do |name, msg| + = content_tag :div, msg, :id => "flash_#{name}" + + - if show_title? + %h1= yield(:title) + + = yield diff --git a/lib/generators/nifty/layout/templates/layout_helper.rb b/lib/generators/nifty/layout/templates/layout_helper.rb new file mode 100644 index 0000000..93011d6 --- /dev/null +++ b/lib/generators/nifty/layout/templates/layout_helper.rb @@ -0,0 +1,38 @@ +# These helper methods can be called in your template to set variables to be used in the layout +# This module should be included in all views globally, +# to do so you may need to add this line to your ApplicationController +# helper :layout +module LayoutHelper + + def title(page_title, show_title = true) + content_for(:title) { strip_tags(page_title.to_s) } + @show_title = show_title + end + + def show_title? + @show_title + end + + def stylesheet(*args) + content_for(:head) { stylesheet_link_tag(*args) } + end + + def javascript(*args) + content_for(:head) { javascript_include_tag(*args) } + end + + def translation_missing?(output) + (output =~ /span/ or output.empty?) + end + + def conditional_hint(translation_key) + output = t(translation_key) + return output unless translation_missing?(output) + false + end + + def conditional_t(translation_key) + output = t(translation_key) + strip_tags(output) + end +end \ No newline at end of file diff --git a/lib/generators/nifty/layout/templates/stylesheet.css b/lib/generators/nifty/layout/templates/stylesheet.css new file mode 100644 index 0000000..448a53f --- /dev/null +++ b/lib/generators/nifty/layout/templates/stylesheet.css @@ -0,0 +1,83 @@ +html, body { + background-color: #4B7399; + font-family: Verdana, Helvetica, Arial; + font-size: 14px; +} + +a img { + border: none; +} + +a { + color: #0000FF; +} + +.clear { + clear: both; + height: 0; + overflow: hidden; +} + +#container { + width: 75%; + margin: 0 auto; + background-color: #FFF; + padding: 20px 40px; + border: solid 1px black; + margin-top: 20px; +} + +#flash_notice, #flash_error, #flash_alert { + padding: 5px 8px; + margin: 10px 0; +} + +#flash_notice { + background-color: #CFC; + border: solid 1px #6C6; +} + +#flash_error, #flash_alert { + background-color: #FCC; + border: solid 1px #C66; +} + +.error_messages { + width: 400px; + border: 2px solid #CF0000; + padding: 0px; + padding-bottom: 12px; + margin-bottom: 20px; + background-color: #f0f0f0; + font-size: 12px; +} + +.error_messages h2 { + text-align: left; + font-weight: bold; + padding: 5px 10px; + font-size: 12px; + margin: 0; + background-color: #c00; + color: #fff; +} + +.error_messages p { + margin: 8px 10px; +} + +.error_messages ul { + margin: 0; +} + +.field_with_errors { + display: inline; +} + +form .field, form .actions { + margin: 10px 0; +} + +form label { + display: block; +} diff --git a/lib/generators/nifty/layout/templates/stylesheet.sass b/lib/generators/nifty/layout/templates/stylesheet.sass new file mode 100644 index 0000000..383bfd3 --- /dev/null +++ b/lib/generators/nifty/layout/templates/stylesheet.sass @@ -0,0 +1,73 @@ +$primary_color: #4b7399 + +body + background-color: $primary_color + font: + family: Verdana, Helvetica, Arial + size: 14px + +a + color: blue + img + border: none + +.clear + clear: both + height: 0 + overflow: hidden + +#container + width: 75% + margin: 0 auto + background: white + padding: 20px 40px + border: solid 1px black + margin-top: 20px + +#flash_notice, +#flash_error, +#flash_alert + padding: 5px 8px + margin: 10px 0 + +#flash_notice + background-color: #ccffcc + border: solid 1px #66cc66 + +#flash_error, +#flash_alert + background-color: #ffcccc + border: solid 1px #cc6666 + +.error_messages + width: 400px + border: 2px solid #cf0000 + padding: 0 + padding-bottom: 12px + margin-bottom: 20px + background-color: #f0f0f0 + font: + size: 12px + h2 + text-align: left + padding: 5px 5px 5px 15px + margin: 0 + font: + weight: bold + size: 12px + background-color: #cc0000 + color: white + p + margin: 8px 10px + ul + margin: 0 + +.field_with_errors + display: inline + +form .field, +form .actions + margin: 10px 0 + +form label + display: block diff --git a/lib/generators/nifty/scaffold/USAGE b/lib/generators/nifty/scaffold/USAGE new file mode 100644 index 0000000..363fd26 --- /dev/null +++ b/lib/generators/nifty/scaffold/USAGE @@ -0,0 +1,51 @@ +Description: + Scaffolds an entire resource, from model and migration to controller and + views. The resource is ready to use as a starting point for your restful, + resource-oriented application. Tests or specs are also generated depending + on if you have a "spec" directory or not. + + IMPORTANT: This generator uses the "title" helper method which is generated + by the nifty_layout generator. You may want to run that generator first. + +Usage: + Pass the name of the model, either CamelCased or under_scored, as the first + argument along with an optional list of attribute pairs and controller actions. + + If no controller actions are specified, they will default to index, show, + new, create, edit, update, and destroy. + + IMPORTANT: If no attribute pairs are specified, no model will be generated. + It will try to determine the attributes from an existing model. + + Attribute pairs are column_name:sql_type arguments specifying the + model's attributes. Timestamps are added by default, so you don't have to + specify them by hand as 'created_at:datetime updated_at:datetime'. + + For example, `nifty:scaffold post name:string content:text hidden:boolean` + gives you a model with those three attributes, a controller that handles + the create/show/update/destroy, forms to create and edit your posts, and + an index that lists them all, as well as a map.resources :posts + declaration in config/routes.rb. + + Adding an "!" in the mix of arguments will invert the passed controller + actions. This will include all 7 controller actitons except the ones + mentioned. This option doesn't affect model attributes. + +Examples: + rails generate nifty:scaffold post + + Will create a controller called "posts" it will contain all seven + CRUD actions along with the views. A model will NOT be created, + instead it will look for an existing model and use those attributes. + + rails generate nifty:scaffold post name:string content:text index new edit + + Will create a Post model and migration file with the name and content + attributes. It will also create a controller with index, new, create, + edit, and update actions. Notice the create and update actions are + added automatically with new and edit. + + rails generate nifty:scaffold post ! show new + + Creates a posts controller (no model) with index, edit, update, and + destroy actions. diff --git a/lib/generators/nifty/scaffold/scaffold_generator.rb b/lib/generators/nifty/scaffold/scaffold_generator.rb new file mode 100644 index 0000000..1283e17 --- /dev/null +++ b/lib/generators/nifty/scaffold/scaffold_generator.rb @@ -0,0 +1,344 @@ +require 'generators/nifty' +require 'rails/generators/migration' +require 'rails/generators/generated_attribute' + +module Nifty + module Generators + class ScaffoldGenerator < Base + include Rails::Generators::Migration + no_tasks { attr_accessor :scaffold_name, :model_attributes, :controller_actions } + + argument :scaffold_name, :type => :string, :required => true, :banner => 'ModelName' + argument :args_for_c_m, :type => :array, :default => [], :banner => 'controller_actions and model:attributes' + + class_option :skip_model, :desc => 'Don\'t generate a model or migration file.', :type => :boolean + class_option :skip_migration, :desc => 'Don\'t generate migration file for model.', :type => :boolean + class_option :skip_timestamps, :desc => 'Don\'t add timestamps to migration file.', :type => :boolean + class_option :skip_controller, :desc => 'Don\'t generate controller, helper, or views.', :type => :boolean + class_option :invert, :desc => 'Generate all controller actions except these mentioned.', :type => :boolean + class_option :namespace_model, :desc => 'If the resource is namespaced, include the model in the namespace.', :type => :boolean + class_option :haml, :desc => 'Generate HAML views instead of ERB.', :type => :boolean, :default => true + + class_option :testunit, :desc => 'Use test/unit for test files.', :group => 'Test framework', :type => :boolean + class_option :rspec, :desc => 'Use RSpec for test files.', :group => 'Test framework', :type => :boolean + class_option :shoulda, :desc => 'Use shoulda for test files.', :group => 'Test framework', :type => :boolean + + def initialize(*args, &block) + super + + print_usage unless scaffold_name.underscore =~ /^[a-z][a-z0-9_\/]+$/ + + @controller_actions = [] + @model_attributes = [] + @skip_model = options.skip_model? + @namespace_model = options.namespace_model? + @invert_actions = options.invert? + + args_for_c_m.each do |arg| + if arg == '!' + @invert_actions = true + elsif arg.include?(':') + @model_attributes << Rails::Generators::GeneratedAttribute.new(*arg.split(':')) + else + @controller_actions << arg + @controller_actions << 'create' if arg == 'new' + @controller_actions << 'update' if arg == 'edit' + end + end + + @controller_actions.uniq! + @model_attributes.uniq! + + if @invert_actions || @controller_actions.empty? + @controller_actions = all_actions - @controller_actions + end + + if @model_attributes.empty? + @skip_model = true # skip model if no attributes + if model_exists? + model_columns_for_attributes.each do |column| + @model_attributes << Rails::Generators::GeneratedAttribute.new(column.name.to_s, column.type.to_s) + end + else + @model_attributes << Rails::Generators::GeneratedAttribute.new('name', 'string') + end + end + end + + def add_gems + # add_gem "mocha", :group => :test + add_gem 'haml' + add_gem 'simple_form' + add_gem 'cancan' + end + + def create_model + unless @skip_model + template 'model.rb', "app/models/#{model_path}.rb" + if test_framework == :rspec + template "tests/rspec/model.rb", "spec/models/#{model_path}_spec.rb" + # FUCK YOU FIXTURES, WE USE FACTORY GIRL. + # template 'fixtures.yml', "spec/fixtures/#{model_path.pluralize}.yml" + else + template "tests/#{test_framework}/model.rb", "test/unit/#{model_path}_test.rb" + template 'fixtures.yml', "test/fixtures/#{model_path.pluralize}.yml" + end + end + end + + def create_migration + unless @skip_model || options.skip_migration? + migration_template 'migration.rb', "db/migrate/create_#{model_path.pluralize.gsub('/', '_')}.rb" + end + end + + def create_controller + unless options.skip_controller? + template 'controller.rb', "app/controllers/#{plural_name}_controller.rb" + + template 'helper.rb', "app/helpers/#{plural_name}_helper.rb" + + controller_actions.each do |action| + if %w[index show new edit].include?(action) # Actions with templates + template "views/#{view_language}/#{action}.html.#{view_language}", "app/views/#{plural_name}/#{action}.html.#{view_language}" + end + end + + # Move the index_core (can't do it on the top.) + template "views/#{view_language}/_index_core.html.#{view_language}", "app/views/#{plural_name}/_index_core.html.#{view_language}" + + + if form_partial? + template "views/#{view_language}/_form.html.#{view_language}", "app/views/#{plural_name}/_form.html.#{view_language}" + template "views/#{view_language}/_form_core.html.#{view_language}", "app/views/#{plural_name}/_form_core.html.#{view_language}" + end + + namespaces = plural_name.split('/') + resource = namespaces.pop + route namespaces.reverse.inject("resources :#{resource}") { |acc, namespace| + "namespace(:#{namespace}){ #{acc} }" + } + + if test_framework == :rspec + template "tests/#{test_framework}/controller.rb", "spec/controllers/#{plural_name}_controller_spec.rb" + else + template "tests/#{test_framework}/controller.rb", "test/functional/#{plural_name}_controller_test.rb" + end + end + end + + def create_locales + template 'locale.yml', "config/locales/views/#{plural_name}/en.yml" + template 'locale_de.yml', "config/locales/views/#{plural_name}/de.yml" + # template 'locale.yml', "config/locales/views/#{plural_name}/es.yml" + # gsub_file("config/locales/views/#{plural_name}/es.yml", 'en:', 'es:') + # gsub_file("config/locales/views/#{plural_name}/de.yml", 'en:', 'de:') + end + + def configuration + gsub_file('config/application.rb', "# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]", + "config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '*', '*', '*.{rb,yml}').to_s]") + end + + private + + def form_partial? + actions? :new, :edit + end + + def all_actions + %w[index show new create edit update destroy] + end + + def action?(name) + controller_actions.include? name.to_s + end + + def actions?(*names) + names.all? { |name| action? name } + end + + def singular_name + scaffold_name.underscore + end + + def plural_name + scaffold_name.underscore.pluralize + end + + def human_name + scaffold_name.humanize + end + + def table_name + if scaffold_name.include?('::') && @namespace_model + plural_name.gsub('/', '_') + end + end + + def class_name + if @namespace_model + scaffold_name.camelize + else + scaffold_name.split('::').last.camelize + end + end + + def model_path + class_name.underscore + end + + def plural_class_name + plural_name.camelize + end + + def instance_name + if @namespace_model + singular_name.gsub('/','_') + else + singular_name.split('/').last + end + end + + def instances_name + instance_name.pluralize + end + + def controller_methods(dir_name) + controller_actions.map do |action| + read_template("#{dir_name}/#{action}.rb") + end.join("\n").strip + end + + def render_form + if form_partial? + if options.haml? + "= render \"form\"" + else + "<%= render \"form\" %>" + end + else + read_template("views/#{view_language}/_form.html.#{view_language}") + end + end + + def item_resource + scaffold_name.underscore.gsub('/','_') + end + + def items_path + if action? :index + "#{item_resource.pluralize}_path" + else + "root_path" + end + end + + def item_path(options = {}) + name = options[:instance_variable] ? "@#{instance_name}" : instance_name + suffix = options[:full_url] ? "url" : "path" + if options[:action].to_s == "new" + "new_#{item_resource}_#{suffix}" + elsif options[:action].to_s == "edit" + "edit_#{item_resource}_#{suffix}(#{name})" + else + if scaffold_name.include?('::') && !@namespace_model + namespace = singular_name.split('/')[0..-2] + "[:#{namespace.join(', :')}, #{name}]" + else + name + end + end + end + + def item_url + if action? :show + item_path(:full_url => true, :instance_variable => true) + else + items_url + end + end + + def items_url + if action? :index + item_resource.pluralize + '_url' + else + "root_url" + end + end + + def item_path_for_spec(suffix = 'path') + if action? :show + "#{item_resource}_#{suffix}(assigns[:#{instance_name}])" + else + if suffix == 'path' + items_path + else + items_url + end + end + end + + def item_path_for_test(suffix = 'path') + if action? :show + "#{item_resource}_#{suffix}(assigns(:#{instance_name}))" + else + if suffix == 'path' + items_path + else + items_url + end + end + end + + def model_columns_for_attributes + class_name.constantize.columns.reject do |column| + column.name.to_s =~ /^(id|created_at|updated_at)$/ + end + end + + def view_language + options.haml? ? 'haml' : 'erb' + end + + def test_framework + return @test_framework if defined?(@test_framework) + if options.testunit? + return @test_framework = :testunit + elsif options.rspec? + return @test_framework = :rspec + elsif options.shoulda? + return @test_framework = :shoulda + else + return @test_framework = default_test_framework + end + end + + def default_test_framework + File.exist?(destination_path("spec")) ? :rspec : :testunit + end + + def model_exists? + File.exist? destination_path("app/models/#{singular_name}.rb") + end + + def read_template(relative_path) + ERB.new(File.read(find_in_source_paths(relative_path)), nil, '-').result(binding) + end + + def destination_path(path) + File.join(destination_root, path) + end + + # FIXME: Should be proxied to ActiveRecord::Generators::Base + # Implement the required interface for Rails::Generators::Migration. + def self.next_migration_number(dirname) #:nodoc: + if ActiveRecord::Base.timestamped_migrations + Time.now.utc.strftime("%Y%m%d%H%M%S") + else + "%.3d" % (current_migration_number(dirname) + 1) + end + end + end + end +end diff --git a/lib/generators/nifty/scaffold/templates/actions/create.rb b/lib/generators/nifty/scaffold/templates/actions/create.rb new file mode 100644 index 0000000..8365f0b --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/actions/create.rb @@ -0,0 +1,8 @@ + def create + @<%= instance_name %> = <%= class_name %>.new(params[:<%= instance_name %>]) + if @<%= instance_name %>.save + redirect_to <%= item_url %>, :notice => t('<%= plural_name %>.controller.successfuly_created') + else + render :new + end + end diff --git a/lib/generators/nifty/scaffold/templates/actions/destroy.rb b/lib/generators/nifty/scaffold/templates/actions/destroy.rb new file mode 100644 index 0000000..8a236e0 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/actions/destroy.rb @@ -0,0 +1,5 @@ + def destroy + @<%= instance_name %> = <%= class_name %>.find(params[:id]) + @<%= instance_name %>.destroy + redirect_to <%= items_url %>, :notice => t('<%= plural_name %>.controller.successfuly_destroyed') + end diff --git a/lib/generators/nifty/scaffold/templates/actions/edit.rb b/lib/generators/nifty/scaffold/templates/actions/edit.rb new file mode 100644 index 0000000..907e928 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/actions/edit.rb @@ -0,0 +1,3 @@ + def edit + @<%= instance_name %> = <%= class_name %>.find(params[:id]) + end diff --git a/lib/generators/nifty/scaffold/templates/actions/index.rb b/lib/generators/nifty/scaffold/templates/actions/index.rb new file mode 100644 index 0000000..0a8420c --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/actions/index.rb @@ -0,0 +1,3 @@ + def index + @<%= instances_name %> = <%= class_name %>.all + end diff --git a/lib/generators/nifty/scaffold/templates/actions/new.rb b/lib/generators/nifty/scaffold/templates/actions/new.rb new file mode 100644 index 0000000..c0991bc --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/actions/new.rb @@ -0,0 +1,3 @@ + def new + @<%= instance_name %> = <%= class_name %>.new + end diff --git a/lib/generators/nifty/scaffold/templates/actions/show.rb b/lib/generators/nifty/scaffold/templates/actions/show.rb new file mode 100644 index 0000000..27a0467 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/actions/show.rb @@ -0,0 +1,3 @@ + def show + @<%= instance_name %> = <%= class_name %>.find(params[:id]) + end diff --git a/lib/generators/nifty/scaffold/templates/actions/update.rb b/lib/generators/nifty/scaffold/templates/actions/update.rb new file mode 100644 index 0000000..a1473a6 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/actions/update.rb @@ -0,0 +1,8 @@ + def update + @<%= instance_name %> = <%= class_name %>.find(params[:id]) + if @<%= instance_name %>.update_attributes(params[:<%= instance_name %>]) + redirect_to <%= item_url %>, :notice => t('<%= plural_name %>.controller.successfuly_updated') + else + render :edit + end + end diff --git a/lib/generators/nifty/scaffold/templates/controller.rb b/lib/generators/nifty/scaffold/templates/controller.rb new file mode 100644 index 0000000..a54de70 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/controller.rb @@ -0,0 +1,3 @@ +class <%= plural_class_name %>Controller < ApplicationController + <%= controller_methods :actions %> +end diff --git a/lib/generators/nifty/scaffold/templates/fixtures.yml b/lib/generators/nifty/scaffold/templates/fixtures.yml new file mode 100644 index 0000000..447eaf9 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/fixtures.yml @@ -0,0 +1,9 @@ +one: +<%- for attribute in model_attributes -%> + <%= attribute.name %>: <%= attribute.default %> +<%- end -%> + +two: +<%- for attribute in model_attributes -%> + <%= attribute.name %>: <%= attribute.default %> +<%- end -%> diff --git a/lib/generators/nifty/scaffold/templates/helper.rb b/lib/generators/nifty/scaffold/templates/helper.rb new file mode 100644 index 0000000..084b485 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/helper.rb @@ -0,0 +1,2 @@ +module <%= plural_class_name %>Helper +end diff --git a/lib/generators/nifty/scaffold/templates/locale.yml b/lib/generators/nifty/scaffold/templates/locale.yml new file mode 100644 index 0000000..46e4ce3 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/locale.yml @@ -0,0 +1,46 @@ +en: + <%= plural_name %>: + name: '<%= human_name %>' + controller: + successfuly_created: 'Successfully created <%= human_name %>.' + successfuly_updated: 'Successfully updated <%= human_name %>.' + successfuly_destroyed: 'Successfully destroyed <%= human_name %>.' + index: + page_title: 'Listing <%= human_name %>' + <%- for attribute in model_attributes -%> + <%= attribute.name %>: '<%= attribute.human_name %>' + <%- end -%> + actions: + confirm: 'Are you sure you want to delete this <%= human_name %>?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New <%= human_name %> for %{resource}' + show: + page_title: 'Show <%= human_name %>' + <%- for attribute in model_attributes -%> + <%= attribute.name %>: '<%= attribute.human_name %>' + <%- end -%> + actions: + confirm: 'Are you sure you want to delete this element?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New <%= human_name %>' + actions: + back_to_list: 'Back to Index' + edit: + page_title: 'Editing <%= human_name %>' + actions: + back_to_list: 'Back to Index' + edit: 'Edit' + view_all: 'View All' + form: + <%- for attribute in model_attributes -%> + <%= attribute.name %>: + label: '<%= attribute.human_name %>' + hint: '' + <%- end -%> + button: 'Submit' \ No newline at end of file diff --git a/lib/generators/nifty/scaffold/templates/locale_de.yml b/lib/generators/nifty/scaffold/templates/locale_de.yml new file mode 100644 index 0000000..027d36d --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/locale_de.yml @@ -0,0 +1,46 @@ +de: + <%= plural_name %>: + name: '<%= human_name %>' + controller: + successfuly_created: '<%= human_name %> wurde angelegt.' + successfuly_updated: '<%= human_name %> wurde aktualisiert.' + successfuly_destroyed: '<%= human_name %> wurde gelöscht.' + index: + page_title: 'Übersicht von <%= human_name %>' + <%- for attribute in model_attributes -%> + <%= attribute.name %>: '<%= attribute.human_name %>' + <%- end -%> + actions: + confirm: 'Sind Sie sicher, dass Sie folgendes löschen möchten: <%= human_name %>' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: '<%= human_name %> neu anlegen für %{resource}' + show: + page_title: '<%= human_name %> bearbeiten' + <%- for attribute in model_attributes -%> + <%= attribute.name %>: '<%= attribute.human_name %>' + <%- end -%> + actions: + confirm: 'Sind Sie sicher, dass die dieses Element löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + new: + page_title: '<%= human_name %> neu anlegen' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: + page_title: '<%= human_name %> bearbeiten' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + form: + <%- for attribute in model_attributes -%> + <%= attribute.name %>: + label: '<%= attribute.human_name %>' + hint: '' + <%- end -%> + button: 'Absenden' \ No newline at end of file diff --git a/lib/generators/nifty/scaffold/templates/migration.rb b/lib/generators/nifty/scaffold/templates/migration.rb new file mode 100644 index 0000000..02fd6bd --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/migration.rb @@ -0,0 +1,16 @@ +class Create<%= class_name.pluralize.delete('::') %> < ActiveRecord::Migration + def self.up + create_table :<%= table_name || plural_name.split('/').last %> do |t| + <%- for attribute in model_attributes -%> + t.<%= attribute.type %> :<%= attribute.name %> + <%- end -%> + <%- unless options[:skip_timestamps] -%> + t.timestamps + <%- end -%> + end + end + + def self.down + drop_table :<%= table_name || plural_name.split('/').last %> + end +end diff --git a/lib/generators/nifty/scaffold/templates/model.rb b/lib/generators/nifty/scaffold/templates/model.rb new file mode 100644 index 0000000..fe5f980 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/model.rb @@ -0,0 +1,4 @@ +class <%= class_name %> < ActiveRecord::Base +<%= " set_table_name :#{table_name}\n" if table_name -%> + attr_accessible <%= model_attributes.map { |a| ":#{a.name}" }.join(", ") %> +end diff --git a/lib/generators/nifty/scaffold/templates/tests/rspec/actions/create.rb b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/create.rb new file mode 100644 index 0000000..ef5a906 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/create.rb @@ -0,0 +1,11 @@ + it "create action should render new template when model is invalid" do + <%= class_name %>.any_instance.stubs(:valid?).returns(false) + post :create + response.should render_template(:new) + end + + it "create action should redirect when model is valid" do + <%= class_name %>.any_instance.stubs(:valid?).returns(true) + post :create + response.should redirect_to(<%= item_path_for_spec('url') %>) + end diff --git a/lib/generators/nifty/scaffold/templates/tests/rspec/actions/destroy.rb b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/destroy.rb new file mode 100644 index 0000000..8372953 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/destroy.rb @@ -0,0 +1,6 @@ + it "destroy action should destroy model and redirect to index action" do + <%= instance_name %> = <%= class_name %>.first + delete :destroy, :id => <%= instance_name %> + response.should redirect_to(<%= items_url %>) + <%= class_name %>.exists?(<%= instance_name %>.id).should be_false + end diff --git a/lib/generators/nifty/scaffold/templates/tests/rspec/actions/edit.rb b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/edit.rb new file mode 100644 index 0000000..e144904 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/edit.rb @@ -0,0 +1,4 @@ + it "edit action should render edit template" do + get :edit, :id => <%= class_name %>.first + response.should render_template(:edit) + end diff --git a/lib/generators/nifty/scaffold/templates/tests/rspec/actions/index.rb b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/index.rb new file mode 100644 index 0000000..a40ea16 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/index.rb @@ -0,0 +1,4 @@ + it "index action should render index template" do + get :index + response.should render_template(:index) + end diff --git a/lib/generators/nifty/scaffold/templates/tests/rspec/actions/new.rb b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/new.rb new file mode 100644 index 0000000..22e1b40 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/new.rb @@ -0,0 +1,4 @@ + it "new action should render new template" do + get :new + response.should render_template(:new) + end diff --git a/lib/generators/nifty/scaffold/templates/tests/rspec/actions/show.rb b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/show.rb new file mode 100644 index 0000000..eaa3d93 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/show.rb @@ -0,0 +1,4 @@ + it "show action should render show template" do + get :show, :id => <%= class_name %>.first + response.should render_template(:show) + end diff --git a/lib/generators/nifty/scaffold/templates/tests/rspec/actions/update.rb b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/update.rb new file mode 100644 index 0000000..c919962 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/rspec/actions/update.rb @@ -0,0 +1,11 @@ + it "update action should render edit template when model is invalid" do + <%= class_name %>.any_instance.stubs(:valid?).returns(false) + put :update, :id => <%= class_name %>.first + response.should render_template(:edit) + end + + it "update action should redirect when model is valid" do + <%= class_name %>.any_instance.stubs(:valid?).returns(true) + put :update, :id => <%= class_name %>.first + response.should redirect_to(<%= item_path_for_spec('url') %>) + end diff --git a/lib/generators/nifty/scaffold/templates/tests/rspec/controller.rb b/lib/generators/nifty/scaffold/templates/tests/rspec/controller.rb new file mode 100644 index 0000000..5d97f63 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/rspec/controller.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe <%= plural_class_name %>Controller do + fixtures :all + render_views + + <%= controller_methods 'tests/rspec/actions' %> +end diff --git a/lib/generators/nifty/scaffold/templates/tests/rspec/model.rb b/lib/generators/nifty/scaffold/templates/tests/rspec/model.rb new file mode 100644 index 0000000..25c3cc4 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/rspec/model.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe <%= class_name %> do + it "should be valid" do + <%= class_name %>.new.should be_valid + end +end diff --git a/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/create.rb b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/create.rb new file mode 100644 index 0000000..f305367 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/create.rb @@ -0,0 +1,13 @@ + context "create action" do + should "render new template when model is invalid" do + <%= class_name %>.any_instance.stubs(:valid?).returns(false) + post :create + assert_template 'new' + end + + should "redirect when model is valid" do + <%= class_name %>.any_instance.stubs(:valid?).returns(true) + post :create + assert_redirected_to <%= item_path_for_test('url') %> + end + end diff --git a/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/destroy.rb b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/destroy.rb new file mode 100644 index 0000000..ea20133 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/destroy.rb @@ -0,0 +1,8 @@ + context "destroy action" do + should "destroy model and redirect to index action" do + <%= instance_name %> = <%= class_name %>.first + delete :destroy, :id => <%= instance_name %> + assert_redirected_to <%= items_url %> + assert !<%= class_name %>.exists?(<%= instance_name %>.id) + end + end diff --git a/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/edit.rb b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/edit.rb new file mode 100644 index 0000000..47597d0 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/edit.rb @@ -0,0 +1,6 @@ + context "edit action" do + should "render edit template" do + get :edit, :id => <%= class_name %>.first + assert_template 'edit' + end + end diff --git a/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/index.rb b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/index.rb new file mode 100644 index 0000000..44b056b --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/index.rb @@ -0,0 +1,6 @@ + context "index action" do + should "render index template" do + get :index + assert_template 'index' + end + end diff --git a/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/new.rb b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/new.rb new file mode 100644 index 0000000..5857a55 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/new.rb @@ -0,0 +1,6 @@ + context "new action" do + should "render new template" do + get :new + assert_template 'new' + end + end diff --git a/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/show.rb b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/show.rb new file mode 100644 index 0000000..75b37f6 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/show.rb @@ -0,0 +1,6 @@ + context "show action" do + should "render show template" do + get :show, :id => <%= class_name %>.first + assert_template 'show' + end + end diff --git a/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/update.rb b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/update.rb new file mode 100644 index 0000000..fc46f72 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/shoulda/actions/update.rb @@ -0,0 +1,13 @@ + context "update action" do + should "render edit template when model is invalid" do + <%= class_name %>.any_instance.stubs(:valid?).returns(false) + put :update, :id => <%= class_name %>.first + assert_template 'edit' + end + + should "redirect when model is valid" do + <%= class_name %>.any_instance.stubs(:valid?).returns(true) + put :update, :id => <%= class_name %>.first + assert_redirected_to <%= item_path_for_test('url') %> + end + end diff --git a/lib/generators/nifty/scaffold/templates/tests/shoulda/controller.rb b/lib/generators/nifty/scaffold/templates/tests/shoulda/controller.rb new file mode 100644 index 0000000..e9f9764 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/shoulda/controller.rb @@ -0,0 +1,5 @@ +require 'test_helper' + +class <%= plural_class_name %>ControllerTest < ActionController::TestCase + <%= controller_methods 'tests/shoulda/actions' %> +end diff --git a/lib/generators/nifty/scaffold/templates/tests/shoulda/model.rb b/lib/generators/nifty/scaffold/templates/tests/shoulda/model.rb new file mode 100644 index 0000000..9065963 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/shoulda/model.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class <%= class_name %>Test < ActiveSupport::TestCase + should "be valid" do + assert <%= class_name %>.new.valid? + end +end diff --git a/lib/generators/nifty/scaffold/templates/tests/testunit/actions/create.rb b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/create.rb new file mode 100644 index 0000000..5a6d2ac --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/create.rb @@ -0,0 +1,11 @@ + def test_create_invalid + <%= class_name %>.any_instance.stubs(:valid?).returns(false) + post :create + assert_template 'new' + end + + def test_create_valid + <%= class_name %>.any_instance.stubs(:valid?).returns(true) + post :create + assert_redirected_to <%= item_path_for_test('url') %> + end diff --git a/lib/generators/nifty/scaffold/templates/tests/testunit/actions/destroy.rb b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/destroy.rb new file mode 100644 index 0000000..adedf91 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/destroy.rb @@ -0,0 +1,6 @@ + def test_destroy + <%= instance_name %> = <%= class_name %>.first + delete :destroy, :id => <%= instance_name %> + assert_redirected_to <%= items_url %> + assert !<%= class_name %>.exists?(<%= instance_name %>.id) + end diff --git a/lib/generators/nifty/scaffold/templates/tests/testunit/actions/edit.rb b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/edit.rb new file mode 100644 index 0000000..55ed24a --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/edit.rb @@ -0,0 +1,4 @@ + def test_edit + get :edit, :id => <%= class_name %>.first + assert_template 'edit' + end diff --git a/lib/generators/nifty/scaffold/templates/tests/testunit/actions/index.rb b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/index.rb new file mode 100644 index 0000000..22d3bad --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/index.rb @@ -0,0 +1,4 @@ + def test_index + get :index + assert_template 'index' + end diff --git a/lib/generators/nifty/scaffold/templates/tests/testunit/actions/new.rb b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/new.rb new file mode 100644 index 0000000..c551327 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/new.rb @@ -0,0 +1,4 @@ + def test_new + get :new + assert_template 'new' + end diff --git a/lib/generators/nifty/scaffold/templates/tests/testunit/actions/show.rb b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/show.rb new file mode 100644 index 0000000..b74f371 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/show.rb @@ -0,0 +1,4 @@ + def test_show + get :show, :id => <%= class_name %>.first + assert_template 'show' + end diff --git a/lib/generators/nifty/scaffold/templates/tests/testunit/actions/update.rb b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/update.rb new file mode 100644 index 0000000..b588bfc --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/testunit/actions/update.rb @@ -0,0 +1,11 @@ + def test_update_invalid + <%= class_name %>.any_instance.stubs(:valid?).returns(false) + put :update, :id => <%= class_name %>.first + assert_template 'edit' + end + + def test_update_valid + <%= class_name %>.any_instance.stubs(:valid?).returns(true) + put :update, :id => <%= class_name %>.first + assert_redirected_to <%= item_path_for_test('url') %> + end diff --git a/lib/generators/nifty/scaffold/templates/tests/testunit/controller.rb b/lib/generators/nifty/scaffold/templates/tests/testunit/controller.rb new file mode 100644 index 0000000..8b99836 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/testunit/controller.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class <%= plural_class_name %>ControllerTest < ActionController::TestCase + setup do + <%= item_path :instance_variable => true %> = <%= plural_name %>(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:<%= plural_name %>) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create <%= item_path %>" do + assert_difference('<%= class_name %>.count') do + post :create, <%= item_path %>: @<%= item_path %>.attributes + end + + assert_redirected_to <%= item_path %>_path(assigns(:<%= item_path %>)) + end + + test "should show <%= item_path %>" do + get :show, id: @<%= item_path %>.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @<%= item_path %>.to_param + assert_response :success + end + + test "should update <%= item_path %>" do + put :update, id: @<%= item_path %>.to_param, <%= item_path %>: @<%= item_path %>.attributes + assert_redirected_to <%= item_path %>_path(assigns(:<%= item_path %>)) + end + + test "should destroy <%= item_path %>" do + assert_difference('<%= class_name %>.count', -1) do + delete :destroy, id: @<%= item_path %>.to_param + end + + assert_redirected_to <%= plural_name %>_path + end +end diff --git a/lib/generators/nifty/scaffold/templates/tests/testunit/model.rb b/lib/generators/nifty/scaffold/templates/tests/testunit/model.rb new file mode 100644 index 0000000..09b835c --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/tests/testunit/model.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class <%= class_name %>Test < ActiveSupport::TestCase + def test_should_be_valid + assert <%= class_name %>.new.valid? + end +end diff --git a/lib/generators/nifty/scaffold/templates/views/haml/_form.html.haml b/lib/generators/nifty/scaffold/templates/views/haml/_form.html.haml new file mode 100644 index 0000000..57cb828 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/views/haml/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for(<%= item_path :instance_variable => true %>) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('<%= plural_name %>.form.submit') \ No newline at end of file diff --git a/lib/generators/nifty/scaffold/templates/views/haml/_form_core.html.haml b/lib/generators/nifty/scaffold/templates/views/haml/_form_core.html.haml new file mode 100644 index 0000000..ca7f253 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/views/haml/_form_core.html.haml @@ -0,0 +1,4 @@ +.inputs +<%- model_attributes.each do |attribute| -%> + = f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %>, :label => t('<%= plural_name %>.form.<%= attribute.name %>.label'), :hint => conditional_hint('<%= plural_name %>.form.<%= attribute.name %>.hint') +<%- end -%> diff --git a/lib/generators/nifty/scaffold/templates/views/haml/_index_core.html.haml b/lib/generators/nifty/scaffold/templates/views/haml/_index_core.html.haml new file mode 100644 index 0000000..9cbea63 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/views/haml/_index_core.html.haml @@ -0,0 +1,13 @@ +%table + %tr + <%- for attribute in model_attributes -%> + %th= t('<%= plural_name %>.index.<%= attribute.name %>') + <%- end -%> + + - reset_cycle + - for <%= instance_name %> in <%= instances_name %> + %tr{:class => cycle('odd', 'even')} + <%- for attribute in model_attributes -%> + %td= <%= instance_name %>.<%= attribute.name %> + <%- end -%> + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:child => <%= instance_name %>} \ No newline at end of file diff --git a/lib/generators/nifty/scaffold/templates/views/haml/edit.html.haml b/lib/generators/nifty/scaffold/templates/views/haml/edit.html.haml new file mode 100644 index 0000000..dc7de62 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/views/haml/edit.html.haml @@ -0,0 +1,3 @@ +- title t("<%= plural_name %>.edit.page_title") + +<%= render_form %> \ No newline at end of file diff --git a/lib/generators/nifty/scaffold/templates/views/haml/index.html.haml b/lib/generators/nifty/scaffold/templates/views/haml/index.html.haml new file mode 100644 index 0000000..86c6b9e --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/views/haml/index.html.haml @@ -0,0 +1,6 @@ +- title t("<%= plural_name %>.index.page_title") + +- if @<%= instances_name %> && @<%= instances_name %>.count > 0 + = render "index_core", :<%= instances_name %> => @<%= instances_name %> + += render :partial => 'shared/create_link', :locals => {:child_class => <%= instances_name.classify %>} \ No newline at end of file diff --git a/lib/generators/nifty/scaffold/templates/views/haml/new.html.haml b/lib/generators/nifty/scaffold/templates/views/haml/new.html.haml new file mode 100644 index 0000000..4e7f871 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/views/haml/new.html.haml @@ -0,0 +1,3 @@ +- title t("<%= plural_name %>.new.page_title") + +<%= render_form %> \ No newline at end of file diff --git a/lib/generators/nifty/scaffold/templates/views/haml/show.html.haml b/lib/generators/nifty/scaffold/templates/views/haml/show.html.haml new file mode 100644 index 0000000..3d01340 --- /dev/null +++ b/lib/generators/nifty/scaffold/templates/views/haml/show.html.haml @@ -0,0 +1,9 @@ +- title t("<%= plural_name %>.show.page_title") + +<%- for attribute in model_attributes -%> +%p + %strong= t('<%= plural_name %>.show.<%= attribute.name %>') + ":" + = @<%= instance_name %>.<%= attribute.name %> +<%- end -%> + += render :partial => 'shared/show_edit_destroy_part', :locals => { :child => @<%= instance_name %> } \ No newline at end of file diff --git a/lib/phone_controllers/snom_phone.rb b/lib/phone_controllers/snom_phone.rb new file mode 100644 index 0000000..9c41e02 --- /dev/null +++ b/lib/phone_controllers/snom_phone.rb @@ -0,0 +1,23 @@ +class SnomPhone + + attr_accessor :phone, :destination_number + + def initialize( attributes = {} ) + @phone = attributes[:phone] + @destination_number = attributes[:destination_number] + end + + def initiate_call + # TODO Initiate a new call to the destination_number. + # Do what ever it takes. + 42 + end + + # persisted is important not to get "undefined method + # `to_key' for" error + # -- Huh? #TODO Add a better description. + def persisted? + false + end + +end diff --git a/lib/tasks/.gitkeep b/lib/tasks/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/lib/tasks/cvs_user_import.rake b/lib/tasks/cvs_user_import.rake new file mode 100644 index 0000000..2475a43 --- /dev/null +++ b/lib/tasks/cvs_user_import.rake @@ -0,0 +1,331 @@ +namespace :user_import do + desc "Import users from a CSV file." + task :csv => :environment do + require 'csv' + require 'digest/md5' + + # Example CSV format in the file: + # UserName,LastName,FirstName,AcademicTitel,PhoneOffice,VoipNr1,VoipNr2,VoipNr3,VoipTelco,CellPhone,HardFax,SoftFax,Email,PIN + # 123456,Mustermann,Max,Dr.,+49 123 1001234,20,21,22,23,+49 160 12345678,+49 123 1001238,29,max.mustermann@example.com,1324 + + # A generic hook to manipulate each given phone number with Ruby tools. + # + def regex_convert_phone_numbers(phone_number = nil) + if phone_number.class == String && !phone_number.blank? + # 123 Example + # + # if !phone_number.match(/^123(..)$/).nil? + # phone_number = phone_number.gsub(/^123(..)$/,'123'+$1) + # end + end + + phone_number + end + + # Read the CSV data and store them in the new_users hash. + # + csv_data = CSV.read(IMPORT_CSV_FILE, encoding: IMPORT_CSV_ENCODING) + headers = csv_data.shift.map {|i| i.to_s } + string_data = csv_data.map {|row| row.map {|cell| cell.to_s } } + new_users = string_data.map {|row| Hash[*headers.zip(row).flatten] } + gs_node_id = GsNode.where(:ip_address => HOMEBASE_IP_ADDRESS).first.try(:id) + + if File.exists?(DOUBLE_CHECK_POSITIVE_USERS_CSV) + csv_data = CSV.read(DOUBLE_CHECK_POSITIVE_USERS_CSV, encoding: IMPORT_CSV_ENCODING) + if csv_data.blank? + double_checked_user_names = [] + else + headers = csv_data.shift.map {|i| i.to_s } + string_data = csv_data.map {|row| row.map {|cell| cell.to_s } } + double_check_positiv_users = string_data.map {|row| Hash[*headers.zip(row).flatten] } + + double_checked_user_names = double_check_positiv_users.map{|user| user['UserName']} + end + else + double_checked_user_names = new_users.map{|user| user['UserName']} + end + + tenant = Tenant.find(DEFAULT_API_TENANT_ID) + + # Destroy deleted user by making a diff of where(:importer_checksum) + # and users in the CSV file. + # + if defined?(USER_NAME_PREFIX) && !USER_NAME_PREFIX.blank? + new_users_user_names = new_users.map{|x| USER_NAME_PREFIX.to_s + x['UserName'].to_s} + else + new_users_user_names = new_users.map{|x| x['UserName']} + end + csv_imported_user_names_in_the_database = User.where('importer_checksum != ?', '').pluck(:user_name) + + + to_be_destroyed_user_names = csv_imported_user_names_in_the_database - new_users_user_names + + User.where(:user_name => to_be_destroyed_user_names, :gs_node_id => gs_node_id).destroy_all + + # Loop through all entries in the CSV file. + # + new_users.each do |csv_user| + if !(csv_user['UserName'].blank? || csv_user['Email'].blank?) && double_checked_user_names.include?(csv_user['UserName']) + csv_user['Email'] = csv_user['Email'].downcase + if defined?(USER_NAME_PREFIX) && !USER_NAME_PREFIX.blank? + csv_user['UserName'] = USER_NAME_PREFIX.to_s + csv_user['UserName'] + end + + md5_sum = Digest::MD5.hexdigest(csv_user.to_yaml) + user = nil + + # Check if this user already exists and has a changed checksum. + # + if tenant.users.where(:user_name => csv_user['UserName']).first.try(:importer_checksum).to_s != md5_sum.to_s + # Find or create the user + # + if tenant.users.where(:user_name => csv_user['UserName']).count > 0 + user = tenant.users.where(:user_name => csv_user['UserName']).first + if defined? IMPORT_IGNORE_PIN_ON_UPDATE && IMPORT_IGNORE_PIN_ON_UPDATE == true + user.update_attributes( + :last_name => csv_user['LastName'], + :first_name => csv_user['FirstName'], + :email => csv_user['Email'], + :importer_checksum => md5_sum, + :gs_node_id => gs_node_id, + ) + else + user.update_attributes( + :last_name => csv_user['LastName'], + :first_name => csv_user['FirstName'], + :email => csv_user['Email'], + :new_pin => csv_user['PIN'], + :new_pin_confirmation => csv_user['PIN'], + :password => csv_user['PIN'], + :password_confirmation => csv_user['PIN'], + :importer_checksum => md5_sum, + :gs_node_id => gs_node_id, + ) + end + else + if csv_user['PIN'].blank? + csv_user['PIN'] = (1..6).map{|i| (0 .. 9).to_a.sample}.join + end + user = tenant.users.create( + :user_name => csv_user['UserName'], + :last_name => csv_user['LastName'], + :first_name => csv_user['FirstName'], + :email => csv_user['Email'], + :new_pin => csv_user['PIN'], + :new_pin_confirmation => csv_user['PIN'], + :password => csv_user['PIN'], + :password_confirmation => csv_user['PIN'], + :language_id => tenant.language_id, + :importer_checksum => md5_sum, + :gs_node_id => gs_node_id, + :send_voicemail_as_email_attachment => true, + ) + end + + # Create group membership + if tenant.user_groups.exists?(:name => 'Users') + tenant.user_groups.where(:name => 'Users').first.user_group_memberships.create(:user => user) + end + end + + if user + # Find or create a sip_accounts + ['VoipNr1', 'VoipNr2', 'VoipNr3'].each_with_index do |phone_number_type, index| + + if index > 0 + auth_name = "#{csv_user['UserName']}_#{index}" + else + auth_name = csv_user['UserName'].to_s + end + + if !phone_number_type.blank? && !csv_user[phone_number_type].blank? + sip_account = user.sip_accounts.where(:auth_name => auth_name).first + if sip_account + if sip_account.caller_name.to_s != user.to_s + sip_account.update_attributes(:caller_name => user.to_s) + end + else + sip_account = user.sip_accounts.create( + :caller_name => user.to_s, + :voicemail_pin => csv_user['PIN'], + :auth_name => auth_name, + :password => csv_user['PIN'], + :clip => true, + :hotdeskable => true, + :callforward_rules_act_per_sip_account => true, + :gs_node_id => gs_node_id, + ) + end + + phone_numbers = Array.new() + phone_numbers.push(csv_user[phone_number_type].to_s.gsub(/[^0-9\+]/, '')) + + # Find or create phone numbers + converted_phone_number = regex_convert_phone_numbers(csv_user[phone_number_type]) + if converted_phone_number != csv_user[phone_number_type] + phone_numbers.push(converted_phone_number.gsub(/[^0-9\+]/, '')) + end + phone_numbers_count = sip_account.phone_numbers.count + phone_numbers.each do |phone_number_number| + phone_number = sip_account.phone_numbers.where(:number => phone_number_number).first + if !phone_number + phone_number = sip_account.phone_numbers.create(:number => phone_number_number, :gs_node_id => gs_node_id) + end + end + + # Create default call forwarding entries + if phone_numbers_count < sip_account.phone_numbers.count + call_forward_case_offline = CallForwardCase.find_by_value('offline') + if call_forward_case_offline + sip_account.phone_numbers.first.call_forwards.create(:call_forward_case_id => call_forward_case_offline.id, :call_forwardable_type => 'Voicemail', :active => true, :depth => DEFAULT_CALL_FORWARD_DEPTH) + end + end + else + user.sip_accounts.where(:auth_name => auth_name).destroy_all + end + end + + if !csv_user['SoftFax'].blank? + phone_numbers = Array.new() + phone_numbers.push(csv_user['SoftFax'].to_s.gsub(/[^0-9\+]/, '')) + converted_phone_number = regex_convert_phone_numbers(csv_user['SoftFax']) + if converted_phone_number != csv_user['SoftFax'] + phone_numbers.push(converted_phone_number.gsub(/[^0-9\+]/, '')) + end + + fax_account = user.fax_accounts.first + if fax_account + if fax_account.name != user.to_s || fax_account.email != user.email + fax_account.update_attributes(:name => user.to_s, :email => user.email) + end + else + fax_account = user.fax_accounts.create( + :name => user.to_s, + :station_id => converted_phone_number.gsub(/[^0-9\+]/,''), + :email => user.email, + :days_till_auto_delete => 90, + :retries => 3, + ) + end + + if fax_account + fax_account.phone_numbers.each do |phone_number| + if !phone_numbers.include?(phone_number.number) + phone_number.delete + end + end + phone_numbers.each do |phone_number_number| + phone_number = fax_account.phone_numbers.where(:number => phone_number_number).first + if !phone_number + phone_number = fax_account.phone_numbers.create(:number => phone_number_number) + end + end + end + else + user.fax_accounts.destroy_all + end + + if !csv_user['HardFax'].blank? + phone_numbers = Array.new() + phone_numbers.push(csv_user['HardFax'].to_s.gsub(/[^0-9\+]/, '')) + converted_phone_number = regex_convert_phone_numbers(csv_user['HardFax']) + if converted_phone_number != csv_user['HardFax'] + phone_numbers.push(converted_phone_number.gsub(/[^0-9\+]/, '')) + end + + # Create a sip_account for a hardware fax. + # + fax_sip_account = user.sip_accounts.where(:description => 'Hardware-Fax').first + if fax_sip_account + if fax_sip_account.caller_name != "Hardware Fax of #{user.to_s}" + fax_sip_account.update_attributes(:caller_name => "Hardware Fax of #{user.to_s}") + end + else + fax_sip_account = user.sip_accounts.create( + :caller_name => "Hardware Fax of #{user.to_s}", + :description => 'Hardware-Fax', + :auth_name => 'HARDFAX' + csv_user['UserName'], + :password => csv_user['PIN'], + :clip => true, + :hotdeskable => false, + :callforward_rules_act_per_sip_account => true, + :gs_node_id => gs_node_id, + ) + end + + if fax_sip_account + fax_sip_account.phone_numbers.each do |phone_number| + if !phone_numbers.include?(phone_number.number) + phone_number.delete + end + end + phone_numbers.each do |phone_number_number| + phone_number = fax_sip_account.phone_numbers.where(:number => phone_number_number).first + if !phone_number + phone_number = fax_sip_account.phone_numbers.create(:number => phone_number_number) + end + end + end + else + user.sip_accounts.where(:description => 'Hardware-Fax').destroy_all + end + + if !csv_user['VoipTelco'].blank? + conference = user.conferences.first + if conference.nil? + # Create a conference room for this user. + # + conference = user.conferences.build + conference.name = "Default Conference for #{user.to_s}" + conference.start = nil + conference.end = nil + conference.open_for_anybody = true + conference.max_members = DEFAULT_MAX_CONFERENCE_MEMBERS + conference.pin = (1..MINIMUM_PIN_LENGTH).map{|i| (0 .. 9).to_a.sample}.join + conference.save + end + + phone_numbers = Array.new() + phone_numbers.push(csv_user['VoipTelco'].to_s.gsub(/[^0-9\+]/, '')) + converted_phone_number = regex_convert_phone_numbers(csv_user['VoipTelco']) + if converted_phone_number != csv_user['VoipTelco'] + phone_numbers.push(converted_phone_number.gsub(/[^0-9\+]/, '')) + end + + if conference + conference.phone_numbers.each do |phone_number| + if !phone_numbers.include?(phone_number.number) + phone_number.delete + end + end + phone_numbers.each do |phone_number_number| + phone_number = conference.phone_numbers.where(:number => phone_number_number).first + if !phone_number + phone_number = conference.phone_numbers.create(:number => phone_number_number) + end + end + end + else + user.conferences.destroy_all + end + + # Create Whitelist Entry for default Callthrough + # + cell_phone_number = csv_user['CellPhone'].to_s.gsub(/[^0-9\+]/, '') + + if !cell_phone_number.blank? + callthrough = tenant.callthroughs.find_or_create_by_name(CALLTHROUGH_NAME_TO_BE_USED_FOR_DEFAULT_ACTIVATION) + + access_authorization = callthrough.access_authorizations.find_or_create_by_name('Cellphones') + + new_phone_number = access_authorization.phone_numbers.find_or_create_by_number(cell_phone_number, :name => user.to_s, :access_authorization_user_id => user.id) + end + end + else + # puts "#{csv_user['UserName']} (#{csv_user['Email']}) has not changed." + end + end + + + end +end \ No newline at end of file diff --git a/lib/tasks/fax.rake b/lib/tasks/fax.rake new file mode 100644 index 0000000..1f1c282 --- /dev/null +++ b/lib/tasks/fax.rake @@ -0,0 +1,74 @@ +# encoding: UTF-8 + +desc "Import inbound fax" + +task :import_inbound_fax, [ + :fax_account_id, + :result_code, + :document_total_pages, + :document_transferred_pages, + :ecm_requested, + :ecm_used, + :image_resolution, + :remote_station_id, + :transfer_rate, + :transmission_time, + :document, + :caller_id_number, + :caller_id_name, + ] => :environment do |t, a| + + TIFF_FUFFIX = ".tiff" + PDF_SUFFIX = ".pdf" + + fax_arguments = a.to_hash + + tiff_file = fax_arguments[:document] + + if !tiff_file or !File.exists?( tiff_file ) + $stderr.puts "File \"#{tiff_file}\" does not exist" + exit 1 + end + + paper_size = "letter" + pdf_file = "#{File.dirname(tiff_file)}/#{File.basename(tiff_file, TIFF_FUFFIX)}#{PDF_SUFFIX}" + + system "tiff2pdf \\ + -o \"#{pdf_file}\" \\ + -p #{paper_size} \\ + -a \"#{fax_arguments[:remote_station_id]}\" \\ + -c \"AMOOMA Gemeinschaft version #{GEMEINSCHAFT_VERSION}\" \\ + -t \"#{fax_arguments[:remote_station_id]}\" \"#{tiff_file}\"" + + if !File.exists?( pdf_file ) + $stderr.puts "File \"#{pdf_file}\" does not exist" + exit 1 + end + + fax_account = FaxAccount.find(fax_arguments[:fax_account_id]) + if !fax_account + $stderr.puts "Fax account \"#{fax_arguments[:fax_account_id]}\" does not exist" + exit 1 + end + + fax_arguments[:document] = nil + fax_arguments[:success] = true + fax_arguments[:inbound] = true + fax_arguments[:sent_at] = Time.now + fax_arguments[:local_station_id] = fax_account.station_id + fax_arguments[:retry_counter] = 0 + fax_arguments[:fax_resolution_id] = FaxResolution.first.id + fax_arguments[:image_size] = File.size(tiff_file) + fax_arguments[:ecm_used] = fax_arguments[:ecm_used] == "on" ? true : false + fax_document = fax_account.fax_documents.build(fax_arguments) + fax_document.document = File.open(pdf_file) + + if fax_document.save + fax_document.mark_as_inbound! + exit 0 + else + $stderr.puts "Error(s) creating fax document:" + $stderr.puts fax_document.errors.inspect + exit 1 + end +end diff --git a/lib/tasks/gs_cluster.rake b/lib/tasks/gs_cluster.rake new file mode 100644 index 0000000..565fd83 --- /dev/null +++ b/lib/tasks/gs_cluster.rake @@ -0,0 +1,333 @@ +namespace :gs_cluster do + desc "Sync local data to other gs cluster nodes." + task :push_waiting_data_to_other_nodes => :environment do + infinity_loop_protection_counter = GsClusterSyncLogEntry.where(:homebase_ip_address => HOMEBASE_IP_ADDRESS, + :waiting_to_be_synced => true).count + 10 + + # One bite at a time. + # + while GsClusterSyncLogEntry.where(:homebase_ip_address => HOMEBASE_IP_ADDRESS, + :waiting_to_be_synced => true).any? && + infinity_loop_protection_counter > 0 + GsClusterSyncLogEntry.where(:homebase_ip_address => HOMEBASE_IP_ADDRESS, + :waiting_to_be_synced => true).first.populate_other_cluster_nodes + infinity_loop_protection_counter -= 1 + end + + end + + desc "Reset gs_cluster_sync_log." + task :reset_sync_log => :environment do + GsClusterSyncLogEntry.destroy_all + + User.where('is_native IS NOT FALSE').each do |user| + puts("Processing User=#{user.id}/#{user.uuid} - #{user.user_name}") + user.create_on_other_gs_nodes + end + + SipAccount.where('is_native IS NOT FALSE').each do |sip_account| + puts("Processing SipAccount=#{sip_account.id}/#{sip_account.uuid} - #{sip_account.auth_name}"); + sip_account.create_on_other_gs_nodes + end + + PhoneNumber.where('is_native IS NOT FALSE AND phone_numberable_type IN ("SipAccount", "Conference", "FaxAccount", "Callthrough", "HuntGroup", "AutomaticCallDistributor")').each do |phone_number| + puts("Processing PhoneNumber=#{phone_number.id}/#{phone_number.uuid} - #{phone_number.number}"); + phone_number.create_on_other_gs_nodes + end + end + + desc "Pull objects from nodes." + task :pull => :environment do + local_node = GsNode.where(:ip_address => HOMEBASE_IP_ADDRESS).first + GsNode.where(:accepts_updates_from => true).each do |remote_node| + if remote_node.id == local_node.id + next + end + + puts "Processing node: #{remote_node.name}" + pull_node(remote_node, local_node) + end + end + + def pull_node(remote_node, local_node) + require 'nokogiri' + require 'open-uri' + + is_native = false + remote_site = remote_node.site + local_node_id = local_node.id + last_sync = remote_node.last_sync.to_i + + remote_objects(remote_site, local_node_id, last_sync, Tenant).each do |tenant| + puts "Processing Tenant: #{tenant[:name]}" + end + + remote_objects(remote_site, local_node_id, last_sync, UserGroup).each do |remote_object| + attributes = make_hash(remote_object.attributes) + tenant = Tenant.where(:name => attributes[:tenant]).first + process_object(UserGroup, tenant.user_groups, UserGroup.where(:name => attributes[:name], :tenant_id => tenant.try(:id)).first, attributes) + end + + remote_objects(remote_site, local_node_id, last_sync, User).each do |remote_object| + attributes = make_hash(remote_object.attributes) + + tenant = Tenant.where(:name => attributes[:current_tenant]).first + attributes[:language_id] = Language.where(:code => attributes[:language]).first.try(:id) + attributes.delete(:language) + attributes.delete(:current_tenant) + + if tenant + if ! attributes[:gs_node].blank? + attributes[:gs_node_id] = GsNode.where(:name => attributes[:gs_node]).first.try(:id) + attributes.delete(:gs_node) + end + + process_object(User, tenant.users, User.where(:uuid => attributes[:uuid]).first, attributes, { :is_native => is_native }) + else + $stderr.puts "NO_PROCESSING User #{attributes[:uuid]} - no current tenant" + end + end + + remote_objects(remote_site, local_node_id, last_sync, UserGroupMembership).each do |remote_object| + attributes = make_hash(remote_object.attributes) + attributes[:user_id] = User.where(:uuid => attributes[:user_uuid]).first.try(:id) + attributes[:user_group_id] = UserGroup.where(:name => attributes[:user_group]).first.try(:id) + attributes.delete(:user_uuid) + attributes.delete(:user_group) + + if attributes[:user_id] && attributes[:user_group_id] + process_object(UserGroupMembership, UserGroupMembership, UserGroupMembership.where(:user_id => attributes[:user_id], :user_group_id => attributes[:user_group_id]).first, attributes) + end + end + + remote_objects(remote_site, local_node_id, last_sync, SipAccount).each do |remote_object| + attributes = make_hash(remote_object.attributes) + attributes[:tenant_id] = Tenant.where(:name => attributes[:tenant]).first.try(:id) + attributes[:sip_domain] = SipDomain.where(:host => attributes[:sip_domain]).first + + if ! attributes[:sip_accountable_uuid].blank? + attributes[:sip_accountable_id] = attributes[:sip_accountable_type].constantize.where(:uuid => attributes[:sip_accountable_uuid]).first.try(:id) + end + + if attributes[:sip_accountable_id] + if ! attributes[:gs_node].blank? + attributes[:gs_node_id] = GsNode.where(:name => attributes[:gs_node]).first.try(:id) + attributes.delete(:gs_node) + end + + attributes.delete(:sip_accountable_uuid) + attributes.delete(:tenant) + process_object(SipAccount, SipAccount, SipAccount.where(:uuid => attributes[:uuid]).first, attributes, { :is_native => is_native }) + end + end + + remote_objects(remote_site, local_node_id, last_sync, Conference).each do |remote_object| + attributes = make_hash(remote_object.attributes) + + if ! attributes[:conferenceable_uuid].blank? + attributes[:conferenceable_id] = attributes[:conferenceable_type].constantize.where(:uuid => attributes[:conferenceable_uuid]).first.try(:id) + end + attributes.delete(:conferenceable_uuid) + + process_object(Conference, Conference, Conference.where(:uuid => attributes[:uuid]).first, attributes) + end + + remote_objects(remote_site, local_node_id, last_sync, FaxAccount).each do |remote_object| + attributes = make_hash(remote_object.attributes) + attributes[:tenant_id] = Tenant.where(:name => attributes[:tenant]).first.try(:id) + if ! attributes[:fax_accountable_uuid].blank? + attributes[:fax_accountable_id] = attributes[:fax_accountable_type].constantize.where(:uuid => attributes[:fax_accountable_uuid]).first.try(:id) + end + attributes.delete(:fax_accountable_uuid) + attributes.delete(:tenant) + process_object(FaxAccount, FaxAccount, FaxAccount.where(:uuid => attributes[:uuid]).first, attributes) + end + + remote_objects(remote_site, local_node_id, last_sync, PhoneBook).each do |remote_object| + attributes = make_hash(remote_object.attributes) + + if ! attributes[:phone_bookable_uuid].blank? + attributes[:phone_bookable_id] = attributes[:phone_bookable_type].constantize.where(:uuid => attributes[:phone_bookable_uuid]).first.try(:id) + end + attributes.delete(:phone_bookable_uuid) + process_object(PhoneBook, PhoneBook, PhoneBook.where(:uuid => attributes[:uuid]).first, attributes) + end + + remote_objects(remote_site, local_node_id, last_sync, PhoneBookEntry).each do |remote_object| + attributes = make_hash(remote_object.attributes) + attributes[:phone_book_id] = PhoneBook.where(:uuid => attributes[:phone_book_uuid]).first.try(:id) + attributes.delete(:phone_book_uuid) + process_object(PhoneBookEntry, PhoneBookEntry, PhoneBookEntry.where(:uuid => attributes[:uuid]).first, attributes) + end + + remote_objects(remote_site, local_node_id, last_sync, PhoneNumber).each do |remote_object| + attributes = make_hash(remote_object.attributes) + + if ! attributes[:phone_numberable_uuid].blank? + attributes[:phone_numberable_id] = attributes[:phone_numberable_type].constantize.where(:uuid => attributes[:phone_numberable_uuid]).first.try(:id) + end + + if ! attributes[:gs_node].blank? + attributes[:gs_node_id] = GsNode.where(:name => attributes[:gs_node]).first.try(:id) + attributes.delete(:gs_node) + end + + if !attributes[:phone_numberable_id] + puts "WARNING PhoneNumber #{attributes[:number]} has no local parent object #{attributes[:phone_numberable_type]}/#{attributes[:phone_numberable_uuid]}" + end + + attributes.delete(:phone_numberable_uuid) + process_object(PhoneNumber, PhoneNumber, PhoneNumber.where(:uuid => attributes[:uuid]).first, attributes, { :is_native => is_native }) + end + + remote_objects(remote_site, local_node_id, last_sync, CallForward).each do |remote_object| + attributes = make_hash(remote_object.attributes) + + attributes[:phone_number_id] = PhoneNumber.where(:uuid => attributes[:phone_number_uuid]).first.try(:id) + + if ! attributes[:call_forwardable_uuid].blank? + attributes[:call_forwardable_id] = attributes[:call_forwardable_type].constantize.where(:uuid => attributes[:call_forwardable_uuid]).first.try(:id) + attributes.delete(:call_forwardable_uuid) + end + + attributes[:call_forward_case_id] = CallForwardCase.where(:value => attributes[:service]).first.try(:id) + + attributes.delete(:phone_number_uuid) + attributes.delete(:service) + + process_object(CallForward, CallForward, CallForward.where(:uuid => attributes[:uuid]).first, attributes) + end + + remote_objects(remote_site, local_node_id, last_sync, Softkey).each do |remote_object| + attributes = make_hash(remote_object.attributes) + attributes[:sip_account_id] = SipAccount.where(:uuid => attributes[:sip_account_uuid]).first.try(:id) + attributes[:call_forward_id] = CallForward.where(:uuid => attributes[:call_forward_uuid]).first.try(:id) + attributes[:softkey_function_id] = SoftkeyFunction.where(:name => attributes[:function]).first.try(:id) + attributes.delete(:sip_account_uuid) + attributes.delete(:call_forward_uuid) + attributes.delete(:softkey_function) + process_object(Softkey, Softkey, Softkey.where(:uuid => attributes[:uuid]).first, attributes) + end + + remote_objects(remote_site, local_node_id, last_sync, Ringtone).each do |remote_object| + attributes = make_hash(remote_object.attributes) + if ! attributes[:ringtoneable_uuid].blank? + attributes[:ringtoneable_id] = attributes[:ringtoneable_type].constantize.where(:uuid => attributes[:ringtoneable_uuid]).first.try(:id) + end + + if !attributes[:ringtoneable_id] + puts "WARNING Ringtone #{attributes[:number]} has no local parent object #{attributes[:ringtoneable_type]}/#{attributes[:ringtoneable_uuid]}" + else + attributes.delete(:ringtoneable_uuid) + process_object(Ringtone, Ringtone, Ringtone.where(:ringtoneable_type => attributes[:ringtoneable_type], :ringtoneable_id => attributes[:ringtoneable_id]).first, attributes) + end + end + + remote_objects(remote_site, local_node_id, last_sync, ConferenceInvitee).each do |remote_object| + attributes = make_hash(remote_object.attributes) + attributes[:conference_id] = Conference.where(:uuid => attributes[:conference_uuid]).first.try(:id) + attributes[:phone_number] = PhoneNumber.where(:uuid => attributes[:phone_number_uuid]).first + if !attributes[:conference_id] + puts "WARNING ConferenceInvitee #{attributes[:uuid]} has no local Conference object #{attributes[:conference_uuid]}" + else + attributes[:phone_book_entry_id] = PhoneBookEntry.where(:uuid => attributes[:phone_book_entry_uuid]).first.try(:id) + attributes.delete(:conference_uuid) + attributes.delete(:phone_number_uuid) + attributes.delete(:phone_book_entry_uuid) + process_object(ConferenceInvitee, ConferenceInvitee, ConferenceInvitee.where(:uuid => attributes[:uuid]).first, attributes) + end + end + + #remote_objects(remote_site, local_node_id, last_sync, FaxDocument).each do |remote_object| + # attributes = make_hash(remote_object.attributes) + # attributes[:fax_account_id] = FaxAccount.where(:uuid => attributes[:fax_account_uuid]).first.try(:id) + # attributes[:fax_resolution_id] = FaxResolution.where(:resolution_value => attributes[:fax_resolution]).first.try(:id) + # attributes.delete(:fax_account_uuid) + # attributes.delete(:fax_resolution) + # process_object(FaxDocument, FaxDocument, FaxDocument.where(:uuid => attributes[:uuid]).first, attributes) + #end + + #remote_objects(remote_site, local_node_id, last_sync, CallHistory).each do |remote_object| + # attributes = make_hash(remote_object.attributes) + # process_object(CallHistory, CallHistory, CallHistory.where(:caller_channel_uuid => attributes[:caller_channel_uuid], :call_historyable_type => attributes[:caller_channel_type], :call_historyable_id => call_historyable.try(:id)).first, attributes) + #end + + remote_objects(remote_site, local_node_id, last_sync, DeletedItem).each do |remote_object| + attributes = make_hash(remote_object.attributes) + deleted_item = remote_object[:class_name].constantize.where(:uuid => attributes[:uuid]).first + + if deleted_item + print "DELETE #{deleted_item.class.to_s} #{deleted_item.to_s} : " + + if deleted_item.destroy + puts "OK" + else + $stderr.puts "Couldn't delete #{deleted_item.class.to_s}. #{deleted_item.errors.inspect}" + end + else + puts "NO_DELETE #{remote_object[:class_name]} #{remote_object[:uuid]}" + end + end + + if ! remote_node.synced + $stderr.puts "Errors updating node #{remote_node.name}. #{remote_node.errors.inspect}" + end + end + + def make_hash(attributes, new_hash = Hash.new) + attributes.each do |key, value| + new_hash[key.to_sym] = value.to_s + end + return new_hash + end + + def remote_objects(remote_site, local_node_id, last_sync, object_class) + class_name = object_class.to_s.underscore + section_name = class_name.pluralize + doc = Nokogiri::XML(open("#{remote_site}/gs_nodes/#{local_node_id}/sync.xml?newer=#{last_sync}&image=false&class=#{section_name}", :proxy => nil, :read_timeout => 120)) + return doc.xpath("//gemeinschaft_sync/#{section_name}/#{class_name}") + end + + def process_object(object_class, belongs_to, local_object, attributes, local_attributes = Hash.new) + if local_object + if local_object.updated_at < attributes[:updated_at] + print "UPDATE #{object_class.to_s} #{local_object.to_s} : " + update_object(local_object, attributes, local_attributes) + else + print "NO_UPDATE #{object_class.to_s}: #{local_object.to_s} - last update: #{local_object.updated_at}, remote: #{attributes[:updated_at]}" + end + else + print "CREATE #{object_class.to_s} #{attributes[:name].to_s} #{attributes[:uuid].to_s} : " + create_object(belongs_to, attributes, local_attributes) + end + puts "." + end + + def create_object(object_class, attributes, local_attributes) + attributes = attributes.merge(local_attributes) + + new_local_copy = object_class.create(attributes, :without_protection => true) + if new_local_copy && new_local_copy.errors.count == 0 + print "Created object, #{new_local_copy.class.to_s} #{new_local_copy.to_s}" + return true + else + $stderr.print "Couldn't create object. #{new_local_copy.errors.messages.inspect}" + return false + end + end + + def update_object(local_object, attributes, local_attributes) + attributes = attributes.merge(local_attributes) + + if local_object.update_attributes(attributes, :without_protection => true) + print "Updated #{local_object.class.to_s}, ID #{local_object.id}." + return true + else + $stderr.print "Couldn't update UserGroup. #{local_user_group.errors.inspect}" + return true + end + end + + class DeletedItem + end +end diff --git a/lib/tasks/originate.rake b/lib/tasks/originate.rake new file mode 100644 index 0000000..5e7dfe3 --- /dev/null +++ b/lib/tasks/originate.rake @@ -0,0 +1,13 @@ +desc "Originate call" + +task :originate, [ + :sip_account_id, + :extension, + ] => :environment do |t, a| + + extension = a.extension.to_s + sip_account = SipAccount.where(:id => a.sip_account_id.to_i).first + + print "Originate #{sip_account} -> #{extension} ... " + puts sip_account.call(extension) +end \ No newline at end of file diff --git a/lib/tasks/populate_area_codes_de.rake b/lib/tasks/populate_area_codes_de.rake new file mode 100644 index 0000000..7237f5d --- /dev/null +++ b/lib/tasks/populate_area_codes_de.rake @@ -0,0 +1,5211 @@ +# encoding: UTF-8 + +desc "Populate database with German area codes" +task :areacodes_germany => :environment do + if ! germany = Country.where( :name => 'Germany' ).first + $stderr.puts "Error. Country not found." + exit 1 + end + + AreaCode.create(:country => germany, :name => "Essen", :area_code => "201") + AreaCode.create(:country => germany, :name => "Wuppertal", :area_code => "202") + AreaCode.create(:country => germany, :name => "Duisburg", :area_code => "203") + AreaCode.create(:country => germany, :name => "Bottrop", :area_code => "2041") + AreaCode.create(:country => germany, :name => "Gladbeck", :area_code => "2043") + AreaCode.create(:country => germany, :name => "Bottrop-Kirchhellen", :area_code => "2045") + AreaCode.create(:country => germany, :name => "Velbert", :area_code => "2051") + AreaCode.create(:country => germany, :name => "Velbert-Langenberg", :area_code => "2052") + AreaCode.create(:country => germany, :name => "Velbert-Neviges", :area_code => "2053") + AreaCode.create(:country => germany, :name => "Essen-Kettwig", :area_code => "2054") + AreaCode.create(:country => germany, :name => "Heiligenhaus", :area_code => "2056") + AreaCode.create(:country => germany, :name => "Wülfrath", :area_code => "2058") + AreaCode.create(:country => germany, :name => "Dinslaken", :area_code => "2064") + AreaCode.create(:country => germany, :name => "Duisburg-Rheinhausen", :area_code => "2065") + AreaCode.create(:country => germany, :name => "Duisburg-Homberg", :area_code => "2066") + AreaCode.create(:country => germany, :name => "Oberhausen Rheinl", :area_code => "208") + AreaCode.create(:country => germany, :name => "Gelsenkirchen", :area_code => "209") + AreaCode.create(:country => germany, :name => "Ratingen", :area_code => "2102") + AreaCode.create(:country => germany, :name => "Hilden", :area_code => "2103") + AreaCode.create(:country => germany, :name => "Mettmann", :area_code => "2104") + AreaCode.create(:country => germany, :name => "Düsseldorf", :area_code => "211") + AreaCode.create(:country => germany, :name => "Solingen", :area_code => "212") + AreaCode.create(:country => germany, :name => "Haan Rheinl", :area_code => "2129") + AreaCode.create(:country => germany, :name => "Neuss", :area_code => "2131") + AreaCode.create(:country => germany, :name => "Meerbusch-Büderich", :area_code => "2132") + AreaCode.create(:country => germany, :name => "Dormagen", :area_code => "2133") + AreaCode.create(:country => germany, :name => "Neuss-Norf", :area_code => "2137") + AreaCode.create(:country => germany, :name => "Leverkusen", :area_code => "214") + AreaCode.create(:country => germany, :name => "Meerbusch-Lank", :area_code => "2150") + AreaCode.create(:country => germany, :name => "Krefeld", :area_code => "2151") + AreaCode.create(:country => germany, :name => "Kempen", :area_code => "2152") + AreaCode.create(:country => germany, :name => "Nettetal-Lobberich", :area_code => "2153") + AreaCode.create(:country => germany, :name => "Willich", :area_code => "2154") + AreaCode.create(:country => germany, :name => "Willich-Anrath", :area_code => "2156") + AreaCode.create(:country => germany, :name => "Nettetal-Kaldenkirchen", :area_code => "2157") + AreaCode.create(:country => germany, :name => "Grefrath b Krefeld", :area_code => "2158") + AreaCode.create(:country => germany, :name => "Meerbusch-Osterath", :area_code => "2159") + AreaCode.create(:country => germany, :name => "Mönchengladbach", :area_code => "2161") + AreaCode.create(:country => germany, :name => "Viersen", :area_code => "2162") + AreaCode.create(:country => germany, :name => "Schwalmtal Niederrhein", :area_code => "2163") + AreaCode.create(:country => germany, :name => "Jüchen-Otzenrath", :area_code => "2164") + AreaCode.create(:country => germany, :name => "Jüchen", :area_code => "2165") + AreaCode.create(:country => germany, :name => "Mönchengladbach-Rheydt", :area_code => "2166") + AreaCode.create(:country => germany, :name => "Leverkusen-Opladen", :area_code => "2171") + AreaCode.create(:country => germany, :name => "Langenfeld Rheinland", :area_code => "2173") + AreaCode.create(:country => germany, :name => "Burscheid Rheinl", :area_code => "2174") + AreaCode.create(:country => germany, :name => "Leichlingen Rheinland", :area_code => "2175") + AreaCode.create(:country => germany, :name => "Grevenbroich", :area_code => "2181") + AreaCode.create(:country => germany, :name => "Grevenbroich-Kapellen", :area_code => "2182") + AreaCode.create(:country => germany, :name => "Rommerskirchen", :area_code => "2183") + AreaCode.create(:country => germany, :name => "Remscheid", :area_code => "2191") + AreaCode.create(:country => germany, :name => "Hückeswagen", :area_code => "2192") + AreaCode.create(:country => germany, :name => "Dabringhausen", :area_code => "2193") + AreaCode.create(:country => germany, :name => "Radevormwald", :area_code => "2195") + AreaCode.create(:country => germany, :name => "Wermelskirchen", :area_code => "2196") + AreaCode.create(:country => germany, :name => "Bergisch Gladbach", :area_code => "2202") + AreaCode.create(:country => germany, :name => "Köln-Porz", :area_code => "2203") + AreaCode.create(:country => germany, :name => "Bensberg", :area_code => "2204") + AreaCode.create(:country => germany, :name => "Rösrath", :area_code => "2205") + AreaCode.create(:country => germany, :name => "Overath", :area_code => "2206") + AreaCode.create(:country => germany, :name => "Kürten-Dürscheid", :area_code => "2207") + AreaCode.create(:country => germany, :name => "Niederkassel", :area_code => "2208") + AreaCode.create(:country => germany, :name => "Köln", :area_code => "221") + AreaCode.create(:country => germany, :name => "Bornheim Rheinl", :area_code => "2222") + AreaCode.create(:country => germany, :name => "Königswinter", :area_code => "2223") + AreaCode.create(:country => germany, :name => "Bad Honnef", :area_code => "2224") + AreaCode.create(:country => germany, :name => "Meckenheim Rheinl", :area_code => "2225") + AreaCode.create(:country => germany, :name => "Rheinbach", :area_code => "2226") + AreaCode.create(:country => germany, :name => "Bornheim-Merten", :area_code => "2227") + AreaCode.create(:country => germany, :name => "Remagen-Rolandseck", :area_code => "2228") + AreaCode.create(:country => germany, :name => "Brühl Rheinl", :area_code => "2232") + AreaCode.create(:country => germany, :name => "Hürth Rheinl", :area_code => "2233") + AreaCode.create(:country => germany, :name => "Frechen", :area_code => "2234") + AreaCode.create(:country => germany, :name => "Erftstadt", :area_code => "2235") + AreaCode.create(:country => germany, :name => "Wesseling Rheinl", :area_code => "2236") + AreaCode.create(:country => germany, :name => "Kerpen Rheinl-Türnich", :area_code => "2237") + AreaCode.create(:country => germany, :name => "Pulheim", :area_code => "2238") + AreaCode.create(:country => germany, :name => "Siegburg", :area_code => "2241") + AreaCode.create(:country => germany, :name => "Hennef Sieg", :area_code => "2242") + AreaCode.create(:country => germany, :name => "Eitorf", :area_code => "2243") + AreaCode.create(:country => germany, :name => "Königswinter-Oberpleis", :area_code => "2244") + AreaCode.create(:country => germany, :name => "Much", :area_code => "2245") + AreaCode.create(:country => germany, :name => "Lohmar", :area_code => "2246") + AreaCode.create(:country => germany, :name => "Neunkirchen-Seelscheid", :area_code => "2247") + AreaCode.create(:country => germany, :name => "Hennef-Uckerath", :area_code => "2248") + AreaCode.create(:country => germany, :name => "Euskirchen", :area_code => "2251") + AreaCode.create(:country => germany, :name => "Zülpich", :area_code => "2252") + AreaCode.create(:country => germany, :name => "Bad Münstereifel", :area_code => "2253") + AreaCode.create(:country => germany, :name => "Weilerswist", :area_code => "2254") + AreaCode.create(:country => germany, :name => "Euskirchen-Flamersheim", :area_code => "2255") + AreaCode.create(:country => germany, :name => "Mechernich-Satzvey", :area_code => "2256") + AreaCode.create(:country => germany, :name => "Reckerscheid", :area_code => "2257") + AreaCode.create(:country => germany, :name => "Gummersbach", :area_code => "2261") + AreaCode.create(:country => germany, :name => "Wiehl", :area_code => "2262") + AreaCode.create(:country => germany, :name => "Engelskirchen", :area_code => "2263") + AreaCode.create(:country => germany, :name => "Marienheide", :area_code => "2264") + AreaCode.create(:country => germany, :name => "Reichshof-Eckenhagen", :area_code => "2265") + AreaCode.create(:country => germany, :name => "Lindlar", :area_code => "2266") + AreaCode.create(:country => germany, :name => "Wipperfürth", :area_code => "2267") + AreaCode.create(:country => germany, :name => "Kürten", :area_code => "2268") + AreaCode.create(:country => germany, :name => "Kierspe-Rönsahl", :area_code => "2269") + AreaCode.create(:country => germany, :name => "Bergheim Erft", :area_code => "2271") + AreaCode.create(:country => germany, :name => "Bedburg Erft", :area_code => "2272") + AreaCode.create(:country => germany, :name => "Kerpen-Horrem", :area_code => "2273") + AreaCode.create(:country => germany, :name => "Elsdorf Rheinl", :area_code => "2274") + AreaCode.create(:country => germany, :name => "Kerpen-Buir", :area_code => "2275") + AreaCode.create(:country => germany, :name => "Bonn", :area_code => "228") + AreaCode.create(:country => germany, :name => "Waldbröl", :area_code => "2291") + AreaCode.create(:country => germany, :name => "Windeck Sieg", :area_code => "2292") + AreaCode.create(:country => germany, :name => "Nümbrecht", :area_code => "2293") + AreaCode.create(:country => germany, :name => "Morsbach Sieg", :area_code => "2294") + AreaCode.create(:country => germany, :name => "Ruppichteroth", :area_code => "2295") + AreaCode.create(:country => germany, :name => "Reichshof-Brüchermühle", :area_code => "2296") + AreaCode.create(:country => germany, :name => "Wildbergerhütte", :area_code => "2297") + AreaCode.create(:country => germany, :name => "Holzwickede", :area_code => "2301") + AreaCode.create(:country => germany, :name => "Witten", :area_code => "2302") + AreaCode.create(:country => germany, :name => "Unna", :area_code => "2303") + AreaCode.create(:country => germany, :name => "Schwerte", :area_code => "2304") + AreaCode.create(:country => germany, :name => "Castrop-Rauxel", :area_code => "2305") + AreaCode.create(:country => germany, :name => "Lünen", :area_code => "2306") + AreaCode.create(:country => germany, :name => "Kamen", :area_code => "2307") + AreaCode.create(:country => germany, :name => "Unna-Hemmerde", :area_code => "2308") + AreaCode.create(:country => germany, :name => "Waltrop", :area_code => "2309") + AreaCode.create(:country => germany, :name => "Dortmund", :area_code => "231") + AreaCode.create(:country => germany, :name => "Herne", :area_code => "2323") + AreaCode.create(:country => germany, :name => "Hattingen Ruhr", :area_code => "2324") + AreaCode.create(:country => germany, :name => "Wanne-Eickel", :area_code => "2325") + AreaCode.create(:country => germany, :name => "Bochum-Wattenscheid", :area_code => "2327") + AreaCode.create(:country => germany, :name => "Herdecke", :area_code => "2330") + AreaCode.create(:country => germany, :name => "Hagen Westf", :area_code => "2331") + AreaCode.create(:country => germany, :name => "Gevelsberg", :area_code => "2332") + AreaCode.create(:country => germany, :name => "Ennepetal", :area_code => "2333") + AreaCode.create(:country => germany, :name => "Hagen-Hohenlimburg", :area_code => "2334") + AreaCode.create(:country => germany, :name => "Wetter Ruhr", :area_code => "2335") + AreaCode.create(:country => germany, :name => "Schwelm", :area_code => "2336") + AreaCode.create(:country => germany, :name => "Hagen-Dahl", :area_code => "2337") + AreaCode.create(:country => germany, :name => "Breckerfeld", :area_code => "2338") + AreaCode.create(:country => germany, :name => "Sprockhövel-Haßlinghausen", :area_code => "2339") + AreaCode.create(:country => germany, :name => "Bochum", :area_code => "234") + AreaCode.create(:country => germany, :name => "Lüdenscheid", :area_code => "2351") + AreaCode.create(:country => germany, :name => "Altena Westf", :area_code => "2352") + AreaCode.create(:country => germany, :name => "Halver", :area_code => "2353") + AreaCode.create(:country => germany, :name => "Meinerzhagen", :area_code => "2354") + AreaCode.create(:country => germany, :name => "Schalksmühle", :area_code => "2355") + AreaCode.create(:country => germany, :name => "Herscheid Westf", :area_code => "2357") + AreaCode.create(:country => germany, :name => "Meinerzhagen-Valbert", :area_code => "2358") + AreaCode.create(:country => germany, :name => "Kierspe", :area_code => "2359") + AreaCode.create(:country => germany, :name => "Haltern-Lippramsdorf", :area_code => "2360") + AreaCode.create(:country => germany, :name => "Recklinghausen", :area_code => "2361") + AreaCode.create(:country => germany, :name => "Dorsten", :area_code => "2362") + AreaCode.create(:country => germany, :name => "Datteln", :area_code => "2363") + AreaCode.create(:country => germany, :name => "Haltern Westf", :area_code => "2364") + AreaCode.create(:country => germany, :name => "Marl", :area_code => "2365") + AreaCode.create(:country => germany, :name => "Herten Westf", :area_code => "2366") + AreaCode.create(:country => germany, :name => "Henrichenburg", :area_code => "2367") + AreaCode.create(:country => germany, :name => "Oer-Erkenschwick", :area_code => "2368") + AreaCode.create(:country => germany, :name => "Dorsten-Wulfen", :area_code => "2369") + AreaCode.create(:country => germany, :name => "Iserlohn", :area_code => "2371") + AreaCode.create(:country => germany, :name => "Hemer", :area_code => "2372") + AreaCode.create(:country => germany, :name => "Menden Sauerland", :area_code => "2373") + AreaCode.create(:country => germany, :name => "Iserlohn-Letmathe", :area_code => "2374") + AreaCode.create(:country => germany, :name => "Balve", :area_code => "2375") + AreaCode.create(:country => germany, :name => "Wickede Ruhr", :area_code => "2377") + AreaCode.create(:country => germany, :name => "Fröndenberg-Langschede", :area_code => "2378") + AreaCode.create(:country => germany, :name => "Menden-Asbeck", :area_code => "2379") + AreaCode.create(:country => germany, :name => "Hamm Westf", :area_code => "2381") + AreaCode.create(:country => germany, :name => "Ahlen Westf", :area_code => "2382") + AreaCode.create(:country => germany, :name => "Bönen", :area_code => "2383") + AreaCode.create(:country => germany, :name => "Welver", :area_code => "2384") + AreaCode.create(:country => germany, :name => "Hamm-Rhynern", :area_code => "2385") + AreaCode.create(:country => germany, :name => "Drensteinfurt-Walstedde", :area_code => "2387") + AreaCode.create(:country => germany, :name => "Hamm-Uentrop", :area_code => "2388") + AreaCode.create(:country => germany, :name => "Werne", :area_code => "2389") + AreaCode.create(:country => germany, :name => "Plettenberg", :area_code => "2391") + AreaCode.create(:country => germany, :name => "Werdohl", :area_code => "2392") + AreaCode.create(:country => germany, :name => "Sundern-Allendorf", :area_code => "2393") + AreaCode.create(:country => germany, :name => "Neuenrade-Affeln", :area_code => "2394") + AreaCode.create(:country => germany, :name => "Finnentrop-Rönkhausen", :area_code => "2395") + AreaCode.create(:country => germany, :name => "Baesweiler", :area_code => "2401") + AreaCode.create(:country => germany, :name => "Stolberg Rheinl", :area_code => "2402") + AreaCode.create(:country => germany, :name => "Eschweiler Rheinl", :area_code => "2403") + AreaCode.create(:country => germany, :name => "Alsdorf Rheinl", :area_code => "2404") + AreaCode.create(:country => germany, :name => "Würselen", :area_code => "2405") + AreaCode.create(:country => germany, :name => "Herzogenrath", :area_code => "2406") + AreaCode.create(:country => germany, :name => "Herzogenrath-Kohlscheid", :area_code => "2407") + AreaCode.create(:country => germany, :name => "Aachen-Kornelimünster", :area_code => "2408") + AreaCode.create(:country => germany, :name => "Stolberg-Gressenich", :area_code => "2409") + AreaCode.create(:country => germany, :name => "Aachen", :area_code => "241") + AreaCode.create(:country => germany, :name => "Düren", :area_code => "2421") + AreaCode.create(:country => germany, :name => "Kreuzau", :area_code => "2422") + AreaCode.create(:country => germany, :name => "Langerwehe", :area_code => "2423") + AreaCode.create(:country => germany, :name => "Vettweiss", :area_code => "2424") + AreaCode.create(:country => germany, :name => "Nideggen-Embken", :area_code => "2425") + AreaCode.create(:country => germany, :name => "Nörvenich", :area_code => "2426") + AreaCode.create(:country => germany, :name => "Nideggen", :area_code => "2427") + AreaCode.create(:country => germany, :name => "Niederzier", :area_code => "2428") + AreaCode.create(:country => germany, :name => "Hürtgenwald", :area_code => "2429") + AreaCode.create(:country => germany, :name => "Erkelenz", :area_code => "2431") + AreaCode.create(:country => germany, :name => "Wassenberg", :area_code => "2432") + AreaCode.create(:country => germany, :name => "Hückelhoven", :area_code => "2433") + AreaCode.create(:country => germany, :name => "Wegberg", :area_code => "2434") + AreaCode.create(:country => germany, :name => "Erkelenz-Lövenich", :area_code => "2435") + AreaCode.create(:country => germany, :name => "Wegberg-Rödgen", :area_code => "2436") + AreaCode.create(:country => germany, :name => "Nettersheim-Tondorf", :area_code => "2440") + AreaCode.create(:country => germany, :name => "Kall", :area_code => "2441") + AreaCode.create(:country => germany, :name => "Mechernich", :area_code => "2443") + AreaCode.create(:country => germany, :name => "Schleiden-Gemünd", :area_code => "2444") + AreaCode.create(:country => germany, :name => "Schleiden Eifel", :area_code => "2445") + AreaCode.create(:country => germany, :name => "Heimbach Eifel", :area_code => "2446") + AreaCode.create(:country => germany, :name => "Dahlem b Kall", :area_code => "2447") + AreaCode.create(:country => germany, :name => "Hellenthal-Rescheid", :area_code => "2448") + AreaCode.create(:country => germany, :name => "Blankenheim Ahr", :area_code => "2449") + AreaCode.create(:country => germany, :name => "Geilenkirchen", :area_code => "2451") + AreaCode.create(:country => germany, :name => "Heinsberg Rheinl", :area_code => "2452") + AreaCode.create(:country => germany, :name => "Heinsberg-Randerath", :area_code => "2453") + AreaCode.create(:country => germany, :name => "Gangelt", :area_code => "2454") + AreaCode.create(:country => germany, :name => "Waldfeucht", :area_code => "2455") + AreaCode.create(:country => germany, :name => "Selfkant", :area_code => "2456") + AreaCode.create(:country => germany, :name => "Jülich", :area_code => "2461") + AreaCode.create(:country => germany, :name => "Linnich", :area_code => "2462") + AreaCode.create(:country => germany, :name => "Titz", :area_code => "2463") + AreaCode.create(:country => germany, :name => "Aldenhoven b Jülich", :area_code => "2464") + AreaCode.create(:country => germany, :name => "Inden", :area_code => "2465") + AreaCode.create(:country => germany, :name => "Roetgen Eifel", :area_code => "2471") + AreaCode.create(:country => germany, :name => "Monschau", :area_code => "2472") + AreaCode.create(:country => germany, :name => "Simmerath", :area_code => "2473") + AreaCode.create(:country => germany, :name => "Nideggen-Schmidt", :area_code => "2474") + AreaCode.create(:country => germany, :name => "Hellenthal", :area_code => "2482") + AreaCode.create(:country => germany, :name => "Mechernich-Eiserfey", :area_code => "2484") + AreaCode.create(:country => germany, :name => "Schleiden-Dreiborn", :area_code => "2485") + AreaCode.create(:country => germany, :name => "Nettersheim", :area_code => "2486") + AreaCode.create(:country => germany, :name => "Münster-Hiltrup", :area_code => "2501") + AreaCode.create(:country => germany, :name => "Nottuln", :area_code => "2502") + AreaCode.create(:country => germany, :name => "Telgte", :area_code => "2504") + AreaCode.create(:country => germany, :name => "Altenberge Westf", :area_code => "2505") + AreaCode.create(:country => germany, :name => "Münster-Wolbeck", :area_code => "2506") + AreaCode.create(:country => germany, :name => "Havixbeck", :area_code => "2507") + AreaCode.create(:country => germany, :name => "Drensteinfurt", :area_code => "2508") + AreaCode.create(:country => germany, :name => "Nottuln-Appelhülsen", :area_code => "2509") + AreaCode.create(:country => germany, :name => "Münster", :area_code => "251") + AreaCode.create(:country => germany, :name => "Wadersloh-Diestedde", :area_code => "2520") + AreaCode.create(:country => germany, :name => "Beckum", :area_code => "2521") + AreaCode.create(:country => germany, :name => "Oelde", :area_code => "2522") + AreaCode.create(:country => germany, :name => "Wadersloh", :area_code => "2523") + AreaCode.create(:country => germany, :name => "Ennigerloh", :area_code => "2524") + AreaCode.create(:country => germany, :name => "Beckum-Neubeckum", :area_code => "2525") + AreaCode.create(:country => germany, :name => "Sendenhorst", :area_code => "2526") + AreaCode.create(:country => germany, :name => "Lippetal-Lippborg", :area_code => "2527") + AreaCode.create(:country => germany, :name => "Ennigerloh-Enniger", :area_code => "2528") + AreaCode.create(:country => germany, :name => "Oelde-Stromberg", :area_code => "2529") + AreaCode.create(:country => germany, :name => "Ostbevern", :area_code => "2532") + AreaCode.create(:country => germany, :name => "Münster-Nienberge", :area_code => "2533") + AreaCode.create(:country => germany, :name => "Münster-Roxel", :area_code => "2534") + AreaCode.create(:country => germany, :name => "Sendenhorst-Albersloh", :area_code => "2535") + AreaCode.create(:country => germany, :name => "Münster-Albachten", :area_code => "2536") + AreaCode.create(:country => germany, :name => "Drensteinfurt-Rinkerode", :area_code => "2538") + AreaCode.create(:country => germany, :name => "Coesfeld", :area_code => "2541") + AreaCode.create(:country => germany, :name => "Gescher", :area_code => "2542") + AreaCode.create(:country => germany, :name => "Billerbeck Westf", :area_code => "2543") + AreaCode.create(:country => germany, :name => "Rosendahl-Darfeld", :area_code => "2545") + AreaCode.create(:country => germany, :name => "Coesfeld-Lette", :area_code => "2546") + AreaCode.create(:country => germany, :name => "Rosendahl-Osterwick", :area_code => "2547") + AreaCode.create(:country => germany, :name => "Dülmen-Rorup", :area_code => "2548") + AreaCode.create(:country => germany, :name => "Steinfurt-Burgsteinfurt", :area_code => "2551") + AreaCode.create(:country => germany, :name => "Steinfurt-Borghorst", :area_code => "2552") + AreaCode.create(:country => germany, :name => "Ochtrup", :area_code => "2553") + AreaCode.create(:country => germany, :name => "Laer Kr Steinfurt", :area_code => "2554") + AreaCode.create(:country => germany, :name => "Schöppingen", :area_code => "2555") + AreaCode.create(:country => germany, :name => "Metelen", :area_code => "2556") + AreaCode.create(:country => germany, :name => "Wettringen Kr Steinfurt", :area_code => "2557") + AreaCode.create(:country => germany, :name => "Horstmar", :area_code => "2558") + AreaCode.create(:country => germany, :name => "Ahaus", :area_code => "2561") + AreaCode.create(:country => germany, :name => "Gronau Westfalen", :area_code => "2562") + AreaCode.create(:country => germany, :name => "Stadtlohn", :area_code => "2563") + AreaCode.create(:country => germany, :name => "Vreden", :area_code => "2564") + AreaCode.create(:country => germany, :name => "Gronau-Epe", :area_code => "2565") + AreaCode.create(:country => germany, :name => "Legden", :area_code => "2566") + AreaCode.create(:country => germany, :name => "Ahaus-Alstätte", :area_code => "2567") + AreaCode.create(:country => germany, :name => "Heek", :area_code => "2568") + AreaCode.create(:country => germany, :name => "Greven Westf", :area_code => "2571") + AreaCode.create(:country => germany, :name => "Emsdetten", :area_code => "2572") + AreaCode.create(:country => germany, :name => "Nordwalde", :area_code => "2573") + AreaCode.create(:country => germany, :name => "Saerbeck", :area_code => "2574") + AreaCode.create(:country => germany, :name => "Greven-Reckenfeld", :area_code => "2575") + AreaCode.create(:country => germany, :name => "Warendorf", :area_code => "2581") + AreaCode.create(:country => germany, :name => "Everswinkel", :area_code => "2582") + AreaCode.create(:country => germany, :name => "Sassenberg", :area_code => "2583") + AreaCode.create(:country => germany, :name => "Warendorf-Milte", :area_code => "2584") + AreaCode.create(:country => germany, :name => "Warendorf-Hoetmar", :area_code => "2585") + AreaCode.create(:country => germany, :name => "Beelen", :area_code => "2586") + AreaCode.create(:country => germany, :name => "Ennigerloh-Westkirchen", :area_code => "2587") + AreaCode.create(:country => germany, :name => "Harsewinkel-Greffen", :area_code => "2588") + AreaCode.create(:country => germany, :name => "Dülmen-Buldern", :area_code => "2590") + AreaCode.create(:country => germany, :name => "Lüdinghausen", :area_code => "2591") + AreaCode.create(:country => germany, :name => "Selm", :area_code => "2592") + AreaCode.create(:country => germany, :name => "Ascheberg Westf", :area_code => "2593") + AreaCode.create(:country => germany, :name => "Dülmen", :area_code => "2594") + AreaCode.create(:country => germany, :name => "Olfen", :area_code => "2595") + AreaCode.create(:country => germany, :name => "Nordkirchen", :area_code => "2596") + AreaCode.create(:country => germany, :name => "Senden Westf", :area_code => "2597") + AreaCode.create(:country => germany, :name => "Senden-Ottmarsbocholt", :area_code => "2598") + AreaCode.create(:country => germany, :name => "Ascheberg-Herbern", :area_code => "2599") + AreaCode.create(:country => germany, :name => "Nauort", :area_code => "2601") + AreaCode.create(:country => germany, :name => "Montabaur", :area_code => "2602") + AreaCode.create(:country => germany, :name => "Bad Ems", :area_code => "2603") + AreaCode.create(:country => germany, :name => "Nassau Lahn", :area_code => "2604") + AreaCode.create(:country => germany, :name => "Löf", :area_code => "2605") + AreaCode.create(:country => germany, :name => "Winningen Mosel", :area_code => "2606") + AreaCode.create(:country => germany, :name => "Kobern-Gondorf", :area_code => "2607") + AreaCode.create(:country => germany, :name => "Welschneudorf", :area_code => "2608") + AreaCode.create(:country => germany, :name => "Koblenz a Rhein", :area_code => "261") + AreaCode.create(:country => germany, :name => "Neuhäusel Westerw", :area_code => "2620") + AreaCode.create(:country => germany, :name => "Lahnstein", :area_code => "2621") + AreaCode.create(:country => germany, :name => "Bendorf Rhein", :area_code => "2622") + AreaCode.create(:country => germany, :name => "Ransbach-Baumbach", :area_code => "2623") + AreaCode.create(:country => germany, :name => "Höhr-Grenzhausen", :area_code => "2624") + AreaCode.create(:country => germany, :name => "Ochtendung", :area_code => "2625") + AreaCode.create(:country => germany, :name => "Selters Westerwald", :area_code => "2626") + AreaCode.create(:country => germany, :name => "Braubach", :area_code => "2627") + AreaCode.create(:country => germany, :name => "Rhens", :area_code => "2628") + AreaCode.create(:country => germany, :name => "Mülheim-Kärlich", :area_code => "2630") + AreaCode.create(:country => germany, :name => "Neuwied", :area_code => "2631") + AreaCode.create(:country => germany, :name => "Andernach", :area_code => "2632") + AreaCode.create(:country => germany, :name => "Brohl-Lützing", :area_code => "2633") + AreaCode.create(:country => germany, :name => "Rengsdorf", :area_code => "2634") + AreaCode.create(:country => germany, :name => "Rheinbrohl", :area_code => "2635") + AreaCode.create(:country => germany, :name => "Burgbrohl", :area_code => "2636") + AreaCode.create(:country => germany, :name => "Weissenthurm", :area_code => "2637") + AreaCode.create(:country => germany, :name => "Waldbreitbach", :area_code => "2638") + AreaCode.create(:country => germany, :name => "Anhausen Kr Neuwied", :area_code => "2639") + AreaCode.create(:country => germany, :name => "Bad Neuenahr-Ahrweiler", :area_code => "2641") + AreaCode.create(:country => germany, :name => "Remagen", :area_code => "2642") + AreaCode.create(:country => germany, :name => "Altenahr", :area_code => "2643") + AreaCode.create(:country => germany, :name => "Linz am Rhein", :area_code => "2644") + AreaCode.create(:country => germany, :name => "Vettelschoss", :area_code => "2645") + AreaCode.create(:country => germany, :name => "Königsfeld Eifel", :area_code => "2646") + AreaCode.create(:country => germany, :name => "Kesseling", :area_code => "2647") + AreaCode.create(:country => germany, :name => "Mayen", :area_code => "2651") + AreaCode.create(:country => germany, :name => "Mendig", :area_code => "2652") + AreaCode.create(:country => germany, :name => "Kaisersesch", :area_code => "2653") + AreaCode.create(:country => germany, :name => "Polch", :area_code => "2654") + AreaCode.create(:country => germany, :name => "Weibern", :area_code => "2655") + AreaCode.create(:country => germany, :name => "Virneburg", :area_code => "2656") + AreaCode.create(:country => germany, :name => "Uersfeld", :area_code => "2657") + AreaCode.create(:country => germany, :name => "Bad Marienberg Westerwald", :area_code => "2661") + AreaCode.create(:country => germany, :name => "Hachenburg", :area_code => "2662") + AreaCode.create(:country => germany, :name => "Westerburg Westerw", :area_code => "2663") + AreaCode.create(:country => germany, :name => "Rennerod", :area_code => "2664") + AreaCode.create(:country => germany, :name => "Freilingen Westerw", :area_code => "2666") + AreaCode.create(:country => germany, :name => "Stein-Neukirch", :area_code => "2667") + AreaCode.create(:country => germany, :name => "Cochem", :area_code => "2671") + AreaCode.create(:country => germany, :name => "Treis-Karden", :area_code => "2672") + AreaCode.create(:country => germany, :name => "Ellenz-Poltersdorf", :area_code => "2673") + AreaCode.create(:country => germany, :name => "Bad Bertrich", :area_code => "2674") + AreaCode.create(:country => germany, :name => "Ediger-Eller", :area_code => "2675") + AreaCode.create(:country => germany, :name => "Ulmen", :area_code => "2676") + AreaCode.create(:country => germany, :name => "Lutzerath", :area_code => "2677") + AreaCode.create(:country => germany, :name => "Büchel b Cochem", :area_code => "2678") + AreaCode.create(:country => germany, :name => "Mündersbach", :area_code => "2680") + AreaCode.create(:country => germany, :name => "Altenkirchen Westerwald", :area_code => "2681") + AreaCode.create(:country => germany, :name => "Hamm Sieg", :area_code => "2682") + AreaCode.create(:country => germany, :name => "Asbach Westerw", :area_code => "2683") + AreaCode.create(:country => germany, :name => "Puderbach Westerw", :area_code => "2684") + AreaCode.create(:country => germany, :name => "Flammersfeld", :area_code => "2685") + AreaCode.create(:country => germany, :name => "Weyerbusch", :area_code => "2686") + AreaCode.create(:country => germany, :name => "Horhausen Westerwald", :area_code => "2687") + AreaCode.create(:country => germany, :name => "Kroppach", :area_code => "2688") + AreaCode.create(:country => germany, :name => "Dierdorf", :area_code => "2689") + AreaCode.create(:country => germany, :name => "Adenau", :area_code => "2691") + AreaCode.create(:country => germany, :name => "Kelberg", :area_code => "2692") + AreaCode.create(:country => germany, :name => "Antweiler", :area_code => "2693") + AreaCode.create(:country => germany, :name => "Wershofen", :area_code => "2694") + AreaCode.create(:country => germany, :name => "Insul", :area_code => "2695") + AreaCode.create(:country => germany, :name => "Nohn Eifel", :area_code => "2696") + AreaCode.create(:country => germany, :name => "Blankenheim-Ahrhütte", :area_code => "2697") + AreaCode.create(:country => germany, :name => "Siegen", :area_code => "271") + AreaCode.create(:country => germany, :name => "Lennestadt", :area_code => "2721") + AreaCode.create(:country => germany, :name => "Attendorn", :area_code => "2722") + AreaCode.create(:country => germany, :name => "Kirchhundem", :area_code => "2723") + AreaCode.create(:country => germany, :name => "Finnentrop-Serkenrode", :area_code => "2724") + AreaCode.create(:country => germany, :name => "Lennestadt-Oedingen", :area_code => "2725") + AreaCode.create(:country => germany, :name => "Kreuztal", :area_code => "2732") + AreaCode.create(:country => germany, :name => "Hilchenbach", :area_code => "2733") + AreaCode.create(:country => germany, :name => "Freudenberg Westf", :area_code => "2734") + AreaCode.create(:country => germany, :name => "Neunkirchen Siegerl", :area_code => "2735") + AreaCode.create(:country => germany, :name => "Burbach Siegerl", :area_code => "2736") + AreaCode.create(:country => germany, :name => "Netphen-Deuz", :area_code => "2737") + AreaCode.create(:country => germany, :name => "Netphen", :area_code => "2738") + AreaCode.create(:country => germany, :name => "Wilnsdorf", :area_code => "2739") + AreaCode.create(:country => germany, :name => "Betzdorf", :area_code => "2741") + AreaCode.create(:country => germany, :name => "Wissen", :area_code => "2742") + AreaCode.create(:country => germany, :name => "Daaden", :area_code => "2743") + AreaCode.create(:country => germany, :name => "Herdorf", :area_code => "2744") + AreaCode.create(:country => germany, :name => "Brachbach Sieg", :area_code => "2745") + AreaCode.create(:country => germany, :name => "Molzhain", :area_code => "2747") + AreaCode.create(:country => germany, :name => "Diedenshausen", :area_code => "2750") + AreaCode.create(:country => germany, :name => "Bad Berleburg", :area_code => "2751") + AreaCode.create(:country => germany, :name => "Bad Laasphe", :area_code => "2752") + AreaCode.create(:country => germany, :name => "Erndtebrück", :area_code => "2753") + AreaCode.create(:country => germany, :name => "Bad Laasphe-Feudingen", :area_code => "2754") + AreaCode.create(:country => germany, :name => "Bad Berleburg-Schwarzenau", :area_code => "2755") + AreaCode.create(:country => germany, :name => "Bad Berleburg-Girkhausen", :area_code => "2758") + AreaCode.create(:country => germany, :name => "Bad Berleburg-Aue", :area_code => "2759") + AreaCode.create(:country => germany, :name => "Olpe Biggesee", :area_code => "2761") + AreaCode.create(:country => germany, :name => "Wenden Südsauerland", :area_code => "2762") + AreaCode.create(:country => germany, :name => "Drolshagen-Bleche", :area_code => "2763") + AreaCode.create(:country => germany, :name => "Welschen Ennest", :area_code => "2764") + AreaCode.create(:country => germany, :name => "Eschenburg", :area_code => "2770") + AreaCode.create(:country => germany, :name => "Dillenburg", :area_code => "2771") + AreaCode.create(:country => germany, :name => "Herborn Hess", :area_code => "2772") + AreaCode.create(:country => germany, :name => "Haiger", :area_code => "2773") + AreaCode.create(:country => germany, :name => "Dietzhölztal", :area_code => "2774") + AreaCode.create(:country => germany, :name => "Driedorf", :area_code => "2775") + AreaCode.create(:country => germany, :name => "Bad Endbach-Hartenrod", :area_code => "2776") + AreaCode.create(:country => germany, :name => "Breitscheid Hess", :area_code => "2777") + AreaCode.create(:country => germany, :name => "Siegbach", :area_code => "2778") + AreaCode.create(:country => germany, :name => "Greifenstein-Beilstein", :area_code => "2779") + AreaCode.create(:country => germany, :name => "Xanten", :area_code => "2801") + AreaCode.create(:country => germany, :name => "Alpen", :area_code => "2802") + AreaCode.create(:country => germany, :name => "Wesel-Büderich", :area_code => "2803") + AreaCode.create(:country => germany, :name => "Xanten-Marienbaum", :area_code => "2804") + AreaCode.create(:country => germany, :name => "Wesel", :area_code => "281") + AreaCode.create(:country => germany, :name => "Kleve Niederrhein", :area_code => "2821") + AreaCode.create(:country => germany, :name => "Emmerich", :area_code => "2822") + AreaCode.create(:country => germany, :name => "Goch", :area_code => "2823") + AreaCode.create(:country => germany, :name => "Kalkar", :area_code => "2824") + AreaCode.create(:country => germany, :name => "Uedem", :area_code => "2825") + AreaCode.create(:country => germany, :name => "Kranenburg Niederrhein", :area_code => "2826") + AreaCode.create(:country => germany, :name => "Goch-Hassum", :area_code => "2827") + AreaCode.create(:country => germany, :name => "Emmerich-Elten", :area_code => "2828") + AreaCode.create(:country => germany, :name => "Geldern", :area_code => "2831") + AreaCode.create(:country => germany, :name => "Kevelaer", :area_code => "2832") + AreaCode.create(:country => germany, :name => "Kerken", :area_code => "2833") + AreaCode.create(:country => germany, :name => "Straelen", :area_code => "2834") + AreaCode.create(:country => germany, :name => "Issum", :area_code => "2835") + AreaCode.create(:country => germany, :name => "Wachtendonk", :area_code => "2836") + AreaCode.create(:country => germany, :name => "Weeze", :area_code => "2837") + AreaCode.create(:country => germany, :name => "Sonsbeck", :area_code => "2838") + AreaCode.create(:country => germany, :name => "Straelen-Herongen", :area_code => "2839") + AreaCode.create(:country => germany, :name => "Moers", :area_code => "2841") + AreaCode.create(:country => germany, :name => "Kamp-Lintfort", :area_code => "2842") + AreaCode.create(:country => germany, :name => "Rheinberg", :area_code => "2843") + AreaCode.create(:country => germany, :name => "Rheinberg-Orsoy", :area_code => "2844") + AreaCode.create(:country => germany, :name => "Neukirchen-Vluyn", :area_code => "2845") + AreaCode.create(:country => germany, :name => "Rees-Haldern", :area_code => "2850") + AreaCode.create(:country => germany, :name => "Rees", :area_code => "2851") + AreaCode.create(:country => germany, :name => "Hamminkeln", :area_code => "2852") + AreaCode.create(:country => germany, :name => "Schermbeck", :area_code => "2853") + AreaCode.create(:country => germany, :name => "Voerde Niederrhein", :area_code => "2855") + AreaCode.create(:country => germany, :name => "Hamminkeln-Brünen", :area_code => "2856") + AreaCode.create(:country => germany, :name => "Rees-Mehr", :area_code => "2857") + AreaCode.create(:country => germany, :name => "Hünxe", :area_code => "2858") + AreaCode.create(:country => germany, :name => "Wesel-Bislich", :area_code => "2859") + AreaCode.create(:country => germany, :name => "Borken Westf", :area_code => "2861") + AreaCode.create(:country => germany, :name => "Südlohn", :area_code => "2862") + AreaCode.create(:country => germany, :name => "Velen", :area_code => "2863") + AreaCode.create(:country => germany, :name => "Reken", :area_code => "2864") + AreaCode.create(:country => germany, :name => "Raesfeld", :area_code => "2865") + AreaCode.create(:country => germany, :name => "Dorsten-Rhade", :area_code => "2866") + AreaCode.create(:country => germany, :name => "Heiden Kr Borken", :area_code => "2867") + AreaCode.create(:country => germany, :name => "Bocholt", :area_code => "2871") + AreaCode.create(:country => germany, :name => "Rhede Westf", :area_code => "2872") + AreaCode.create(:country => germany, :name => "Isselburg-Werth", :area_code => "2873") + AreaCode.create(:country => germany, :name => "Isselburg", :area_code => "2874") + AreaCode.create(:country => germany, :name => "Warstein", :area_code => "2902") + AreaCode.create(:country => germany, :name => "Meschede-Freienohl", :area_code => "2903") + AreaCode.create(:country => germany, :name => "Bestwig", :area_code => "2904") + AreaCode.create(:country => germany, :name => "Bestwig-Ramsbeck", :area_code => "2905") + AreaCode.create(:country => germany, :name => "Meschede", :area_code => "291") + AreaCode.create(:country => germany, :name => "Soest", :area_code => "2921") + AreaCode.create(:country => germany, :name => "Werl", :area_code => "2922") + AreaCode.create(:country => germany, :name => "Lippetal-Herzfeld", :area_code => "2923") + AreaCode.create(:country => germany, :name => "Möhnesee", :area_code => "2924") + AreaCode.create(:country => germany, :name => "Warstein-Allagen", :area_code => "2925") + AreaCode.create(:country => germany, :name => "Neuengeseke", :area_code => "2927") + AreaCode.create(:country => germany, :name => "Soest-Ostönnen", :area_code => "2928") + AreaCode.create(:country => germany, :name => "Arnsberg", :area_code => "2931") + AreaCode.create(:country => germany, :name => "Neheim-Hüsten", :area_code => "2932") + AreaCode.create(:country => germany, :name => "Sundern Sauerland", :area_code => "2933") + AreaCode.create(:country => germany, :name => "Sundern-Altenhellefeld", :area_code => "2934") + AreaCode.create(:country => germany, :name => "Sundern-Hachen", :area_code => "2935") + AreaCode.create(:country => germany, :name => "Arnsberg-Oeventrop", :area_code => "2937") + AreaCode.create(:country => germany, :name => "Ense", :area_code => "2938") + AreaCode.create(:country => germany, :name => "Lippstadt", :area_code => "2941") + AreaCode.create(:country => germany, :name => "Geseke", :area_code => "2942") + AreaCode.create(:country => germany, :name => "Erwitte", :area_code => "2943") + AreaCode.create(:country => germany, :name => "Rietberg-Mastholte", :area_code => "2944") + AreaCode.create(:country => germany, :name => "Lippstadt-Benninghausen", :area_code => "2945") + AreaCode.create(:country => germany, :name => "Anröchte", :area_code => "2947") + AreaCode.create(:country => germany, :name => "Lippstadt-Rebbeke", :area_code => "2948") + AreaCode.create(:country => germany, :name => "Büren", :area_code => "2951") + AreaCode.create(:country => germany, :name => "Rüthen", :area_code => "2952") + AreaCode.create(:country => germany, :name => "Wünnenberg", :area_code => "2953") + AreaCode.create(:country => germany, :name => "Rüthen-Oestereiden", :area_code => "2954") + AreaCode.create(:country => germany, :name => "Büren-Wewelsburg", :area_code => "2955") + AreaCode.create(:country => germany, :name => "Wünnenberg-Haaren", :area_code => "2957") + AreaCode.create(:country => germany, :name => "Büren-Harth", :area_code => "2958") + AreaCode.create(:country => germany, :name => "Brilon", :area_code => "2961") + AreaCode.create(:country => germany, :name => "Olsberg", :area_code => "2962") + AreaCode.create(:country => germany, :name => "Brilon-Messinghausen", :area_code => "2963") + AreaCode.create(:country => germany, :name => "Brilon-Alme", :area_code => "2964") + AreaCode.create(:country => germany, :name => "Schmallenberg-Dorlar", :area_code => "2971") + AreaCode.create(:country => germany, :name => "Schmallenberg", :area_code => "2972") + AreaCode.create(:country => germany, :name => "Eslohe Sauerland", :area_code => "2973") + AreaCode.create(:country => germany, :name => "Schmallenberg-Fredeburg", :area_code => "2974") + AreaCode.create(:country => germany, :name => "Schmallenberg-Oberkirchen", :area_code => "2975") + AreaCode.create(:country => germany, :name => "Schmallenberg-Bödefeld", :area_code => "2977") + AreaCode.create(:country => germany, :name => "Winterberg Westf", :area_code => "2981") + AreaCode.create(:country => germany, :name => "Medebach", :area_code => "2982") + AreaCode.create(:country => germany, :name => "Winterberg-Siedlinghausen", :area_code => "2983") + AreaCode.create(:country => germany, :name => "Hallenberg", :area_code => "2984") + AreaCode.create(:country => germany, :name => "Winterberg-Niedersfeld", :area_code => "2985") + AreaCode.create(:country => germany, :name => "Marsberg-Bredelar", :area_code => "2991") + AreaCode.create(:country => germany, :name => "Marsberg", :area_code => "2992") + AreaCode.create(:country => germany, :name => "Marsberg-Canstein", :area_code => "2993") + AreaCode.create(:country => germany, :name => "Marsberg-Westheim", :area_code => "2994") + AreaCode.create(:country => germany, :name => "Berlin", :area_code => "30") + AreaCode.create(:country => germany, :name => "Oranienburg", :area_code => "3301") + AreaCode.create(:country => germany, :name => "Hennigsdorf", :area_code => "3302") + AreaCode.create(:country => germany, :name => "Birkenwerder", :area_code => "3303") + AreaCode.create(:country => germany, :name => "Velten", :area_code => "3304") + AreaCode.create(:country => germany, :name => "Nassenheide", :area_code => "33051") + AreaCode.create(:country => germany, :name => "Zehlendorf Kr Oberhavel", :area_code => "33053") + AreaCode.create(:country => germany, :name => "Liebenwalde", :area_code => "33054") + AreaCode.create(:country => germany, :name => "Kremmen", :area_code => "33055") + AreaCode.create(:country => germany, :name => "Mühlenbeck Kr Oberhavel", :area_code => "33056") + AreaCode.create(:country => germany, :name => "Gransee", :area_code => "3306") + AreaCode.create(:country => germany, :name => "Zehdenick", :area_code => "3307") + AreaCode.create(:country => germany, :name => "Marienthal Kr Oberhavel", :area_code => "33080") + AreaCode.create(:country => germany, :name => "Menz Kr Oberhavel", :area_code => "33082") + AreaCode.create(:country => germany, :name => "Schulzendorf Kr Oberhavel", :area_code => "33083") + AreaCode.create(:country => germany, :name => "Gutengermendorf", :area_code => "33084") + AreaCode.create(:country => germany, :name => "Seilershof", :area_code => "33085") + AreaCode.create(:country => germany, :name => "Grieben Kr Oberhavel", :area_code => "33086") + AreaCode.create(:country => germany, :name => "Bredereiche", :area_code => "33087") + AreaCode.create(:country => germany, :name => "Falkenthal", :area_code => "33088") + AreaCode.create(:country => germany, :name => "Himmelpfort", :area_code => "33089") + AreaCode.create(:country => germany, :name => "Fürstenberg Havel", :area_code => "33093") + AreaCode.create(:country => germany, :name => "Löwenberg", :area_code => "33094") + AreaCode.create(:country => germany, :name => "Potsdam", :area_code => "331") + AreaCode.create(:country => germany, :name => "Bergholz-Rehbrücke", :area_code => "33200") + AreaCode.create(:country => germany, :name => "Gross Glienicke", :area_code => "33201") + AreaCode.create(:country => germany, :name => "Töplitz", :area_code => "33202") + AreaCode.create(:country => germany, :name => "Kleinmachnow", :area_code => "33203") + AreaCode.create(:country => germany, :name => "Beelitz Mark", :area_code => "33204") + AreaCode.create(:country => germany, :name => "Michendorf", :area_code => "33205") + AreaCode.create(:country => germany, :name => "Fichtenwalde", :area_code => "33206") + AreaCode.create(:country => germany, :name => "Gross Kreutz", :area_code => "33207") + AreaCode.create(:country => germany, :name => "Fahrland", :area_code => "33208") + AreaCode.create(:country => germany, :name => "Caputh", :area_code => "33209") + AreaCode.create(:country => germany, :name => "Nauen Brandenb", :area_code => "3321") + AreaCode.create(:country => germany, :name => "Falkensee", :area_code => "3322") + AreaCode.create(:country => germany, :name => "Börnicke Kr Havelland", :area_code => "33230") + AreaCode.create(:country => germany, :name => "Pausin", :area_code => "33231") + AreaCode.create(:country => germany, :name => "Brieselang", :area_code => "33232") + AreaCode.create(:country => germany, :name => "Ketzin", :area_code => "33233") + AreaCode.create(:country => germany, :name => "Wustermark", :area_code => "33234") + AreaCode.create(:country => germany, :name => "Friesack", :area_code => "33235") + AreaCode.create(:country => germany, :name => "Paulinenaue", :area_code => "33237") + AreaCode.create(:country => germany, :name => "Senzke", :area_code => "33238") + AreaCode.create(:country => germany, :name => "Gross Behnitz", :area_code => "33239") + AreaCode.create(:country => germany, :name => "Werder Havel", :area_code => "3327") + AreaCode.create(:country => germany, :name => "Teltow", :area_code => "3328") + AreaCode.create(:country => germany, :name => "Stahnsdorf", :area_code => "3329") + AreaCode.create(:country => germany, :name => "Angermünde", :area_code => "3331") + AreaCode.create(:country => germany, :name => "Schwedt/Oder", :area_code => "3332") + AreaCode.create(:country => germany, :name => "Casekow", :area_code => "33331") + AreaCode.create(:country => germany, :name => "Gartz Oder", :area_code => "33332") + AreaCode.create(:country => germany, :name => "Tantow", :area_code => "33333") + AreaCode.create(:country => germany, :name => "Greiffenberg", :area_code => "33334") + AreaCode.create(:country => germany, :name => "Pinnow Kr Uckermark", :area_code => "33335") + AreaCode.create(:country => germany, :name => "Passow Kr Uckermark", :area_code => "33336") + AreaCode.create(:country => germany, :name => "Altkünkendorf", :area_code => "33337") + AreaCode.create(:country => germany, :name => "Stolpe/Oder", :area_code => "33338") + AreaCode.create(:country => germany, :name => "Eberswalde", :area_code => "3334") + AreaCode.create(:country => germany, :name => "Finowfurt", :area_code => "3335") + AreaCode.create(:country => germany, :name => "Joachimsthal", :area_code => "33361") + AreaCode.create(:country => germany, :name => "Liepe Kr Barnim", :area_code => "33362") + AreaCode.create(:country => germany, :name => "Altenhof Kr Barnim", :area_code => "33363") + AreaCode.create(:country => germany, :name => "Gross Ziethen Kr Barnim", :area_code => "33364") + AreaCode.create(:country => germany, :name => "Lüdersdorf Kr Barnim", :area_code => "33365") + AreaCode.create(:country => germany, :name => "Chorin", :area_code => "33366") + AreaCode.create(:country => germany, :name => "Friedrichswalde Brandenb", :area_code => "33367") + AreaCode.create(:country => germany, :name => "Hohensaaten", :area_code => "33368") + AreaCode.create(:country => germany, :name => "Oderberg", :area_code => "33369") + AreaCode.create(:country => germany, :name => "Biesenthal Brandenb", :area_code => "3337") + AreaCode.create(:country => germany, :name => "Bernau Brandenb", :area_code => "3338") + AreaCode.create(:country => germany, :name => "Gross Schönebeck Kr Barnim", :area_code => "33393") + AreaCode.create(:country => germany, :name => "Blumberg Kr Barnim", :area_code => "33394") + AreaCode.create(:country => germany, :name => "Zerpenschleuse", :area_code => "33395") + AreaCode.create(:country => germany, :name => "Klosterfelde", :area_code => "33396") + AreaCode.create(:country => germany, :name => "Wandlitz", :area_code => "33397") + AreaCode.create(:country => germany, :name => "Werneuchen", :area_code => "33398") + AreaCode.create(:country => germany, :name => "Strausberg", :area_code => "3341") + AreaCode.create(:country => germany, :name => "Neuenhagen b Berlin", :area_code => "3342") + AreaCode.create(:country => germany, :name => "Müncheberg", :area_code => "33432") + AreaCode.create(:country => germany, :name => "Buckow Märk Schweiz", :area_code => "33433") + AreaCode.create(:country => germany, :name => "Herzfelde b Strausberg", :area_code => "33434") + AreaCode.create(:country => germany, :name => "Rehfelde", :area_code => "33435") + AreaCode.create(:country => germany, :name => "Prötzel", :area_code => "33436") + AreaCode.create(:country => germany, :name => "Reichenberg b Strausberg", :area_code => "33437") + AreaCode.create(:country => germany, :name => "Altlandsberg", :area_code => "33438") + AreaCode.create(:country => germany, :name => "Fredersdorf-Vogelsdorf", :area_code => "33439") + AreaCode.create(:country => germany, :name => "Bad Freienwalde", :area_code => "3344") + AreaCode.create(:country => germany, :name => "Heckelberg", :area_code => "33451") + AreaCode.create(:country => germany, :name => "Neulewin", :area_code => "33452") + AreaCode.create(:country => germany, :name => "Wölsickendorf/Wollenberg", :area_code => "33454") + AreaCode.create(:country => germany, :name => "Wriezen", :area_code => "33456") + AreaCode.create(:country => germany, :name => "Altreetz", :area_code => "33457") + AreaCode.create(:country => germany, :name => "Falkenberg Mark", :area_code => "33458") + AreaCode.create(:country => germany, :name => "Seelow", :area_code => "3346") + AreaCode.create(:country => germany, :name => "Lietzen", :area_code => "33470") + AreaCode.create(:country => germany, :name => "Golzow b Seelow", :area_code => "33472") + AreaCode.create(:country => germany, :name => "Zechin", :area_code => "33473") + AreaCode.create(:country => germany, :name => "Neutrebbin", :area_code => "33474") + AreaCode.create(:country => germany, :name => "Letschin", :area_code => "33475") + AreaCode.create(:country => germany, :name => "Neuhardenberg", :area_code => "33476") + AreaCode.create(:country => germany, :name => "Trebnitz b Müncheberg", :area_code => "33477") + AreaCode.create(:country => germany, :name => "Gross Neuendorf", :area_code => "33478") + AreaCode.create(:country => germany, :name => "Küstrin-Kietz", :area_code => "33479") + AreaCode.create(:country => germany, :name => "Frankfurt (Oder)", :area_code => "335") + AreaCode.create(:country => germany, :name => "Podelzig", :area_code => "33601") + AreaCode.create(:country => germany, :name => "Alt Zeschdorf", :area_code => "33602") + AreaCode.create(:country => germany, :name => "Falkenhagen b Seelow", :area_code => "33603") + AreaCode.create(:country => germany, :name => "Lebus", :area_code => "33604") + AreaCode.create(:country => germany, :name => "Boossen", :area_code => "33605") + AreaCode.create(:country => germany, :name => "Müllrose", :area_code => "33606") + AreaCode.create(:country => germany, :name => "Briesen Mark", :area_code => "33607") + AreaCode.create(:country => germany, :name => "Jacobsdorf Mark", :area_code => "33608") + AreaCode.create(:country => germany, :name => "Brieskow-Finkenheerd", :area_code => "33609") + AreaCode.create(:country => germany, :name => "Fürstenwalde Spree", :area_code => "3361") + AreaCode.create(:country => germany, :name => "Erkner", :area_code => "3362") + AreaCode.create(:country => germany, :name => "Bad Saarow-Pieskow", :area_code => "33631") + AreaCode.create(:country => germany, :name => "Hangelsberg", :area_code => "33632") + AreaCode.create(:country => germany, :name => "Spreenhagen", :area_code => "33633") + AreaCode.create(:country => germany, :name => "Berkenbrück Kr Oder-Spree", :area_code => "33634") + AreaCode.create(:country => germany, :name => "Arensdorf Kr Oder-Spree", :area_code => "33635") + AreaCode.create(:country => germany, :name => "Steinhöfel Kr Oder-Spree", :area_code => "33636") + AreaCode.create(:country => germany, :name => "Beerfelde", :area_code => "33637") + AreaCode.create(:country => germany, :name => "Rüdersdorf b Berlin", :area_code => "33638") + AreaCode.create(:country => germany, :name => "Eisenhüttenstadt", :area_code => "3364") + AreaCode.create(:country => germany, :name => "Neuzelle", :area_code => "33652") + AreaCode.create(:country => germany, :name => "Ziltendorf", :area_code => "33653") + AreaCode.create(:country => germany, :name => "Fünfeichen", :area_code => "33654") + AreaCode.create(:country => germany, :name => "Grunow Kr Oder-Spree", :area_code => "33655") + AreaCode.create(:country => germany, :name => "Bahro", :area_code => "33656") + AreaCode.create(:country => germany, :name => "Steinsdorf Brandenb", :area_code => "33657") + AreaCode.create(:country => germany, :name => "Beeskow", :area_code => "3366") + AreaCode.create(:country => germany, :name => "Lieberose", :area_code => "33671") + AreaCode.create(:country => germany, :name => "Pfaffendorf b Beeskow", :area_code => "33672") + AreaCode.create(:country => germany, :name => "Weichensdorf", :area_code => "33673") + AreaCode.create(:country => germany, :name => "Trebatsch", :area_code => "33674") + AreaCode.create(:country => germany, :name => "Tauche", :area_code => "33675") + AreaCode.create(:country => germany, :name => "Friedland b Beeskow", :area_code => "33676") + AreaCode.create(:country => germany, :name => "Glienicke b Beeskow", :area_code => "33677") + AreaCode.create(:country => germany, :name => "Storkow Mark", :area_code => "33678") + AreaCode.create(:country => germany, :name => "Wendisch Rietz", :area_code => "33679") + AreaCode.create(:country => germany, :name => "Grossbeeren", :area_code => "33701") + AreaCode.create(:country => germany, :name => "Wünsdorf", :area_code => "33702") + AreaCode.create(:country => germany, :name => "Sperenberg", :area_code => "33703") + AreaCode.create(:country => germany, :name => "Baruth Mark", :area_code => "33704") + AreaCode.create(:country => germany, :name => "Rangsdorf", :area_code => "33708") + AreaCode.create(:country => germany, :name => "Luckenwalde", :area_code => "3371") + AreaCode.create(:country => germany, :name => "Jüterbog", :area_code => "3372") + AreaCode.create(:country => germany, :name => "Trebbin", :area_code => "33731") + AreaCode.create(:country => germany, :name => "Hennickendorf b Luckenwalde", :area_code => "33732") + AreaCode.create(:country => germany, :name => "Stülpe", :area_code => "33733") + AreaCode.create(:country => germany, :name => "Felgentreu", :area_code => "33734") + AreaCode.create(:country => germany, :name => "Niedergörsdorf", :area_code => "33741") + AreaCode.create(:country => germany, :name => "Oehna Brandenb", :area_code => "33742") + AreaCode.create(:country => germany, :name => "Blönsdorf", :area_code => "33743") + AreaCode.create(:country => germany, :name => "Hohenseefeld", :area_code => "33744") + AreaCode.create(:country => germany, :name => "Petkus", :area_code => "33745") + AreaCode.create(:country => germany, :name => "Werbig b Jüterbog", :area_code => "33746") + AreaCode.create(:country => germany, :name => "Marzahna", :area_code => "33747") + AreaCode.create(:country => germany, :name => "Treuenbrietzen", :area_code => "33748") + AreaCode.create(:country => germany, :name => "Königs Wusterhausen", :area_code => "3375") + AreaCode.create(:country => germany, :name => "Münchehofe Kr Dahme-Spreewald", :area_code => "33760") + AreaCode.create(:country => germany, :name => "Zeuthen", :area_code => "33762") + AreaCode.create(:country => germany, :name => "Bestensee", :area_code => "33763") + AreaCode.create(:country => germany, :name => "Mittenwalde Mark", :area_code => "33764") + AreaCode.create(:country => germany, :name => "Märkisch Buchholz", :area_code => "33765") + AreaCode.create(:country => germany, :name => "Teupitz", :area_code => "33766") + AreaCode.create(:country => germany, :name => "Friedersdorf b Berlin", :area_code => "33767") + AreaCode.create(:country => germany, :name => "Prieros", :area_code => "33768") + AreaCode.create(:country => germany, :name => "Töpchin", :area_code => "33769") + AreaCode.create(:country => germany, :name => "Zossen Brandenb", :area_code => "3377") + AreaCode.create(:country => germany, :name => "Ludwigsfelde", :area_code => "3378") + AreaCode.create(:country => germany, :name => "Mahlow", :area_code => "3379") + AreaCode.create(:country => germany, :name => "Brandenburg an der Havel", :area_code => "3381") + AreaCode.create(:country => germany, :name => "Lehnin", :area_code => "3382") + AreaCode.create(:country => germany, :name => "Ziesar", :area_code => "33830") + AreaCode.create(:country => germany, :name => "Weseram", :area_code => "33831") + AreaCode.create(:country => germany, :name => "Rogäsen", :area_code => "33832") + AreaCode.create(:country => germany, :name => "Wollin b Brandenburg", :area_code => "33833") + AreaCode.create(:country => germany, :name => "Pritzerbe", :area_code => "33834") + AreaCode.create(:country => germany, :name => "Golzow b Brandenburg", :area_code => "33835") + AreaCode.create(:country => germany, :name => "Butzow b Brandenburg", :area_code => "33836") + AreaCode.create(:country => germany, :name => "Brielow", :area_code => "33837") + AreaCode.create(:country => germany, :name => "Päwesin", :area_code => "33838") + AreaCode.create(:country => germany, :name => "Wusterwitz", :area_code => "33839") + AreaCode.create(:country => germany, :name => "Belzig", :area_code => "33841") + AreaCode.create(:country => germany, :name => "Niemegk", :area_code => "33843") + AreaCode.create(:country => germany, :name => "Brück Brandenb", :area_code => "33844") + AreaCode.create(:country => germany, :name => "Borkheide", :area_code => "33845") + AreaCode.create(:country => germany, :name => "Dippmannsdorf", :area_code => "33846") + AreaCode.create(:country => germany, :name => "Görzke", :area_code => "33847") + AreaCode.create(:country => germany, :name => "Raben", :area_code => "33848") + AreaCode.create(:country => germany, :name => "Wiesenburg Mark", :area_code => "33849") + AreaCode.create(:country => germany, :name => "Rathenow", :area_code => "3385") + AreaCode.create(:country => germany, :name => "Premnitz", :area_code => "3386") + AreaCode.create(:country => germany, :name => "Zollchow b Rathenow", :area_code => "33870") + AreaCode.create(:country => germany, :name => "Hohennauen", :area_code => "33872") + AreaCode.create(:country => germany, :name => "Grosswudicke", :area_code => "33873") + AreaCode.create(:country => germany, :name => "Stechow Brandenb", :area_code => "33874") + AreaCode.create(:country => germany, :name => "Rhinow", :area_code => "33875") + AreaCode.create(:country => germany, :name => "Buschow", :area_code => "33876") + AreaCode.create(:country => germany, :name => "Nitzahn", :area_code => "33877") + AreaCode.create(:country => germany, :name => "Nennhausen", :area_code => "33878") + AreaCode.create(:country => germany, :name => "Neuruppin", :area_code => "3391") + AreaCode.create(:country => germany, :name => "Walsleben b Neuruppin", :area_code => "33920") + AreaCode.create(:country => germany, :name => "Zechlinerhütte", :area_code => "33921") + AreaCode.create(:country => germany, :name => "Karwesee", :area_code => "33922") + AreaCode.create(:country => germany, :name => "Flecken Zechlin", :area_code => "33923") + AreaCode.create(:country => germany, :name => "Rägelin", :area_code => "33924") + AreaCode.create(:country => germany, :name => "Wustrau-Altfriesack", :area_code => "33925") + AreaCode.create(:country => germany, :name => "Herzberg Mark", :area_code => "33926") + AreaCode.create(:country => germany, :name => "Wildberg Brandenb", :area_code => "33928") + AreaCode.create(:country => germany, :name => "Gühlen-Glienicke", :area_code => "33929") + AreaCode.create(:country => germany, :name => "Rheinsberg Mark", :area_code => "33931") + AreaCode.create(:country => germany, :name => "Fehrbellin", :area_code => "33932") + AreaCode.create(:country => germany, :name => "Lindow Mark", :area_code => "33933") + AreaCode.create(:country => germany, :name => "Wittstock Dosse", :area_code => "3394") + AreaCode.create(:country => germany, :name => "Pritzwalk", :area_code => "3395") + AreaCode.create(:country => germany, :name => "Heiligengrabe", :area_code => "33962") + AreaCode.create(:country => germany, :name => "Wulfersdorf b Wittstock", :area_code => "33963") + AreaCode.create(:country => germany, :name => "Fretzdorf", :area_code => "33964") + AreaCode.create(:country => germany, :name => "Herzsprung b Wittstock", :area_code => "33965") + AreaCode.create(:country => germany, :name => "Dranse", :area_code => "33966") + AreaCode.create(:country => germany, :name => "Freyenstein", :area_code => "33967") + AreaCode.create(:country => germany, :name => "Meyenburg Kr Prignitz", :area_code => "33968") + AreaCode.create(:country => germany, :name => "Stepenitz", :area_code => "33969") + AreaCode.create(:country => germany, :name => "Neustadt Dosse", :area_code => "33970") + AreaCode.create(:country => germany, :name => "Kyritz Brandenb", :area_code => "33971") + AreaCode.create(:country => germany, :name => "Breddin", :area_code => "33972") + AreaCode.create(:country => germany, :name => "Zernitz b Neustadt Dosse", :area_code => "33973") + AreaCode.create(:country => germany, :name => "Dessow", :area_code => "33974") + AreaCode.create(:country => germany, :name => "Dannenwalde Kr Prignitz", :area_code => "33975") + AreaCode.create(:country => germany, :name => "Wutike", :area_code => "33976") + AreaCode.create(:country => germany, :name => "Gumtow", :area_code => "33977") + AreaCode.create(:country => germany, :name => "Segeletz", :area_code => "33978") + AreaCode.create(:country => germany, :name => "Wusterhausen Dosse", :area_code => "33979") + AreaCode.create(:country => germany, :name => "Putlitz", :area_code => "33981") + AreaCode.create(:country => germany, :name => "Hoppenrade Kr Prignitz", :area_code => "33982") + AreaCode.create(:country => germany, :name => "Gross Pankow Kr Prignitz", :area_code => "33983") + AreaCode.create(:country => germany, :name => "Blumenthal b Pritzwalk", :area_code => "33984") + AreaCode.create(:country => germany, :name => "Falkenhagen Kr Prignitz", :area_code => "33986") + AreaCode.create(:country => germany, :name => "Sadenbeck", :area_code => "33989") + AreaCode.create(:country => germany, :name => "Dessau Anh", :area_code => "340") + AreaCode.create(:country => germany, :name => "Leipzig", :area_code => "341") + AreaCode.create(:country => germany, :name => "Delitzsch", :area_code => "34202") + AreaCode.create(:country => germany, :name => "Zwenkau", :area_code => "34203") + AreaCode.create(:country => germany, :name => "Schkeuditz", :area_code => "34204") + AreaCode.create(:country => germany, :name => "Markranstädt", :area_code => "34205") + AreaCode.create(:country => germany, :name => "Rötha", :area_code => "34206") + AreaCode.create(:country => germany, :name => "Zwochau", :area_code => "34207") + AreaCode.create(:country => germany, :name => "Löbnitz b Delitzsch", :area_code => "34208") + AreaCode.create(:country => germany, :name => "Torgau", :area_code => "3421") + AreaCode.create(:country => germany, :name => "Schildau Gneisenaustadt", :area_code => "34221") + AreaCode.create(:country => germany, :name => "Arzberg b Torgau", :area_code => "34222") + AreaCode.create(:country => germany, :name => "Dommitzsch", :area_code => "34223") + AreaCode.create(:country => germany, :name => "Belgern Sachs", :area_code => "34224") + AreaCode.create(:country => germany, :name => "Eilenburg", :area_code => "3423") + AreaCode.create(:country => germany, :name => "Jesewitz", :area_code => "34241") + AreaCode.create(:country => germany, :name => "Hohenpriessnitz", :area_code => "34242") + AreaCode.create(:country => germany, :name => "Bad Düben", :area_code => "34243") + AreaCode.create(:country => germany, :name => "Mockrehna", :area_code => "34244") + AreaCode.create(:country => germany, :name => "Wurzen", :area_code => "3425") + AreaCode.create(:country => germany, :name => "Kühren b Wurzen", :area_code => "34261") + AreaCode.create(:country => germany, :name => "Falkenhain b Wurzen", :area_code => "34262") + AreaCode.create(:country => germany, :name => "Hohburg", :area_code => "34263") + AreaCode.create(:country => germany, :name => "Borsdorf", :area_code => "34291") + AreaCode.create(:country => germany, :name => "Brandis b Wurzen", :area_code => "34292") + AreaCode.create(:country => germany, :name => "Naunhof b Grimma", :area_code => "34293") + AreaCode.create(:country => germany, :name => "Rackwitz", :area_code => "34294") + AreaCode.create(:country => germany, :name => "Krensitz", :area_code => "34295") + AreaCode.create(:country => germany, :name => "Groitzsch b Pegau", :area_code => "34296") + AreaCode.create(:country => germany, :name => "Liebertwolkwitz", :area_code => "34297") + AreaCode.create(:country => germany, :name => "Taucha b Leipzig", :area_code => "34298") + AreaCode.create(:country => germany, :name => "Gaschwitz", :area_code => "34299") + AreaCode.create(:country => germany, :name => "Döbeln", :area_code => "3431") + AreaCode.create(:country => germany, :name => "Leisnig", :area_code => "34321") + AreaCode.create(:country => germany, :name => "Rosswein", :area_code => "34322") + AreaCode.create(:country => germany, :name => "Ostrau Sachs", :area_code => "34324") + AreaCode.create(:country => germany, :name => "Mochau-Lüttewitz", :area_code => "34325") + AreaCode.create(:country => germany, :name => "Waldheim Sachs", :area_code => "34327") + AreaCode.create(:country => germany, :name => "Hartha b Döbeln", :area_code => "34328") + AreaCode.create(:country => germany, :name => "Borna Stadt", :area_code => "3433") + AreaCode.create(:country => germany, :name => "Geithain", :area_code => "34341") + AreaCode.create(:country => germany, :name => "Neukieritzsch", :area_code => "34342") + AreaCode.create(:country => germany, :name => "Regis-Breitingen", :area_code => "34343") + AreaCode.create(:country => germany, :name => "Kohren-Sahlis", :area_code => "34344") + AreaCode.create(:country => germany, :name => "Bad Lausick", :area_code => "34345") + AreaCode.create(:country => germany, :name => "Narsdorf", :area_code => "34346") + AreaCode.create(:country => germany, :name => "Oelzschau b Borna", :area_code => "34347") + AreaCode.create(:country => germany, :name => "Frohburg", :area_code => "34348") + AreaCode.create(:country => germany, :name => "Oschatz", :area_code => "3435") + AreaCode.create(:country => germany, :name => "Dahlen Sachs", :area_code => "34361") + AreaCode.create(:country => germany, :name => "Mügeln b Oschatz", :area_code => "34362") + AreaCode.create(:country => germany, :name => "Cavertitz", :area_code => "34363") + AreaCode.create(:country => germany, :name => "Wermsdorf", :area_code => "34364") + AreaCode.create(:country => germany, :name => "Grimma", :area_code => "3437") + AreaCode.create(:country => germany, :name => "Colditz", :area_code => "34381") + AreaCode.create(:country => germany, :name => "Nerchau", :area_code => "34382") + AreaCode.create(:country => germany, :name => "Trebsen Mulde", :area_code => "34383") + AreaCode.create(:country => germany, :name => "Grossbothen", :area_code => "34384") + AreaCode.create(:country => germany, :name => "Mutzschen", :area_code => "34385") + AreaCode.create(:country => germany, :name => "Dürrweitzschen b Grimma", :area_code => "34386") + AreaCode.create(:country => germany, :name => "Zeitz", :area_code => "3441") + AreaCode.create(:country => germany, :name => "Osterfeld", :area_code => "34422") + AreaCode.create(:country => germany, :name => "Heuckewalde", :area_code => "34423") + AreaCode.create(:country => germany, :name => "Reuden b Zeitz", :area_code => "34424") + AreaCode.create(:country => germany, :name => "Droyssig", :area_code => "34425") + AreaCode.create(:country => germany, :name => "Kayna", :area_code => "34426") + AreaCode.create(:country => germany, :name => "Weissenfels Sachs-Anh", :area_code => "3443") + AreaCode.create(:country => germany, :name => "Hohenmölsen", :area_code => "34441") + AreaCode.create(:country => germany, :name => "Teuchern", :area_code => "34443") + AreaCode.create(:country => germany, :name => "Lützen", :area_code => "34444") + AreaCode.create(:country => germany, :name => "Stößen", :area_code => "34445") + AreaCode.create(:country => germany, :name => "Grosskorbetha", :area_code => "34446") + AreaCode.create(:country => germany, :name => "Naumburg Saale", :area_code => "3445") + AreaCode.create(:country => germany, :name => "Nebra Unstrut", :area_code => "34461") + AreaCode.create(:country => germany, :name => "Laucha Unstrut", :area_code => "34462") + AreaCode.create(:country => germany, :name => "Bad Kösen", :area_code => "34463") + AreaCode.create(:country => germany, :name => "Freyburg Unstrut", :area_code => "34464") + AreaCode.create(:country => germany, :name => "Bad Bibra", :area_code => "34465") + AreaCode.create(:country => germany, :name => "Janisroda", :area_code => "34466") + AreaCode.create(:country => germany, :name => "Eckartsberga", :area_code => "34467") + AreaCode.create(:country => germany, :name => "Altenburg Thür", :area_code => "3447") + AreaCode.create(:country => germany, :name => "Meuselwitz Thür", :area_code => "3448") + AreaCode.create(:country => germany, :name => "Schmölln Thür", :area_code => "34491") + AreaCode.create(:country => germany, :name => "Lucka", :area_code => "34492") + AreaCode.create(:country => germany, :name => "Gößnitz Thür", :area_code => "34493") + AreaCode.create(:country => germany, :name => "Ehrenhain", :area_code => "34494") + AreaCode.create(:country => germany, :name => "Dobitschen", :area_code => "34495") + AreaCode.create(:country => germany, :name => "Nöbdenitz", :area_code => "34496") + AreaCode.create(:country => germany, :name => "Langenleuba-Niederhain", :area_code => "34497") + AreaCode.create(:country => germany, :name => "Rositz", :area_code => "34498") + AreaCode.create(:country => germany, :name => "Halle Saale", :area_code => "345") + AreaCode.create(:country => germany, :name => "Ostrau Saalkreis", :area_code => "34600") + AreaCode.create(:country => germany, :name => "Teutschenthal", :area_code => "34601") + AreaCode.create(:country => germany, :name => "Landsberg Sachs-Anh", :area_code => "34602") + AreaCode.create(:country => germany, :name => "Nauendorf Sachs-Anh", :area_code => "34603") + AreaCode.create(:country => germany, :name => "Niemberg", :area_code => "34604") + AreaCode.create(:country => germany, :name => "Gröbers", :area_code => "34605") + AreaCode.create(:country => germany, :name => "Teicha Sachs-Anh", :area_code => "34606") + AreaCode.create(:country => germany, :name => "Wettin", :area_code => "34607") + AreaCode.create(:country => germany, :name => "Salzmünde", :area_code => "34609") + AreaCode.create(:country => germany, :name => "Merseburg Saale", :area_code => "3461") + AreaCode.create(:country => germany, :name => "Bad Dürrenberg", :area_code => "3462") + AreaCode.create(:country => germany, :name => "Mücheln Geiseltal", :area_code => "34632") + AreaCode.create(:country => germany, :name => "Braunsbedra", :area_code => "34633") + AreaCode.create(:country => germany, :name => "Bad Lauchstädt", :area_code => "34635") + AreaCode.create(:country => germany, :name => "Schafstädt", :area_code => "34636") + AreaCode.create(:country => germany, :name => "Frankleben", :area_code => "34637") + AreaCode.create(:country => germany, :name => "Zöschen", :area_code => "34638") + AreaCode.create(:country => germany, :name => "Wallendorf Luppe", :area_code => "34639") + AreaCode.create(:country => germany, :name => "Sangerhausen", :area_code => "3464") + AreaCode.create(:country => germany, :name => "Rossla", :area_code => "34651") + AreaCode.create(:country => germany, :name => "Allstedt", :area_code => "34652") + AreaCode.create(:country => germany, :name => "Rottleberode", :area_code => "34653") + AreaCode.create(:country => germany, :name => "Stolberg Harz", :area_code => "34654") + AreaCode.create(:country => germany, :name => "Wallhausen Sachs-Anh", :area_code => "34656") + AreaCode.create(:country => germany, :name => "Hayn Harz", :area_code => "34658") + AreaCode.create(:country => germany, :name => "Blankenheim b Sangerhausen", :area_code => "34659") + AreaCode.create(:country => germany, :name => "Artern Unstrut", :area_code => "3466") + AreaCode.create(:country => germany, :name => "Bad Frankenhausen Kyffhäuser", :area_code => "34671") + AreaCode.create(:country => germany, :name => "Rossleben", :area_code => "34672") + AreaCode.create(:country => germany, :name => "Heldrungen", :area_code => "34673") + AreaCode.create(:country => germany, :name => "Könnern", :area_code => "34691") + AreaCode.create(:country => germany, :name => "Alsleben Saale", :area_code => "34692") + AreaCode.create(:country => germany, :name => "Bernburg Saale", :area_code => "3471") + AreaCode.create(:country => germany, :name => "Nienburg Saale", :area_code => "34721") + AreaCode.create(:country => germany, :name => "Preusslitz", :area_code => "34722") + AreaCode.create(:country => germany, :name => "Aschersleben Sachs-Anh", :area_code => "3473") + AreaCode.create(:country => germany, :name => "Frose", :area_code => "34741") + AreaCode.create(:country => germany, :name => "Sylda", :area_code => "34742") + AreaCode.create(:country => germany, :name => "Ermsleben", :area_code => "34743") + AreaCode.create(:country => germany, :name => "Winningen Sachs-Anh", :area_code => "34745") + AreaCode.create(:country => germany, :name => "Giersleben", :area_code => "34746") + AreaCode.create(:country => germany, :name => "Lutherstadt Eisleben", :area_code => "3475") + AreaCode.create(:country => germany, :name => "Hettstedt Sachs-Anh", :area_code => "3476") + AreaCode.create(:country => germany, :name => "Querfurt", :area_code => "34771") + AreaCode.create(:country => germany, :name => "Helbra", :area_code => "34772") + AreaCode.create(:country => germany, :name => "Schwittersdorf", :area_code => "34773") + AreaCode.create(:country => germany, :name => "Röblingen am See", :area_code => "34774") + AreaCode.create(:country => germany, :name => "Wippra", :area_code => "34775") + AreaCode.create(:country => germany, :name => "Rothenschirmbach", :area_code => "34776") + AreaCode.create(:country => germany, :name => "Abberode", :area_code => "34779") + AreaCode.create(:country => germany, :name => "Greifenhagen", :area_code => "34781") + AreaCode.create(:country => germany, :name => "Mansfeld Südharz", :area_code => "34782") + AreaCode.create(:country => germany, :name => "Gerbstedt", :area_code => "34783") + AreaCode.create(:country => germany, :name => "Sandersleben", :area_code => "34785") + AreaCode.create(:country => germany, :name => "Roßlau Elbe", :area_code => "34901") + AreaCode.create(:country => germany, :name => "Coswig Anhalt", :area_code => "34903") + AreaCode.create(:country => germany, :name => "Oranienbaum", :area_code => "34904") + AreaCode.create(:country => germany, :name => "Wörlitz", :area_code => "34905") + AreaCode.create(:country => germany, :name => "Raguhn", :area_code => "34906") + AreaCode.create(:country => germany, :name => "Jeber-Bergfrieden", :area_code => "34907") + AreaCode.create(:country => germany, :name => "Aken Elbe", :area_code => "34909") + AreaCode.create(:country => germany, :name => "Lutherstadt Wittenberg", :area_code => "3491") + AreaCode.create(:country => germany, :name => "Kropstädt", :area_code => "34920") + AreaCode.create(:country => germany, :name => "Kemberg", :area_code => "34921") + AreaCode.create(:country => germany, :name => "Mühlanger", :area_code => "34922") + AreaCode.create(:country => germany, :name => "Cobbelsdorf", :area_code => "34923") + AreaCode.create(:country => germany, :name => "Zahna", :area_code => "34924") + AreaCode.create(:country => germany, :name => "Bad Schmiedeberg", :area_code => "34925") + AreaCode.create(:country => germany, :name => "Pretzsch Elbe", :area_code => "34926") + AreaCode.create(:country => germany, :name => "Globig-Bleddin", :area_code => "34927") + AreaCode.create(:country => germany, :name => "Seegrehna", :area_code => "34928") + AreaCode.create(:country => germany, :name => "Straach", :area_code => "34929") + AreaCode.create(:country => germany, :name => "Bitterfeld", :area_code => "3493") + AreaCode.create(:country => germany, :name => "Wolfen", :area_code => "3494") + AreaCode.create(:country => germany, :name => "Gräfenhainichen", :area_code => "34953") + AreaCode.create(:country => germany, :name => "Roitzsch b Bitterfeld", :area_code => "34954") + AreaCode.create(:country => germany, :name => "Gossa", :area_code => "34955") + AreaCode.create(:country => germany, :name => "Zörbig", :area_code => "34956") + AreaCode.create(:country => germany, :name => "Köthen Anhalt", :area_code => "3496") + AreaCode.create(:country => germany, :name => "Osternienburg", :area_code => "34973") + AreaCode.create(:country => germany, :name => "Görzig Kr Köthen", :area_code => "34975") + AreaCode.create(:country => germany, :name => "Gröbzig", :area_code => "34976") + AreaCode.create(:country => germany, :name => "Quellendorf", :area_code => "34977") + AreaCode.create(:country => germany, :name => "Radegast Kr Köthen", :area_code => "34978") + AreaCode.create(:country => germany, :name => "Wulfen Sachs-Anh", :area_code => "34979") + AreaCode.create(:country => germany, :name => "Pirna", :area_code => "3501") + AreaCode.create(:country => germany, :name => "Struppen", :area_code => "35020") + AreaCode.create(:country => germany, :name => "Königstein Sächs Schweiz", :area_code => "35021") + AreaCode.create(:country => germany, :name => "Bad Schandau", :area_code => "35022") + AreaCode.create(:country => germany, :name => "Bad Gottleuba", :area_code => "35023") + AreaCode.create(:country => germany, :name => "Stadt Wehlen", :area_code => "35024") + AreaCode.create(:country => germany, :name => "Liebstadt", :area_code => "35025") + AreaCode.create(:country => germany, :name => "Dürrröhrsdorf-Dittersbach", :area_code => "35026") + AreaCode.create(:country => germany, :name => "Weesenstein", :area_code => "35027") + AreaCode.create(:country => germany, :name => "Krippen", :area_code => "35028") + AreaCode.create(:country => germany, :name => "Langenhennersdorf", :area_code => "35032") + AreaCode.create(:country => germany, :name => "Rosenthal Sächs Schweiz", :area_code => "35033") + AreaCode.create(:country => germany, :name => "Dippoldiswalde", :area_code => "3504") + AreaCode.create(:country => germany, :name => "Kipsdorf Kurort", :area_code => "35052") + AreaCode.create(:country => germany, :name => "Glashütte Sachs", :area_code => "35053") + AreaCode.create(:country => germany, :name => "Lauenstein Sachs", :area_code => "35054") + AreaCode.create(:country => germany, :name => "Höckendorf b Dippoldiswalde", :area_code => "35055") + AreaCode.create(:country => germany, :name => "Altenberg Sachs", :area_code => "35056") + AreaCode.create(:country => germany, :name => "Hermsdorf Erzgeb", :area_code => "35057") + AreaCode.create(:country => germany, :name => "Pretzschendorf", :area_code => "35058") + AreaCode.create(:country => germany, :name => "Dresden", :area_code => "351") + AreaCode.create(:country => germany, :name => "Arnsdorf b Dresden", :area_code => "35200") + AreaCode.create(:country => germany, :name => "Langebrück", :area_code => "35201") + AreaCode.create(:country => germany, :name => "Klingenberg Sachs", :area_code => "35202") + AreaCode.create(:country => germany, :name => "Tharandt", :area_code => "35203") + AreaCode.create(:country => germany, :name => "Wilsdruff", :area_code => "35204") + AreaCode.create(:country => germany, :name => "Ottendorf-Okrilla", :area_code => "35205") + AreaCode.create(:country => germany, :name => "Kreischa b Dresden", :area_code => "35206") + AreaCode.create(:country => germany, :name => "Moritzburg", :area_code => "35207") + AreaCode.create(:country => germany, :name => "Radeburg", :area_code => "35208") + AreaCode.create(:country => germany, :name => "Mohorn", :area_code => "35209") + AreaCode.create(:country => germany, :name => "Meissen", :area_code => "3521") + AreaCode.create(:country => germany, :name => "Grossenhain Sachs", :area_code => "3522") + AreaCode.create(:country => germany, :name => "Coswig b Dresden", :area_code => "3523") + AreaCode.create(:country => germany, :name => "Tauscha b Großenhain", :area_code => "35240") + AreaCode.create(:country => germany, :name => "Lommatzsch", :area_code => "35241") + AreaCode.create(:country => germany, :name => "Nossen", :area_code => "35242") + AreaCode.create(:country => germany, :name => "Weinböhla", :area_code => "35243") + AreaCode.create(:country => germany, :name => "Krögis", :area_code => "35244") + AreaCode.create(:country => germany, :name => "Burkhardswalde-Munzig", :area_code => "35245") + AreaCode.create(:country => germany, :name => "Ziegenhain Sachs", :area_code => "35246") + AreaCode.create(:country => germany, :name => "Zehren Sachs", :area_code => "35247") + AreaCode.create(:country => germany, :name => "Schönfeld b Großenhain", :area_code => "35248") + AreaCode.create(:country => germany, :name => "Basslitz", :area_code => "35249") + AreaCode.create(:country => germany, :name => "Riesa", :area_code => "3525") + AreaCode.create(:country => germany, :name => "Gröditz b Riesa", :area_code => "35263") + AreaCode.create(:country => germany, :name => "Strehla", :area_code => "35264") + AreaCode.create(:country => germany, :name => "Glaubitz", :area_code => "35265") + AreaCode.create(:country => germany, :name => "Heyda b Riesa", :area_code => "35266") + AreaCode.create(:country => germany, :name => "Diesbar-Seusslitz", :area_code => "35267") + AreaCode.create(:country => germany, :name => "Stauchitz", :area_code => "35268") + AreaCode.create(:country => germany, :name => "Radeberg", :area_code => "3528") + AreaCode.create(:country => germany, :name => "Heidenau Sachs", :area_code => "3529") + AreaCode.create(:country => germany, :name => "Finsterwalde", :area_code => "3531") + AreaCode.create(:country => germany, :name => "Doberlug-Kirchhain", :area_code => "35322") + AreaCode.create(:country => germany, :name => "Sonnewalde", :area_code => "35323") + AreaCode.create(:country => germany, :name => "Crinitz", :area_code => "35324") + AreaCode.create(:country => germany, :name => "Rückersdorf b Finsterwalde", :area_code => "35325") + AreaCode.create(:country => germany, :name => "Schönborn Kr Elbe-Elster", :area_code => "35326") + AreaCode.create(:country => germany, :name => "Priessen", :area_code => "35327") + AreaCode.create(:country => germany, :name => "Dollenchen", :area_code => "35329") + AreaCode.create(:country => germany, :name => "Elsterwerda", :area_code => "3533") + AreaCode.create(:country => germany, :name => "Bad Liebenwerda", :area_code => "35341") + AreaCode.create(:country => germany, :name => "Mühlberg Elbe", :area_code => "35342") + AreaCode.create(:country => germany, :name => "Hirschfeld b Elsterwerda", :area_code => "35343") + AreaCode.create(:country => germany, :name => "Herzberg Elster", :area_code => "3535") + AreaCode.create(:country => germany, :name => "Schlieben", :area_code => "35361") + AreaCode.create(:country => germany, :name => "Schönewalde b Herzberg", :area_code => "35362") + AreaCode.create(:country => germany, :name => "Fermerswalde", :area_code => "35363") + AreaCode.create(:country => germany, :name => "Lebusa", :area_code => "35364") + AreaCode.create(:country => germany, :name => "Falkenberg Elster", :area_code => "35365") + AreaCode.create(:country => germany, :name => "Jessen Elster", :area_code => "3537") + AreaCode.create(:country => germany, :name => "Elster Elbe", :area_code => "35383") + AreaCode.create(:country => germany, :name => "Steinsdorf b Jessen", :area_code => "35384") + AreaCode.create(:country => germany, :name => "Annaburg", :area_code => "35385") + AreaCode.create(:country => germany, :name => "Prettin", :area_code => "35386") + AreaCode.create(:country => germany, :name => "Seyda", :area_code => "35387") + AreaCode.create(:country => germany, :name => "Klöden", :area_code => "35388") + AreaCode.create(:country => germany, :name => "Holzdorf Elster", :area_code => "35389") + AreaCode.create(:country => germany, :name => "Calau", :area_code => "3541") + AreaCode.create(:country => germany, :name => "Lübbenau Spreewald", :area_code => "3542") + AreaCode.create(:country => germany, :name => "Vetschau", :area_code => "35433") + AreaCode.create(:country => germany, :name => "Altdöbern", :area_code => "35434") + AreaCode.create(:country => germany, :name => "Gollmitz b Calau", :area_code => "35435") + AreaCode.create(:country => germany, :name => "Laasow b Calau", :area_code => "35436") + AreaCode.create(:country => germany, :name => "Zinnitz", :area_code => "35439") + AreaCode.create(:country => germany, :name => "Luckau Brandenb", :area_code => "3544") + AreaCode.create(:country => germany, :name => "Dahme Brandenb", :area_code => "35451") + AreaCode.create(:country => germany, :name => "Golssen", :area_code => "35452") + AreaCode.create(:country => germany, :name => "Drahnsdorf", :area_code => "35453") + AreaCode.create(:country => germany, :name => "Uckro", :area_code => "35454") + AreaCode.create(:country => germany, :name => "Walddrehna", :area_code => "35455") + AreaCode.create(:country => germany, :name => "Terpt", :area_code => "35456") + AreaCode.create(:country => germany, :name => "Lübben Spreewald", :area_code => "3546") + AreaCode.create(:country => germany, :name => "Birkenhainchen", :area_code => "35471") + AreaCode.create(:country => germany, :name => "Schlepzig", :area_code => "35472") + AreaCode.create(:country => germany, :name => "Neu Lübbenau", :area_code => "35473") + AreaCode.create(:country => germany, :name => "Schönwalde b Lübben", :area_code => "35474") + AreaCode.create(:country => germany, :name => "Straupitz", :area_code => "35475") + AreaCode.create(:country => germany, :name => "Wittmannsdorf-Bückchen", :area_code => "35476") + AreaCode.create(:country => germany, :name => "Rietzneuendorf-Friedrichshof", :area_code => "35477") + AreaCode.create(:country => germany, :name => "Goyatz", :area_code => "35478") + AreaCode.create(:country => germany, :name => "Cottbus", :area_code => "355") + AreaCode.create(:country => germany, :name => "Döbern NL", :area_code => "35600") + AreaCode.create(:country => germany, :name => "Peitz", :area_code => "35601") + AreaCode.create(:country => germany, :name => "Drebkau", :area_code => "35602") + AreaCode.create(:country => germany, :name => "Burg Spreewald", :area_code => "35603") + AreaCode.create(:country => germany, :name => "Krieschow", :area_code => "35604") + AreaCode.create(:country => germany, :name => "Komptendorf", :area_code => "35605") + AreaCode.create(:country => germany, :name => "Briesen b Cottbus", :area_code => "35606") + AreaCode.create(:country => germany, :name => "Jänschwalde", :area_code => "35607") + AreaCode.create(:country => germany, :name => "Gross Ossnig", :area_code => "35608") + AreaCode.create(:country => germany, :name => "Drachhausen", :area_code => "35609") + AreaCode.create(:country => germany, :name => "Guben", :area_code => "3561") + AreaCode.create(:country => germany, :name => "Forst Lausitz", :area_code => "3562") + AreaCode.create(:country => germany, :name => "Spremberg", :area_code => "3563") + AreaCode.create(:country => germany, :name => "Schwarze Pumpe", :area_code => "3564") + AreaCode.create(:country => germany, :name => "Bärenklau NL", :area_code => "35691") + AreaCode.create(:country => germany, :name => "Kerkwitz", :area_code => "35692") + AreaCode.create(:country => germany, :name => "Lauschütz", :area_code => "35693") + AreaCode.create(:country => germany, :name => "Gosda b Klinge", :area_code => "35694") + AreaCode.create(:country => germany, :name => "Simmersdorf", :area_code => "35695") + AreaCode.create(:country => germany, :name => "Briesnig", :area_code => "35696") + AreaCode.create(:country => germany, :name => "Bagenz", :area_code => "35697") + AreaCode.create(:country => germany, :name => "Hornow", :area_code => "35698") + AreaCode.create(:country => germany, :name => "Hoyerswerda", :area_code => "3571") + AreaCode.create(:country => germany, :name => "Lauta b Hoyerswerda", :area_code => "35722") + AreaCode.create(:country => germany, :name => "Bernsdorf OL", :area_code => "35723") + AreaCode.create(:country => germany, :name => "Lohsa", :area_code => "35724") + AreaCode.create(:country => germany, :name => "Wittichenau", :area_code => "35725") + AreaCode.create(:country => germany, :name => "Groß Särchen", :area_code => "35726") + AreaCode.create(:country => germany, :name => "Burghammer", :area_code => "35727") + AreaCode.create(:country => germany, :name => "Uhyst Spree", :area_code => "35728") + AreaCode.create(:country => germany, :name => "Senftenberg", :area_code => "3573") + AreaCode.create(:country => germany, :name => "Lauchhammer", :area_code => "3574") + AreaCode.create(:country => germany, :name => "Welzow", :area_code => "35751") + AreaCode.create(:country => germany, :name => "Ruhland", :area_code => "35752") + AreaCode.create(:country => germany, :name => "Großräschen", :area_code => "35753") + AreaCode.create(:country => germany, :name => "Klettwitz", :area_code => "35754") + AreaCode.create(:country => germany, :name => "Ortrand", :area_code => "35755") + AreaCode.create(:country => germany, :name => "Hosena", :area_code => "35756") + AreaCode.create(:country => germany, :name => "Weisswasser", :area_code => "3576") + AreaCode.create(:country => germany, :name => "Bad Muskau", :area_code => "35771") + AreaCode.create(:country => germany, :name => "Rietschen", :area_code => "35772") + AreaCode.create(:country => germany, :name => "Schleife", :area_code => "35773") + AreaCode.create(:country => germany, :name => "Boxberg Sachs", :area_code => "35774") + AreaCode.create(:country => germany, :name => "Pechern", :area_code => "35775") + AreaCode.create(:country => germany, :name => "Kamenz", :area_code => "3578") + AreaCode.create(:country => germany, :name => "Ossling", :area_code => "35792") + AreaCode.create(:country => germany, :name => "Elstra", :area_code => "35793") + AreaCode.create(:country => germany, :name => "Königsbrück", :area_code => "35795") + AreaCode.create(:country => germany, :name => "Panschwitz-Kuckau", :area_code => "35796") + AreaCode.create(:country => germany, :name => "Schwepnitz", :area_code => "35797") + AreaCode.create(:country => germany, :name => "Görlitz", :area_code => "3581") + AreaCode.create(:country => germany, :name => "Zodel", :area_code => "35820") + AreaCode.create(:country => germany, :name => "Hagenwerder", :area_code => "35822") + AreaCode.create(:country => germany, :name => "Ostritz", :area_code => "35823") + AreaCode.create(:country => germany, :name => "Kodersdorf", :area_code => "35825") + AreaCode.create(:country => germany, :name => "Königshain b Görlitz", :area_code => "35826") + AreaCode.create(:country => germany, :name => "Nieder-Seifersdorf", :area_code => "35827") + AreaCode.create(:country => germany, :name => "Reichenbach OL", :area_code => "35828") + AreaCode.create(:country => germany, :name => "Gersdorf b Görlitz", :area_code => "35829") + AreaCode.create(:country => germany, :name => "Zittau", :area_code => "3583") + AreaCode.create(:country => germany, :name => "Großschönau Sachs", :area_code => "35841") + AreaCode.create(:country => germany, :name => "Oderwitz", :area_code => "35842") + AreaCode.create(:country => germany, :name => "Hirschfelde b Zittau", :area_code => "35843") + AreaCode.create(:country => germany, :name => "Oybin Kurort", :area_code => "35844") + AreaCode.create(:country => germany, :name => "Löbau", :area_code => "3585") + AreaCode.create(:country => germany, :name => "Neugersdorf ,Sachs", :area_code => "3586") + AreaCode.create(:country => germany, :name => "Neusalza-Spremberg", :area_code => "35872") + AreaCode.create(:country => germany, :name => "Herrnhut", :area_code => "35873") + AreaCode.create(:country => germany, :name => "Bernstadt a d Eigen", :area_code => "35874") + AreaCode.create(:country => germany, :name => "Obercunnersdorf b Löbau", :area_code => "35875") + AreaCode.create(:country => germany, :name => "Weissenberg Sachs", :area_code => "35876") + AreaCode.create(:country => germany, :name => "Cunewalde", :area_code => "35877") + AreaCode.create(:country => germany, :name => "Niesky", :area_code => "3588") + AreaCode.create(:country => germany, :name => "Rothenburg OL", :area_code => "35891") + AreaCode.create(:country => germany, :name => "Horka OL", :area_code => "35892") + AreaCode.create(:country => germany, :name => "Mücka", :area_code => "35893") + AreaCode.create(:country => germany, :name => "Hähnichen", :area_code => "35894") + AreaCode.create(:country => germany, :name => "Klitten", :area_code => "35895") + AreaCode.create(:country => germany, :name => "Bautzen", :area_code => "3591") + AreaCode.create(:country => germany, :name => "Kirschau", :area_code => "3592") + AreaCode.create(:country => germany, :name => "Seitschen", :area_code => "35930") + AreaCode.create(:country => germany, :name => "Königswartha", :area_code => "35931") + AreaCode.create(:country => germany, :name => "Guttau", :area_code => "35932") + AreaCode.create(:country => germany, :name => "Neschwitz", :area_code => "35933") + AreaCode.create(:country => germany, :name => "Grossdubrau", :area_code => "35934") + AreaCode.create(:country => germany, :name => "Kleinwelka", :area_code => "35935") + AreaCode.create(:country => germany, :name => "Sohland Spree", :area_code => "35936") + AreaCode.create(:country => germany, :name => "Prischwitz", :area_code => "35937") + AreaCode.create(:country => germany, :name => "Großpostwitz OL", :area_code => "35938") + AreaCode.create(:country => germany, :name => "Hochkirch", :area_code => "35939") + AreaCode.create(:country => germany, :name => "Bischofswerda", :area_code => "3594") + AreaCode.create(:country => germany, :name => "Neukirch Lausitz", :area_code => "35951") + AreaCode.create(:country => germany, :name => "Großröhrsdorf OL", :area_code => "35952") + AreaCode.create(:country => germany, :name => "Burkau", :area_code => "35953") + AreaCode.create(:country => germany, :name => "Grossharthau", :area_code => "35954") + AreaCode.create(:country => germany, :name => "Pulsnitz", :area_code => "35955") + AreaCode.create(:country => germany, :name => "Neustadt i Sa", :area_code => "3596") + AreaCode.create(:country => germany, :name => "Sebnitz", :area_code => "35971") + AreaCode.create(:country => germany, :name => "Stolpen", :area_code => "35973") + AreaCode.create(:country => germany, :name => "Hinterhermsdorf", :area_code => "35974") + AreaCode.create(:country => germany, :name => "Hohnstein", :area_code => "35975") + AreaCode.create(:country => germany, :name => "Mühlhausen Thür", :area_code => "3601") + AreaCode.create(:country => germany, :name => "Ebeleben", :area_code => "36020") + AreaCode.create(:country => germany, :name => "Schlotheim", :area_code => "36021") + AreaCode.create(:country => germany, :name => "Grossengottern", :area_code => "36022") + AreaCode.create(:country => germany, :name => "Horsmar", :area_code => "36023") + AreaCode.create(:country => germany, :name => "Diedorf b Mühlhausen Thür", :area_code => "36024") + AreaCode.create(:country => germany, :name => "Körner", :area_code => "36025") + AreaCode.create(:country => germany, :name => "Struth b Mühlhausen Thür", :area_code => "36026") + AreaCode.create(:country => germany, :name => "Lengenfeld Unterm Stein", :area_code => "36027") + AreaCode.create(:country => germany, :name => "Kammerforst Thür", :area_code => "36028") + AreaCode.create(:country => germany, :name => "Menteroda", :area_code => "36029") + AreaCode.create(:country => germany, :name => "Bad Langensalza", :area_code => "3603") + AreaCode.create(:country => germany, :name => "Bad Tennstedt", :area_code => "36041") + AreaCode.create(:country => germany, :name => "Tonna", :area_code => "36042") + AreaCode.create(:country => germany, :name => "Kirchheilingen", :area_code => "36043") + AreaCode.create(:country => germany, :name => "Leinefelde", :area_code => "3605") + AreaCode.create(:country => germany, :name => "Heiligenstadt Heilbad", :area_code => "3606") + AreaCode.create(:country => germany, :name => "Teistungen", :area_code => "36071") + AreaCode.create(:country => germany, :name => "Weißenborn-Lüderode", :area_code => "36072") + AreaCode.create(:country => germany, :name => "Worbis", :area_code => "36074") + AreaCode.create(:country => germany, :name => "Dingelstädt Eichsfeld", :area_code => "36075") + AreaCode.create(:country => germany, :name => "Niederorschel", :area_code => "36076") + AreaCode.create(:country => germany, :name => "Grossbodungen", :area_code => "36077") + AreaCode.create(:country => germany, :name => "Arenshausen", :area_code => "36081") + AreaCode.create(:country => germany, :name => "Ershausen", :area_code => "36082") + AreaCode.create(:country => germany, :name => "Uder", :area_code => "36083") + AreaCode.create(:country => germany, :name => "Heuthen", :area_code => "36084") + AreaCode.create(:country => germany, :name => "Reinholterode", :area_code => "36085") + AreaCode.create(:country => germany, :name => "Wüstheuterode", :area_code => "36087") + AreaCode.create(:country => germany, :name => "Erfurt", :area_code => "361") + AreaCode.create(:country => germany, :name => "Elxleben b Arnstadt", :area_code => "36200") + AreaCode.create(:country => germany, :name => "Walschleben", :area_code => "36201") + AreaCode.create(:country => germany, :name => "Neudietendorf", :area_code => "36202") + AreaCode.create(:country => germany, :name => "Vieselbach", :area_code => "36203") + AreaCode.create(:country => germany, :name => "Stotternheim", :area_code => "36204") + AreaCode.create(:country => germany, :name => "Gräfenroda", :area_code => "36205") + AreaCode.create(:country => germany, :name => "Grossfahner", :area_code => "36206") + AreaCode.create(:country => germany, :name => "Plaue Thür", :area_code => "36207") + AreaCode.create(:country => germany, :name => "Ermstedt", :area_code => "36208") + AreaCode.create(:country => germany, :name => "Klettbach", :area_code => "36209") + AreaCode.create(:country => germany, :name => "Gotha Thür", :area_code => "3621") + AreaCode.create(:country => germany, :name => "Waltershausen Thür", :area_code => "3622") + AreaCode.create(:country => germany, :name => "Friedrichroda", :area_code => "3623") + AreaCode.create(:country => germany, :name => "Ohrdruf", :area_code => "3624") + AreaCode.create(:country => germany, :name => "Tambach-Dietharz Thür Wald", :area_code => "36252") + AreaCode.create(:country => germany, :name => "Georgenthal Thür Wald", :area_code => "36253") + AreaCode.create(:country => germany, :name => "Friedrichswerth", :area_code => "36254") + AreaCode.create(:country => germany, :name => "Goldbach b Gotha", :area_code => "36255") + AreaCode.create(:country => germany, :name => "Wechmar", :area_code => "36256") + AreaCode.create(:country => germany, :name => "Luisenthal Thür", :area_code => "36257") + AreaCode.create(:country => germany, :name => "Friemar", :area_code => "36258") + AreaCode.create(:country => germany, :name => "Tabarz Thür Wald", :area_code => "36259") + AreaCode.create(:country => germany, :name => "Arnstadt", :area_code => "3628") + AreaCode.create(:country => germany, :name => "Stadtilm", :area_code => "3629") + AreaCode.create(:country => germany, :name => "Nordhausen Thür", :area_code => "3631") + AreaCode.create(:country => germany, :name => "Sondershausen", :area_code => "3632") + AreaCode.create(:country => germany, :name => "Grossberndten", :area_code => "36330") + AreaCode.create(:country => germany, :name => "Ilfeld", :area_code => "36331") + AreaCode.create(:country => germany, :name => "Ellrich", :area_code => "36332") + AreaCode.create(:country => germany, :name => "Heringen Helme", :area_code => "36333") + AreaCode.create(:country => germany, :name => "Wolkramshausen", :area_code => "36334") + AreaCode.create(:country => germany, :name => "Grosswechsungen", :area_code => "36335") + AreaCode.create(:country => germany, :name => "Klettenberg", :area_code => "36336") + AreaCode.create(:country => germany, :name => "Schiedungen", :area_code => "36337") + AreaCode.create(:country => germany, :name => "Bleicherode", :area_code => "36338") + AreaCode.create(:country => germany, :name => "Sömmerda", :area_code => "3634") + AreaCode.create(:country => germany, :name => "Kölleda", :area_code => "3635") + AreaCode.create(:country => germany, :name => "Greussen", :area_code => "3636") + AreaCode.create(:country => germany, :name => "Grossenehrich", :area_code => "36370") + AreaCode.create(:country => germany, :name => "Schlossvippach", :area_code => "36371") + AreaCode.create(:country => germany, :name => "Kleinneuhausen", :area_code => "36372") + AreaCode.create(:country => germany, :name => "Buttstädt", :area_code => "36373") + AreaCode.create(:country => germany, :name => "Weissensee", :area_code => "36374") + AreaCode.create(:country => germany, :name => "Kindelbrück", :area_code => "36375") + AreaCode.create(:country => germany, :name => "Straussfurt", :area_code => "36376") + AreaCode.create(:country => germany, :name => "Rastenberg", :area_code => "36377") + AreaCode.create(:country => germany, :name => "Ostramondra", :area_code => "36378") + AreaCode.create(:country => germany, :name => "Holzengel", :area_code => "36379") + AreaCode.create(:country => germany, :name => "Jena", :area_code => "3641") + AreaCode.create(:country => germany, :name => "Camburg", :area_code => "36421") + AreaCode.create(:country => germany, :name => "Reinstädt Thür", :area_code => "36422") + AreaCode.create(:country => germany, :name => "Orlamünde", :area_code => "36423") + AreaCode.create(:country => germany, :name => "Kahla Thür", :area_code => "36424") + AreaCode.create(:country => germany, :name => "Isserstedt", :area_code => "36425") + AreaCode.create(:country => germany, :name => "Ottendorf b Stadtroda", :area_code => "36426") + AreaCode.create(:country => germany, :name => "Dornburg Saale", :area_code => "36427") + AreaCode.create(:country => germany, :name => "Stadtroda", :area_code => "36428") + AreaCode.create(:country => germany, :name => "Weimar Thür", :area_code => "3643") + AreaCode.create(:country => germany, :name => "Apolda", :area_code => "3644") + AreaCode.create(:country => germany, :name => "Kranichfeld", :area_code => "36450") + AreaCode.create(:country => germany, :name => "Buttelstedt", :area_code => "36451") + AreaCode.create(:country => germany, :name => "Berlstedt", :area_code => "36452") + AreaCode.create(:country => germany, :name => "Mellingen", :area_code => "36453") + AreaCode.create(:country => germany, :name => "Magdala", :area_code => "36454") + AreaCode.create(:country => germany, :name => "Bad Berka", :area_code => "36458") + AreaCode.create(:country => germany, :name => "Blankenhain Thür", :area_code => "36459") + AreaCode.create(:country => germany, :name => "Bad Sulza", :area_code => "36461") + AreaCode.create(:country => germany, :name => "Ossmannstedt", :area_code => "36462") + AreaCode.create(:country => germany, :name => "Gebstedt", :area_code => "36463") + AreaCode.create(:country => germany, :name => "Wormstedt", :area_code => "36464") + AreaCode.create(:country => germany, :name => "Oberndorf b Apolda", :area_code => "36465") + AreaCode.create(:country => germany, :name => "Pößneck", :area_code => "3647") + AreaCode.create(:country => germany, :name => "Neustadt an der Orla", :area_code => "36481") + AreaCode.create(:country => germany, :name => "Triptis", :area_code => "36482") + AreaCode.create(:country => germany, :name => "Ziegenrück", :area_code => "36483") + AreaCode.create(:country => germany, :name => "Knau b Pößneck", :area_code => "36484") + AreaCode.create(:country => germany, :name => "Gera", :area_code => "365") + AreaCode.create(:country => germany, :name => "Hermsdorf Thür", :area_code => "36601") + AreaCode.create(:country => germany, :name => "Ronneburg Thür", :area_code => "36602") + AreaCode.create(:country => germany, :name => "Weida", :area_code => "36603") + AreaCode.create(:country => germany, :name => "Münchenbernsdorf", :area_code => "36604") + AreaCode.create(:country => germany, :name => "Bad Köstritz", :area_code => "36605") + AreaCode.create(:country => germany, :name => "Kraftsdorf", :area_code => "36606") + AreaCode.create(:country => germany, :name => "Niederpöllnitz", :area_code => "36607") + AreaCode.create(:country => germany, :name => "Seelingstädt b Gera", :area_code => "36608") + AreaCode.create(:country => germany, :name => "Greiz", :area_code => "3661") + AreaCode.create(:country => germany, :name => "Elsterberg b Plauen", :area_code => "36621") + AreaCode.create(:country => germany, :name => "Triebes", :area_code => "36622") + AreaCode.create(:country => germany, :name => "Berga Elster", :area_code => "36623") + AreaCode.create(:country => germany, :name => "Teichwolframsdorf", :area_code => "36624") + AreaCode.create(:country => germany, :name => "Langenwetzendorf", :area_code => "36625") + AreaCode.create(:country => germany, :name => "Auma", :area_code => "36626") + AreaCode.create(:country => germany, :name => "Zeulenroda", :area_code => "36628") + AreaCode.create(:country => germany, :name => "Schleiz", :area_code => "3663") + AreaCode.create(:country => germany, :name => "Remptendorf", :area_code => "36640") + AreaCode.create(:country => germany, :name => "Harra", :area_code => "36642") + AreaCode.create(:country => germany, :name => "Thimmendorf", :area_code => "36643") + AreaCode.create(:country => germany, :name => "Hirschberg Saale", :area_code => "36644") + AreaCode.create(:country => germany, :name => "Mühltroff", :area_code => "36645") + AreaCode.create(:country => germany, :name => "Tanna b Schleiz", :area_code => "36646") + AreaCode.create(:country => germany, :name => "Saalburg Thür", :area_code => "36647") + AreaCode.create(:country => germany, :name => "Dittersdorf b Schleiz", :area_code => "36648") + AreaCode.create(:country => germany, :name => "Gefell b Schleiz", :area_code => "36649") + AreaCode.create(:country => germany, :name => "Lobenstein", :area_code => "36651") + AreaCode.create(:country => germany, :name => "Wurzbach", :area_code => "36652") + AreaCode.create(:country => germany, :name => "Lehesten Thür Wald", :area_code => "36653") + AreaCode.create(:country => germany, :name => "Eisenberg Thür", :area_code => "36691") + AreaCode.create(:country => germany, :name => "Bürgel", :area_code => "36692") + AreaCode.create(:country => germany, :name => "Crossen an der Elster", :area_code => "36693") + AreaCode.create(:country => germany, :name => "Schkölen Thür", :area_code => "36694") + AreaCode.create(:country => germany, :name => "Söllmnitz", :area_code => "36695") + AreaCode.create(:country => germany, :name => "Lichte", :area_code => "36701") + AreaCode.create(:country => germany, :name => "Lauscha", :area_code => "36702") + AreaCode.create(:country => germany, :name => "Gräfenthal", :area_code => "36703") + AreaCode.create(:country => germany, :name => "Steinheid", :area_code => "36704") + AreaCode.create(:country => germany, :name => "Oberweißbach Thür Wald", :area_code => "36705") + AreaCode.create(:country => germany, :name => "Saalfeld Saale", :area_code => "3671") + AreaCode.create(:country => germany, :name => "Rudolstadt", :area_code => "3672") + AreaCode.create(:country => germany, :name => "Sitzendorf", :area_code => "36730") + AreaCode.create(:country => germany, :name => "Unterloquitz", :area_code => "36731") + AreaCode.create(:country => germany, :name => "Könitz", :area_code => "36732") + AreaCode.create(:country => germany, :name => "Kaulsdorf", :area_code => "36733") + AreaCode.create(:country => germany, :name => "Leutenberg", :area_code => "36734") + AreaCode.create(:country => germany, :name => "Probstzella", :area_code => "36735") + AreaCode.create(:country => germany, :name => "Arnsgereuth", :area_code => "36736") + AreaCode.create(:country => germany, :name => "Drognitz", :area_code => "36737") + AreaCode.create(:country => germany, :name => "Königsee", :area_code => "36738") + AreaCode.create(:country => germany, :name => "Rottenbach", :area_code => "36739") + AreaCode.create(:country => germany, :name => "Bad Blankenburg", :area_code => "36741") + AreaCode.create(:country => germany, :name => "Uhlstädt", :area_code => "36742") + AreaCode.create(:country => germany, :name => "Teichel", :area_code => "36743") + AreaCode.create(:country => germany, :name => "Remda", :area_code => "36744") + AreaCode.create(:country => germany, :name => "Sonneberg Thür", :area_code => "3675") + AreaCode.create(:country => germany, :name => "Heubisch", :area_code => "36761") + AreaCode.create(:country => germany, :name => "Steinach Thür", :area_code => "36762") + AreaCode.create(:country => germany, :name => "Neuhaus-Schierschnitz", :area_code => "36764") + AreaCode.create(:country => germany, :name => "Schalkau", :area_code => "36766") + AreaCode.create(:country => germany, :name => "Ilmenau Thür", :area_code => "3677") + AreaCode.create(:country => germany, :name => "Grossbreitenbach", :area_code => "36781") + AreaCode.create(:country => germany, :name => "Schmiedefeld a Rennsteig", :area_code => "36782") + AreaCode.create(:country => germany, :name => "Gehren Thür", :area_code => "36783") + AreaCode.create(:country => germany, :name => "Stützerbach", :area_code => "36784") + AreaCode.create(:country => germany, :name => "Gräfinau-Angstedt", :area_code => "36785") + AreaCode.create(:country => germany, :name => "Neuhaus a Rennweg", :area_code => "3679") + AreaCode.create(:country => germany, :name => "Suhl", :area_code => "3681") + AreaCode.create(:country => germany, :name => "Zella-Mehlis", :area_code => "3682") + AreaCode.create(:country => germany, :name => "Schmalkalden", :area_code => "3683") + AreaCode.create(:country => germany, :name => "Trusetal", :area_code => "36840") + AreaCode.create(:country => germany, :name => "Schleusingen", :area_code => "36841") + AreaCode.create(:country => germany, :name => "Oberhof Thür", :area_code => "36842") + AreaCode.create(:country => germany, :name => "Benshausen", :area_code => "36843") + AreaCode.create(:country => germany, :name => "Rohr Thür", :area_code => "36844") + AreaCode.create(:country => germany, :name => "Gehlberg", :area_code => "36845") + AreaCode.create(:country => germany, :name => "Suhl-Dietzhausen", :area_code => "36846") + AreaCode.create(:country => germany, :name => "Steinbach-Hallenberg", :area_code => "36847") + AreaCode.create(:country => germany, :name => "Wernshausen", :area_code => "36848") + AreaCode.create(:country => germany, :name => "Kleinschmalkalden", :area_code => "36849") + AreaCode.create(:country => germany, :name => "Hildburghausen", :area_code => "3685") + AreaCode.create(:country => germany, :name => "Eisfeld", :area_code => "3686") + AreaCode.create(:country => germany, :name => "Masserberg", :area_code => "36870") + AreaCode.create(:country => germany, :name => "Bad Colberg-Heldburg", :area_code => "36871") + AreaCode.create(:country => germany, :name => "Themar", :area_code => "36873") + AreaCode.create(:country => germany, :name => "Schönbrunn b Hildburghaus", :area_code => "36874") + AreaCode.create(:country => germany, :name => "Straufhain-Streufdorf", :area_code => "36875") + AreaCode.create(:country => germany, :name => "Oberland", :area_code => "36878") + AreaCode.create(:country => germany, :name => "Eisenach Thür", :area_code => "3691") + AreaCode.create(:country => germany, :name => "Grossenlupnitz", :area_code => "36920") + AreaCode.create(:country => germany, :name => "Wutha-Farnroda", :area_code => "36921") + AreaCode.create(:country => germany, :name => "Gerstungen", :area_code => "36922") + AreaCode.create(:country => germany, :name => "Treffurt", :area_code => "36923") + AreaCode.create(:country => germany, :name => "Mihla", :area_code => "36924") + AreaCode.create(:country => germany, :name => "Marksuhl", :area_code => "36925") + AreaCode.create(:country => germany, :name => "Creuzburg", :area_code => "36926") + AreaCode.create(:country => germany, :name => "Unterellen", :area_code => "36927") + AreaCode.create(:country => germany, :name => "Neuenhof Thür", :area_code => "36928") + AreaCode.create(:country => germany, :name => "Ruhla", :area_code => "36929") + AreaCode.create(:country => germany, :name => "Meiningen", :area_code => "3693") + AreaCode.create(:country => germany, :name => "Oepfershausen", :area_code => "36940") + AreaCode.create(:country => germany, :name => "Wasungen", :area_code => "36941") + AreaCode.create(:country => germany, :name => "Bettenhausen Thür", :area_code => "36943") + AreaCode.create(:country => germany, :name => "Rentwertshausen", :area_code => "36944") + AreaCode.create(:country => germany, :name => "Henneberg", :area_code => "36945") + AreaCode.create(:country => germany, :name => "Erbenhausen Thür", :area_code => "36946") + AreaCode.create(:country => germany, :name => "Jüchsen", :area_code => "36947") + AreaCode.create(:country => germany, :name => "Römhild", :area_code => "36948") + AreaCode.create(:country => germany, :name => "Obermaßfeld-Grimmenthal", :area_code => "36949") + AreaCode.create(:country => germany, :name => "Bad Salzungen", :area_code => "3695") + AreaCode.create(:country => germany, :name => "Bad Liebenstein", :area_code => "36961") + AreaCode.create(:country => germany, :name => "Vacha", :area_code => "36962") + AreaCode.create(:country => germany, :name => "Dorndorf Rhön", :area_code => "36963") + AreaCode.create(:country => germany, :name => "Dermbach Rhön", :area_code => "36964") + AreaCode.create(:country => germany, :name => "Stadtlengsfeld", :area_code => "36965") + AreaCode.create(:country => germany, :name => "Kaltennordheim", :area_code => "36966") + AreaCode.create(:country => germany, :name => "Geisa", :area_code => "36967") + AreaCode.create(:country => germany, :name => "Rossdorf Rhön", :area_code => "36968") + AreaCode.create(:country => germany, :name => "Merkers", :area_code => "36969") + AreaCode.create(:country => germany, :name => "Chemnitz Sachs", :area_code => "371") + AreaCode.create(:country => germany, :name => "Wittgensdorf b Chemnitz", :area_code => "37200") + AreaCode.create(:country => germany, :name => "Claussnitz b Chemnitz", :area_code => "37202") + AreaCode.create(:country => germany, :name => "Gersdorf b Chemnitz", :area_code => "37203") + AreaCode.create(:country => germany, :name => "Lichtenstein Sachs", :area_code => "37204") + AreaCode.create(:country => germany, :name => "Frankenberg", :area_code => "37206") + AreaCode.create(:country => germany, :name => "Hainichen", :area_code => "37207") + AreaCode.create(:country => germany, :name => "Auerswalde", :area_code => "37208") + AreaCode.create(:country => germany, :name => "Einsiedel b Chemnitz", :area_code => "37209") + AreaCode.create(:country => germany, :name => "Meinersdorf", :area_code => "3721") + AreaCode.create(:country => germany, :name => "Limbach-Oberfrohna", :area_code => "3722") + AreaCode.create(:country => germany, :name => "Hohenstein-Ernstthal", :area_code => "3723") + AreaCode.create(:country => germany, :name => "Burgstädt", :area_code => "3724") + AreaCode.create(:country => germany, :name => "Zschopau", :area_code => "3725") + AreaCode.create(:country => germany, :name => "Flöha", :area_code => "3726") + AreaCode.create(:country => germany, :name => "Mittweida", :area_code => "3727") + AreaCode.create(:country => germany, :name => "Augustusburg", :area_code => "37291") + AreaCode.create(:country => germany, :name => "Oederan", :area_code => "37292") + AreaCode.create(:country => germany, :name => "Eppendorf Sachs", :area_code => "37293") + AreaCode.create(:country => germany, :name => "Grünhainichen", :area_code => "37294") + AreaCode.create(:country => germany, :name => "Lugau Erzgeb", :area_code => "37295") + AreaCode.create(:country => germany, :name => "Stollberg Erzgeb", :area_code => "37296") + AreaCode.create(:country => germany, :name => "Thum Sachs", :area_code => "37297") + AreaCode.create(:country => germany, :name => "Oelsnitz Erzgeb", :area_code => "37298") + AreaCode.create(:country => germany, :name => "Freiberg Sachs", :area_code => "3731") + AreaCode.create(:country => germany, :name => "Mulda Sachs", :area_code => "37320") + AreaCode.create(:country => germany, :name => "Frankenstein Sachs", :area_code => "37321") + AreaCode.create(:country => germany, :name => "Brand-Erbisdorf", :area_code => "37322") + AreaCode.create(:country => germany, :name => "Lichtenberg Erzgeb", :area_code => "37323") + AreaCode.create(:country => germany, :name => "Reinsberg Sachs", :area_code => "37324") + AreaCode.create(:country => germany, :name => "Niederbobritzsch", :area_code => "37325") + AreaCode.create(:country => germany, :name => "Frauenstein Sachs", :area_code => "37326") + AreaCode.create(:country => germany, :name => "Rechenberg-Bienenmühle", :area_code => "37327") + AreaCode.create(:country => germany, :name => "Grossschirma", :area_code => "37328") + AreaCode.create(:country => germany, :name => "Grosshartmannsdorf", :area_code => "37329") + AreaCode.create(:country => germany, :name => "Annaberg-Buchholz", :area_code => "3733") + AreaCode.create(:country => germany, :name => "Ehrenfriedersdorf", :area_code => "37341") + AreaCode.create(:country => germany, :name => "Cranzahl", :area_code => "37342") + AreaCode.create(:country => germany, :name => "Jöhstadt", :area_code => "37343") + AreaCode.create(:country => germany, :name => "Crottendorf Sachs", :area_code => "37344") + AreaCode.create(:country => germany, :name => "Geyer", :area_code => "37346") + AreaCode.create(:country => germany, :name => "Bärenstein Kr Annaberg", :area_code => "37347") + AreaCode.create(:country => germany, :name => "Oberwiesenthal Kurort", :area_code => "37348") + AreaCode.create(:country => germany, :name => "Scheibenberg", :area_code => "37349") + AreaCode.create(:country => germany, :name => "Marienberg Sachs", :area_code => "3735") + AreaCode.create(:country => germany, :name => "Olbernhau", :area_code => "37360") + AreaCode.create(:country => germany, :name => "Neuhausen Erzgeb", :area_code => "37361") + AreaCode.create(:country => germany, :name => "Seiffen Erzgeb", :area_code => "37362") + AreaCode.create(:country => germany, :name => "Zöblitz", :area_code => "37363") + AreaCode.create(:country => germany, :name => "Reitzenhain Erzgeb", :area_code => "37364") + AreaCode.create(:country => germany, :name => "Sayda", :area_code => "37365") + AreaCode.create(:country => germany, :name => "Rübenau", :area_code => "37366") + AreaCode.create(:country => germany, :name => "Lengefeld Erzgeb", :area_code => "37367") + AreaCode.create(:country => germany, :name => "Deutschneudorf", :area_code => "37368") + AreaCode.create(:country => germany, :name => "Wolkenstein", :area_code => "37369") + AreaCode.create(:country => germany, :name => "Rochlitz", :area_code => "3737") + AreaCode.create(:country => germany, :name => "Penig", :area_code => "37381") + AreaCode.create(:country => germany, :name => "Geringswalde", :area_code => "37382") + AreaCode.create(:country => germany, :name => "Lunzenau", :area_code => "37383") + AreaCode.create(:country => germany, :name => "Wechselburg", :area_code => "37384") + AreaCode.create(:country => germany, :name => "Plauen", :area_code => "3741") + AreaCode.create(:country => germany, :name => "Oelsnitz Vogtl", :area_code => "37421") + AreaCode.create(:country => germany, :name => "Markneukirchen", :area_code => "37422") + AreaCode.create(:country => germany, :name => "Adorf Vogtl", :area_code => "37423") + AreaCode.create(:country => germany, :name => "Eichigt", :area_code => "37430") + AreaCode.create(:country => germany, :name => "Mehltheuer Vogtl", :area_code => "37431") + AreaCode.create(:country => germany, :name => "Pausa Vogtl", :area_code => "37432") + AreaCode.create(:country => germany, :name => "Gutenfürst", :area_code => "37433") + AreaCode.create(:country => germany, :name => "Bobenneukirchen", :area_code => "37434") + AreaCode.create(:country => germany, :name => "Reuth b Plauen", :area_code => "37435") + AreaCode.create(:country => germany, :name => "Weischlitz", :area_code => "37436") + AreaCode.create(:country => germany, :name => "Bad Elster", :area_code => "37437") + AreaCode.create(:country => germany, :name => "Bad Brambach", :area_code => "37438") + AreaCode.create(:country => germany, :name => "Jocketa", :area_code => "37439") + AreaCode.create(:country => germany, :name => "Auerbach Vogtl.", :area_code => "3744") + AreaCode.create(:country => germany, :name => "Falkenstein Vogtl", :area_code => "3745") + AreaCode.create(:country => germany, :name => "Rothenkirchen Vogtl", :area_code => "37462") + AreaCode.create(:country => germany, :name => "Bergen Vogtl", :area_code => "37463") + AreaCode.create(:country => germany, :name => "Schöneck Vogtl", :area_code => "37464") + AreaCode.create(:country => germany, :name => "Tannenbergsthal Vogtl", :area_code => "37465") + AreaCode.create(:country => germany, :name => "Klingenthal Sachs", :area_code => "37467") + AreaCode.create(:country => germany, :name => "Treuen Vogtl", :area_code => "37468") + AreaCode.create(:country => germany, :name => "Zwickau", :area_code => "375") + AreaCode.create(:country => germany, :name => "Neumark Sachs", :area_code => "37600") + AreaCode.create(:country => germany, :name => "Mülsen Skt Jacob", :area_code => "37601") + AreaCode.create(:country => germany, :name => "Kirchberg Sachs", :area_code => "37602") + AreaCode.create(:country => germany, :name => "Wildenfels", :area_code => "37603") + AreaCode.create(:country => germany, :name => "Mosel", :area_code => "37604") + AreaCode.create(:country => germany, :name => "Hartenstein Sachs", :area_code => "37605") + AreaCode.create(:country => germany, :name => "Lengenfeld Vogtl", :area_code => "37606") + AreaCode.create(:country => germany, :name => "Ebersbrunn Sachs", :area_code => "37607") + AreaCode.create(:country => germany, :name => "Waldenburg Sachs", :area_code => "37608") + AreaCode.create(:country => germany, :name => "Wolkenburg Mulde", :area_code => "37609") + AreaCode.create(:country => germany, :name => "Werdau Sachs", :area_code => "3761") + AreaCode.create(:country => germany, :name => "Crimmitschau", :area_code => "3762") + AreaCode.create(:country => germany, :name => "Glauchau", :area_code => "3763") + AreaCode.create(:country => germany, :name => "Meerane", :area_code => "3764") + AreaCode.create(:country => germany, :name => "Reichenbach Vogtl", :area_code => "3765") + AreaCode.create(:country => germany, :name => "Aue Sachs", :area_code => "3771") + AreaCode.create(:country => germany, :name => "Schneeberg Erzgeb", :area_code => "3772") + AreaCode.create(:country => germany, :name => "Johanngeorgenstadt", :area_code => "3773") + AreaCode.create(:country => germany, :name => "Schwarzenberg", :area_code => "3774") + AreaCode.create(:country => germany, :name => "Eibenstock", :area_code => "37752") + AreaCode.create(:country => germany, :name => "Zwönitz", :area_code => "37754") + AreaCode.create(:country => germany, :name => "Schönheide Erzgeb", :area_code => "37755") + AreaCode.create(:country => germany, :name => "Breitenbrunn Erzgeb", :area_code => "37756") + AreaCode.create(:country => germany, :name => "Rittersgrün", :area_code => "37757") + AreaCode.create(:country => germany, :name => "Rostock", :area_code => "381") + AreaCode.create(:country => germany, :name => "Gelbensande", :area_code => "38201") + AreaCode.create(:country => germany, :name => "Volkenshagen", :area_code => "38202") + AreaCode.create(:country => germany, :name => "Bad Doberan", :area_code => "38203") + AreaCode.create(:country => germany, :name => "Broderstorf", :area_code => "38204") + AreaCode.create(:country => germany, :name => "Tessin b Rostock", :area_code => "38205") + AreaCode.create(:country => germany, :name => "Graal-Müritz Seeheilbad", :area_code => "38206") + AreaCode.create(:country => germany, :name => "Stäbelow", :area_code => "38207") + AreaCode.create(:country => germany, :name => "Kavelstorf", :area_code => "38208") + AreaCode.create(:country => germany, :name => "Sanitz b Rostock", :area_code => "38209") + AreaCode.create(:country => germany, :name => "Ribnitz-Damgarten", :area_code => "3821") + AreaCode.create(:country => germany, :name => "Wustrow Ostseebad", :area_code => "38220") + AreaCode.create(:country => germany, :name => "Marlow", :area_code => "38221") + AreaCode.create(:country => germany, :name => "Semlow", :area_code => "38222") + AreaCode.create(:country => germany, :name => "Saal Vorpom", :area_code => "38223") + AreaCode.create(:country => germany, :name => "Gresenhorst", :area_code => "38224") + AreaCode.create(:country => germany, :name => "Trinwillershagen", :area_code => "38225") + AreaCode.create(:country => germany, :name => "Dierhagen Ostseebad", :area_code => "38226") + AreaCode.create(:country => germany, :name => "Lüdershagen b Barth", :area_code => "38227") + AreaCode.create(:country => germany, :name => "Dettmannsdorf-Kölzow", :area_code => "38228") + AreaCode.create(:country => germany, :name => "Bad Sülze", :area_code => "38229") + AreaCode.create(:country => germany, :name => "Barth", :area_code => "38231") + AreaCode.create(:country => germany, :name => "Zingst Ostseebad", :area_code => "38232") + AreaCode.create(:country => germany, :name => "Prerow Ostseebad", :area_code => "38233") + AreaCode.create(:country => germany, :name => "Born a Darß", :area_code => "38234") + AreaCode.create(:country => germany, :name => "Kröpelin", :area_code => "38292") + AreaCode.create(:country => germany, :name => "Kühlungsborn Ostseebad", :area_code => "38293") + AreaCode.create(:country => germany, :name => "Neubukow", :area_code => "38294") + AreaCode.create(:country => germany, :name => "Satow b Bad Doberan", :area_code => "38295") + AreaCode.create(:country => germany, :name => "Rerik Ostseebad", :area_code => "38296") + AreaCode.create(:country => germany, :name => "Moitin", :area_code => "38297") + AreaCode.create(:country => germany, :name => "Insel Hiddensee", :area_code => "38300") + AreaCode.create(:country => germany, :name => "Putbus", :area_code => "38301") + AreaCode.create(:country => germany, :name => "Sagard", :area_code => "38302") + AreaCode.create(:country => germany, :name => "Sellin Ostseebad", :area_code => "38303") + AreaCode.create(:country => germany, :name => "Garz Rügen", :area_code => "38304") + AreaCode.create(:country => germany, :name => "Gingst", :area_code => "38305") + AreaCode.create(:country => germany, :name => "Samtens", :area_code => "38306") + AreaCode.create(:country => germany, :name => "Poseritz", :area_code => "38307") + AreaCode.create(:country => germany, :name => "Göhren Rügen", :area_code => "38308") + AreaCode.create(:country => germany, :name => "Trent", :area_code => "38309") + AreaCode.create(:country => germany, :name => "Stralsund", :area_code => "3831") + AreaCode.create(:country => germany, :name => "Tribsees", :area_code => "38320") + AreaCode.create(:country => germany, :name => "Martensdorf b Stralsund", :area_code => "38321") + AreaCode.create(:country => germany, :name => "Richtenberg", :area_code => "38322") + AreaCode.create(:country => germany, :name => "Prohn", :area_code => "38323") + AreaCode.create(:country => germany, :name => "Velgast", :area_code => "38324") + AreaCode.create(:country => germany, :name => "Rolofshagen", :area_code => "38325") + AreaCode.create(:country => germany, :name => "Grimmen", :area_code => "38326") + AreaCode.create(:country => germany, :name => "Elmenhorst Vorpom", :area_code => "38327") + AreaCode.create(:country => germany, :name => "Miltzow", :area_code => "38328") + AreaCode.create(:country => germany, :name => "Rakow Vorpom", :area_code => "38331") + AreaCode.create(:country => germany, :name => "Gross Bisdorf", :area_code => "38332") + AreaCode.create(:country => germany, :name => "Horst b Grimmen", :area_code => "38333") + AreaCode.create(:country => germany, :name => "Grammendorf", :area_code => "38334") + AreaCode.create(:country => germany, :name => "Greifswald", :area_code => "3834") + AreaCode.create(:country => germany, :name => "Mesekenhagen", :area_code => "38351") + AreaCode.create(:country => germany, :name => "Kemnitz b Greifswald", :area_code => "38352") + AreaCode.create(:country => germany, :name => "Gützkow b Greifswald", :area_code => "38353") + AreaCode.create(:country => germany, :name => "Wusterhusen", :area_code => "38354") + AreaCode.create(:country => germany, :name => "Züssow", :area_code => "38355") + AreaCode.create(:country => germany, :name => "Behrenhoff", :area_code => "38356") + AreaCode.create(:country => germany, :name => "Wolgast", :area_code => "3836") + AreaCode.create(:country => germany, :name => "Kröslin", :area_code => "38370") + AreaCode.create(:country => germany, :name => "Karlshagen", :area_code => "38371") + AreaCode.create(:country => germany, :name => "Usedom", :area_code => "38372") + AreaCode.create(:country => germany, :name => "Katzow", :area_code => "38373") + AreaCode.create(:country => germany, :name => "Lassan b Wolgast", :area_code => "38374") + AreaCode.create(:country => germany, :name => "Koserow", :area_code => "38375") + AreaCode.create(:country => germany, :name => "Zirchow", :area_code => "38376") + AreaCode.create(:country => germany, :name => "Zinnowitz", :area_code => "38377") + AreaCode.create(:country => germany, :name => "Heringsdorf Seebad", :area_code => "38378") + AreaCode.create(:country => germany, :name => "Benz Usedom", :area_code => "38379") + AreaCode.create(:country => germany, :name => "Bergen auf Rügen", :area_code => "3838") + AreaCode.create(:country => germany, :name => "Altenkirchen Rügen", :area_code => "38391") + AreaCode.create(:country => germany, :name => "Sassnitz", :area_code => "38392") + AreaCode.create(:country => germany, :name => "Binz Ostseebad", :area_code => "38393") + AreaCode.create(:country => germany, :name => "Wismar Meckl", :area_code => "3841") + AreaCode.create(:country => germany, :name => "Neukloster", :area_code => "38422") + AreaCode.create(:country => germany, :name => "Bad Kleinen", :area_code => "38423") + AreaCode.create(:country => germany, :name => "Bobitz", :area_code => "38424") + AreaCode.create(:country => germany, :name => "Kirchdorf Poel", :area_code => "38425") + AreaCode.create(:country => germany, :name => "Neuburg-Steinhausen", :area_code => "38426") + AreaCode.create(:country => germany, :name => "Blowatz", :area_code => "38427") + AreaCode.create(:country => germany, :name => "Hohenkirchen b Wismar", :area_code => "38428") + AreaCode.create(:country => germany, :name => "Glasin", :area_code => "38429") + AreaCode.create(:country => germany, :name => "Güstrow", :area_code => "3843") + AreaCode.create(:country => germany, :name => "Schwaan", :area_code => "3844") + AreaCode.create(:country => germany, :name => "Tarnow b Bützow", :area_code => "38450") + AreaCode.create(:country => germany, :name => "Hoppenrade b Güstrow", :area_code => "38451") + AreaCode.create(:country => germany, :name => "Lalendorf", :area_code => "38452") + AreaCode.create(:country => germany, :name => "Mistorf", :area_code => "38453") + AreaCode.create(:country => germany, :name => "Kritzkow", :area_code => "38454") + AreaCode.create(:country => germany, :name => "Plaaz", :area_code => "38455") + AreaCode.create(:country => germany, :name => "Langhagen b Güstrow", :area_code => "38456") + AreaCode.create(:country => germany, :name => "Krakow am See", :area_code => "38457") + AreaCode.create(:country => germany, :name => "Zehna", :area_code => "38458") + AreaCode.create(:country => germany, :name => "Laage", :area_code => "38459") + AreaCode.create(:country => germany, :name => "Bützow", :area_code => "38461") + AreaCode.create(:country => germany, :name => "Baumgarten Meckl", :area_code => "38462") + AreaCode.create(:country => germany, :name => "Bernitt", :area_code => "38464") + AreaCode.create(:country => germany, :name => "Jürgenshagen", :area_code => "38466") + AreaCode.create(:country => germany, :name => "Sternberg", :area_code => "3847") + AreaCode.create(:country => germany, :name => "Witzin", :area_code => "38481") + AreaCode.create(:country => germany, :name => "Warin", :area_code => "38482") + AreaCode.create(:country => germany, :name => "Brüel", :area_code => "38483") + AreaCode.create(:country => germany, :name => "Ventschow", :area_code => "38484") + AreaCode.create(:country => germany, :name => "Dabel", :area_code => "38485") + AreaCode.create(:country => germany, :name => "Gustävel", :area_code => "38486") + AreaCode.create(:country => germany, :name => "Demen", :area_code => "38488") + AreaCode.create(:country => germany, :name => "Schwerin Meckl", :area_code => "385") + AreaCode.create(:country => germany, :name => "Raben Steinfeld", :area_code => "3860") + AreaCode.create(:country => germany, :name => "Plate", :area_code => "3861") + AreaCode.create(:country => germany, :name => "Crivitz", :area_code => "3863") + AreaCode.create(:country => germany, :name => "Holthusen", :area_code => "3865") + AreaCode.create(:country => germany, :name => "Cambs", :area_code => "3866") + AreaCode.create(:country => germany, :name => "Lübstorf", :area_code => "3867") + AreaCode.create(:country => germany, :name => "Rastow", :area_code => "3868") + AreaCode.create(:country => germany, :name => "Dümmer", :area_code => "3869") + AreaCode.create(:country => germany, :name => "Parchim", :area_code => "3871") + AreaCode.create(:country => germany, :name => "Grebbin", :area_code => "38720") + AreaCode.create(:country => germany, :name => "Ziegendorf", :area_code => "38721") + AreaCode.create(:country => germany, :name => "Raduhn", :area_code => "38722") + AreaCode.create(:country => germany, :name => "Kladrum", :area_code => "38723") + AreaCode.create(:country => germany, :name => "Siggelkow", :area_code => "38724") + AreaCode.create(:country => germany, :name => "Gross Godems", :area_code => "38725") + AreaCode.create(:country => germany, :name => "Spornitz", :area_code => "38726") + AreaCode.create(:country => germany, :name => "Mestlin", :area_code => "38727") + AreaCode.create(:country => germany, :name => "Domsühl", :area_code => "38728") + AreaCode.create(:country => germany, :name => "Marnitz", :area_code => "38729") + AreaCode.create(:country => germany, :name => "Lübz", :area_code => "38731") + AreaCode.create(:country => germany, :name => "Gallin b Lübz", :area_code => "38732") + AreaCode.create(:country => germany, :name => "Karbow-Vietlübbe", :area_code => "38733") + AreaCode.create(:country => germany, :name => "Plau am See", :area_code => "38735") + AreaCode.create(:country => germany, :name => "Goldberg Meckl", :area_code => "38736") + AreaCode.create(:country => germany, :name => "Ganzlin", :area_code => "38737") + AreaCode.create(:country => germany, :name => "Karow b Lübz", :area_code => "38738") + AreaCode.create(:country => germany, :name => "Ludwigslust Meckl", :area_code => "3874") + AreaCode.create(:country => germany, :name => "Malliss", :area_code => "38750") + AreaCode.create(:country => germany, :name => "Picher", :area_code => "38751") + AreaCode.create(:country => germany, :name => "Zierzow b Ludwigslust", :area_code => "38752") + AreaCode.create(:country => germany, :name => "Wöbbelin", :area_code => "38753") + AreaCode.create(:country => germany, :name => "Leussow b Ludwigslust", :area_code => "38754") + AreaCode.create(:country => germany, :name => "Eldena", :area_code => "38755") + AreaCode.create(:country => germany, :name => "Grabow Meckl", :area_code => "38756") + AreaCode.create(:country => germany, :name => "Neustadt-Glewe", :area_code => "38757") + AreaCode.create(:country => germany, :name => "Dömitz", :area_code => "38758") + AreaCode.create(:country => germany, :name => "Tewswoos", :area_code => "38759") + AreaCode.create(:country => germany, :name => "Perleberg", :area_code => "3876") + AreaCode.create(:country => germany, :name => "Wittenberge", :area_code => "3877") + AreaCode.create(:country => germany, :name => "Lanz Brandenb", :area_code => "38780") + AreaCode.create(:country => germany, :name => "Mellen", :area_code => "38781") + AreaCode.create(:country => germany, :name => "Reetz b Perleberg", :area_code => "38782") + AreaCode.create(:country => germany, :name => "Dallmin", :area_code => "38783") + AreaCode.create(:country => germany, :name => "Kleinow Kr Prignitz", :area_code => "38784") + AreaCode.create(:country => germany, :name => "Berge b Perleberg", :area_code => "38785") + AreaCode.create(:country => germany, :name => "Glöwen", :area_code => "38787") + AreaCode.create(:country => germany, :name => "Gross Warnow", :area_code => "38788") + AreaCode.create(:country => germany, :name => "Wolfshagen b Perleberg", :area_code => "38789") + AreaCode.create(:country => germany, :name => "Bad Wilsnack", :area_code => "38791") + AreaCode.create(:country => germany, :name => "Lenzen (Elbe)", :area_code => "38792") + AreaCode.create(:country => germany, :name => "Dergenthin", :area_code => "38793") + AreaCode.create(:country => germany, :name => "Cumlosen", :area_code => "38794") + AreaCode.create(:country => germany, :name => "Viesecke", :area_code => "38796") + AreaCode.create(:country => germany, :name => "Karstädt Kr Prignitz", :area_code => "38797") + AreaCode.create(:country => germany, :name => "Grevesmühlen", :area_code => "3881") + AreaCode.create(:country => germany, :name => "Lüdersdorf Meckl", :area_code => "38821") + AreaCode.create(:country => germany, :name => "Diedrichshagen b Grevesmühlen", :area_code => "38822") + AreaCode.create(:country => germany, :name => "Selmsdorf", :area_code => "38823") + AreaCode.create(:country => germany, :name => "Mallentin", :area_code => "38824") + AreaCode.create(:country => germany, :name => "Klütz", :area_code => "38825") + AreaCode.create(:country => germany, :name => "Dassow", :area_code => "38826") + AreaCode.create(:country => germany, :name => "Kalkhorst", :area_code => "38827") + AreaCode.create(:country => germany, :name => "Schönberg Meckl", :area_code => "38828") + AreaCode.create(:country => germany, :name => "Hagenow", :area_code => "3883") + AreaCode.create(:country => germany, :name => "Neuhaus Elbe", :area_code => "38841") + AreaCode.create(:country => germany, :name => "Lüttenmark", :area_code => "38842") + AreaCode.create(:country => germany, :name => "Bennin", :area_code => "38843") + AreaCode.create(:country => germany, :name => "Gülze", :area_code => "38844") + AreaCode.create(:country => germany, :name => "Kaarssen", :area_code => "38845") + AreaCode.create(:country => germany, :name => "Boizenburg Elbe", :area_code => "38847") + AreaCode.create(:country => germany, :name => "Vellahn", :area_code => "38848") + AreaCode.create(:country => germany, :name => "Gammelin", :area_code => "38850") + AreaCode.create(:country => germany, :name => "Zarrentin Meckl", :area_code => "38851") + AreaCode.create(:country => germany, :name => "Wittenburg", :area_code => "38852") + AreaCode.create(:country => germany, :name => "Drönnewitz b Hagenow", :area_code => "38853") + AreaCode.create(:country => germany, :name => "Redefin", :area_code => "38854") + AreaCode.create(:country => germany, :name => "Lübtheen", :area_code => "38855") + AreaCode.create(:country => germany, :name => "Pritzier b Hagenow", :area_code => "38856") + AreaCode.create(:country => germany, :name => "Lassahn", :area_code => "38858") + AreaCode.create(:country => germany, :name => "Alt Zachun", :area_code => "38859") + AreaCode.create(:country => germany, :name => "Gadebusch", :area_code => "3886") + AreaCode.create(:country => germany, :name => "Mühlen Eichsen", :area_code => "38871") + AreaCode.create(:country => germany, :name => "Rehna", :area_code => "38872") + AreaCode.create(:country => germany, :name => "Carlow", :area_code => "38873") + AreaCode.create(:country => germany, :name => "Lützow", :area_code => "38874") + AreaCode.create(:country => germany, :name => "Schlagsdorf b Gadebusch", :area_code => "38875") + AreaCode.create(:country => germany, :name => "Roggendorf", :area_code => "38876") + AreaCode.create(:country => germany, :name => "Beetzendorf", :area_code => "39000") + AreaCode.create(:country => germany, :name => "Apenburg", :area_code => "39001") + AreaCode.create(:country => germany, :name => "Oebisfelde", :area_code => "39002") + AreaCode.create(:country => germany, :name => "Jübar", :area_code => "39003") + AreaCode.create(:country => germany, :name => "Köckte b Gardelegen", :area_code => "39004") + AreaCode.create(:country => germany, :name => "Kusey", :area_code => "39005") + AreaCode.create(:country => germany, :name => "Miesterhorst", :area_code => "39006") + AreaCode.create(:country => germany, :name => "Tangeln", :area_code => "39007") + AreaCode.create(:country => germany, :name => "Kunrau", :area_code => "39008") + AreaCode.create(:country => germany, :name => "Badel", :area_code => "39009") + AreaCode.create(:country => germany, :name => "Salzwedel", :area_code => "3901") + AreaCode.create(:country => germany, :name => "Diesdorf Altm", :area_code => "3902") + AreaCode.create(:country => germany, :name => "Brunau", :area_code => "39030") + AreaCode.create(:country => germany, :name => "Dähre", :area_code => "39031") + AreaCode.create(:country => germany, :name => "Mahlsdorf b Salzwedel", :area_code => "39032") + AreaCode.create(:country => germany, :name => "Wallstawe", :area_code => "39033") + AreaCode.create(:country => germany, :name => "Fleetmark", :area_code => "39034") + AreaCode.create(:country => germany, :name => "Kuhfelde", :area_code => "39035") + AreaCode.create(:country => germany, :name => "Binde", :area_code => "39036") + AreaCode.create(:country => germany, :name => "Pretzier", :area_code => "39037") + AreaCode.create(:country => germany, :name => "Henningen", :area_code => "39038") + AreaCode.create(:country => germany, :name => "Bonese", :area_code => "39039") + AreaCode.create(:country => germany, :name => "Haldensleben", :area_code => "3904") + AreaCode.create(:country => germany, :name => "Bartensleben", :area_code => "39050") + AreaCode.create(:country => germany, :name => "Calvörde", :area_code => "39051") + AreaCode.create(:country => germany, :name => "Erxleben b Haldensleben", :area_code => "39052") + AreaCode.create(:country => germany, :name => "Süplingen", :area_code => "39053") + AreaCode.create(:country => germany, :name => "Flechtingen", :area_code => "39054") + AreaCode.create(:country => germany, :name => "Hörsingen", :area_code => "39055") + AreaCode.create(:country => germany, :name => "Klüden", :area_code => "39056") + AreaCode.create(:country => germany, :name => "Rätzlingen Sachs-Anh", :area_code => "39057") + AreaCode.create(:country => germany, :name => "Uthmöden", :area_code => "39058") + AreaCode.create(:country => germany, :name => "Wegenstedt", :area_code => "39059") + AreaCode.create(:country => germany, :name => "Weferlingen", :area_code => "39061") + AreaCode.create(:country => germany, :name => "Bebertal", :area_code => "39062") + AreaCode.create(:country => germany, :name => "Gardelegen", :area_code => "3907") + AreaCode.create(:country => germany, :name => "Kalbe Milde", :area_code => "39080") + AreaCode.create(:country => germany, :name => "Kakerbeck Sachs-Anh", :area_code => "39081") + AreaCode.create(:country => germany, :name => "Mieste", :area_code => "39082") + AreaCode.create(:country => germany, :name => "Messdorf", :area_code => "39083") + AreaCode.create(:country => germany, :name => "Lindstedt", :area_code => "39084") + AreaCode.create(:country => germany, :name => "Zichtau", :area_code => "39085") + AreaCode.create(:country => germany, :name => "Jävenitz", :area_code => "39086") + AreaCode.create(:country => germany, :name => "Jerchel Altmark", :area_code => "39087") + AreaCode.create(:country => germany, :name => "Letzlingen", :area_code => "39088") + AreaCode.create(:country => germany, :name => "Bismark Altmark", :area_code => "39089") + AreaCode.create(:country => germany, :name => "Klötze Altmark", :area_code => "3909") + AreaCode.create(:country => germany, :name => "Magdeburg", :area_code => "391") + AreaCode.create(:country => germany, :name => "Gommern", :area_code => "39200") + AreaCode.create(:country => germany, :name => "Wolmirstedt", :area_code => "39201") + AreaCode.create(:country => germany, :name => "Gross Ammensleben", :area_code => "39202") + AreaCode.create(:country => germany, :name => "Barleben", :area_code => "39203") + AreaCode.create(:country => germany, :name => "Niederndodeleben", :area_code => "39204") + AreaCode.create(:country => germany, :name => "Langenweddingen", :area_code => "39205") + AreaCode.create(:country => germany, :name => "Eichenbarleben", :area_code => "39206") + AreaCode.create(:country => germany, :name => "Colbitz", :area_code => "39207") + AreaCode.create(:country => germany, :name => "Loitsche", :area_code => "39208") + AreaCode.create(:country => germany, :name => "Wanzleben", :area_code => "39209") + AreaCode.create(:country => germany, :name => "Burg b Magdeburg", :area_code => "3921") + AreaCode.create(:country => germany, :name => "Möckern b Magdeburg", :area_code => "39221") + AreaCode.create(:country => germany, :name => "Möser", :area_code => "39222") + AreaCode.create(:country => germany, :name => "Theessen", :area_code => "39223") + AreaCode.create(:country => germany, :name => "Büden", :area_code => "39224") + AreaCode.create(:country => germany, :name => "Altengrabow", :area_code => "39225") + AreaCode.create(:country => germany, :name => "Hohenziatz", :area_code => "39226") + AreaCode.create(:country => germany, :name => "Zerbst", :area_code => "3923") + AreaCode.create(:country => germany, :name => "Leitzkau", :area_code => "39241") + AreaCode.create(:country => germany, :name => "Prödel", :area_code => "39242") + AreaCode.create(:country => germany, :name => "Nedlitz b Zerbst", :area_code => "39243") + AreaCode.create(:country => germany, :name => "Steutz", :area_code => "39244") + AreaCode.create(:country => germany, :name => "Loburg", :area_code => "39245") + AreaCode.create(:country => germany, :name => "Lindau Anh", :area_code => "39246") + AreaCode.create(:country => germany, :name => "Güterglück", :area_code => "39247") + AreaCode.create(:country => germany, :name => "Dobritz", :area_code => "39248") + AreaCode.create(:country => germany, :name => "Stassfurt", :area_code => "3925") + AreaCode.create(:country => germany, :name => "Güsten Anh", :area_code => "39262") + AreaCode.create(:country => germany, :name => "Unseburg", :area_code => "39263") + AreaCode.create(:country => germany, :name => "Kroppenstedt", :area_code => "39264") + AreaCode.create(:country => germany, :name => "Löderburg", :area_code => "39265") + AreaCode.create(:country => germany, :name => "Förderstedt", :area_code => "39266") + AreaCode.create(:country => germany, :name => "Schneidlingen", :area_code => "39267") + AreaCode.create(:country => germany, :name => "Egeln", :area_code => "39268") + AreaCode.create(:country => germany, :name => "Schönebeck Elbe", :area_code => "3928") + AreaCode.create(:country => germany, :name => "Calbe Saale", :area_code => "39291") + AreaCode.create(:country => germany, :name => "Biederitz", :area_code => "39292") + AreaCode.create(:country => germany, :name => "Dreileben", :area_code => "39293") + AreaCode.create(:country => germany, :name => "Gross Rosenburg", :area_code => "39294") + AreaCode.create(:country => germany, :name => "Zuchau", :area_code => "39295") + AreaCode.create(:country => germany, :name => "Welsleben", :area_code => "39296") + AreaCode.create(:country => germany, :name => "Eickendorf Kr Schönebeck", :area_code => "39297") + AreaCode.create(:country => germany, :name => "Barby Elbe", :area_code => "39298") + AreaCode.create(:country => germany, :name => "Stendal", :area_code => "3931") + AreaCode.create(:country => germany, :name => "Schinne", :area_code => "39320") + AreaCode.create(:country => germany, :name => "Arneburg", :area_code => "39321") + AreaCode.create(:country => germany, :name => "Tangermünde", :area_code => "39322") + AreaCode.create(:country => germany, :name => "Schönhausen Elbe", :area_code => "39323") + AreaCode.create(:country => germany, :name => "Kläden b Stendal", :area_code => "39324") + AreaCode.create(:country => germany, :name => "Vinzelberg", :area_code => "39325") + AreaCode.create(:country => germany, :name => "Klietz", :area_code => "39327") + AreaCode.create(:country => germany, :name => "Rochau", :area_code => "39328") + AreaCode.create(:country => germany, :name => "Möringen", :area_code => "39329") + AreaCode.create(:country => germany, :name => "Genthin", :area_code => "3933") + AreaCode.create(:country => germany, :name => "Redekin", :area_code => "39341") + AreaCode.create(:country => germany, :name => "Gladau", :area_code => "39342") + AreaCode.create(:country => germany, :name => "Jerichow", :area_code => "39343") + AreaCode.create(:country => germany, :name => "Güsen", :area_code => "39344") + AreaCode.create(:country => germany, :name => "Parchen", :area_code => "39345") + AreaCode.create(:country => germany, :name => "Tucheim", :area_code => "39346") + AreaCode.create(:country => germany, :name => "Kade", :area_code => "39347") + AreaCode.create(:country => germany, :name => "Klitsche", :area_code => "39348") + AreaCode.create(:country => germany, :name => "Parey Elbe", :area_code => "39349") + AreaCode.create(:country => germany, :name => "Tangerhütte", :area_code => "3935") + AreaCode.create(:country => germany, :name => "Lüderitz", :area_code => "39361") + AreaCode.create(:country => germany, :name => "Grieben b Tangerhütte", :area_code => "39362") + AreaCode.create(:country => germany, :name => "Angern", :area_code => "39363") + AreaCode.create(:country => germany, :name => "Dolle", :area_code => "39364") + AreaCode.create(:country => germany, :name => "Bellingen b Stendal", :area_code => "39365") + AreaCode.create(:country => germany, :name => "Kehnert", :area_code => "39366") + AreaCode.create(:country => germany, :name => "Osterburg Altmark", :area_code => "3937") + AreaCode.create(:country => germany, :name => "Kamern", :area_code => "39382") + AreaCode.create(:country => germany, :name => "Sandau Elbe", :area_code => "39383") + AreaCode.create(:country => germany, :name => "Arendsee Altmark", :area_code => "39384") + AreaCode.create(:country => germany, :name => "Seehausen Altmark", :area_code => "39386") + AreaCode.create(:country => germany, :name => "Havelberg", :area_code => "39387") + AreaCode.create(:country => germany, :name => "Goldbeck Altm", :area_code => "39388") + AreaCode.create(:country => germany, :name => "Schollene", :area_code => "39389") + AreaCode.create(:country => germany, :name => "Iden", :area_code => "39390") + AreaCode.create(:country => germany, :name => "Lückstedt", :area_code => "39391") + AreaCode.create(:country => germany, :name => "Rönnebeck Sachs-Ahn", :area_code => "39392") + AreaCode.create(:country => germany, :name => "Werben Elbe", :area_code => "39393") + AreaCode.create(:country => germany, :name => "Hohenberg-Krusemark", :area_code => "39394") + AreaCode.create(:country => germany, :name => "Wanzer", :area_code => "39395") + AreaCode.create(:country => germany, :name => "Neukirchen Altmark", :area_code => "39396") + AreaCode.create(:country => germany, :name => "Geestgottberg", :area_code => "39397") + AreaCode.create(:country => germany, :name => "Gross Garz", :area_code => "39398") + AreaCode.create(:country => germany, :name => "Kleinau", :area_code => "39399") + AreaCode.create(:country => germany, :name => "Wefensleben", :area_code => "39400") + AreaCode.create(:country => germany, :name => "Neuwegersleben", :area_code => "39401") + AreaCode.create(:country => germany, :name => "Völpke", :area_code => "39402") + AreaCode.create(:country => germany, :name => "Gröningen Sachs-Ahn", :area_code => "39403") + AreaCode.create(:country => germany, :name => "Ausleben", :area_code => "39404") + AreaCode.create(:country => germany, :name => "Hötensleben", :area_code => "39405") + AreaCode.create(:country => germany, :name => "Harbke", :area_code => "39406") + AreaCode.create(:country => germany, :name => "Seehausen Börde", :area_code => "39407") + AreaCode.create(:country => germany, :name => "Hadmersleben", :area_code => "39408") + AreaCode.create(:country => germany, :name => "Eilsleben", :area_code => "39409") + AreaCode.create(:country => germany, :name => "Halberstadt", :area_code => "3941") + AreaCode.create(:country => germany, :name => "Osterwieck", :area_code => "39421") + AreaCode.create(:country => germany, :name => "Badersleben", :area_code => "39422") + AreaCode.create(:country => germany, :name => "Wegeleben", :area_code => "39423") + AreaCode.create(:country => germany, :name => "Schwanebeck Sachs-Anh", :area_code => "39424") + AreaCode.create(:country => germany, :name => "Dingelstedt a Huy", :area_code => "39425") + AreaCode.create(:country => germany, :name => "Hessen", :area_code => "39426") + AreaCode.create(:country => germany, :name => "Ströbeck", :area_code => "39427") + AreaCode.create(:country => germany, :name => "Pabstorf", :area_code => "39428") + AreaCode.create(:country => germany, :name => "Wernigerode", :area_code => "3943") + AreaCode.create(:country => germany, :name => "Blankenburg Harz", :area_code => "3944") + AreaCode.create(:country => germany, :name => "Wasserleben", :area_code => "39451") + AreaCode.create(:country => germany, :name => "Ilsenburg", :area_code => "39452") + AreaCode.create(:country => germany, :name => "Derenburg", :area_code => "39453") + AreaCode.create(:country => germany, :name => "Elbingerode Harz", :area_code => "39454") + AreaCode.create(:country => germany, :name => "Schierke", :area_code => "39455") + AreaCode.create(:country => germany, :name => "Altenbrak", :area_code => "39456") + AreaCode.create(:country => germany, :name => "Benneckenstein Harz", :area_code => "39457") + AreaCode.create(:country => germany, :name => "Heudeber", :area_code => "39458") + AreaCode.create(:country => germany, :name => "Hasselfelde", :area_code => "39459") + AreaCode.create(:country => germany, :name => "Quedlinburg", :area_code => "3946") + AreaCode.create(:country => germany, :name => "Thale", :area_code => "3947") + AreaCode.create(:country => germany, :name => "Hedersleben b Aschersleben", :area_code => "39481") + AreaCode.create(:country => germany, :name => "Gatersleben", :area_code => "39482") + AreaCode.create(:country => germany, :name => "Ballenstedt", :area_code => "39483") + AreaCode.create(:country => germany, :name => "Harzgerode", :area_code => "39484") + AreaCode.create(:country => germany, :name => "Gernrode Harz", :area_code => "39485") + AreaCode.create(:country => germany, :name => "Friedrichsbrunn", :area_code => "39487") + AreaCode.create(:country => germany, :name => "Güntersberge", :area_code => "39488") + AreaCode.create(:country => germany, :name => "Strassberg Harz", :area_code => "39489") + AreaCode.create(:country => germany, :name => "Oschersleben Bode", :area_code => "3949") + AreaCode.create(:country => germany, :name => "Neubrandenburg", :area_code => "395") + AreaCode.create(:country => germany, :name => "Zwiedorf", :area_code => "39600") + AreaCode.create(:country => germany, :name => "Friedland Meckl", :area_code => "39601") + AreaCode.create(:country => germany, :name => "Kleeth", :area_code => "39602") + AreaCode.create(:country => germany, :name => "Burg Stargard", :area_code => "39603") + AreaCode.create(:country => germany, :name => "Wildberg b Altentreptow", :area_code => "39604") + AreaCode.create(:country => germany, :name => "Gross Nemerow", :area_code => "39605") + AreaCode.create(:country => germany, :name => "Glienke", :area_code => "39606") + AreaCode.create(:country => germany, :name => "Kotelow", :area_code => "39607") + AreaCode.create(:country => germany, :name => "Staven", :area_code => "39608") + AreaCode.create(:country => germany, :name => "Altentreptow", :area_code => "3961") + AreaCode.create(:country => germany, :name => "Penzlin b Waren", :area_code => "3962") + AreaCode.create(:country => germany, :name => "Woldegk", :area_code => "3963") + AreaCode.create(:country => germany, :name => "Bredenfelde b Strasburg", :area_code => "3964") + AreaCode.create(:country => germany, :name => "Burow b Altentreptow", :area_code => "3965") + AreaCode.create(:country => germany, :name => "Cölpin", :area_code => "3966") + AreaCode.create(:country => germany, :name => "Oertzenhof b Strasburg", :area_code => "3967") + AreaCode.create(:country => germany, :name => "Schönbeck Meckl", :area_code => "3968") + AreaCode.create(:country => germany, :name => "Siedenbollentin", :area_code => "3969") + AreaCode.create(:country => germany, :name => "Anklam", :area_code => "3971") + AreaCode.create(:country => germany, :name => "Liepen b Anklam", :area_code => "39721") + AreaCode.create(:country => germany, :name => "Sarnow b Anklam", :area_code => "39722") + AreaCode.create(:country => germany, :name => "Krien", :area_code => "39723") + AreaCode.create(:country => germany, :name => "Klein Bünzow", :area_code => "39724") + AreaCode.create(:country => germany, :name => "Ducherow", :area_code => "39726") + AreaCode.create(:country => germany, :name => "Spantekow", :area_code => "39727") + AreaCode.create(:country => germany, :name => "Medow b Anklam", :area_code => "39728") + AreaCode.create(:country => germany, :name => "Pasewalk", :area_code => "3973") + AreaCode.create(:country => germany, :name => "Nechlin", :area_code => "39740") + AreaCode.create(:country => germany, :name => "Jatznick", :area_code => "39741") + AreaCode.create(:country => germany, :name => "Brüssow b Pasewalk", :area_code => "39742") + AreaCode.create(:country => germany, :name => "Zerrenthin", :area_code => "39743") + AreaCode.create(:country => germany, :name => "Rothenklempenow", :area_code => "39744") + AreaCode.create(:country => germany, :name => "Hetzdorf b Strasburg", :area_code => "39745") + AreaCode.create(:country => germany, :name => "Krackow", :area_code => "39746") + AreaCode.create(:country => germany, :name => "Züsedom", :area_code => "39747") + AreaCode.create(:country => germany, :name => "Viereck", :area_code => "39748") + AreaCode.create(:country => germany, :name => "Grambow b Pasewalk", :area_code => "39749") + AreaCode.create(:country => germany, :name => "Penkun", :area_code => "39751") + AreaCode.create(:country => germany, :name => "Blumenhagen b Strasburg", :area_code => "39752") + AreaCode.create(:country => germany, :name => "Strasburg", :area_code => "39753") + AreaCode.create(:country => germany, :name => "Löcknitz Vorpom", :area_code => "39754") + AreaCode.create(:country => germany, :name => "Torgelow b Ueckermünde", :area_code => "3976") + AreaCode.create(:country => germany, :name => "Ueckermünde", :area_code => "39771") + AreaCode.create(:country => germany, :name => "Rothemühl", :area_code => "39772") + AreaCode.create(:country => germany, :name => "Altwarp", :area_code => "39773") + AreaCode.create(:country => germany, :name => "Mönkebude", :area_code => "39774") + AreaCode.create(:country => germany, :name => "Ahlbeck b Torgelow", :area_code => "39775") + AreaCode.create(:country => germany, :name => "Hintersee", :area_code => "39776") + AreaCode.create(:country => germany, :name => "Borkenfriede", :area_code => "39777") + AreaCode.create(:country => germany, :name => "Ferdinandshof b Torgelow", :area_code => "39778") + AreaCode.create(:country => germany, :name => "Eggesin", :area_code => "39779") + AreaCode.create(:country => germany, :name => "Neustrelitz", :area_code => "3981") + AreaCode.create(:country => germany, :name => "Triepkendorf", :area_code => "39820") + AreaCode.create(:country => germany, :name => "Carpin", :area_code => "39821") + AreaCode.create(:country => germany, :name => "Kratzeburg", :area_code => "39822") + AreaCode.create(:country => germany, :name => "Rechlin", :area_code => "39823") + AreaCode.create(:country => germany, :name => "Hohenzieritz", :area_code => "39824") + AreaCode.create(:country => germany, :name => "Wokuhl", :area_code => "39825") + AreaCode.create(:country => germany, :name => "Blankensee b Neustrelitz", :area_code => "39826") + AreaCode.create(:country => germany, :name => "Schwarz b Neustrelitz", :area_code => "39827") + AreaCode.create(:country => germany, :name => "Wustrow Kr Mecklenburg-Strelitz", :area_code => "39828") + AreaCode.create(:country => germany, :name => "Blankenförde", :area_code => "39829") + AreaCode.create(:country => germany, :name => "Feldberg Meckl", :area_code => "39831") + AreaCode.create(:country => germany, :name => "Wesenberg Meckl", :area_code => "39832") + AreaCode.create(:country => germany, :name => "Mirow Kr Neustrelitz", :area_code => "39833") + AreaCode.create(:country => germany, :name => "Prenzlau", :area_code => "3984") + AreaCode.create(:country => germany, :name => "Göritz b Prenzlau", :area_code => "39851") + AreaCode.create(:country => germany, :name => "Schönermark b Prenzlau", :area_code => "39852") + AreaCode.create(:country => germany, :name => "Holzendorf b Prenzlau", :area_code => "39853") + AreaCode.create(:country => germany, :name => "Kleptow", :area_code => "39854") + AreaCode.create(:country => germany, :name => "Parmen-Weggun", :area_code => "39855") + AreaCode.create(:country => germany, :name => "Beenz b Prenzlau", :area_code => "39856") + AreaCode.create(:country => germany, :name => "Drense", :area_code => "39857") + AreaCode.create(:country => germany, :name => "Bietikow", :area_code => "39858") + AreaCode.create(:country => germany, :name => "Fürstenwerder", :area_code => "39859") + AreaCode.create(:country => germany, :name => "Gramzow b Prenzlau", :area_code => "39861") + AreaCode.create(:country => germany, :name => "Schmölln b Prenzlau", :area_code => "39862") + AreaCode.create(:country => germany, :name => "Seehausen b Prenzlau", :area_code => "39863") + AreaCode.create(:country => germany, :name => "Templin", :area_code => "3987") + AreaCode.create(:country => germany, :name => "Ringenwalde b Templin", :area_code => "39881") + AreaCode.create(:country => germany, :name => "Gollin", :area_code => "39882") + AreaCode.create(:country => germany, :name => "Groß Dölln", :area_code => "39883") + AreaCode.create(:country => germany, :name => "Hassleben b Prenzlau", :area_code => "39884") + AreaCode.create(:country => germany, :name => "Jakobshagen", :area_code => "39885") + AreaCode.create(:country => germany, :name => "Milmersdorf", :area_code => "39886") + AreaCode.create(:country => germany, :name => "Gerswalde", :area_code => "39887") + AreaCode.create(:country => germany, :name => "Lychen", :area_code => "39888") + AreaCode.create(:country => germany, :name => "Boitzenburg", :area_code => "39889") + AreaCode.create(:country => germany, :name => "Waren Müritz", :area_code => "3991") + AreaCode.create(:country => germany, :name => "Ankershagen", :area_code => "39921") + AreaCode.create(:country => germany, :name => "Dambeck b Röbel", :area_code => "39922") + AreaCode.create(:country => germany, :name => "Priborn", :area_code => "39923") + AreaCode.create(:country => germany, :name => "Stuer", :area_code => "39924") + AreaCode.create(:country => germany, :name => "Wredenhagen", :area_code => "39925") + AreaCode.create(:country => germany, :name => "Grabowhöfe", :area_code => "39926") + AreaCode.create(:country => germany, :name => "Nossentiner Hütte", :area_code => "39927") + AreaCode.create(:country => germany, :name => "Möllenhagen", :area_code => "39928") + AreaCode.create(:country => germany, :name => "Jabel b Waren", :area_code => "39929") + AreaCode.create(:country => germany, :name => "Röbel Müritz", :area_code => "39931") + AreaCode.create(:country => germany, :name => "Malchow b Waren", :area_code => "39932") + AreaCode.create(:country => germany, :name => "Vollrathsruhe", :area_code => "39933") + AreaCode.create(:country => germany, :name => "Groß Plasten", :area_code => "39934") + AreaCode.create(:country => germany, :name => "Malchin", :area_code => "3994") + AreaCode.create(:country => germany, :name => "Faulenrost", :area_code => "39951") + AreaCode.create(:country => germany, :name => "Grammentin", :area_code => "39952") + AreaCode.create(:country => germany, :name => "Schwinkendorf", :area_code => "39953") + AreaCode.create(:country => germany, :name => "Stavenhagen Reuterstadt", :area_code => "39954") + AreaCode.create(:country => germany, :name => "Jürgenstorf Meckl", :area_code => "39955") + AreaCode.create(:country => germany, :name => "Neukalen", :area_code => "39956") + AreaCode.create(:country => germany, :name => "Gielow", :area_code => "39957") + AreaCode.create(:country => germany, :name => "Dargun", :area_code => "39959") + AreaCode.create(:country => germany, :name => "Teterow", :area_code => "3996") + AreaCode.create(:country => germany, :name => "Gnoien", :area_code => "39971") + AreaCode.create(:country => germany, :name => "Walkendorf", :area_code => "39972") + AreaCode.create(:country => germany, :name => "Altkalen", :area_code => "39973") + AreaCode.create(:country => germany, :name => "Thürkow", :area_code => "39975") + AreaCode.create(:country => germany, :name => "Groß Bützin", :area_code => "39976") + AreaCode.create(:country => germany, :name => "Jördenstorf", :area_code => "39977") + AreaCode.create(:country => germany, :name => "Gross Roge", :area_code => "39978") + AreaCode.create(:country => germany, :name => "Demmin", :area_code => "3998") + AreaCode.create(:country => germany, :name => "Daberkow", :area_code => "39991") + AreaCode.create(:country => germany, :name => "Görmin", :area_code => "39992") + AreaCode.create(:country => germany, :name => "Hohenmocker", :area_code => "39993") + AreaCode.create(:country => germany, :name => "Metschow", :area_code => "39994") + AreaCode.create(:country => germany, :name => "Nossendorf", :area_code => "39995") + AreaCode.create(:country => germany, :name => "Törpin", :area_code => "39996") + AreaCode.create(:country => germany, :name => "Jarmen", :area_code => "39997") + AreaCode.create(:country => germany, :name => "Loitz b Demmin", :area_code => "39998") + AreaCode.create(:country => germany, :name => "Tutow", :area_code => "39999") + AreaCode.create(:country => germany, :name => "Hamburg", :area_code => "40") + AreaCode.create(:country => germany, :name => "Pinneberg", :area_code => "4101") + AreaCode.create(:country => germany, :name => "Ahrensburg", :area_code => "4102") + AreaCode.create(:country => germany, :name => "Wedel", :area_code => "4103") + AreaCode.create(:country => germany, :name => "Aumühle b Hamburg", :area_code => "4104") + AreaCode.create(:country => germany, :name => "Seevetal", :area_code => "4105") + AreaCode.create(:country => germany, :name => "Quickborn Kr Pinneberg", :area_code => "4106") + AreaCode.create(:country => germany, :name => "Siek Kr Stormarn", :area_code => "4107") + AreaCode.create(:country => germany, :name => "Rosengarten Kr Harburg", :area_code => "4108") + AreaCode.create(:country => germany, :name => "Tangstedt Bz Hamburg", :area_code => "4109") + AreaCode.create(:country => germany, :name => "Ellerhoop", :area_code => "4120") + AreaCode.create(:country => germany, :name => "Elmshorn", :area_code => "4121") + AreaCode.create(:country => germany, :name => "Uetersen", :area_code => "4122") + AreaCode.create(:country => germany, :name => "Barmstedt", :area_code => "4123") + AreaCode.create(:country => germany, :name => "Glückstadt", :area_code => "4124") + AreaCode.create(:country => germany, :name => "Seestermühe", :area_code => "4125") + AreaCode.create(:country => germany, :name => "Horst Holstein", :area_code => "4126") + AreaCode.create(:country => germany, :name => "Westerhorn", :area_code => "4127") + AreaCode.create(:country => germany, :name => "Kollmar", :area_code => "4128") + AreaCode.create(:country => germany, :name => "Haseldorf", :area_code => "4129") + AreaCode.create(:country => germany, :name => "Lüneburg", :area_code => "4131") + AreaCode.create(:country => germany, :name => "Amelinghausen", :area_code => "4132") + AreaCode.create(:country => germany, :name => "Wittorf Kr Lüneburg", :area_code => "4133") + AreaCode.create(:country => germany, :name => "Embsen Kr Lünebeburg", :area_code => "4134") + AreaCode.create(:country => germany, :name => "Kirchgellersen", :area_code => "4135") + AreaCode.create(:country => germany, :name => "Scharnebeck", :area_code => "4136") + AreaCode.create(:country => germany, :name => "Barendorf", :area_code => "4137") + AreaCode.create(:country => germany, :name => "Betzendorf Kr Lünebeburg", :area_code => "4138") + AreaCode.create(:country => germany, :name => "Hohnstorf Elbe", :area_code => "4139") + AreaCode.create(:country => germany, :name => "Estorf Kr Stade", :area_code => "4140") + AreaCode.create(:country => germany, :name => "Stade", :area_code => "4141") + AreaCode.create(:country => germany, :name => "Steinkirchen Kr Stade", :area_code => "4142") + AreaCode.create(:country => germany, :name => "Drochtersen", :area_code => "4143") + AreaCode.create(:country => germany, :name => "Himmelpforten", :area_code => "4144") + AreaCode.create(:country => germany, :name => "Stade-Bützfleth", :area_code => "4146") + AreaCode.create(:country => germany, :name => "Drochtersen-Assel", :area_code => "4148") + AreaCode.create(:country => germany, :name => "Fredenbeck", :area_code => "4149") + AreaCode.create(:country => germany, :name => "Schwarzenbek", :area_code => "4151") + AreaCode.create(:country => germany, :name => "Geesthacht", :area_code => "4152") + AreaCode.create(:country => germany, :name => "Lauenburg Elbe", :area_code => "4153") + AreaCode.create(:country => germany, :name => "Trittau", :area_code => "4154") + AreaCode.create(:country => germany, :name => "Büchen", :area_code => "4155") + AreaCode.create(:country => germany, :name => "Talkau", :area_code => "4156") + AreaCode.create(:country => germany, :name => "Roseburg", :area_code => "4158") + AreaCode.create(:country => germany, :name => "Basthorst", :area_code => "4159") + AreaCode.create(:country => germany, :name => "Buxtehude", :area_code => "4161") + AreaCode.create(:country => germany, :name => "Jork", :area_code => "4162") + AreaCode.create(:country => germany, :name => "Horneburg Niederelbe", :area_code => "4163") + AreaCode.create(:country => germany, :name => "Harsefeld", :area_code => "4164") + AreaCode.create(:country => germany, :name => "Hollenstedt Nordheide", :area_code => "4165") + AreaCode.create(:country => germany, :name => "Ahlerstedt", :area_code => "4166") + AreaCode.create(:country => germany, :name => "Apensen", :area_code => "4167") + AreaCode.create(:country => germany, :name => "Neu Wulmstorf-Elstorf", :area_code => "4168") + AreaCode.create(:country => germany, :name => "Sauensiek", :area_code => "4169") + AreaCode.create(:country => germany, :name => "Winsen Luhe", :area_code => "4171") + AreaCode.create(:country => germany, :name => "Salzhausen", :area_code => "4172") + AreaCode.create(:country => germany, :name => "Wulfsen", :area_code => "4173") + AreaCode.create(:country => germany, :name => "Stelle Kr Harburg", :area_code => "4174") + AreaCode.create(:country => germany, :name => "Egestorf Nordheide", :area_code => "4175") + AreaCode.create(:country => germany, :name => "Marschacht", :area_code => "4176") + AreaCode.create(:country => germany, :name => "Drage Elbe", :area_code => "4177") + AreaCode.create(:country => germany, :name => "Radbruch", :area_code => "4178") + AreaCode.create(:country => germany, :name => "Winsen-Tönnhausen", :area_code => "4179") + AreaCode.create(:country => germany, :name => "Königsmoor", :area_code => "4180") + AreaCode.create(:country => germany, :name => "Buchholz in der Nordheide", :area_code => "4181") + AreaCode.create(:country => germany, :name => "Tostedt", :area_code => "4182") + AreaCode.create(:country => germany, :name => "Jesteburg", :area_code => "4183") + AreaCode.create(:country => germany, :name => "Hanstedt Nordheide", :area_code => "4184") + AreaCode.create(:country => germany, :name => "Marxen Auetal", :area_code => "4185") + AreaCode.create(:country => germany, :name => "Buchholz-Trelde", :area_code => "4186") + AreaCode.create(:country => germany, :name => "Holm-Seppensen", :area_code => "4187") + AreaCode.create(:country => germany, :name => "Welle Nordheide", :area_code => "4188") + AreaCode.create(:country => germany, :name => "Undeloh", :area_code => "4189") + AreaCode.create(:country => germany, :name => "Kaltenkirchen Holst", :area_code => "4191") + AreaCode.create(:country => germany, :name => "Bad Bramstedt", :area_code => "4192") + AreaCode.create(:country => germany, :name => "Henstedt-Ulzburg", :area_code => "4193") + AreaCode.create(:country => germany, :name => "Sievershütten", :area_code => "4194") + AreaCode.create(:country => germany, :name => "Hartenholm", :area_code => "4195") + AreaCode.create(:country => germany, :name => "Achim b Bremen", :area_code => "4202") + AreaCode.create(:country => germany, :name => "Weyhe b Bremen", :area_code => "4203") + AreaCode.create(:country => germany, :name => "Thedinghausen", :area_code => "4204") + AreaCode.create(:country => germany, :name => "Ottersberg", :area_code => "4205") + AreaCode.create(:country => germany, :name => "Stuhr-Heiligenrode", :area_code => "4206") + AreaCode.create(:country => germany, :name => "Oyten", :area_code => "4207") + AreaCode.create(:country => germany, :name => "Grasberg", :area_code => "4208") + AreaCode.create(:country => germany, :name => "Schwanewede", :area_code => "4209") + AreaCode.create(:country => germany, :name => "Bremen", :area_code => "421") + AreaCode.create(:country => germany, :name => "Delmenhorst", :area_code => "4221") + AreaCode.create(:country => germany, :name => "Ganderkesee", :area_code => "4222") + AreaCode.create(:country => germany, :name => "Ganderkesee-Bookholzberg", :area_code => "4223") + AreaCode.create(:country => germany, :name => "Gross Ippener", :area_code => "4224") + AreaCode.create(:country => germany, :name => "Verden-Walle", :area_code => "4230") + AreaCode.create(:country => germany, :name => "Verden Aller", :area_code => "4231") + AreaCode.create(:country => germany, :name => "Langwedel Kr Verden", :area_code => "4232") + AreaCode.create(:country => germany, :name => "Blender", :area_code => "4233") + AreaCode.create(:country => germany, :name => "Dörverden", :area_code => "4234") + AreaCode.create(:country => germany, :name => "Langwedel-Etelsen", :area_code => "4235") + AreaCode.create(:country => germany, :name => "Kirchlinteln", :area_code => "4236") + AreaCode.create(:country => germany, :name => "Bendingbostel", :area_code => "4237") + AreaCode.create(:country => germany, :name => "Neddenaverbergen", :area_code => "4238") + AreaCode.create(:country => germany, :name => "Dörverden-Westen", :area_code => "4239") + AreaCode.create(:country => germany, :name => "Syke-Heiligenfelde", :area_code => "4240") + AreaCode.create(:country => germany, :name => "Bassum", :area_code => "4241") + AreaCode.create(:country => germany, :name => "Syke", :area_code => "4242") + AreaCode.create(:country => germany, :name => "Twistringen", :area_code => "4243") + AreaCode.create(:country => germany, :name => "Harpstedt", :area_code => "4244") + AreaCode.create(:country => germany, :name => "Neuenkirchen b Bassum", :area_code => "4245") + AreaCode.create(:country => germany, :name => "Twistringen-Heiligenloh", :area_code => "4246") + AreaCode.create(:country => germany, :name => "Affinghausen", :area_code => "4247") + AreaCode.create(:country => germany, :name => "Bassum-Neubruchhausen", :area_code => "4248") + AreaCode.create(:country => germany, :name => "Bassum-Nordwohlde", :area_code => "4249") + AreaCode.create(:country => germany, :name => "Hoya", :area_code => "4251") + AreaCode.create(:country => germany, :name => "Bruchhausen-Vilsen", :area_code => "4252") + AreaCode.create(:country => germany, :name => "Asendorf Kr Diepholz", :area_code => "4253") + AreaCode.create(:country => germany, :name => "Eystrup", :area_code => "4254") + AreaCode.create(:country => germany, :name => "Martfeld", :area_code => "4255") + AreaCode.create(:country => germany, :name => "Hilgermissen", :area_code => "4256") + AreaCode.create(:country => germany, :name => "Schweringen", :area_code => "4257") + AreaCode.create(:country => germany, :name => "Schwarme", :area_code => "4258") + AreaCode.create(:country => germany, :name => "Visselhövede-Wittorf", :area_code => "4260") + AreaCode.create(:country => germany, :name => "Rotenburg Wümme", :area_code => "4261") + AreaCode.create(:country => germany, :name => "Visselhövede", :area_code => "4262") + AreaCode.create(:country => germany, :name => "Scheessel", :area_code => "4263") + AreaCode.create(:country => germany, :name => "Sottrum Kr Rotenburg", :area_code => "4264") + AreaCode.create(:country => germany, :name => "Fintel", :area_code => "4265") + AreaCode.create(:country => germany, :name => "Brockel", :area_code => "4266") + AreaCode.create(:country => germany, :name => "Lauenbrück", :area_code => "4267") + AreaCode.create(:country => germany, :name => "Bötersen", :area_code => "4268") + AreaCode.create(:country => germany, :name => "Ahausen-Kirchwalsede", :area_code => "4269") + AreaCode.create(:country => germany, :name => "Sulingen", :area_code => "4271") + AreaCode.create(:country => germany, :name => "Siedenburg", :area_code => "4272") + AreaCode.create(:country => germany, :name => "Kirchdorf b Sulingen", :area_code => "4273") + AreaCode.create(:country => germany, :name => "Varrel b Sulingen", :area_code => "4274") + AreaCode.create(:country => germany, :name => "Ehrenburg", :area_code => "4275") + AreaCode.create(:country => germany, :name => "Borstel b Sulingen", :area_code => "4276") + AreaCode.create(:country => germany, :name => "Schwaförden", :area_code => "4277") + AreaCode.create(:country => germany, :name => "Zeven", :area_code => "4281") + AreaCode.create(:country => germany, :name => "Sittensen", :area_code => "4282") + AreaCode.create(:country => germany, :name => "Tarmstedt", :area_code => "4283") + AreaCode.create(:country => germany, :name => "Selsingen", :area_code => "4284") + AreaCode.create(:country => germany, :name => "Rhade b Zeven", :area_code => "4285") + AreaCode.create(:country => germany, :name => "Gyhum", :area_code => "4286") + AreaCode.create(:country => germany, :name => "Heeslingen-Boitzen", :area_code => "4287") + AreaCode.create(:country => germany, :name => "Horstedt Kr Rotenburg", :area_code => "4288") + AreaCode.create(:country => germany, :name => "Kirchtimke", :area_code => "4289") + AreaCode.create(:country => germany, :name => "Ritterhude", :area_code => "4292") + AreaCode.create(:country => germany, :name => "Ottersberg-Fischerhude", :area_code => "4293") + AreaCode.create(:country => germany, :name => "Riede Kr Verden", :area_code => "4294") + AreaCode.create(:country => germany, :name => "Emtinghausen", :area_code => "4295") + AreaCode.create(:country => germany, :name => "Schwanewede-Aschwarden", :area_code => "4296") + AreaCode.create(:country => germany, :name => "Ottersberg-Posthausen", :area_code => "4297") + AreaCode.create(:country => germany, :name => "Lilienthal", :area_code => "4298") + AreaCode.create(:country => germany, :name => "Kirchbarkau", :area_code => "4302") + AreaCode.create(:country => germany, :name => "Schlesen", :area_code => "4303") + AreaCode.create(:country => germany, :name => "Westensee", :area_code => "4305") + AreaCode.create(:country => germany, :name => "Raisdorf", :area_code => "4307") + AreaCode.create(:country => germany, :name => "Schwedeneck", :area_code => "4308") + AreaCode.create(:country => germany, :name => "Kiel", :area_code => "431") + AreaCode.create(:country => germany, :name => "Heidmühlen", :area_code => "4320") + AreaCode.create(:country => germany, :name => "Neumünster", :area_code => "4321") + AreaCode.create(:country => germany, :name => "Bordesholm", :area_code => "4322") + AreaCode.create(:country => germany, :name => "Bornhöved", :area_code => "4323") + AreaCode.create(:country => germany, :name => "Brokstedt", :area_code => "4324") + AreaCode.create(:country => germany, :name => "Wankendorf", :area_code => "4326") + AreaCode.create(:country => germany, :name => "Grossenaspe", :area_code => "4327") + AreaCode.create(:country => germany, :name => "Rickling", :area_code => "4328") + AreaCode.create(:country => germany, :name => "Langwedel Holst", :area_code => "4329") + AreaCode.create(:country => germany, :name => "Emkendorf", :area_code => "4330") + AreaCode.create(:country => germany, :name => "Rendsburg", :area_code => "4331") + AreaCode.create(:country => germany, :name => "Hamdorf b Rendsburg", :area_code => "4332") + AreaCode.create(:country => germany, :name => "Erfde", :area_code => "4333") + AreaCode.create(:country => germany, :name => "Bredenbek b Rendsburg", :area_code => "4334") + AreaCode.create(:country => germany, :name => "Hohn b Rendsburg", :area_code => "4335") + AreaCode.create(:country => germany, :name => "Owschlag", :area_code => "4336") + AreaCode.create(:country => germany, :name => "Jevenstedt", :area_code => "4337") + AreaCode.create(:country => germany, :name => "Alt Duvenstedt", :area_code => "4338") + AreaCode.create(:country => germany, :name => "Christiansholm", :area_code => "4339") + AreaCode.create(:country => germany, :name => "Achterwehr", :area_code => "4340") + AreaCode.create(:country => germany, :name => "Preetz Kr Plön", :area_code => "4342") + AreaCode.create(:country => germany, :name => "Laboe", :area_code => "4343") + AreaCode.create(:country => germany, :name => "Schönberg Holstein", :area_code => "4344") + AreaCode.create(:country => germany, :name => "Gettorf", :area_code => "4346") + AreaCode.create(:country => germany, :name => "Flintbek", :area_code => "4347") + AreaCode.create(:country => germany, :name => "Schönkirchen", :area_code => "4348") + AreaCode.create(:country => germany, :name => "Dänischenhagen", :area_code => "4349") + AreaCode.create(:country => germany, :name => "Eckernförde", :area_code => "4351") + AreaCode.create(:country => germany, :name => "Damp", :area_code => "4352") + AreaCode.create(:country => germany, :name => "Ascheffel", :area_code => "4353") + AreaCode.create(:country => germany, :name => "Fleckeby", :area_code => "4354") + AreaCode.create(:country => germany, :name => "Rieseby", :area_code => "4355") + AreaCode.create(:country => germany, :name => "Gross Wittensee", :area_code => "4356") + AreaCode.create(:country => germany, :name => "Sehestedt Eider", :area_code => "4357") + AreaCode.create(:country => germany, :name => "Loose b Eckernförde", :area_code => "4358") + AreaCode.create(:country => germany, :name => "Oldenburg in Holstein", :area_code => "4361") + AreaCode.create(:country => germany, :name => "Heiligenhafen", :area_code => "4362") + AreaCode.create(:country => germany, :name => "Lensahn", :area_code => "4363") + AreaCode.create(:country => germany, :name => "Dahme Kr Ostholstein", :area_code => "4364") + AreaCode.create(:country => germany, :name => "Heringsdorf Holst", :area_code => "4365") + AreaCode.create(:country => germany, :name => "Grömitz-Cismar", :area_code => "4366") + AreaCode.create(:country => germany, :name => "Grossenbrode", :area_code => "4367") + AreaCode.create(:country => germany, :name => "Burg auf Fehmarn", :area_code => "4371") + AreaCode.create(:country => germany, :name => "Westfehmarn", :area_code => "4372") + AreaCode.create(:country => germany, :name => "Lütjenburg", :area_code => "4381") + AreaCode.create(:country => germany, :name => "Wangels", :area_code => "4382") + AreaCode.create(:country => germany, :name => "Grebin", :area_code => "4383") + AreaCode.create(:country => germany, :name => "Selent", :area_code => "4384") + AreaCode.create(:country => germany, :name => "Hohenfelde b Kiel", :area_code => "4385") + AreaCode.create(:country => germany, :name => "Nortorf b Neumünster", :area_code => "4392") + AreaCode.create(:country => germany, :name => "Boostedt", :area_code => "4393") + AreaCode.create(:country => germany, :name => "Bokhorst", :area_code => "4394") + AreaCode.create(:country => germany, :name => "Brake Unterweser", :area_code => "4401") + AreaCode.create(:country => germany, :name => "Rastede", :area_code => "4402") + AreaCode.create(:country => germany, :name => "Bad Zwischenahn", :area_code => "4403") + AreaCode.create(:country => germany, :name => "Elsfleth", :area_code => "4404") + AreaCode.create(:country => germany, :name => "Edewecht", :area_code => "4405") + AreaCode.create(:country => germany, :name => "Berne", :area_code => "4406") + AreaCode.create(:country => germany, :name => "Wardenburg", :area_code => "4407") + AreaCode.create(:country => germany, :name => "Hude Oldenburg", :area_code => "4408") + AreaCode.create(:country => germany, :name => "Westerstede-Ocholt", :area_code => "4409") + AreaCode.create(:country => germany, :name => "Oldenburg (Oldb)", :area_code => "441") + AreaCode.create(:country => germany, :name => "Wilhelmshaven", :area_code => "4421") + AreaCode.create(:country => germany, :name => "Sande Kr Friesl", :area_code => "4422") + AreaCode.create(:country => germany, :name => "Fedderwarden", :area_code => "4423") + AreaCode.create(:country => germany, :name => "Wangerland-Hooksiel", :area_code => "4425") + AreaCode.create(:country => germany, :name => "Wangerland-Horumersiel", :area_code => "4426") + AreaCode.create(:country => germany, :name => "Wildeshausen", :area_code => "4431") + AreaCode.create(:country => germany, :name => "Dötlingen-Brettorf", :area_code => "4432") + AreaCode.create(:country => germany, :name => "Dötlingen", :area_code => "4433") + AreaCode.create(:country => germany, :name => "Colnrade", :area_code => "4434") + AreaCode.create(:country => germany, :name => "Grossenkneten", :area_code => "4435") + AreaCode.create(:country => germany, :name => "Vechta", :area_code => "4441") + AreaCode.create(:country => germany, :name => "Lohne Oldenburg", :area_code => "4442") + AreaCode.create(:country => germany, :name => "Dinklage", :area_code => "4443") + AreaCode.create(:country => germany, :name => "Goldenstedt", :area_code => "4444") + AreaCode.create(:country => germany, :name => "Visbek Kr Vechta", :area_code => "4445") + AreaCode.create(:country => germany, :name => "Bakum Kr Vechta", :area_code => "4446") + AreaCode.create(:country => germany, :name => "Vechta-Langförden", :area_code => "4447") + AreaCode.create(:country => germany, :name => "Varel Jadebusen", :area_code => "4451") + AreaCode.create(:country => germany, :name => "Zetel-Neuenburg", :area_code => "4452") + AreaCode.create(:country => germany, :name => "Zetel", :area_code => "4453") + AreaCode.create(:country => germany, :name => "Jade", :area_code => "4454") + AreaCode.create(:country => germany, :name => "Jade-Schweiburg", :area_code => "4455") + AreaCode.create(:country => germany, :name => "Varel-Altjührden", :area_code => "4456") + AreaCode.create(:country => germany, :name => "Wiefelstede-Spohle", :area_code => "4458") + AreaCode.create(:country => germany, :name => "Jever", :area_code => "4461") + AreaCode.create(:country => germany, :name => "Wittmund", :area_code => "4462") + AreaCode.create(:country => germany, :name => "Wangerland", :area_code => "4463") + AreaCode.create(:country => germany, :name => "Wittmund-Carolinensiel", :area_code => "4464") + AreaCode.create(:country => germany, :name => "Friedeburg Ostfriesl", :area_code => "4465") + AreaCode.create(:country => germany, :name => "Wittmund-Ardorf", :area_code => "4466") + AreaCode.create(:country => germany, :name => "Wittmund-Funnix", :area_code => "4467") + AreaCode.create(:country => germany, :name => "Friedeburg-Reepsholt", :area_code => "4468") + AreaCode.create(:country => germany, :name => "Wangerooge", :area_code => "4469") + AreaCode.create(:country => germany, :name => "Cloppenburg", :area_code => "4471") + AreaCode.create(:country => germany, :name => "Lastrup", :area_code => "4472") + AreaCode.create(:country => germany, :name => "Emstek", :area_code => "4473") + AreaCode.create(:country => germany, :name => "Garrel", :area_code => "4474") + AreaCode.create(:country => germany, :name => "Molbergen", :area_code => "4475") + AreaCode.create(:country => germany, :name => "Lastrup-Hemmelte", :area_code => "4477") + AreaCode.create(:country => germany, :name => "Cappeln Oldenburg", :area_code => "4478") + AreaCode.create(:country => germany, :name => "Molbergen-Peheim", :area_code => "4479") + AreaCode.create(:country => germany, :name => "Ovelgönne-Strückhausen", :area_code => "4480") + AreaCode.create(:country => germany, :name => "Hatten-Sandkrug", :area_code => "4481") + AreaCode.create(:country => germany, :name => "Hatten", :area_code => "4482") + AreaCode.create(:country => germany, :name => "Ovelgönne-Großenmeer", :area_code => "4483") + AreaCode.create(:country => germany, :name => "Hude-Wüsting", :area_code => "4484") + AreaCode.create(:country => germany, :name => "Elsfleth-Huntorf", :area_code => "4485") + AreaCode.create(:country => germany, :name => "Edewecht-Friedrichsfehn", :area_code => "4486") + AreaCode.create(:country => germany, :name => "Grossenkneten-Huntlosen", :area_code => "4487") + AreaCode.create(:country => germany, :name => "Westerstede", :area_code => "4488") + AreaCode.create(:country => germany, :name => "Apen", :area_code => "4489") + AreaCode.create(:country => germany, :name => "Friesoythe", :area_code => "4491") + AreaCode.create(:country => germany, :name => "Saterland", :area_code => "4492") + AreaCode.create(:country => germany, :name => "Friesoythe-Gehlenberg", :area_code => "4493") + AreaCode.create(:country => germany, :name => "Bösel Oldenburg", :area_code => "4494") + AreaCode.create(:country => germany, :name => "Friesoythe-Thüle", :area_code => "4495") + AreaCode.create(:country => germany, :name => "Friesoythe-Markhausen", :area_code => "4496") + AreaCode.create(:country => germany, :name => "Barßel-Harkebrügge", :area_code => "4497") + AreaCode.create(:country => germany, :name => "Saterland-Ramsloh", :area_code => "4498") + AreaCode.create(:country => germany, :name => "Barssel", :area_code => "4499") + AreaCode.create(:country => germany, :name => "Kastorf Holst", :area_code => "4501") + AreaCode.create(:country => germany, :name => "Lübeck-Travemünde", :area_code => "4502") + AreaCode.create(:country => germany, :name => "Timmendorfer Strand", :area_code => "4503") + AreaCode.create(:country => germany, :name => "Ratekau", :area_code => "4504") + AreaCode.create(:country => germany, :name => "Stockelsdorf-Curau", :area_code => "4505") + AreaCode.create(:country => germany, :name => "Stockelsdorf-Krumbeck", :area_code => "4506") + AreaCode.create(:country => germany, :name => "Krummesse", :area_code => "4508") + AreaCode.create(:country => germany, :name => "Groß Grönau", :area_code => "4509") + AreaCode.create(:country => germany, :name => "Lübeck", :area_code => "451") + AreaCode.create(:country => germany, :name => "Eutin", :area_code => "4521") + AreaCode.create(:country => germany, :name => "Plön", :area_code => "4522") + AreaCode.create(:country => germany, :name => "Malente", :area_code => "4523") + AreaCode.create(:country => germany, :name => "Scharbeutz-Pönitz", :area_code => "4524") + AreaCode.create(:country => germany, :name => "Ahrensbök", :area_code => "4525") + AreaCode.create(:country => germany, :name => "Ascheberg Holstein", :area_code => "4526") + AreaCode.create(:country => germany, :name => "Bosau", :area_code => "4527") + AreaCode.create(:country => germany, :name => "Schönwalde am Bungsberg", :area_code => "4528") + AreaCode.create(:country => germany, :name => "Süsel-Bujendorf", :area_code => "4529") + AreaCode.create(:country => germany, :name => "Bad Oldesloe", :area_code => "4531") + AreaCode.create(:country => germany, :name => "Bargteheide", :area_code => "4532") + AreaCode.create(:country => germany, :name => "Reinfeld Holstein", :area_code => "4533") + AreaCode.create(:country => germany, :name => "Steinburg Kr Storman", :area_code => "4534") + AreaCode.create(:country => germany, :name => "Nahe", :area_code => "4535") + AreaCode.create(:country => germany, :name => "Steinhorst Lauenb", :area_code => "4536") + AreaCode.create(:country => germany, :name => "Sülfeld Holst", :area_code => "4537") + AreaCode.create(:country => germany, :name => "Westerau", :area_code => "4539") + AreaCode.create(:country => germany, :name => "Ratzeburg", :area_code => "4541") + AreaCode.create(:country => germany, :name => "Mölln Lauenb", :area_code => "4542") + AreaCode.create(:country => germany, :name => "Nusse", :area_code => "4543") + AreaCode.create(:country => germany, :name => "Berkenthin", :area_code => "4544") + AreaCode.create(:country => germany, :name => "Seedorf Lauenb", :area_code => "4545") + AreaCode.create(:country => germany, :name => "Mustin Lauenburg", :area_code => "4546") + AreaCode.create(:country => germany, :name => "Gudow Lauenb", :area_code => "4547") + AreaCode.create(:country => germany, :name => "Bühnsdorf", :area_code => "4550") + AreaCode.create(:country => germany, :name => "Bad Segeberg", :area_code => "4551") + AreaCode.create(:country => germany, :name => "Leezen", :area_code => "4552") + AreaCode.create(:country => germany, :name => "Geschendorf", :area_code => "4553") + AreaCode.create(:country => germany, :name => "Wahlstedt", :area_code => "4554") + AreaCode.create(:country => germany, :name => "Seedorf b Bad Segeberg", :area_code => "4555") + AreaCode.create(:country => germany, :name => "Ahrensbök-Gnissau", :area_code => "4556") + AreaCode.create(:country => germany, :name => "Blunk", :area_code => "4557") + AreaCode.create(:country => germany, :name => "Todesfelde", :area_code => "4558") + AreaCode.create(:country => germany, :name => "Wensin", :area_code => "4559") + AreaCode.create(:country => germany, :name => "Neustadt in Holstein", :area_code => "4561") + AreaCode.create(:country => germany, :name => "Grömitz", :area_code => "4562") + AreaCode.create(:country => germany, :name => "Scharbeutz-Haffkrug", :area_code => "4563") + AreaCode.create(:country => germany, :name => "Schashagen", :area_code => "4564") + AreaCode.create(:country => germany, :name => "Freienwill", :area_code => "4602") + AreaCode.create(:country => germany, :name => "Havetoft", :area_code => "4603") + AreaCode.create(:country => germany, :name => "Grossenwiehe", :area_code => "4604") + AreaCode.create(:country => germany, :name => "Medelby", :area_code => "4605") + AreaCode.create(:country => germany, :name => "Wanderup", :area_code => "4606") + AreaCode.create(:country => germany, :name => "Janneby", :area_code => "4607") + AreaCode.create(:country => germany, :name => "Handewitt", :area_code => "4608") + AreaCode.create(:country => germany, :name => "Eggebek", :area_code => "4609") + AreaCode.create(:country => germany, :name => "Flensburg", :area_code => "461") + AreaCode.create(:country => germany, :name => "Schleswig", :area_code => "4621") + AreaCode.create(:country => germany, :name => "Taarstedt", :area_code => "4622") + AreaCode.create(:country => germany, :name => "Böklund", :area_code => "4623") + AreaCode.create(:country => germany, :name => "Kropp", :area_code => "4624") + AreaCode.create(:country => germany, :name => "Jübek", :area_code => "4625") + AreaCode.create(:country => germany, :name => "Treia", :area_code => "4626") + AreaCode.create(:country => germany, :name => "Dörpstedt", :area_code => "4627") + AreaCode.create(:country => germany, :name => "Barderup", :area_code => "4630") + AreaCode.create(:country => germany, :name => "Glücksburg Ostsee", :area_code => "4631") + AreaCode.create(:country => germany, :name => "Steinbergkirche", :area_code => "4632") + AreaCode.create(:country => germany, :name => "Satrup", :area_code => "4633") + AreaCode.create(:country => germany, :name => "Husby", :area_code => "4634") + AreaCode.create(:country => germany, :name => "Sörup", :area_code => "4635") + AreaCode.create(:country => germany, :name => "Langballig", :area_code => "4636") + AreaCode.create(:country => germany, :name => "Sterup", :area_code => "4637") + AreaCode.create(:country => germany, :name => "Tarp", :area_code => "4638") + AreaCode.create(:country => germany, :name => "Schafflund", :area_code => "4639") + AreaCode.create(:country => germany, :name => "Süderbrarup", :area_code => "4641") + AreaCode.create(:country => germany, :name => "Kappeln Schlei", :area_code => "4642") + AreaCode.create(:country => germany, :name => "Gelting Angeln", :area_code => "4643") + AreaCode.create(:country => germany, :name => "Karby", :area_code => "4644") + AreaCode.create(:country => germany, :name => "Mohrkirch", :area_code => "4646") + AreaCode.create(:country => germany, :name => "Sylt", :area_code => "4651") + AreaCode.create(:country => germany, :name => "Niebüll", :area_code => "4661") + AreaCode.create(:country => germany, :name => "Leck", :area_code => "4662") + AreaCode.create(:country => germany, :name => "Süderlügum", :area_code => "4663") + AreaCode.create(:country => germany, :name => "Neukirchen b Niebüll", :area_code => "4664") + AreaCode.create(:country => germany, :name => "Emmelsbüll-Horsbüll", :area_code => "4665") + AreaCode.create(:country => germany, :name => "Ladelund", :area_code => "4666") + AreaCode.create(:country => germany, :name => "Dagebüll", :area_code => "4667") + AreaCode.create(:country => germany, :name => "Klanxbüll", :area_code => "4668") + AreaCode.create(:country => germany, :name => "Bredstedt", :area_code => "4671") + AreaCode.create(:country => germany, :name => "Langenhorn", :area_code => "4672") + AreaCode.create(:country => germany, :name => "Joldelund", :area_code => "4673") + AreaCode.create(:country => germany, :name => "Ockholm", :area_code => "4674") + AreaCode.create(:country => germany, :name => "Wyk auf Föhr", :area_code => "4681") + AreaCode.create(:country => germany, :name => "Amrum", :area_code => "4682") + AreaCode.create(:country => germany, :name => "Oldsum", :area_code => "4683") + AreaCode.create(:country => germany, :name => "Langeneß Hallig", :area_code => "4684") + AreaCode.create(:country => germany, :name => "Sandstedt", :area_code => "4702") + AreaCode.create(:country => germany, :name => "Loxstedt-Donnern", :area_code => "4703") + AreaCode.create(:country => germany, :name => "Drangstedt", :area_code => "4704") + AreaCode.create(:country => germany, :name => "Wremen", :area_code => "4705") + AreaCode.create(:country => germany, :name => "Schiffdorf", :area_code => "4706") + AreaCode.create(:country => germany, :name => "Langen-Neuenwalde", :area_code => "4707") + AreaCode.create(:country => germany, :name => "Ringstedt", :area_code => "4708") + AreaCode.create(:country => germany, :name => "Bremerhaven", :area_code => "471") + AreaCode.create(:country => germany, :name => "Cuxhaven", :area_code => "4721") + AreaCode.create(:country => germany, :name => "Cuxhaven-Altenbruch", :area_code => "4722") + AreaCode.create(:country => germany, :name => "Cuxhaven-Altenwalde", :area_code => "4723") + AreaCode.create(:country => germany, :name => "Cuxhaven-Lüdingworth", :area_code => "4724") + AreaCode.create(:country => germany, :name => "Helgoland", :area_code => "4725") + AreaCode.create(:country => germany, :name => "Nordenham", :area_code => "4731") + AreaCode.create(:country => germany, :name => "Stadland-Rodenkirchen", :area_code => "4732") + AreaCode.create(:country => germany, :name => "Butjadingen-Burhave", :area_code => "4733") + AreaCode.create(:country => germany, :name => "Stadland-Seefeld", :area_code => "4734") + AreaCode.create(:country => germany, :name => "Butjadingen-Stollhamm", :area_code => "4735") + AreaCode.create(:country => germany, :name => "Butjadingen-Tossens", :area_code => "4736") + AreaCode.create(:country => germany, :name => "Stadland-Schwei", :area_code => "4737") + AreaCode.create(:country => germany, :name => "Loxstedt-Dedesdorf", :area_code => "4740") + AreaCode.create(:country => germany, :name => "Nordholz b Bremerhaven", :area_code => "4741") + AreaCode.create(:country => germany, :name => "Dorum", :area_code => "4742") + AreaCode.create(:country => germany, :name => "Langen b Bremerhaven", :area_code => "4743") + AreaCode.create(:country => germany, :name => "Loxstedt", :area_code => "4744") + AreaCode.create(:country => germany, :name => "Bad Bederkesa", :area_code => "4745") + AreaCode.create(:country => germany, :name => "Hagen b Bremerhaven", :area_code => "4746") + AreaCode.create(:country => germany, :name => "Beverstedt", :area_code => "4747") + AreaCode.create(:country => germany, :name => "Stubben b Bremerhaven", :area_code => "4748") + AreaCode.create(:country => germany, :name => "Schiffdorf-Geestenseth", :area_code => "4749") + AreaCode.create(:country => germany, :name => "Otterndorf", :area_code => "4751") + AreaCode.create(:country => germany, :name => "Neuhaus Oste", :area_code => "4752") + AreaCode.create(:country => germany, :name => "Balje", :area_code => "4753") + AreaCode.create(:country => germany, :name => "Bülkau", :area_code => "4754") + AreaCode.create(:country => germany, :name => "Ihlienworth", :area_code => "4755") + AreaCode.create(:country => germany, :name => "Odisheim", :area_code => "4756") + AreaCode.create(:country => germany, :name => "Wanna", :area_code => "4757") + AreaCode.create(:country => germany, :name => "Nordleda", :area_code => "4758") + AreaCode.create(:country => germany, :name => "Bremervörde", :area_code => "4761") + AreaCode.create(:country => germany, :name => "Kutenholz", :area_code => "4762") + AreaCode.create(:country => germany, :name => "Gnarrenburg", :area_code => "4763") + AreaCode.create(:country => germany, :name => "Gnarrenburg-Klenkendorf", :area_code => "4764") + AreaCode.create(:country => germany, :name => "Ebersdorf b Bremervörde", :area_code => "4765") + AreaCode.create(:country => germany, :name => "Basdahl", :area_code => "4766") + AreaCode.create(:country => germany, :name => "Bremervörde-Bevern", :area_code => "4767") + AreaCode.create(:country => germany, :name => "Hipstedt", :area_code => "4768") + AreaCode.create(:country => germany, :name => "Bremervörde-Iselersheim", :area_code => "4769") + AreaCode.create(:country => germany, :name => "Wischhafen", :area_code => "4770") + AreaCode.create(:country => germany, :name => "Hemmoor", :area_code => "4771") + AreaCode.create(:country => germany, :name => "Oberndorf Oste", :area_code => "4772") + AreaCode.create(:country => germany, :name => "Lamstedt", :area_code => "4773") + AreaCode.create(:country => germany, :name => "Hechthausen", :area_code => "4774") + AreaCode.create(:country => germany, :name => "Grossenwörden", :area_code => "4775") + AreaCode.create(:country => germany, :name => "Osten-Altendorf", :area_code => "4776") + AreaCode.create(:country => germany, :name => "Cadenberge", :area_code => "4777") + AreaCode.create(:country => germany, :name => "Wingst", :area_code => "4778") + AreaCode.create(:country => germany, :name => "Freiburg Elbe", :area_code => "4779") + AreaCode.create(:country => germany, :name => "Osterholz-Scharmbeck", :area_code => "4791") + AreaCode.create(:country => germany, :name => "Worpswede", :area_code => "4792") + AreaCode.create(:country => germany, :name => "Hambergen", :area_code => "4793") + AreaCode.create(:country => germany, :name => "Worpswede-Ostersode", :area_code => "4794") + AreaCode.create(:country => germany, :name => "Garlstedt", :area_code => "4795") + AreaCode.create(:country => germany, :name => "Teufelsmoor", :area_code => "4796") + AreaCode.create(:country => germany, :name => "Wrohm", :area_code => "4802") + AreaCode.create(:country => germany, :name => "Pahlen", :area_code => "4803") + AreaCode.create(:country => germany, :name => "Nordhastedt", :area_code => "4804") + AreaCode.create(:country => germany, :name => "Schafstedt", :area_code => "4805") + AreaCode.create(:country => germany, :name => "Sarzbüttel", :area_code => "4806") + AreaCode.create(:country => germany, :name => "Heide Holst", :area_code => "481") + AreaCode.create(:country => germany, :name => "Itzehoe", :area_code => "4821") + AreaCode.create(:country => germany, :name => "Kellinghusen", :area_code => "4822") + AreaCode.create(:country => germany, :name => "Wilster", :area_code => "4823") + AreaCode.create(:country => germany, :name => "Krempe", :area_code => "4824") + AreaCode.create(:country => germany, :name => "Burg Dithmarschen", :area_code => "4825") + AreaCode.create(:country => germany, :name => "Hohenlockstedt", :area_code => "4826") + AreaCode.create(:country => germany, :name => "Wacken", :area_code => "4827") + AreaCode.create(:country => germany, :name => "Lägerdorf", :area_code => "4828") + AreaCode.create(:country => germany, :name => "Wewelsfleth", :area_code => "4829") + AreaCode.create(:country => germany, :name => "Süderhastedt", :area_code => "4830") + AreaCode.create(:country => germany, :name => "Meldorf", :area_code => "4832") + AreaCode.create(:country => germany, :name => "Wesselburen", :area_code => "4833") + AreaCode.create(:country => germany, :name => "Büsum", :area_code => "4834") + AreaCode.create(:country => germany, :name => "Albersdorf Holst", :area_code => "4835") + AreaCode.create(:country => germany, :name => "Hennstedt Dithm", :area_code => "4836") + AreaCode.create(:country => germany, :name => "Neuenkirchen Dithm", :area_code => "4837") + AreaCode.create(:country => germany, :name => "Tellingstedt", :area_code => "4838") + AreaCode.create(:country => germany, :name => "Wöhrden Dithm", :area_code => "4839") + AreaCode.create(:country => germany, :name => "Husum Nordsee", :area_code => "4841") + AreaCode.create(:country => germany, :name => "Nordstrand", :area_code => "4842") + AreaCode.create(:country => germany, :name => "Viöl", :area_code => "4843") + AreaCode.create(:country => germany, :name => "Pellworm", :area_code => "4844") + AreaCode.create(:country => germany, :name => "Ostenfeld Husum", :area_code => "4845") + AreaCode.create(:country => germany, :name => "Hattstedt", :area_code => "4846") + AreaCode.create(:country => germany, :name => "Oster-Ohrstedt", :area_code => "4847") + AreaCode.create(:country => germany, :name => "Rantrum", :area_code => "4848") + AreaCode.create(:country => germany, :name => "Hooge", :area_code => "4849") + AreaCode.create(:country => germany, :name => "Marne", :area_code => "4851") + AreaCode.create(:country => germany, :name => "Brunsbüttel", :area_code => "4852") + AreaCode.create(:country => germany, :name => "Sankt Michaelisdonn", :area_code => "4853") + AreaCode.create(:country => germany, :name => "Friedrichskoog", :area_code => "4854") + AreaCode.create(:country => germany, :name => "Eddelak", :area_code => "4855") + AreaCode.create(:country => germany, :name => "Kronprinzenkoog", :area_code => "4856") + AreaCode.create(:country => germany, :name => "Barlt", :area_code => "4857") + AreaCode.create(:country => germany, :name => "Sankt Margarethen Holst", :area_code => "4858") + AreaCode.create(:country => germany, :name => "Windbergen", :area_code => "4859") + AreaCode.create(:country => germany, :name => "Tönning", :area_code => "4861") + AreaCode.create(:country => germany, :name => "Garding", :area_code => "4862") + AreaCode.create(:country => germany, :name => "Sankt Peter-Ording", :area_code => "4863") + AreaCode.create(:country => germany, :name => "Oldenswort", :area_code => "4864") + AreaCode.create(:country => germany, :name => "Osterhever", :area_code => "4865") + AreaCode.create(:country => germany, :name => "Hohenwestedt", :area_code => "4871") + AreaCode.create(:country => germany, :name => "Hanerau-Hademarschen", :area_code => "4872") + AreaCode.create(:country => germany, :name => "Aukrug", :area_code => "4873") + AreaCode.create(:country => germany, :name => "Todenbüttel", :area_code => "4874") + AreaCode.create(:country => germany, :name => "Stafstedt", :area_code => "4875") + AreaCode.create(:country => germany, :name => "Reher Holst", :area_code => "4876") + AreaCode.create(:country => germany, :name => "Hennstedt b Itzehoe", :area_code => "4877") + AreaCode.create(:country => germany, :name => "Friedrichstadt", :area_code => "4881") + AreaCode.create(:country => germany, :name => "Lunden", :area_code => "4882") + AreaCode.create(:country => germany, :name => "Süderstapel", :area_code => "4883") + AreaCode.create(:country => germany, :name => "Schwabstedt", :area_code => "4884") + AreaCode.create(:country => germany, :name => "Bergenhusen", :area_code => "4885") + AreaCode.create(:country => germany, :name => "Schenefeld Mittelholst", :area_code => "4892") + AreaCode.create(:country => germany, :name => "Hohenaspe", :area_code => "4893") + AreaCode.create(:country => germany, :name => "Jemgum-Ditzum", :area_code => "4902") + AreaCode.create(:country => germany, :name => "Wymeer", :area_code => "4903") + AreaCode.create(:country => germany, :name => "Leer Ostfriesland", :area_code => "491") + AreaCode.create(:country => germany, :name => "Wirdum", :area_code => "4920") + AreaCode.create(:country => germany, :name => "Emden Stadt", :area_code => "4921") + AreaCode.create(:country => germany, :name => "Borkum", :area_code => "4922") + AreaCode.create(:country => germany, :name => "Krummhörn-Pewsum", :area_code => "4923") + AreaCode.create(:country => germany, :name => "Moormerland-Oldersum", :area_code => "4924") + AreaCode.create(:country => germany, :name => "Hinte", :area_code => "4925") + AreaCode.create(:country => germany, :name => "Krummhörn-Greetsiel", :area_code => "4926") + AreaCode.create(:country => germany, :name => "Krummhörn-Loquard", :area_code => "4927") + AreaCode.create(:country => germany, :name => "Ihlow-Riepe", :area_code => "4928") + AreaCode.create(:country => germany, :name => "Ihlow Kr Aurich", :area_code => "4929") + AreaCode.create(:country => germany, :name => "Norden", :area_code => "4931") + AreaCode.create(:country => germany, :name => "Norderney", :area_code => "4932") + AreaCode.create(:country => germany, :name => "Dornum Ostfriesl", :area_code => "4933") + AreaCode.create(:country => germany, :name => "Marienhafe", :area_code => "4934") + AreaCode.create(:country => germany, :name => "Juist", :area_code => "4935") + AreaCode.create(:country => germany, :name => "Grossheide", :area_code => "4936") + AreaCode.create(:country => germany, :name => "Hagermarsch", :area_code => "4938") + AreaCode.create(:country => germany, :name => "Baltrum", :area_code => "4939") + AreaCode.create(:country => germany, :name => "Aurich", :area_code => "4941") + AreaCode.create(:country => germany, :name => "Südbrookmerland", :area_code => "4942") + AreaCode.create(:country => germany, :name => "Grossefehn", :area_code => "4943") + AreaCode.create(:country => germany, :name => "Wiesmoor", :area_code => "4944") + AreaCode.create(:country => germany, :name => "Grossefehn-Timmel", :area_code => "4945") + AreaCode.create(:country => germany, :name => "Grossefehn-Bagband", :area_code => "4946") + AreaCode.create(:country => germany, :name => "Aurich-Ogenbargen", :area_code => "4947") + AreaCode.create(:country => germany, :name => "Wiesmoor-Marcardsmoor", :area_code => "4948") + AreaCode.create(:country => germany, :name => "Holtland", :area_code => "4950") + AreaCode.create(:country => germany, :name => "Weener", :area_code => "4951") + AreaCode.create(:country => germany, :name => "Rhauderfehn", :area_code => "4952") + AreaCode.create(:country => germany, :name => "Bunde", :area_code => "4953") + AreaCode.create(:country => germany, :name => "Moormerland", :area_code => "4954") + AreaCode.create(:country => germany, :name => "Westoverledingen", :area_code => "4955") + AreaCode.create(:country => germany, :name => "Uplengen", :area_code => "4956") + AreaCode.create(:country => germany, :name => "Detern", :area_code => "4957") + AreaCode.create(:country => germany, :name => "Jemgum", :area_code => "4958") + AreaCode.create(:country => germany, :name => "Dollart", :area_code => "4959") + AreaCode.create(:country => germany, :name => "Papenburg", :area_code => "4961") + AreaCode.create(:country => germany, :name => "Papenburg-Aschendorf", :area_code => "4962") + AreaCode.create(:country => germany, :name => "Dörpen", :area_code => "4963") + AreaCode.create(:country => germany, :name => "Rhede Ems", :area_code => "4964") + AreaCode.create(:country => germany, :name => "Surwold", :area_code => "4965") + AreaCode.create(:country => germany, :name => "Neubörger", :area_code => "4966") + AreaCode.create(:country => germany, :name => "Rhauderfehn-Burlage", :area_code => "4967") + AreaCode.create(:country => germany, :name => "Neulehe", :area_code => "4968") + AreaCode.create(:country => germany, :name => "Esens", :area_code => "4971") + AreaCode.create(:country => germany, :name => "Langeoog", :area_code => "4972") + AreaCode.create(:country => germany, :name => "Wittmund-Burhafe", :area_code => "4973") + AreaCode.create(:country => germany, :name => "Neuharlingersiel", :area_code => "4974") + AreaCode.create(:country => germany, :name => "Westerholt Ostfriesl", :area_code => "4975") + AreaCode.create(:country => germany, :name => "Spiekeroog", :area_code => "4976") + AreaCode.create(:country => germany, :name => "Blomberg Ostfriesl", :area_code => "4977") + AreaCode.create(:country => germany, :name => "Nienburg Weser", :area_code => "5021") + AreaCode.create(:country => germany, :name => "Wietzen", :area_code => "5022") + AreaCode.create(:country => germany, :name => "Liebenau Kr Nienburg Weser", :area_code => "5023") + AreaCode.create(:country => germany, :name => "Rohrsen Kr Nienburg Weser", :area_code => "5024") + AreaCode.create(:country => germany, :name => "Estorf Weser", :area_code => "5025") + AreaCode.create(:country => germany, :name => "Steimbke", :area_code => "5026") + AreaCode.create(:country => germany, :name => "Linsburg", :area_code => "5027") + AreaCode.create(:country => germany, :name => "Pennigsehl", :area_code => "5028") + AreaCode.create(:country => germany, :name => "Wunstorf", :area_code => "5031") + AreaCode.create(:country => germany, :name => "Neustadt am Rübenberge", :area_code => "5032") + AreaCode.create(:country => germany, :name => "Wunstorf-Grossenheidorn", :area_code => "5033") + AreaCode.create(:country => germany, :name => "Neustadt-Hagen", :area_code => "5034") + AreaCode.create(:country => germany, :name => "Gross Munzel", :area_code => "5035") + AreaCode.create(:country => germany, :name => "Neustadt-Schneeren", :area_code => "5036") + AreaCode.create(:country => germany, :name => "Bad Rehburg", :area_code => "5037") + AreaCode.create(:country => germany, :name => "Springe Deister", :area_code => "5041") + AreaCode.create(:country => germany, :name => "Bad Münder am Deister", :area_code => "5042") + AreaCode.create(:country => germany, :name => "Lauenau", :area_code => "5043") + AreaCode.create(:country => germany, :name => "Springe-Eldagsen", :area_code => "5044") + AreaCode.create(:country => germany, :name => "Springe-Bennigsen", :area_code => "5045") + AreaCode.create(:country => germany, :name => "Bergen Kr Celle", :area_code => "5051") + AreaCode.create(:country => germany, :name => "Hermannsburg", :area_code => "5052") + AreaCode.create(:country => germany, :name => "Faßberg-Müden", :area_code => "5053") + AreaCode.create(:country => germany, :name => "Bergen-Sülze", :area_code => "5054") + AreaCode.create(:country => germany, :name => "Fassberg", :area_code => "5055") + AreaCode.create(:country => germany, :name => "Winsen-Meissendorf", :area_code => "5056") + AreaCode.create(:country => germany, :name => "Bodenburg", :area_code => "5060") + AreaCode.create(:country => germany, :name => "Holle b Hildesheim", :area_code => "5062") + AreaCode.create(:country => germany, :name => "Bad Salzdetfurth", :area_code => "5063") + AreaCode.create(:country => germany, :name => "Groß Düngen", :area_code => "5064") + AreaCode.create(:country => germany, :name => "Sibbesse", :area_code => "5065") + AreaCode.create(:country => germany, :name => "Sarstedt", :area_code => "5066") + AreaCode.create(:country => germany, :name => "Bockenem", :area_code => "5067") + AreaCode.create(:country => germany, :name => "Elze Leine", :area_code => "5068") + AreaCode.create(:country => germany, :name => "Nordstemmen", :area_code => "5069") + AreaCode.create(:country => germany, :name => "Schwarmstedt", :area_code => "5071") + AreaCode.create(:country => germany, :name => "Neustadt-Mandelsloh", :area_code => "5072") + AreaCode.create(:country => germany, :name => "Neustadt-Esperke", :area_code => "5073") + AreaCode.create(:country => germany, :name => "Rodewald", :area_code => "5074") + AreaCode.create(:country => germany, :name => "Langlingen", :area_code => "5082") + AreaCode.create(:country => germany, :name => "Hohne b Celle", :area_code => "5083") + AreaCode.create(:country => germany, :name => "Hambühren", :area_code => "5084") + AreaCode.create(:country => germany, :name => "Burgdorf-Ehlershausen", :area_code => "5085") + AreaCode.create(:country => germany, :name => "Celle-Scheuen", :area_code => "5086") + AreaCode.create(:country => germany, :name => "Pattensen", :area_code => "5101") + AreaCode.create(:country => germany, :name => "Laatzen", :area_code => "5102") + AreaCode.create(:country => germany, :name => "Wennigsen Deister", :area_code => "5103") + AreaCode.create(:country => germany, :name => "Barsinghausen", :area_code => "5105") + AreaCode.create(:country => germany, :name => "Gehrden Han", :area_code => "5108") + AreaCode.create(:country => germany, :name => "Ronnenberg", :area_code => "5109") + AreaCode.create(:country => germany, :name => "Hannover", :area_code => "511") + AreaCode.create(:country => germany, :name => "Hildesheim", :area_code => "5121") + AreaCode.create(:country => germany, :name => "Schellerten", :area_code => "5123") + AreaCode.create(:country => germany, :name => "Algermissen", :area_code => "5126") + AreaCode.create(:country => germany, :name => "Harsum", :area_code => "5127") + AreaCode.create(:country => germany, :name => "Hohenhameln", :area_code => "5128") + AreaCode.create(:country => germany, :name => "Söhlde", :area_code => "5129") + AreaCode.create(:country => germany, :name => "Wedemark", :area_code => "5130") + AreaCode.create(:country => germany, :name => "Garbsen", :area_code => "5131") + AreaCode.create(:country => germany, :name => "Lehrte", :area_code => "5132") + AreaCode.create(:country => germany, :name => "Burgwedel-Fuhrberg", :area_code => "5135") + AreaCode.create(:country => germany, :name => "Burgdorf Kr Hannover", :area_code => "5136") + AreaCode.create(:country => germany, :name => "Seelze", :area_code => "5137") + AreaCode.create(:country => germany, :name => "Sehnde", :area_code => "5138") + AreaCode.create(:country => germany, :name => "Burgwedel", :area_code => "5139") + AreaCode.create(:country => germany, :name => "Celle", :area_code => "5141") + AreaCode.create(:country => germany, :name => "Eschede", :area_code => "5142") + AreaCode.create(:country => germany, :name => "Winsen Aller", :area_code => "5143") + AreaCode.create(:country => germany, :name => "Wathlingen", :area_code => "5144") + AreaCode.create(:country => germany, :name => "Beedenbostel", :area_code => "5145") + AreaCode.create(:country => germany, :name => "Wietze", :area_code => "5146") + AreaCode.create(:country => germany, :name => "Uetze-Hänigsen", :area_code => "5147") + AreaCode.create(:country => germany, :name => "Steinhorst Niedersachs", :area_code => "5148") + AreaCode.create(:country => germany, :name => "Wienhausen", :area_code => "5149") + AreaCode.create(:country => germany, :name => "Hameln", :area_code => "5151") + AreaCode.create(:country => germany, :name => "Hessisch Oldendorf", :area_code => "5152") + AreaCode.create(:country => germany, :name => "Salzhemmendorf", :area_code => "5153") + AreaCode.create(:country => germany, :name => "Aerzen", :area_code => "5154") + AreaCode.create(:country => germany, :name => "Emmerthal", :area_code => "5155") + AreaCode.create(:country => germany, :name => "Coppenbrügge", :area_code => "5156") + AreaCode.create(:country => germany, :name => "Emmerthal-Börry", :area_code => "5157") + AreaCode.create(:country => germany, :name => "Hemeringen", :area_code => "5158") + AreaCode.create(:country => germany, :name => "Coppenbrügge-Bisperode", :area_code => "5159") + AreaCode.create(:country => germany, :name => "Walsrode", :area_code => "5161") + AreaCode.create(:country => germany, :name => "Fallingbostel", :area_code => "5162") + AreaCode.create(:country => germany, :name => "Fallingbostel-Dorfmark", :area_code => "5163") + AreaCode.create(:country => germany, :name => "Hodenhagen", :area_code => "5164") + AreaCode.create(:country => germany, :name => "Rethem Aller", :area_code => "5165") + AreaCode.create(:country => germany, :name => "Walsrode-Kirchboitzen", :area_code => "5166") + AreaCode.create(:country => germany, :name => "Walsrode-Westenholz", :area_code => "5167") + AreaCode.create(:country => germany, :name => "Walsrode-Stellichte", :area_code => "5168") + AreaCode.create(:country => germany, :name => "Peine", :area_code => "5171") + AreaCode.create(:country => germany, :name => "Ilsede", :area_code => "5172") + AreaCode.create(:country => germany, :name => "Uetze", :area_code => "5173") + AreaCode.create(:country => germany, :name => "Lahstedt", :area_code => "5174") + AreaCode.create(:country => germany, :name => "Lehrte-Arpke", :area_code => "5175") + AreaCode.create(:country => germany, :name => "Edemissen", :area_code => "5176") + AreaCode.create(:country => germany, :name => "Edemissen-Abbensen", :area_code => "5177") + AreaCode.create(:country => germany, :name => "Alfeld Leine", :area_code => "5181") + AreaCode.create(:country => germany, :name => "Gronau Leine", :area_code => "5182") + AreaCode.create(:country => germany, :name => "Lamspringe", :area_code => "5183") + AreaCode.create(:country => germany, :name => "Freden Leine", :area_code => "5184") + AreaCode.create(:country => germany, :name => "Duingen", :area_code => "5185") + AreaCode.create(:country => germany, :name => "Salzhemmendorf-Wallensen", :area_code => "5186") + AreaCode.create(:country => germany, :name => "Delligsen", :area_code => "5187") + AreaCode.create(:country => germany, :name => "Soltau-Emmingen", :area_code => "5190") + AreaCode.create(:country => germany, :name => "Soltau", :area_code => "5191") + AreaCode.create(:country => germany, :name => "Munster", :area_code => "5192") + AreaCode.create(:country => germany, :name => "Schneverdingen", :area_code => "5193") + AreaCode.create(:country => germany, :name => "Bispingen", :area_code => "5194") + AreaCode.create(:country => germany, :name => "Neuenkirchen b Soltau", :area_code => "5195") + AreaCode.create(:country => germany, :name => "Wietzendorf", :area_code => "5196") + AreaCode.create(:country => germany, :name => "Soltau-Frielingen", :area_code => "5197") + AreaCode.create(:country => germany, :name => "Schneverdingen-Wintermoor", :area_code => "5198") + AreaCode.create(:country => germany, :name => "Schneverdingen-Heber", :area_code => "5199") + AreaCode.create(:country => germany, :name => "Halle Westf", :area_code => "5201") + AreaCode.create(:country => germany, :name => "Oerlinghausen", :area_code => "5202") + AreaCode.create(:country => germany, :name => "Werther Westf", :area_code => "5203") + AreaCode.create(:country => germany, :name => "Steinhagen Westf", :area_code => "5204") + AreaCode.create(:country => germany, :name => "Bielefeld-Sennestadt", :area_code => "5205") + AreaCode.create(:country => germany, :name => "Bielefeld-Jöllenbeck", :area_code => "5206") + AreaCode.create(:country => germany, :name => "Schloss Holte-Stukenbrock", :area_code => "5207") + AreaCode.create(:country => germany, :name => "Leopoldshöhe", :area_code => "5208") + AreaCode.create(:country => germany, :name => "Gütersloh-Friedrichsdorf", :area_code => "5209") + AreaCode.create(:country => germany, :name => "Bielefeld", :area_code => "521") + AreaCode.create(:country => germany, :name => "Herford", :area_code => "5221") + AreaCode.create(:country => germany, :name => "Bad Salzuflen", :area_code => "5222") + AreaCode.create(:country => germany, :name => "Bünde", :area_code => "5223") + AreaCode.create(:country => germany, :name => "Enger Westf", :area_code => "5224") + AreaCode.create(:country => germany, :name => "Spenge", :area_code => "5225") + AreaCode.create(:country => germany, :name => "Bruchmühlen Westf", :area_code => "5226") + AreaCode.create(:country => germany, :name => "Vlotho-Exter", :area_code => "5228") + AreaCode.create(:country => germany, :name => "Detmold", :area_code => "5231") + AreaCode.create(:country => germany, :name => "Lage Lippe", :area_code => "5232") + AreaCode.create(:country => germany, :name => "Steinheim Westf", :area_code => "5233") + AreaCode.create(:country => germany, :name => "Horn-Bad Meinberg", :area_code => "5234") + AreaCode.create(:country => germany, :name => "Blomberg Lippe", :area_code => "5235") + AreaCode.create(:country => germany, :name => "Blomberg-Grossenmarpe", :area_code => "5236") + AreaCode.create(:country => germany, :name => "Augustdorf", :area_code => "5237") + AreaCode.create(:country => germany, :name => "Nieheim-Himmighausen", :area_code => "5238") + AreaCode.create(:country => germany, :name => "Gütersloh", :area_code => "5241") + AreaCode.create(:country => germany, :name => "Rheda-Wiedenbrück", :area_code => "5242") + AreaCode.create(:country => germany, :name => "Rietberg", :area_code => "5244") + AreaCode.create(:country => germany, :name => "Herzebrock-Clarholz", :area_code => "5245") + AreaCode.create(:country => germany, :name => "Verl", :area_code => "5246") + AreaCode.create(:country => germany, :name => "Harsewinkel", :area_code => "5247") + AreaCode.create(:country => germany, :name => "Langenberg Kr Gütersloh", :area_code => "5248") + AreaCode.create(:country => germany, :name => "Delbrück Westf", :area_code => "5250") + AreaCode.create(:country => germany, :name => "Paderborn", :area_code => "5251") + AreaCode.create(:country => germany, :name => "Bad Lippspringe", :area_code => "5252") + AreaCode.create(:country => germany, :name => "Bad Driburg", :area_code => "5253") + AreaCode.create(:country => germany, :name => "Paderborn-Schloss Neuhaus", :area_code => "5254") + AreaCode.create(:country => germany, :name => "Altenbeken", :area_code => "5255") + AreaCode.create(:country => germany, :name => "Hövelhof", :area_code => "5257") + AreaCode.create(:country => germany, :name => "Salzkotten", :area_code => "5258") + AreaCode.create(:country => germany, :name => "Bad Driburg-Neuenheerse", :area_code => "5259") + AreaCode.create(:country => germany, :name => "Lemgo", :area_code => "5261") + AreaCode.create(:country => germany, :name => "Extertal", :area_code => "5262") + AreaCode.create(:country => germany, :name => "Barntrup", :area_code => "5263") + AreaCode.create(:country => germany, :name => "Kalletal", :area_code => "5264") + AreaCode.create(:country => germany, :name => "Dörentrup", :area_code => "5265") + AreaCode.create(:country => germany, :name => "Lemgo-Kirchheide", :area_code => "5266") + AreaCode.create(:country => germany, :name => "Höxter", :area_code => "5271") + AreaCode.create(:country => germany, :name => "Brakel Westf", :area_code => "5272") + AreaCode.create(:country => germany, :name => "Beverungen", :area_code => "5273") + AreaCode.create(:country => germany, :name => "Nieheim", :area_code => "5274") + AreaCode.create(:country => germany, :name => "Höxter-Ottbergen", :area_code => "5275") + AreaCode.create(:country => germany, :name => "Marienmünster", :area_code => "5276") + AreaCode.create(:country => germany, :name => "Höxter-Fürstenau", :area_code => "5277") + AreaCode.create(:country => germany, :name => "Höxter-Ovenhausen", :area_code => "5278") + AreaCode.create(:country => germany, :name => "Bad Pyrmont", :area_code => "5281") + AreaCode.create(:country => germany, :name => "Schieder-Schwalenberg", :area_code => "5282") + AreaCode.create(:country => germany, :name => "Lügde-Rischenau", :area_code => "5283") + AreaCode.create(:country => germany, :name => "Schwalenberg", :area_code => "5284") + AreaCode.create(:country => germany, :name => "Bad Pyrmont-Kleinenberg", :area_code => "5285") + AreaCode.create(:country => germany, :name => "Ottenstein Niedersachs", :area_code => "5286") + AreaCode.create(:country => germany, :name => "Lichtenau-Atteln", :area_code => "5292") + AreaCode.create(:country => germany, :name => "Paderborn-Dahl", :area_code => "5293") + AreaCode.create(:country => germany, :name => "Hövelhof-Espeln", :area_code => "5294") + AreaCode.create(:country => germany, :name => "Lichtenau Westf", :area_code => "5295") + AreaCode.create(:country => germany, :name => "Salzgitter-Üfingen", :area_code => "5300") + AreaCode.create(:country => germany, :name => "Lehre-Essenrode", :area_code => "5301") + AreaCode.create(:country => germany, :name => "Vechelde", :area_code => "5302") + AreaCode.create(:country => germany, :name => "Wendeburg", :area_code => "5303") + AreaCode.create(:country => germany, :name => "Meine", :area_code => "5304") + AreaCode.create(:country => germany, :name => "Sickte", :area_code => "5305") + AreaCode.create(:country => germany, :name => "Cremlingen", :area_code => "5306") + AreaCode.create(:country => germany, :name => "Braunschweig-Wenden", :area_code => "5307") + AreaCode.create(:country => germany, :name => "Lehre", :area_code => "5308") + AreaCode.create(:country => germany, :name => "Lehre-Wendhausen", :area_code => "5309") + AreaCode.create(:country => germany, :name => "Braunschweig", :area_code => "531") + AreaCode.create(:country => germany, :name => "Torfhaus", :area_code => "5320") + AreaCode.create(:country => germany, :name => "Goslar", :area_code => "5321") + AreaCode.create(:country => germany, :name => "Bad Harzburg", :area_code => "5322") + AreaCode.create(:country => germany, :name => "Clausthal-Zellerfeld", :area_code => "5323") + AreaCode.create(:country => germany, :name => "Vienenburg", :area_code => "5324") + AreaCode.create(:country => germany, :name => "Goslar-Hahnenklee", :area_code => "5325") + AreaCode.create(:country => germany, :name => "Langelsheim", :area_code => "5326") + AreaCode.create(:country => germany, :name => "Bad Grund Harz", :area_code => "5327") + AreaCode.create(:country => germany, :name => "Altenau Harz", :area_code => "5328") + AreaCode.create(:country => germany, :name => "Schulenberg im Oberharz", :area_code => "5329") + AreaCode.create(:country => germany, :name => "Wolfenbüttel", :area_code => "5331") + AreaCode.create(:country => germany, :name => "Schöppenstedt", :area_code => "5332") + AreaCode.create(:country => germany, :name => "Dettum", :area_code => "5333") + AreaCode.create(:country => germany, :name => "Hornburg Kr Wolfenbüttel", :area_code => "5334") + AreaCode.create(:country => germany, :name => "Schladen", :area_code => "5335") + AreaCode.create(:country => germany, :name => "Semmenstedt", :area_code => "5336") + AreaCode.create(:country => germany, :name => "Kissenbrück", :area_code => "5337") + AreaCode.create(:country => germany, :name => "Gielde", :area_code => "5339") + AreaCode.create(:country => germany, :name => "Salzgitter", :area_code => "5341") + AreaCode.create(:country => germany, :name => "Lengede", :area_code => "5344") + AreaCode.create(:country => germany, :name => "Baddeckenstedt", :area_code => "5345") + AreaCode.create(:country => germany, :name => "Liebenburg", :area_code => "5346") + AreaCode.create(:country => germany, :name => "Burgdorf b Salzgitter", :area_code => "5347") + AreaCode.create(:country => germany, :name => "Helmstedt", :area_code => "5351") + AreaCode.create(:country => germany, :name => "Schöningen", :area_code => "5352") + AreaCode.create(:country => germany, :name => "Königslutter am Elm", :area_code => "5353") + AreaCode.create(:country => germany, :name => "Jerxheim", :area_code => "5354") + AreaCode.create(:country => germany, :name => "Frellstedt", :area_code => "5355") + AreaCode.create(:country => germany, :name => "Helmstedt-Barmke", :area_code => "5356") + AreaCode.create(:country => germany, :name => "Grasleben", :area_code => "5357") + AreaCode.create(:country => germany, :name => "Bahrdorf-Mackendorf", :area_code => "5358") + AreaCode.create(:country => germany, :name => "Wolfsburg", :area_code => "5361") + AreaCode.create(:country => germany, :name => "Wolfsburg-Fallersleben", :area_code => "5362") + AreaCode.create(:country => germany, :name => "Wolfsburg-Vorsfelde", :area_code => "5363") + AreaCode.create(:country => germany, :name => "Velpke", :area_code => "5364") + AreaCode.create(:country => germany, :name => "Wolfsburg-Neindorf", :area_code => "5365") + AreaCode.create(:country => germany, :name => "Jembke", :area_code => "5366") + AreaCode.create(:country => germany, :name => "Rühen", :area_code => "5367") + AreaCode.create(:country => germany, :name => "Parsau", :area_code => "5368") + AreaCode.create(:country => germany, :name => "Gifhorn", :area_code => "5371") + AreaCode.create(:country => germany, :name => "Meinersen", :area_code => "5372") + AreaCode.create(:country => germany, :name => "Hillerse Kr Gifhorn", :area_code => "5373") + AreaCode.create(:country => germany, :name => "Isenbüttel", :area_code => "5374") + AreaCode.create(:country => germany, :name => "Müden Aller", :area_code => "5375") + AreaCode.create(:country => germany, :name => "Wesendorf Kr Gifhorn", :area_code => "5376") + AreaCode.create(:country => germany, :name => "Ehra-Lessien", :area_code => "5377") + AreaCode.create(:country => germany, :name => "Sassenburg-Platendorf", :area_code => "5378") + AreaCode.create(:country => germany, :name => "Sassenburg-Grussendorf", :area_code => "5379") + AreaCode.create(:country => germany, :name => "Seesen", :area_code => "5381") + AreaCode.create(:country => germany, :name => "Bad Gandersheim", :area_code => "5382") + AreaCode.create(:country => germany, :name => "Lutter am Barenberge", :area_code => "5383") + AreaCode.create(:country => germany, :name => "Seesen-Groß Rhüden", :area_code => "5384") + AreaCode.create(:country => germany, :name => "Georgsmarienhütte", :area_code => "5401") + AreaCode.create(:country => germany, :name => "Bissendorf Kr Osnabrück", :area_code => "5402") + AreaCode.create(:country => germany, :name => "Bad Iburg", :area_code => "5403") + AreaCode.create(:country => germany, :name => "Westerkappeln", :area_code => "5404") + AreaCode.create(:country => germany, :name => "Hasbergen Kr Osnabrück", :area_code => "5405") + AreaCode.create(:country => germany, :name => "Belm", :area_code => "5406") + AreaCode.create(:country => germany, :name => "Wallenhorst", :area_code => "5407") + AreaCode.create(:country => germany, :name => "Hilter am Teutoburger Wald", :area_code => "5409") + AreaCode.create(:country => germany, :name => "Osnabrück", :area_code => "541") + AreaCode.create(:country => germany, :name => "Dissen am Teutoburger Wald", :area_code => "5421") + AreaCode.create(:country => germany, :name => "Melle", :area_code => "5422") + AreaCode.create(:country => germany, :name => "Versmold", :area_code => "5423") + AreaCode.create(:country => germany, :name => "Bad Rothenfelde", :area_code => "5424") + AreaCode.create(:country => germany, :name => "Borgholzhausen", :area_code => "5425") + AreaCode.create(:country => germany, :name => "Glandorf", :area_code => "5426") + AreaCode.create(:country => germany, :name => "Melle-Buer", :area_code => "5427") + AreaCode.create(:country => germany, :name => "Melle-Neuenkirchen", :area_code => "5428") + AreaCode.create(:country => germany, :name => "Melle-Wellingholzhausen", :area_code => "5429") + AreaCode.create(:country => germany, :name => "Quakenbrück", :area_code => "5431") + AreaCode.create(:country => germany, :name => "Löningen", :area_code => "5432") + AreaCode.create(:country => germany, :name => "Badbergen", :area_code => "5433") + AreaCode.create(:country => germany, :name => "Essen Oldenburg", :area_code => "5434") + AreaCode.create(:country => germany, :name => "Berge b Quakenbrück", :area_code => "5435") + AreaCode.create(:country => germany, :name => "Nortrup", :area_code => "5436") + AreaCode.create(:country => germany, :name => "Menslage", :area_code => "5437") + AreaCode.create(:country => germany, :name => "Bakum-Lüsche", :area_code => "5438") + AreaCode.create(:country => germany, :name => "Bersenbrück", :area_code => "5439") + AreaCode.create(:country => germany, :name => "Diepholz", :area_code => "5441") + AreaCode.create(:country => germany, :name => "Barnstorf Kr Diepholz", :area_code => "5442") + AreaCode.create(:country => germany, :name => "Lemförde", :area_code => "5443") + AreaCode.create(:country => germany, :name => "Wagenfeld", :area_code => "5444") + AreaCode.create(:country => germany, :name => "Drebber", :area_code => "5445") + AreaCode.create(:country => germany, :name => "Rehden", :area_code => "5446") + AreaCode.create(:country => germany, :name => "Lembruch", :area_code => "5447") + AreaCode.create(:country => germany, :name => "Barver", :area_code => "5448") + AreaCode.create(:country => germany, :name => "Ibbenbüren", :area_code => "5451") + AreaCode.create(:country => germany, :name => "Mettingen Westf", :area_code => "5452") + AreaCode.create(:country => germany, :name => "Recke", :area_code => "5453") + AreaCode.create(:country => germany, :name => "Hörstel-Riesenbeck", :area_code => "5454") + AreaCode.create(:country => germany, :name => "Tecklenburg-Brochterbeck", :area_code => "5455") + AreaCode.create(:country => germany, :name => "Westerkappeln-Velpe", :area_code => "5456") + AreaCode.create(:country => germany, :name => "Hopsten-Schale", :area_code => "5457") + AreaCode.create(:country => germany, :name => "Hopsten", :area_code => "5458") + AreaCode.create(:country => germany, :name => "Hörstel", :area_code => "5459") + AreaCode.create(:country => germany, :name => "Bramsche Hase", :area_code => "5461") + AreaCode.create(:country => germany, :name => "Ankum", :area_code => "5462") + AreaCode.create(:country => germany, :name => "Alfhausen", :area_code => "5464") + AreaCode.create(:country => germany, :name => "Neuenkirchen b Bramsche", :area_code => "5465") + AreaCode.create(:country => germany, :name => "Merzen", :area_code => "5466") + AreaCode.create(:country => germany, :name => "Voltlage", :area_code => "5467") + AreaCode.create(:country => germany, :name => "Bramsche-Engter", :area_code => "5468") + AreaCode.create(:country => germany, :name => "Bohmte", :area_code => "5471") + AreaCode.create(:country => germany, :name => "Bad Essen", :area_code => "5472") + AreaCode.create(:country => germany, :name => "Ostercappeln", :area_code => "5473") + AreaCode.create(:country => germany, :name => "Stemwede-Dielingen", :area_code => "5474") + AreaCode.create(:country => germany, :name => "Bohmte-Hunteburg", :area_code => "5475") + AreaCode.create(:country => germany, :name => "Ostercappeln-Venne", :area_code => "5476") + AreaCode.create(:country => germany, :name => "Lengerich Westf", :area_code => "5481") + AreaCode.create(:country => germany, :name => "Tecklenburg", :area_code => "5482") + AreaCode.create(:country => germany, :name => "Lienen", :area_code => "5483") + AreaCode.create(:country => germany, :name => "Lienen-Kattenvenne", :area_code => "5484") + AreaCode.create(:country => germany, :name => "Ladbergen", :area_code => "5485") + AreaCode.create(:country => germany, :name => "Damme Dümmer", :area_code => "5491") + AreaCode.create(:country => germany, :name => "Steinfeld Oldenburg", :area_code => "5492") + AreaCode.create(:country => germany, :name => "Neuenkirchen Kr Vechta", :area_code => "5493") + AreaCode.create(:country => germany, :name => "Holdorf Niedersachs", :area_code => "5494") + AreaCode.create(:country => germany, :name => "Vörden Kr Vechta", :area_code => "5495") + AreaCode.create(:country => germany, :name => "Dransfeld", :area_code => "5502") + AreaCode.create(:country => germany, :name => "Nörten-Hardenberg", :area_code => "5503") + AreaCode.create(:country => germany, :name => "Friedland Kr Göttingen", :area_code => "5504") + AreaCode.create(:country => germany, :name => "Hardegsen", :area_code => "5505") + AreaCode.create(:country => germany, :name => "Adelebsen", :area_code => "5506") + AreaCode.create(:country => germany, :name => "Ebergötzen", :area_code => "5507") + AreaCode.create(:country => germany, :name => "Gleichen-Rittmarshausen", :area_code => "5508") + AreaCode.create(:country => germany, :name => "Rosdorf Kr Göttingen", :area_code => "5509") + AreaCode.create(:country => germany, :name => "Göttingen", :area_code => "551") + AreaCode.create(:country => germany, :name => "Braunlage", :area_code => "5520") + AreaCode.create(:country => germany, :name => "Herzberg am Harz", :area_code => "5521") + AreaCode.create(:country => germany, :name => "Osterode am Harz", :area_code => "5522") + AreaCode.create(:country => germany, :name => "Bad Sachsa", :area_code => "5523") + AreaCode.create(:country => germany, :name => "Bad Lauterberg im Harz", :area_code => "5524") + AreaCode.create(:country => germany, :name => "Walkenried", :area_code => "5525") + AreaCode.create(:country => germany, :name => "Duderstadt", :area_code => "5527") + AreaCode.create(:country => germany, :name => "Gieboldehausen", :area_code => "5528") + AreaCode.create(:country => germany, :name => "Rhumspringe", :area_code => "5529") + AreaCode.create(:country => germany, :name => "Holzminden", :area_code => "5531") + AreaCode.create(:country => germany, :name => "Stadtoldendorf", :area_code => "5532") + AreaCode.create(:country => germany, :name => "Bodenwerder", :area_code => "5533") + AreaCode.create(:country => germany, :name => "Eschershausen a d Lenne", :area_code => "5534") + AreaCode.create(:country => germany, :name => "Polle", :area_code => "5535") + AreaCode.create(:country => germany, :name => "Holzminden-Neuhaus", :area_code => "5536") + AreaCode.create(:country => germany, :name => "Hann. Münden", :area_code => "5541") + AreaCode.create(:country => germany, :name => "Witzenhausen", :area_code => "5542") + AreaCode.create(:country => germany, :name => "Staufenberg Niedersachs", :area_code => "5543") + AreaCode.create(:country => germany, :name => "Reinhardshagen", :area_code => "5544") + AreaCode.create(:country => germany, :name => "Hedemünden", :area_code => "5545") + AreaCode.create(:country => germany, :name => "Scheden", :area_code => "5546") + AreaCode.create(:country => germany, :name => "Northeim", :area_code => "5551") + AreaCode.create(:country => germany, :name => "Katlenburg", :area_code => "5552") + AreaCode.create(:country => germany, :name => "Kalefeld", :area_code => "5553") + AreaCode.create(:country => germany, :name => "Moringen", :area_code => "5554") + AreaCode.create(:country => germany, :name => "Moringen-Fredelsloh", :area_code => "5555") + AreaCode.create(:country => germany, :name => "Lindau Harz", :area_code => "5556") + AreaCode.create(:country => germany, :name => "Einbeck", :area_code => "5561") + AreaCode.create(:country => germany, :name => "Dassel-Markoldendorf", :area_code => "5562") + AreaCode.create(:country => germany, :name => "Kreiensen", :area_code => "5563") + AreaCode.create(:country => germany, :name => "Dassel", :area_code => "5564") + AreaCode.create(:country => germany, :name => "Einbeck-Wenzen", :area_code => "5565") + AreaCode.create(:country => germany, :name => "Uslar", :area_code => "5571") + AreaCode.create(:country => germany, :name => "Bodenfelde", :area_code => "5572") + AreaCode.create(:country => germany, :name => "Uslar-Volpriehausen", :area_code => "5573") + AreaCode.create(:country => germany, :name => "Oberweser", :area_code => "5574") + AreaCode.create(:country => germany, :name => "Sankt Andreasberg", :area_code => "5582") + AreaCode.create(:country => germany, :name => "Braunlage-Hohegeiss", :area_code => "5583") + AreaCode.create(:country => germany, :name => "Hattorf am Harz", :area_code => "5584") + AreaCode.create(:country => germany, :name => "Herzberg-Sieber", :area_code => "5585") + AreaCode.create(:country => germany, :name => "Wieda", :area_code => "5586") + AreaCode.create(:country => germany, :name => "Gleichen-Bremke", :area_code => "5592") + AreaCode.create(:country => germany, :name => "Bovenden-Lenglern", :area_code => "5593") + AreaCode.create(:country => germany, :name => "Bovenden-Reyershausen", :area_code => "5594") + AreaCode.create(:country => germany, :name => "Schauenburg", :area_code => "5601") + AreaCode.create(:country => germany, :name => "Hessisch Lichtenau", :area_code => "5602") + AreaCode.create(:country => germany, :name => "Gudensberg", :area_code => "5603") + AreaCode.create(:country => germany, :name => "Grossalmerode", :area_code => "5604") + AreaCode.create(:country => germany, :name => "Kaufungen Hess", :area_code => "5605") + AreaCode.create(:country => germany, :name => "Zierenberg", :area_code => "5606") + AreaCode.create(:country => germany, :name => "Fuldatal", :area_code => "5607") + AreaCode.create(:country => germany, :name => "Söhrewald", :area_code => "5608") + AreaCode.create(:country => germany, :name => "Ahnatal", :area_code => "5609") + AreaCode.create(:country => germany, :name => "Kassel", :area_code => "561") + AreaCode.create(:country => germany, :name => "Bad Wildungen", :area_code => "5621") + AreaCode.create(:country => germany, :name => "Fritzlar", :area_code => "5622") + AreaCode.create(:country => germany, :name => "Edertal", :area_code => "5623") + AreaCode.create(:country => germany, :name => "Bad Emstal", :area_code => "5624") + AreaCode.create(:country => germany, :name => "Naumburg Hess", :area_code => "5625") + AreaCode.create(:country => germany, :name => "Bad Zwesten", :area_code => "5626") + AreaCode.create(:country => germany, :name => "Korbach", :area_code => "5631") + AreaCode.create(:country => germany, :name => "Willingen Upland", :area_code => "5632") + AreaCode.create(:country => germany, :name => "Diemelsee", :area_code => "5633") + AreaCode.create(:country => germany, :name => "Waldeck-Sachsenhausen", :area_code => "5634") + AreaCode.create(:country => germany, :name => "Vöhl", :area_code => "5635") + AreaCode.create(:country => germany, :name => "Lichtenfels-Goddelsheim", :area_code => "5636") + AreaCode.create(:country => germany, :name => "Warburg", :area_code => "5641") + AreaCode.create(:country => germany, :name => "Warburg-Scherfede", :area_code => "5642") + AreaCode.create(:country => germany, :name => "Borgentreich", :area_code => "5643") + AreaCode.create(:country => germany, :name => "Willebadessen-Peckelsheim", :area_code => "5644") + AreaCode.create(:country => germany, :name => "Borgentreich-Borgholz", :area_code => "5645") + AreaCode.create(:country => germany, :name => "Willebadessen", :area_code => "5646") + AreaCode.create(:country => germany, :name => "Lichtenau-Kleinenberg", :area_code => "5647") + AreaCode.create(:country => germany, :name => "Brakel-Gehrden", :area_code => "5648") + AreaCode.create(:country => germany, :name => "Cornberg", :area_code => "5650") + AreaCode.create(:country => germany, :name => "Eschwege", :area_code => "5651") + AreaCode.create(:country => germany, :name => "Bad Sooden-Allendorf", :area_code => "5652") + AreaCode.create(:country => germany, :name => "Sontra", :area_code => "5653") + AreaCode.create(:country => germany, :name => "Herleshausen", :area_code => "5654") + AreaCode.create(:country => germany, :name => "Wanfried", :area_code => "5655") + AreaCode.create(:country => germany, :name => "Waldkappel", :area_code => "5656") + AreaCode.create(:country => germany, :name => "Meissner", :area_code => "5657") + AreaCode.create(:country => germany, :name => "Wehretal", :area_code => "5658") + AreaCode.create(:country => germany, :name => "Ringgau", :area_code => "5659") + AreaCode.create(:country => germany, :name => "Melsungen", :area_code => "5661") + AreaCode.create(:country => germany, :name => "Felsberg Hess", :area_code => "5662") + AreaCode.create(:country => germany, :name => "Spangenberg", :area_code => "5663") + AreaCode.create(:country => germany, :name => "Morschen", :area_code => "5664") + AreaCode.create(:country => germany, :name => "Guxhagen", :area_code => "5665") + AreaCode.create(:country => germany, :name => "Hofgeismar", :area_code => "5671") + AreaCode.create(:country => germany, :name => "Bad Karlshafen", :area_code => "5672") + AreaCode.create(:country => germany, :name => "Immenhausen Hess", :area_code => "5673") + AreaCode.create(:country => germany, :name => "Grebenstein", :area_code => "5674") + AreaCode.create(:country => germany, :name => "Trendelburg", :area_code => "5675") + AreaCode.create(:country => germany, :name => "Liebenau Hess", :area_code => "5676") + AreaCode.create(:country => germany, :name => "Calden-Westuffeln", :area_code => "5677") + AreaCode.create(:country => germany, :name => "Homberg Efze", :area_code => "5681") + AreaCode.create(:country => germany, :name => "Borken Hessen", :area_code => "5682") + AreaCode.create(:country => germany, :name => "Wabern Hess", :area_code => "5683") + AreaCode.create(:country => germany, :name => "Frielendorf", :area_code => "5684") + AreaCode.create(:country => germany, :name => "Knüllwald", :area_code => "5685") + AreaCode.create(:country => germany, :name => "Schwarzenborn Knüll", :area_code => "5686") + AreaCode.create(:country => germany, :name => "Bad Arolsen", :area_code => "5691") + AreaCode.create(:country => germany, :name => "Wolfhagen", :area_code => "5692") + AreaCode.create(:country => germany, :name => "Volkmarsen", :area_code => "5693") + AreaCode.create(:country => germany, :name => "Diemelstadt", :area_code => "5694") + AreaCode.create(:country => germany, :name => "Twistetal", :area_code => "5695") + AreaCode.create(:country => germany, :name => "Bad Arolsen-Landau", :area_code => "5696") + AreaCode.create(:country => germany, :name => "Petershagen-Lahde", :area_code => "5702") + AreaCode.create(:country => germany, :name => "Hille", :area_code => "5703") + AreaCode.create(:country => germany, :name => "Petershagen-Friedewalde", :area_code => "5704") + AreaCode.create(:country => germany, :name => "Petershagen-Windheim", :area_code => "5705") + AreaCode.create(:country => germany, :name => "Porta Westfalica", :area_code => "5706") + AreaCode.create(:country => germany, :name => "Petershagen Weser", :area_code => "5707") + AreaCode.create(:country => germany, :name => "Minden Westf", :area_code => "571") + AreaCode.create(:country => germany, :name => "Stadthagen", :area_code => "5721") + AreaCode.create(:country => germany, :name => "Bückeburg", :area_code => "5722") + AreaCode.create(:country => germany, :name => "Bad Nenndorf", :area_code => "5723") + AreaCode.create(:country => germany, :name => "Obernkirchen", :area_code => "5724") + AreaCode.create(:country => germany, :name => "Lindhorst b Stadthagen", :area_code => "5725") + AreaCode.create(:country => germany, :name => "Wiedensahl", :area_code => "5726") + AreaCode.create(:country => germany, :name => "Bad Oeynhausen", :area_code => "5731") + AreaCode.create(:country => germany, :name => "Löhne", :area_code => "5732") + AreaCode.create(:country => germany, :name => "Vlotho", :area_code => "5733") + AreaCode.create(:country => germany, :name => "Bergkirchen Westf", :area_code => "5734") + AreaCode.create(:country => germany, :name => "Lübbecke", :area_code => "5741") + AreaCode.create(:country => germany, :name => "Preussisch Oldendorf", :area_code => "5742") + AreaCode.create(:country => germany, :name => "Espelkamp-Gestringen", :area_code => "5743") + AreaCode.create(:country => germany, :name => "Hüllhorst", :area_code => "5744") + AreaCode.create(:country => germany, :name => "Stemwede-Levern", :area_code => "5745") + AreaCode.create(:country => germany, :name => "Rödinghausen", :area_code => "5746") + AreaCode.create(:country => germany, :name => "Rinteln", :area_code => "5751") + AreaCode.create(:country => germany, :name => "Auetal-Hattendorf", :area_code => "5752") + AreaCode.create(:country => germany, :name => "Auetal-Bernsen", :area_code => "5753") + AreaCode.create(:country => germany, :name => "Extertal-Bremke", :area_code => "5754") + AreaCode.create(:country => germany, :name => "Kalletal-Varenholz", :area_code => "5755") + AreaCode.create(:country => germany, :name => "Stolzenau", :area_code => "5761") + AreaCode.create(:country => germany, :name => "Uchte", :area_code => "5763") + AreaCode.create(:country => germany, :name => "Steyerberg", :area_code => "5764") + AreaCode.create(:country => germany, :name => "Raddestorf", :area_code => "5765") + AreaCode.create(:country => germany, :name => "Rehburg-Loccum", :area_code => "5766") + AreaCode.create(:country => germany, :name => "Warmsen", :area_code => "5767") + AreaCode.create(:country => germany, :name => "Petershagen-Heimsen", :area_code => "5768") + AreaCode.create(:country => germany, :name => "Steyerberg-Voigtei", :area_code => "5769") + AreaCode.create(:country => germany, :name => "Rahden Westf", :area_code => "5771") + AreaCode.create(:country => germany, :name => "Espelkamp", :area_code => "5772") + AreaCode.create(:country => germany, :name => "Stemwede-Wehdem", :area_code => "5773") + AreaCode.create(:country => germany, :name => "Wagenfeld-Ströhen", :area_code => "5774") + AreaCode.create(:country => germany, :name => "Diepenau", :area_code => "5775") + AreaCode.create(:country => germany, :name => "Preussisch Ströhen", :area_code => "5776") + AreaCode.create(:country => germany, :name => "Diepenau-Essern", :area_code => "5777") + AreaCode.create(:country => germany, :name => "Wrestedt", :area_code => "5802") + AreaCode.create(:country => germany, :name => "Rosche", :area_code => "5803") + AreaCode.create(:country => germany, :name => "Rätzlingen Kr Uelzen", :area_code => "5804") + AreaCode.create(:country => germany, :name => "Oetzen", :area_code => "5805") + AreaCode.create(:country => germany, :name => "Barum b Bad Bevensen", :area_code => "5806") + AreaCode.create(:country => germany, :name => "Altenmedingen", :area_code => "5807") + AreaCode.create(:country => germany, :name => "Gerdau", :area_code => "5808") + AreaCode.create(:country => germany, :name => "Uelzen", :area_code => "581") + AreaCode.create(:country => germany, :name => "Suhlendorf", :area_code => "5820") + AreaCode.create(:country => germany, :name => "Bad Bevensen", :area_code => "5821") + AreaCode.create(:country => germany, :name => "Ebstorf", :area_code => "5822") + AreaCode.create(:country => germany, :name => "Bienenbüttel", :area_code => "5823") + AreaCode.create(:country => germany, :name => "Bad Bodenteich", :area_code => "5824") + AreaCode.create(:country => germany, :name => "Wieren", :area_code => "5825") + AreaCode.create(:country => germany, :name => "Suderburg", :area_code => "5826") + AreaCode.create(:country => germany, :name => "Unterlüß", :area_code => "5827") + AreaCode.create(:country => germany, :name => "Himbergen", :area_code => "5828") + AreaCode.create(:country => germany, :name => "Wriedel", :area_code => "5829") + AreaCode.create(:country => germany, :name => "Wittingen", :area_code => "5831") + AreaCode.create(:country => germany, :name => "Hankensbüttel", :area_code => "5832") + AreaCode.create(:country => germany, :name => "Brome", :area_code => "5833") + AreaCode.create(:country => germany, :name => "Wittingen-Knesebeck", :area_code => "5834") + AreaCode.create(:country => germany, :name => "Wahrenholz", :area_code => "5835") + AreaCode.create(:country => germany, :name => "Wittingen-Radenbeck", :area_code => "5836") + AreaCode.create(:country => germany, :name => "Sprakensehl", :area_code => "5837") + AreaCode.create(:country => germany, :name => "Gross Oesingen", :area_code => "5838") + AreaCode.create(:country => germany, :name => "Wittingen-Ohrdorf", :area_code => "5839") + AreaCode.create(:country => germany, :name => "Schnackenburg", :area_code => "5840") + AreaCode.create(:country => germany, :name => "Lüchow Wendland", :area_code => "5841") + AreaCode.create(:country => germany, :name => "Schnega", :area_code => "5842") + AreaCode.create(:country => germany, :name => "Wustrow", :area_code => "5843") + AreaCode.create(:country => germany, :name => "Clenze", :area_code => "5844") + AreaCode.create(:country => germany, :name => "Bergen Dumme", :area_code => "5845") + AreaCode.create(:country => germany, :name => "Gartow Niedersachs", :area_code => "5846") + AreaCode.create(:country => germany, :name => "Trebel", :area_code => "5848") + AreaCode.create(:country => germany, :name => "Waddeweitz", :area_code => "5849") + AreaCode.create(:country => germany, :name => "Neetze", :area_code => "5850") + AreaCode.create(:country => germany, :name => "Dahlenburg", :area_code => "5851") + AreaCode.create(:country => germany, :name => "Bleckede", :area_code => "5852") + AreaCode.create(:country => germany, :name => "Neu Darchau", :area_code => "5853") + AreaCode.create(:country => germany, :name => "Bleckede-Barskamp", :area_code => "5854") + AreaCode.create(:country => germany, :name => "Nahrendorf", :area_code => "5855") + AreaCode.create(:country => germany, :name => "Bleckede-Brackede", :area_code => "5857") + AreaCode.create(:country => germany, :name => "Hitzacker-Wietzetze", :area_code => "5858") + AreaCode.create(:country => germany, :name => "Thomasburg", :area_code => "5859") + AreaCode.create(:country => germany, :name => "Dannenberg Elbe", :area_code => "5861") + AreaCode.create(:country => germany, :name => "Hitzacker Elbe", :area_code => "5862") + AreaCode.create(:country => germany, :name => "Zernien", :area_code => "5863") + AreaCode.create(:country => germany, :name => "Jameln", :area_code => "5864") + AreaCode.create(:country => germany, :name => "Gusborn", :area_code => "5865") + AreaCode.create(:country => germany, :name => "Stoetze", :area_code => "5872") + AreaCode.create(:country => germany, :name => "Eimke", :area_code => "5873") + AreaCode.create(:country => germany, :name => "Soltendieck", :area_code => "5874") + AreaCode.create(:country => germany, :name => "Emmendorf", :area_code => "5875") + AreaCode.create(:country => germany, :name => "Gorleben", :area_code => "5882") + AreaCode.create(:country => germany, :name => "Lemgow", :area_code => "5883") + AreaCode.create(:country => germany, :name => "Fürstenau b Bramsche", :area_code => "5901") + AreaCode.create(:country => germany, :name => "Freren", :area_code => "5902") + AreaCode.create(:country => germany, :name => "Emsbüren", :area_code => "5903") + AreaCode.create(:country => germany, :name => "Lengerich Emsl", :area_code => "5904") + AreaCode.create(:country => germany, :name => "Beesten", :area_code => "5905") + AreaCode.create(:country => germany, :name => "Lünne", :area_code => "5906") + AreaCode.create(:country => germany, :name => "Geeste", :area_code => "5907") + AreaCode.create(:country => germany, :name => "Wietmarschen-Lohne", :area_code => "5908") + AreaCode.create(:country => germany, :name => "Wettrup", :area_code => "5909") + AreaCode.create(:country => germany, :name => "Lingen (Ems)", :area_code => "591") + AreaCode.create(:country => germany, :name => "Nordhorn", :area_code => "5921") + AreaCode.create(:country => germany, :name => "Bad Bentheim", :area_code => "5922") + AreaCode.create(:country => germany, :name => "Schüttorf", :area_code => "5923") + AreaCode.create(:country => germany, :name => "Bad Bentheim-Gildehaus", :area_code => "5924") + AreaCode.create(:country => germany, :name => "Wietmarschen", :area_code => "5925") + AreaCode.create(:country => germany, :name => "Engden", :area_code => "5926") + AreaCode.create(:country => germany, :name => "Meppen", :area_code => "5931") + AreaCode.create(:country => germany, :name => "Haren Ems", :area_code => "5932") + AreaCode.create(:country => germany, :name => "Lathen", :area_code => "5933") + AreaCode.create(:country => germany, :name => "Haren-Rütenbrock", :area_code => "5934") + AreaCode.create(:country => germany, :name => "Twist-Schöninghsdorf", :area_code => "5935") + AreaCode.create(:country => germany, :name => "Twist", :area_code => "5936") + AreaCode.create(:country => germany, :name => "Geeste-Gross Hesepe", :area_code => "5937") + AreaCode.create(:country => germany, :name => "Sustrum", :area_code => "5939") + AreaCode.create(:country => germany, :name => "Neuenhaus Dinkel", :area_code => "5941") + AreaCode.create(:country => germany, :name => "Uelsen", :area_code => "5942") + AreaCode.create(:country => germany, :name => "Emlichheim", :area_code => "5943") + AreaCode.create(:country => germany, :name => "Hoogstede", :area_code => "5944") + AreaCode.create(:country => germany, :name => "Wilsum", :area_code => "5945") + AreaCode.create(:country => germany, :name => "Georgsdorf", :area_code => "5946") + AreaCode.create(:country => germany, :name => "Laar Vechte", :area_code => "5947") + AreaCode.create(:country => germany, :name => "Itterbeck", :area_code => "5948") + AreaCode.create(:country => germany, :name => "Werlte", :area_code => "5951") + AreaCode.create(:country => germany, :name => "Sögel", :area_code => "5952") + AreaCode.create(:country => germany, :name => "Börger", :area_code => "5953") + AreaCode.create(:country => germany, :name => "Lorup", :area_code => "5954") + AreaCode.create(:country => germany, :name => "Esterwegen", :area_code => "5955") + AreaCode.create(:country => germany, :name => "Rastdorf", :area_code => "5956") + AreaCode.create(:country => germany, :name => "Lindern Oldenburg", :area_code => "5957") + AreaCode.create(:country => germany, :name => "Haselünne", :area_code => "5961") + AreaCode.create(:country => germany, :name => "Herzlake", :area_code => "5962") + AreaCode.create(:country => germany, :name => "Bawinkel", :area_code => "5963") + AreaCode.create(:country => germany, :name => "Lähden", :area_code => "5964") + AreaCode.create(:country => germany, :name => "Klein Berssen", :area_code => "5965") + AreaCode.create(:country => germany, :name => "Meppen-Apeldorn", :area_code => "5966") + AreaCode.create(:country => germany, :name => "Rheine", :area_code => "5971") + AreaCode.create(:country => germany, :name => "Neuenkirchen Kr Steinfurt", :area_code => "5973") + AreaCode.create(:country => germany, :name => "Rheine-Mesum", :area_code => "5975") + AreaCode.create(:country => germany, :name => "Salzbergen", :area_code => "5976") + AreaCode.create(:country => germany, :name => "Spelle", :area_code => "5977") + AreaCode.create(:country => germany, :name => "Hörstel-Dreierwalde", :area_code => "5978") + AreaCode.create(:country => germany, :name => "Ober-Mörlen", :area_code => "6002") + AreaCode.create(:country => germany, :name => "Rosbach v d Höhe", :area_code => "6003") + AreaCode.create(:country => germany, :name => "Lich-Eberstadt", :area_code => "6004") + AreaCode.create(:country => germany, :name => "Rosbach-Rodheim", :area_code => "6007") + AreaCode.create(:country => germany, :name => "Echzell", :area_code => "6008") + AreaCode.create(:country => germany, :name => "Heigenbrücken", :area_code => "6020") + AreaCode.create(:country => germany, :name => "Aschaffenburg", :area_code => "6021") + AreaCode.create(:country => germany, :name => "Obernburg a Main", :area_code => "6022") + AreaCode.create(:country => germany, :name => "Alzenau i Ufr", :area_code => "6023") + AreaCode.create(:country => germany, :name => "Schöllkrippen", :area_code => "6024") + AreaCode.create(:country => germany, :name => "Grossostheim", :area_code => "6026") + AreaCode.create(:country => germany, :name => "Stockstadt a Main", :area_code => "6027") + AreaCode.create(:country => germany, :name => "Sulzbach a Main", :area_code => "6028") + AreaCode.create(:country => germany, :name => "Mömbris", :area_code => "6029") + AreaCode.create(:country => germany, :name => "Friedberg Hess", :area_code => "6031") + AreaCode.create(:country => germany, :name => "Bad Nauheim", :area_code => "6032") + AreaCode.create(:country => germany, :name => "Butzbach", :area_code => "6033") + AreaCode.create(:country => germany, :name => "Wöllstadt", :area_code => "6034") + AreaCode.create(:country => germany, :name => "Reichelsheim Wetterau", :area_code => "6035") + AreaCode.create(:country => germany, :name => "Wölfersheim", :area_code => "6036") + AreaCode.create(:country => germany, :name => "Karben", :area_code => "6039") + AreaCode.create(:country => germany, :name => "Glauburg", :area_code => "6041") + AreaCode.create(:country => germany, :name => "Büdingen Hess", :area_code => "6042") + AreaCode.create(:country => germany, :name => "Nidda", :area_code => "6043") + AreaCode.create(:country => germany, :name => "Schotten Hess", :area_code => "6044") + AreaCode.create(:country => germany, :name => "Gedern", :area_code => "6045") + AreaCode.create(:country => germany, :name => "Ortenberg Hess", :area_code => "6046") + AreaCode.create(:country => germany, :name => "Altenstadt Hess", :area_code => "6047") + AreaCode.create(:country => germany, :name => "Büdingen-Eckartshausen", :area_code => "6048") + AreaCode.create(:country => germany, :name => "Kefenrod", :area_code => "6049") + AreaCode.create(:country => germany, :name => "Biebergemünd", :area_code => "6050") + AreaCode.create(:country => germany, :name => "Gelnhausen", :area_code => "6051") + AreaCode.create(:country => germany, :name => "Bad Orb", :area_code => "6052") + AreaCode.create(:country => germany, :name => "Wächtersbach", :area_code => "6053") + AreaCode.create(:country => germany, :name => "Birstein", :area_code => "6054") + AreaCode.create(:country => germany, :name => "Freigericht", :area_code => "6055") + AreaCode.create(:country => germany, :name => "Bad Soden-Salmünster", :area_code => "6056") + AreaCode.create(:country => germany, :name => "Flörsbachtal", :area_code => "6057") + AreaCode.create(:country => germany, :name => "Gründau", :area_code => "6058") + AreaCode.create(:country => germany, :name => "Jossgrund", :area_code => "6059") + AreaCode.create(:country => germany, :name => "Michelstadt", :area_code => "6061") + AreaCode.create(:country => germany, :name => "Erbach Odenw", :area_code => "6062") + AreaCode.create(:country => germany, :name => "Bad König", :area_code => "6063") + AreaCode.create(:country => germany, :name => "Michelstadt-Vielbrunn", :area_code => "6066") + AreaCode.create(:country => germany, :name => "Beerfelden", :area_code => "6068") + AreaCode.create(:country => germany, :name => "Dieburg", :area_code => "6071") + AreaCode.create(:country => germany, :name => "Babenhausen Hess", :area_code => "6073") + AreaCode.create(:country => germany, :name => "Rödermark", :area_code => "6074") + AreaCode.create(:country => germany, :name => "Gross-Umstadt", :area_code => "6078") + AreaCode.create(:country => germany, :name => "Usingen", :area_code => "6081") + AreaCode.create(:country => germany, :name => "Niederreifenberg", :area_code => "6082") + AreaCode.create(:country => germany, :name => "Weilrod", :area_code => "6083") + AreaCode.create(:country => germany, :name => "Schmitten Taunus", :area_code => "6084") + AreaCode.create(:country => germany, :name => "Waldsolms", :area_code => "6085") + AreaCode.create(:country => germany, :name => "Grävenwiesbach", :area_code => "6086") + AreaCode.create(:country => germany, :name => "Waldems", :area_code => "6087") + AreaCode.create(:country => germany, :name => "Heimbuchenthal", :area_code => "6092") + AreaCode.create(:country => germany, :name => "Laufach", :area_code => "6093") + AreaCode.create(:country => germany, :name => "Weibersbrunn", :area_code => "6094") + AreaCode.create(:country => germany, :name => "Bessenbach", :area_code => "6095") + AreaCode.create(:country => germany, :name => "Wiesen Unterfr", :area_code => "6096") + AreaCode.create(:country => germany, :name => "Bad Vilbel", :area_code => "6101") + AreaCode.create(:country => germany, :name => "Neu-Isenburg", :area_code => "6102") + AreaCode.create(:country => germany, :name => "Langen Hess", :area_code => "6103") + AreaCode.create(:country => germany, :name => "Heusenstamm", :area_code => "6104") + AreaCode.create(:country => germany, :name => "Mörfelden-Walldorf", :area_code => "6105") + AreaCode.create(:country => germany, :name => "Rodgau", :area_code => "6106") + AreaCode.create(:country => germany, :name => "Kelsterbach", :area_code => "6107") + AreaCode.create(:country => germany, :name => "Mühlheim am Main", :area_code => "6108") + AreaCode.create(:country => germany, :name => "Frankfurt-Bergen-Enkheim", :area_code => "6109") + AreaCode.create(:country => germany, :name => "Wiesbaden", :area_code => "611") + AreaCode.create(:country => germany, :name => "Aarbergen", :area_code => "6120") + AreaCode.create(:country => germany, :name => "Hofheim-Wallau", :area_code => "6122") + AreaCode.create(:country => germany, :name => "Eltville am Rhein", :area_code => "6123") + AreaCode.create(:country => germany, :name => "Bad Schwalbach", :area_code => "6124") + AreaCode.create(:country => germany, :name => "Idstein", :area_code => "6126") + AreaCode.create(:country => germany, :name => "Niedernhausen Taunus", :area_code => "6127") + AreaCode.create(:country => germany, :name => "Taunusstein", :area_code => "6128") + AreaCode.create(:country => germany, :name => "Schlangenbad", :area_code => "6129") + AreaCode.create(:country => germany, :name => "Schwabenheim an der Selz", :area_code => "6130") + AreaCode.create(:country => germany, :name => "Mainz", :area_code => "6131") + AreaCode.create(:country => germany, :name => "Ingelheim am Rhein", :area_code => "6132") + AreaCode.create(:country => germany, :name => "Oppenheim", :area_code => "6133") + AreaCode.create(:country => germany, :name => "Mainz-Kastel", :area_code => "6134") + AreaCode.create(:country => germany, :name => "Bodenheim Rhein", :area_code => "6135") + AreaCode.create(:country => germany, :name => "Nieder-Olm", :area_code => "6136") + AreaCode.create(:country => germany, :name => "Mommenheim", :area_code => "6138") + AreaCode.create(:country => germany, :name => "Budenheim", :area_code => "6139") + AreaCode.create(:country => germany, :name => "Rüsselsheim", :area_code => "6142") + AreaCode.create(:country => germany, :name => "Bischofsheim b Rüsselsheim", :area_code => "6144") + AreaCode.create(:country => germany, :name => "Flörsheim am Main", :area_code => "6145") + AreaCode.create(:country => germany, :name => "Hochheim am Main", :area_code => "6146") + AreaCode.create(:country => germany, :name => "Trebur", :area_code => "6147") + AreaCode.create(:country => germany, :name => "Weiterstadt", :area_code => "6150") + AreaCode.create(:country => germany, :name => "Darmstadt", :area_code => "6151") + AreaCode.create(:country => germany, :name => "Gross-Gerau", :area_code => "6152") + AreaCode.create(:country => germany, :name => "Ober-Ramstadt", :area_code => "6154") + AreaCode.create(:country => germany, :name => "Griesheim Hess", :area_code => "6155") + AreaCode.create(:country => germany, :name => "Pfungstadt", :area_code => "6157") + AreaCode.create(:country => germany, :name => "Riedstadt", :area_code => "6158") + AreaCode.create(:country => germany, :name => "Messel", :area_code => "6159") + AreaCode.create(:country => germany, :name => "Brensbach", :area_code => "6161") + AreaCode.create(:country => germany, :name => "Reinheim Odenw", :area_code => "6162") + AreaCode.create(:country => germany, :name => "Höchst i Odw", :area_code => "6163") + AreaCode.create(:country => germany, :name => "Reichelsheim Odenwald", :area_code => "6164") + AreaCode.create(:country => germany, :name => "Breuberg", :area_code => "6165") + AreaCode.create(:country => germany, :name => "Fischbachtal", :area_code => "6166") + AreaCode.create(:country => germany, :name => "Modautal", :area_code => "6167") + AreaCode.create(:country => germany, :name => "Oberursel Taunus", :area_code => "6171") + AreaCode.create(:country => germany, :name => "Bad Homburg v d Höhe", :area_code => "6172") + AreaCode.create(:country => germany, :name => "Kronberg im Taunus", :area_code => "6173") + AreaCode.create(:country => germany, :name => "Königstein im Taunus", :area_code => "6174") + AreaCode.create(:country => germany, :name => "Friedrichsdorf Taunus", :area_code => "6175") + AreaCode.create(:country => germany, :name => "Hanau", :area_code => "6181") + AreaCode.create(:country => germany, :name => "Seligenstadt", :area_code => "6182") + AreaCode.create(:country => germany, :name => "Erlensee", :area_code => "6183") + AreaCode.create(:country => germany, :name => "Langenselbold", :area_code => "6184") + AreaCode.create(:country => germany, :name => "Hammersbach Hess", :area_code => "6185") + AreaCode.create(:country => germany, :name => "Grosskrotzenburg", :area_code => "6186") + AreaCode.create(:country => germany, :name => "Schöneck", :area_code => "6187") + AreaCode.create(:country => germany, :name => "Kahl a Main", :area_code => "6188") + AreaCode.create(:country => germany, :name => "Hattersheim a Main", :area_code => "6190") + AreaCode.create(:country => germany, :name => "Hofheim am Taunus", :area_code => "6192") + AreaCode.create(:country => germany, :name => "Kelkheim Taunus", :area_code => "6195") + AreaCode.create(:country => germany, :name => "Bad Soden am Taunus", :area_code => "6196") + AreaCode.create(:country => germany, :name => "Eppstein", :area_code => "6198") + AreaCode.create(:country => germany, :name => "Weinheim Bergstr", :area_code => "6201") + AreaCode.create(:country => germany, :name => "Schwetzingen", :area_code => "6202") + AreaCode.create(:country => germany, :name => "Ladenburg", :area_code => "6203") + AreaCode.create(:country => germany, :name => "Viernheim", :area_code => "6204") + AreaCode.create(:country => germany, :name => "Hockenheim", :area_code => "6205") + AreaCode.create(:country => germany, :name => "Lampertheim", :area_code => "6206") + AreaCode.create(:country => germany, :name => "Wald-Michelbach", :area_code => "6207") + AreaCode.create(:country => germany, :name => "Mörlenbach", :area_code => "6209") + AreaCode.create(:country => germany, :name => "Mannheim", :area_code => "621") + AreaCode.create(:country => germany, :name => "Wilhelmsfeld", :area_code => "6220") + AreaCode.create(:country => germany, :name => "Heidelberg", :area_code => "6221") + AreaCode.create(:country => germany, :name => "Wiesloch", :area_code => "6222") + AreaCode.create(:country => germany, :name => "Neckargemünd", :area_code => "6223") + AreaCode.create(:country => germany, :name => "Sandhausen Baden", :area_code => "6224") + AreaCode.create(:country => germany, :name => "Meckesheim", :area_code => "6226") + AreaCode.create(:country => germany, :name => "Walldorf Baden", :area_code => "6227") + AreaCode.create(:country => germany, :name => "Schönau Odenw", :area_code => "6228") + AreaCode.create(:country => germany, :name => "Neckarsteinach", :area_code => "6229") + AreaCode.create(:country => germany, :name => "Hochdorf-Assenheim", :area_code => "6231") + AreaCode.create(:country => germany, :name => "Speyer", :area_code => "6232") + AreaCode.create(:country => germany, :name => "Frankenthal Pfalz", :area_code => "6233") + AreaCode.create(:country => germany, :name => "Mutterstadt", :area_code => "6234") + AreaCode.create(:country => germany, :name => "Schifferstadt", :area_code => "6235") + AreaCode.create(:country => germany, :name => "Neuhofen Pfalz", :area_code => "6236") + AreaCode.create(:country => germany, :name => "Maxdorf", :area_code => "6237") + AreaCode.create(:country => germany, :name => "Dirmstein", :area_code => "6238") + AreaCode.create(:country => germany, :name => "Bobenheim-Roxheim", :area_code => "6239") + AreaCode.create(:country => germany, :name => "Worms", :area_code => "6241") + AreaCode.create(:country => germany, :name => "Osthofen", :area_code => "6242") + AreaCode.create(:country => germany, :name => "Monsheim", :area_code => "6243") + AreaCode.create(:country => germany, :name => "Westhofen Rheinhess", :area_code => "6244") + AreaCode.create(:country => germany, :name => "Biblis", :area_code => "6245") + AreaCode.create(:country => germany, :name => "Eich Rheinhess", :area_code => "6246") + AreaCode.create(:country => germany, :name => "Worms-Pfeddersheim", :area_code => "6247") + AreaCode.create(:country => germany, :name => "Guntersblum", :area_code => "6249") + AreaCode.create(:country => germany, :name => "Bensheim", :area_code => "6251") + AreaCode.create(:country => germany, :name => "Heppenheim Bergstraße", :area_code => "6252") + AreaCode.create(:country => germany, :name => "Fürth Odenw", :area_code => "6253") + AreaCode.create(:country => germany, :name => "Lautertal Odenwald", :area_code => "6254") + AreaCode.create(:country => germany, :name => "Lindenfels", :area_code => "6255") + AreaCode.create(:country => germany, :name => "Lampertheim-Hüttenfeld", :area_code => "6256") + AreaCode.create(:country => germany, :name => "Seeheim-Jugenheim", :area_code => "6257") + AreaCode.create(:country => germany, :name => "Gernsheim", :area_code => "6258") + AreaCode.create(:country => germany, :name => "Mosbach Baden", :area_code => "6261") + AreaCode.create(:country => germany, :name => "Aglasterhausen", :area_code => "6262") + AreaCode.create(:country => germany, :name => "Neckargerach", :area_code => "6263") + AreaCode.create(:country => germany, :name => "Neudenau", :area_code => "6264") + AreaCode.create(:country => germany, :name => "Billigheim Baden", :area_code => "6265") + AreaCode.create(:country => germany, :name => "Hassmersheim", :area_code => "6266") + AreaCode.create(:country => germany, :name => "Fahrenbach Baden", :area_code => "6267") + AreaCode.create(:country => germany, :name => "Hüffenhardt", :area_code => "6268") + AreaCode.create(:country => germany, :name => "Gundelsheim Württ", :area_code => "6269") + AreaCode.create(:country => germany, :name => "Eberbach Baden", :area_code => "6271") + AreaCode.create(:country => germany, :name => "Hirschhorn Neckar", :area_code => "6272") + AreaCode.create(:country => germany, :name => "Waldbrunn Odenw", :area_code => "6274") + AreaCode.create(:country => germany, :name => "Rothenberg Odenw", :area_code => "6275") + AreaCode.create(:country => germany, :name => "Hesseneck", :area_code => "6276") + AreaCode.create(:country => germany, :name => "Buchen Odenwald", :area_code => "6281") + AreaCode.create(:country => germany, :name => "Walldürn", :area_code => "6282") + AreaCode.create(:country => germany, :name => "Hardheim Odenw", :area_code => "6283") + AreaCode.create(:country => germany, :name => "Mudau", :area_code => "6284") + AreaCode.create(:country => germany, :name => "Walldürn-Altheim", :area_code => "6285") + AreaCode.create(:country => germany, :name => "Walldürn-Rippberg", :area_code => "6286") + AreaCode.create(:country => germany, :name => "Limbach Baden", :area_code => "6287") + AreaCode.create(:country => germany, :name => "Adelsheim", :area_code => "6291") + AreaCode.create(:country => germany, :name => "Seckach", :area_code => "6292") + AreaCode.create(:country => germany, :name => "Schefflenz", :area_code => "6293") + AreaCode.create(:country => germany, :name => "Krautheim Jagst", :area_code => "6294") + AreaCode.create(:country => germany, :name => "RosenbergBaden", :area_code => "6295") + AreaCode.create(:country => germany, :name => "Ahorn Baden", :area_code => "6296") + AreaCode.create(:country => germany, :name => "Ravenstein Baden", :area_code => "6297") + AreaCode.create(:country => germany, :name => "Möckmühl", :area_code => "6298") + AreaCode.create(:country => germany, :name => "Otterbach Pfalz", :area_code => "6301") + AreaCode.create(:country => germany, :name => "Winnweiler", :area_code => "6302") + AreaCode.create(:country => germany, :name => "Enkenbach-Alsenborn", :area_code => "6303") + AreaCode.create(:country => germany, :name => "Wolfstein Pfalz", :area_code => "6304") + AreaCode.create(:country => germany, :name => "Hochspeyer", :area_code => "6305") + AreaCode.create(:country => germany, :name => "Trippstadt", :area_code => "6306") + AreaCode.create(:country => germany, :name => "Schopp", :area_code => "6307") + AreaCode.create(:country => germany, :name => "Olsbrücken", :area_code => "6308") + AreaCode.create(:country => germany, :name => "Kaiserslautern", :area_code => "631") + AreaCode.create(:country => germany, :name => "Neustadt an der Weinstraße", :area_code => "6321") + AreaCode.create(:country => germany, :name => "Bad Dürkheim", :area_code => "6322") + AreaCode.create(:country => germany, :name => "Edenkoben", :area_code => "6323") + AreaCode.create(:country => germany, :name => "Hassloch", :area_code => "6324") + AreaCode.create(:country => germany, :name => "Lambrecht Pfalz", :area_code => "6325") + AreaCode.create(:country => germany, :name => "Deidesheim", :area_code => "6326") + AreaCode.create(:country => germany, :name => "Neustadt-Lachen", :area_code => "6327") + AreaCode.create(:country => germany, :name => "Elmstein", :area_code => "6328") + AreaCode.create(:country => germany, :name => "Weidenthal Pfalz", :area_code => "6329") + AreaCode.create(:country => germany, :name => "Pirmasens", :area_code => "6331") + AreaCode.create(:country => germany, :name => "Zweibrücken", :area_code => "6332") + AreaCode.create(:country => germany, :name => "Waldfischbach-Burgalben", :area_code => "6333") + AreaCode.create(:country => germany, :name => "Thaleischweiler-Fröschen", :area_code => "6334") + AreaCode.create(:country => germany, :name => "Trulben", :area_code => "6335") + AreaCode.create(:country => germany, :name => "Dellfeld", :area_code => "6336") + AreaCode.create(:country => germany, :name => "Grossbundenbach", :area_code => "6337") + AreaCode.create(:country => germany, :name => "Hornbach Pfalz", :area_code => "6338") + AreaCode.create(:country => germany, :name => "Grosssteinhausen", :area_code => "6339") + AreaCode.create(:country => germany, :name => "Wörth-Schaidt", :area_code => "6340") + AreaCode.create(:country => germany, :name => "Landau in der Pfalz", :area_code => "6341") + AreaCode.create(:country => germany, :name => "Schweigen-Rechtenbach", :area_code => "6342") + AreaCode.create(:country => germany, :name => "Bad Bergzabern", :area_code => "6343") + AreaCode.create(:country => germany, :name => "Schwegenheim", :area_code => "6344") + AreaCode.create(:country => germany, :name => "Albersweiler", :area_code => "6345") + AreaCode.create(:country => germany, :name => "Annweiler am Trifels", :area_code => "6346") + AreaCode.create(:country => germany, :name => "Hochstadt Pfalz", :area_code => "6347") + AreaCode.create(:country => germany, :name => "Offenbach an der Queich", :area_code => "6348") + AreaCode.create(:country => germany, :name => "Billigheim-Ingenheim", :area_code => "6349") + AreaCode.create(:country => germany, :name => "Eisenberg Pfalz", :area_code => "6351") + AreaCode.create(:country => germany, :name => "Kirchheimbolanden", :area_code => "6352") + AreaCode.create(:country => germany, :name => "Freinsheim", :area_code => "6353") + AreaCode.create(:country => germany, :name => "Albisheim Pfrimm", :area_code => "6355") + AreaCode.create(:country => germany, :name => "Carlsberg Pfalz", :area_code => "6356") + AreaCode.create(:country => germany, :name => "Standenbühl", :area_code => "6357") + AreaCode.create(:country => germany, :name => "Kriegsfeld", :area_code => "6358") + AreaCode.create(:country => germany, :name => "Grünstadt", :area_code => "6359") + AreaCode.create(:country => germany, :name => "Rockenhausen", :area_code => "6361") + AreaCode.create(:country => germany, :name => "Alsenz", :area_code => "6362") + AreaCode.create(:country => germany, :name => "Niederkirchen", :area_code => "6363") + AreaCode.create(:country => germany, :name => "Nußbach Pfalz", :area_code => "6364") + AreaCode.create(:country => germany, :name => "Landstuhl", :area_code => "6371") + AreaCode.create(:country => germany, :name => "Bruchmühlbach-Miesau", :area_code => "6372") + AreaCode.create(:country => germany, :name => "Schönenberg-Kübelberg", :area_code => "6373") + AreaCode.create(:country => germany, :name => "Weilerbach", :area_code => "6374") + AreaCode.create(:country => germany, :name => "Wallhalben", :area_code => "6375") + AreaCode.create(:country => germany, :name => "Kusel", :area_code => "6381") + AreaCode.create(:country => germany, :name => "Lauterecken", :area_code => "6382") + AreaCode.create(:country => germany, :name => "Glan-Münchweiler", :area_code => "6383") + AreaCode.create(:country => germany, :name => "Konken", :area_code => "6384") + AreaCode.create(:country => germany, :name => "Reichenbach-Steegen", :area_code => "6385") + AreaCode.create(:country => germany, :name => "Altenkirchen Pfalz", :area_code => "6386") + AreaCode.create(:country => germany, :name => "Sankt Julian", :area_code => "6387") + AreaCode.create(:country => germany, :name => "Dahn", :area_code => "6391") + AreaCode.create(:country => germany, :name => "Hauenstein Pfalz", :area_code => "6392") + AreaCode.create(:country => germany, :name => "Fischbach bei Dahn", :area_code => "6393") + AreaCode.create(:country => germany, :name => "Bundenthal", :area_code => "6394") + AreaCode.create(:country => germany, :name => "Münchweiler an der Rodalb", :area_code => "6395") + AreaCode.create(:country => germany, :name => "Hinterweidenthal", :area_code => "6396") + AreaCode.create(:country => germany, :name => "Leimen Pfalz", :area_code => "6397") + AreaCode.create(:country => germany, :name => "Vorderweidenthal", :area_code => "6398") + AreaCode.create(:country => germany, :name => "Mücke", :area_code => "6400") + AreaCode.create(:country => germany, :name => "Grünberg Hess", :area_code => "6401") + AreaCode.create(:country => germany, :name => "Hungen", :area_code => "6402") + AreaCode.create(:country => germany, :name => "Linden Hess", :area_code => "6403") + AreaCode.create(:country => germany, :name => "Lich Hess", :area_code => "6404") + AreaCode.create(:country => germany, :name => "Laubach Hess", :area_code => "6405") + AreaCode.create(:country => germany, :name => "Lollar", :area_code => "6406") + AreaCode.create(:country => germany, :name => "Rabenau Hess", :area_code => "6407") + AreaCode.create(:country => germany, :name => "Buseck", :area_code => "6408") + AreaCode.create(:country => germany, :name => "Biebertal", :area_code => "6409") + AreaCode.create(:country => germany, :name => "Giessen", :area_code => "641") + AreaCode.create(:country => germany, :name => "Lahntal", :area_code => "6420") + AreaCode.create(:country => germany, :name => "Marburg", :area_code => "6421") + AreaCode.create(:country => germany, :name => "Kirchhain", :area_code => "6422") + AreaCode.create(:country => germany, :name => "Wetter Hessen", :area_code => "6423") + AreaCode.create(:country => germany, :name => "Ebsdorfergrund", :area_code => "6424") + AreaCode.create(:country => germany, :name => "Rauschenberg Hess", :area_code => "6425") + AreaCode.create(:country => germany, :name => "Fronhausen", :area_code => "6426") + AreaCode.create(:country => germany, :name => "Cölbe-Schönstadt", :area_code => "6427") + AreaCode.create(:country => germany, :name => "Stadtallendorf", :area_code => "6428") + AreaCode.create(:country => germany, :name => "Schweinsberg Hess", :area_code => "6429") + AreaCode.create(:country => germany, :name => "Hahnstätten", :area_code => "6430") + AreaCode.create(:country => germany, :name => "Limburg a d Lahn", :area_code => "6431") + AreaCode.create(:country => germany, :name => "Diez", :area_code => "6432") + AreaCode.create(:country => germany, :name => "Hadamar", :area_code => "6433") + AreaCode.create(:country => germany, :name => "Bad Camberg", :area_code => "6434") + AreaCode.create(:country => germany, :name => "Wallmerod", :area_code => "6435") + AreaCode.create(:country => germany, :name => "Dornburg Hess", :area_code => "6436") + AreaCode.create(:country => germany, :name => "Hünfelden", :area_code => "6438") + AreaCode.create(:country => germany, :name => "Holzappel", :area_code => "6439") + AreaCode.create(:country => germany, :name => "Kölschhausen", :area_code => "6440") + AreaCode.create(:country => germany, :name => "Wetzlar", :area_code => "6441") + AreaCode.create(:country => germany, :name => "Braunfels", :area_code => "6442") + AreaCode.create(:country => germany, :name => "Ehringshausen Dill", :area_code => "6443") + AreaCode.create(:country => germany, :name => "Bischoffen", :area_code => "6444") + AreaCode.create(:country => germany, :name => "Schöffengrund", :area_code => "6445") + AreaCode.create(:country => germany, :name => "Hohenahr", :area_code => "6446") + AreaCode.create(:country => germany, :name => "Langgöns-Niederkleen", :area_code => "6447") + AreaCode.create(:country => germany, :name => "Ehringshausen-Katzenfurt", :area_code => "6449") + AreaCode.create(:country => germany, :name => "Frankenberg Eder", :area_code => "6451") + AreaCode.create(:country => germany, :name => "Battenberg Eder", :area_code => "6452") + AreaCode.create(:country => germany, :name => "Gemünden Wohra", :area_code => "6453") + AreaCode.create(:country => germany, :name => "Lichtenfels-Sachsenberg", :area_code => "6454") + AreaCode.create(:country => germany, :name => "Frankenau Hess", :area_code => "6455") + AreaCode.create(:country => germany, :name => "Haina Kloster", :area_code => "6456") + AreaCode.create(:country => germany, :name => "Burgwald Eder", :area_code => "6457") + AreaCode.create(:country => germany, :name => "Rosenthal Hess", :area_code => "6458") + AreaCode.create(:country => germany, :name => "Biedenkopf", :area_code => "6461") + AreaCode.create(:country => germany, :name => "Gladenbach", :area_code => "6462") + AreaCode.create(:country => germany, :name => "Angelburg", :area_code => "6464") + AreaCode.create(:country => germany, :name => "Breidenbach b Biedenkopf", :area_code => "6465") + AreaCode.create(:country => germany, :name => "Dautphetal-Friedensdorf", :area_code => "6466") + AreaCode.create(:country => germany, :name => "Hatzfeld Eder", :area_code => "6467") + AreaCode.create(:country => germany, :name => "Dautphetal-Mornshausen", :area_code => "6468") + AreaCode.create(:country => germany, :name => "Weilburg", :area_code => "6471") + AreaCode.create(:country => germany, :name => "Weilmünster", :area_code => "6472") + AreaCode.create(:country => germany, :name => "Leun", :area_code => "6473") + AreaCode.create(:country => germany, :name => "Villmar-Aumenau", :area_code => "6474") + AreaCode.create(:country => germany, :name => "Weilmünster-Wolfenhausen", :area_code => "6475") + AreaCode.create(:country => germany, :name => "Mengerskirchen", :area_code => "6476") + AreaCode.create(:country => germany, :name => "Greifenstein-Nenderoth", :area_code => "6477") + AreaCode.create(:country => germany, :name => "Greifenstein-Ulm", :area_code => "6478") + AreaCode.create(:country => germany, :name => "Waldbrunn Westerwald", :area_code => "6479") + AreaCode.create(:country => germany, :name => "Runkel", :area_code => "6482") + AreaCode.create(:country => germany, :name => "Selters Taunus", :area_code => "6483") + AreaCode.create(:country => germany, :name => "Beselich", :area_code => "6484") + AreaCode.create(:country => germany, :name => "Nentershausen Westerw", :area_code => "6485") + AreaCode.create(:country => germany, :name => "Katzenelnbogen", :area_code => "6486") + AreaCode.create(:country => germany, :name => "Waldrach", :area_code => "6500") + AreaCode.create(:country => germany, :name => "Konz", :area_code => "6501") + AreaCode.create(:country => germany, :name => "Schweich", :area_code => "6502") + AreaCode.create(:country => germany, :name => "Hermeskeil", :area_code => "6503") + AreaCode.create(:country => germany, :name => "Thalfang", :area_code => "6504") + AreaCode.create(:country => germany, :name => "Kordel", :area_code => "6505") + AreaCode.create(:country => germany, :name => "Welschbillig", :area_code => "6506") + AreaCode.create(:country => germany, :name => "Neumagen-Dhron", :area_code => "6507") + AreaCode.create(:country => germany, :name => "Hetzerath Mosel", :area_code => "6508") + AreaCode.create(:country => germany, :name => "Büdlich", :area_code => "6509") + AreaCode.create(:country => germany, :name => "Trier", :area_code => "651") + AreaCode.create(:country => germany, :name => "Mettendorf", :area_code => "6522") + AreaCode.create(:country => germany, :name => "Holsthum", :area_code => "6523") + AreaCode.create(:country => germany, :name => "Rodershausen", :area_code => "6524") + AreaCode.create(:country => germany, :name => "Irrel", :area_code => "6525") + AreaCode.create(:country => germany, :name => "Bollendorf", :area_code => "6526") + AreaCode.create(:country => germany, :name => "Oberweis", :area_code => "6527") + AreaCode.create(:country => germany, :name => "Bernkastel-Kues", :area_code => "6531") + AreaCode.create(:country => germany, :name => "Zeltingen-Rachtig", :area_code => "6532") + AreaCode.create(:country => germany, :name => "Morbach Hunsrück", :area_code => "6533") + AreaCode.create(:country => germany, :name => "Mülheim Mosel", :area_code => "6534") + AreaCode.create(:country => germany, :name => "Osann-Monzel", :area_code => "6535") + AreaCode.create(:country => germany, :name => "Kleinich", :area_code => "6536") + AreaCode.create(:country => germany, :name => "Traben-Trarbach", :area_code => "6541") + AreaCode.create(:country => germany, :name => "Bullay", :area_code => "6542") + AreaCode.create(:country => germany, :name => "Büchenbeuren", :area_code => "6543") + AreaCode.create(:country => germany, :name => "Rhaunen", :area_code => "6544") + AreaCode.create(:country => germany, :name => "Blankenrath", :area_code => "6545") + AreaCode.create(:country => germany, :name => "Irrhausen", :area_code => "6550") + AreaCode.create(:country => germany, :name => "Prüm", :area_code => "6551") + AreaCode.create(:country => germany, :name => "Olzheim", :area_code => "6552") + AreaCode.create(:country => germany, :name => "Schönecken", :area_code => "6553") + AreaCode.create(:country => germany, :name => "Waxweiler", :area_code => "6554") + AreaCode.create(:country => germany, :name => "Bleialf", :area_code => "6555") + AreaCode.create(:country => germany, :name => "Pronsfeld", :area_code => "6556") + AreaCode.create(:country => germany, :name => "Hallschlag", :area_code => "6557") + AreaCode.create(:country => germany, :name => "Büdesheim Eifel", :area_code => "6558") + AreaCode.create(:country => germany, :name => "Leidenborn", :area_code => "6559") + AreaCode.create(:country => germany, :name => "Bitburg", :area_code => "6561") + AreaCode.create(:country => germany, :name => "Speicher", :area_code => "6562") + AreaCode.create(:country => germany, :name => "Kyllburg", :area_code => "6563") + AreaCode.create(:country => germany, :name => "Neuerburg Eifel", :area_code => "6564") + AreaCode.create(:country => germany, :name => "Dudeldorf", :area_code => "6565") + AreaCode.create(:country => germany, :name => "Körperich", :area_code => "6566") + AreaCode.create(:country => germany, :name => "Oberkail", :area_code => "6567") + AreaCode.create(:country => germany, :name => "Wolsfeld", :area_code => "6568") + AreaCode.create(:country => germany, :name => "Bickendorf", :area_code => "6569") + AreaCode.create(:country => germany, :name => "Wittlich", :area_code => "6571") + AreaCode.create(:country => germany, :name => "Manderscheid Eifel", :area_code => "6572") + AreaCode.create(:country => germany, :name => "Gillenfeld", :area_code => "6573") + AreaCode.create(:country => germany, :name => "Hasborn", :area_code => "6574") + AreaCode.create(:country => germany, :name => "Landscheid", :area_code => "6575") + AreaCode.create(:country => germany, :name => "Salmtal", :area_code => "6578") + AreaCode.create(:country => germany, :name => "Zemmer", :area_code => "6580") + AreaCode.create(:country => germany, :name => "Saarburg", :area_code => "6581") + AreaCode.create(:country => germany, :name => "Freudenburg", :area_code => "6582") + AreaCode.create(:country => germany, :name => "Palzem", :area_code => "6583") + AreaCode.create(:country => germany, :name => "Wellen Mosel", :area_code => "6584") + AreaCode.create(:country => germany, :name => "Ralingen", :area_code => "6585") + AreaCode.create(:country => germany, :name => "Beuren Hochwald", :area_code => "6586") + AreaCode.create(:country => germany, :name => "Zerf", :area_code => "6587") + AreaCode.create(:country => germany, :name => "Pluwig", :area_code => "6588") + AreaCode.create(:country => germany, :name => "Kell am See", :area_code => "6589") + AreaCode.create(:country => germany, :name => "Gerolstein", :area_code => "6591") + AreaCode.create(:country => germany, :name => "Daun", :area_code => "6592") + AreaCode.create(:country => germany, :name => "Hillesheim Eifel", :area_code => "6593") + AreaCode.create(:country => germany, :name => "Birresborn", :area_code => "6594") + AreaCode.create(:country => germany, :name => "Dockweiler", :area_code => "6595") + AreaCode.create(:country => germany, :name => "Üdersdorf", :area_code => "6596") + AreaCode.create(:country => germany, :name => "Jünkerath", :area_code => "6597") + AreaCode.create(:country => germany, :name => "Weidenbach b Gerolstein", :area_code => "6599") + AreaCode.create(:country => germany, :name => "Fulda", :area_code => "661") + AreaCode.create(:country => germany, :name => "Philippsthal Werra", :area_code => "6620") + AreaCode.create(:country => germany, :name => "Bad Hersfeld", :area_code => "6621") + AreaCode.create(:country => germany, :name => "Bebra", :area_code => "6622") + AreaCode.create(:country => germany, :name => "Rotenburg a d Fulda", :area_code => "6623") + AreaCode.create(:country => germany, :name => "Heringen Werra", :area_code => "6624") + AreaCode.create(:country => germany, :name => "Niederaula", :area_code => "6625") + AreaCode.create(:country => germany, :name => "Wildeck-Obersuhl", :area_code => "6626") + AreaCode.create(:country => germany, :name => "Nentershausen Hess", :area_code => "6627") + AreaCode.create(:country => germany, :name => "Oberaula", :area_code => "6628") + AreaCode.create(:country => germany, :name => "Schenklengsfeld", :area_code => "6629") + AreaCode.create(:country => germany, :name => "Schwalmtal-Storndorf", :area_code => "6630") + AreaCode.create(:country => germany, :name => "Alsfeld", :area_code => "6631") + AreaCode.create(:country => germany, :name => "Homberg Ohm", :area_code => "6633") + AreaCode.create(:country => germany, :name => "Gemünden Felda", :area_code => "6634") + AreaCode.create(:country => germany, :name => "Kirtorf", :area_code => "6635") + AreaCode.create(:country => germany, :name => "Romrod", :area_code => "6636") + AreaCode.create(:country => germany, :name => "Feldatal", :area_code => "6637") + AreaCode.create(:country => germany, :name => "Schwalmtal-Renzendorf", :area_code => "6638") + AreaCode.create(:country => germany, :name => "Ottrau", :area_code => "6639") + AreaCode.create(:country => germany, :name => "Lauterbach Hessen", :area_code => "6641") + AreaCode.create(:country => germany, :name => "Schlitz", :area_code => "6642") + AreaCode.create(:country => germany, :name => "Herbstein", :area_code => "6643") + AreaCode.create(:country => germany, :name => "Grebenhain", :area_code => "6644") + AreaCode.create(:country => germany, :name => "Ulrichstein", :area_code => "6645") + AreaCode.create(:country => germany, :name => "Grebenau", :area_code => "6646") + AreaCode.create(:country => germany, :name => "Herbstein-Stockhausen", :area_code => "6647") + AreaCode.create(:country => germany, :name => "Bad Salzschlirf", :area_code => "6648") + AreaCode.create(:country => germany, :name => "Hosenfeld", :area_code => "6650") + AreaCode.create(:country => germany, :name => "Rasdorf", :area_code => "6651") + AreaCode.create(:country => germany, :name => "Hünfeld", :area_code => "6652") + AreaCode.create(:country => germany, :name => "Burghaun", :area_code => "6653") + AreaCode.create(:country => germany, :name => "Gersfeld Rhön", :area_code => "6654") + AreaCode.create(:country => germany, :name => "Neuhof Kr Fulda", :area_code => "6655") + AreaCode.create(:country => germany, :name => "Ebersburg", :area_code => "6656") + AreaCode.create(:country => germany, :name => "Hofbieber", :area_code => "6657") + AreaCode.create(:country => germany, :name => "Poppenhausen Wasserkuppe", :area_code => "6658") + AreaCode.create(:country => germany, :name => "Eichenzell", :area_code => "6659") + AreaCode.create(:country => germany, :name => "Steinau-Marjoss", :area_code => "6660") + AreaCode.create(:country => germany, :name => "Schlüchtern", :area_code => "6661") + AreaCode.create(:country => germany, :name => "Steinau an der Straße", :area_code => "6663") + AreaCode.create(:country => germany, :name => "Sinntal-Sterbfritz", :area_code => "6664") + AreaCode.create(:country => germany, :name => "Sinntal-Altengronau", :area_code => "6665") + AreaCode.create(:country => germany, :name => "Freiensteinau", :area_code => "6666") + AreaCode.create(:country => germany, :name => "Steinau-Ulmbach", :area_code => "6667") + AreaCode.create(:country => germany, :name => "Birstein-Lichenroth", :area_code => "6668") + AreaCode.create(:country => germany, :name => "Neuhof-Hauswurz", :area_code => "6669") + AreaCode.create(:country => germany, :name => "Ludwigsau Hess", :area_code => "6670") + AreaCode.create(:country => germany, :name => "Eiterfeld", :area_code => "6672") + AreaCode.create(:country => germany, :name => "Haunetal", :area_code => "6673") + AreaCode.create(:country => germany, :name => "Friedewald Hess", :area_code => "6674") + AreaCode.create(:country => germany, :name => "Breitenbach a Herzberg", :area_code => "6675") + AreaCode.create(:country => germany, :name => "Hohenroda Hess", :area_code => "6676") + AreaCode.create(:country => germany, :name => "Neuenstein Hess", :area_code => "6677") + AreaCode.create(:country => germany, :name => "Wildeck-Hönebach", :area_code => "6678") + AreaCode.create(:country => germany, :name => "Hilders", :area_code => "6681") + AreaCode.create(:country => germany, :name => "Tann Rhön", :area_code => "6682") + AreaCode.create(:country => germany, :name => "Ehrenberg Rhön", :area_code => "6683") + AreaCode.create(:country => germany, :name => "Hofbieber-Schwarzbach", :area_code => "6684") + AreaCode.create(:country => germany, :name => "Schwalmstadt", :area_code => "6691") + AreaCode.create(:country => germany, :name => "Neustadt Hessen", :area_code => "6692") + AreaCode.create(:country => germany, :name => "Neuental", :area_code => "6693") + AreaCode.create(:country => germany, :name => "Neukirchen Knüll", :area_code => "6694") + AreaCode.create(:country => germany, :name => "Jesberg", :area_code => "6695") + AreaCode.create(:country => germany, :name => "Gilserberg", :area_code => "6696") + AreaCode.create(:country => germany, :name => "Willingshausen", :area_code => "6697") + AreaCode.create(:country => germany, :name => "Schrecksbach", :area_code => "6698") + AreaCode.create(:country => germany, :name => "Sprendlingen Rheinhess", :area_code => "6701") + AreaCode.create(:country => germany, :name => "Wöllstein Rheinhess", :area_code => "6703") + AreaCode.create(:country => germany, :name => "Langenlonsheim", :area_code => "6704") + AreaCode.create(:country => germany, :name => "Wallhausen Nahe", :area_code => "6706") + AreaCode.create(:country => germany, :name => "Windesheim", :area_code => "6707") + AreaCode.create(:country => germany, :name => "Bad Münster am Stein-Ebernburg", :area_code => "6708") + AreaCode.create(:country => germany, :name => "Fürfeld Kr Bad Kreuznach", :area_code => "6709") + AreaCode.create(:country => germany, :name => "Bad Kreuznach", :area_code => "671") + AreaCode.create(:country => germany, :name => "Bingen am Rhein", :area_code => "6721") + AreaCode.create(:country => germany, :name => "Rüdesheim am Rhein", :area_code => "6722") + AreaCode.create(:country => germany, :name => "Oestrich-Winkel", :area_code => "6723") + AreaCode.create(:country => germany, :name => "Stromberg Hunsrück", :area_code => "6724") + AreaCode.create(:country => germany, :name => "Gau-Algesheim", :area_code => "6725") + AreaCode.create(:country => germany, :name => "Lorch Rheingau", :area_code => "6726") + AreaCode.create(:country => germany, :name => "Gensingen", :area_code => "6727") + AreaCode.create(:country => germany, :name => "Ober-Hilbersheim", :area_code => "6728") + AreaCode.create(:country => germany, :name => "Alzey", :area_code => "6731") + AreaCode.create(:country => germany, :name => "Wörrstadt", :area_code => "6732") + AreaCode.create(:country => germany, :name => "Gau-Odernheim", :area_code => "6733") + AreaCode.create(:country => germany, :name => "Flonheim", :area_code => "6734") + AreaCode.create(:country => germany, :name => "Eppelsheim", :area_code => "6735") + AreaCode.create(:country => germany, :name => "Bechenheim", :area_code => "6736") + AreaCode.create(:country => germany, :name => "Köngernheim", :area_code => "6737") + AreaCode.create(:country => germany, :name => "St Goar", :area_code => "6741") + AreaCode.create(:country => germany, :name => "Boppard", :area_code => "6742") + AreaCode.create(:country => germany, :name => "Bacharach", :area_code => "6743") + AreaCode.create(:country => germany, :name => "Oberwesel", :area_code => "6744") + AreaCode.create(:country => germany, :name => "Gondershausen", :area_code => "6745") + AreaCode.create(:country => germany, :name => "Pfalzfeld", :area_code => "6746") + AreaCode.create(:country => germany, :name => "Emmelshausen", :area_code => "6747") + AreaCode.create(:country => germany, :name => "Bad Sobernheim", :area_code => "6751") + AreaCode.create(:country => germany, :name => "Kirn Nahe", :area_code => "6752") + AreaCode.create(:country => germany, :name => "Meisenheim", :area_code => "6753") + AreaCode.create(:country => germany, :name => "Martinstein", :area_code => "6754") + AreaCode.create(:country => germany, :name => "Odernheim am Glan", :area_code => "6755") + AreaCode.create(:country => germany, :name => "Winterbach Soonwald", :area_code => "6756") + AreaCode.create(:country => germany, :name => "Becherbach bei Kirn", :area_code => "6757") + AreaCode.create(:country => germany, :name => "Waldböckelheim", :area_code => "6758") + AreaCode.create(:country => germany, :name => "Simmern Hunsrück", :area_code => "6761") + AreaCode.create(:country => germany, :name => "Kastellaun", :area_code => "6762") + AreaCode.create(:country => germany, :name => "Kirchberg Hunsrück", :area_code => "6763") + AreaCode.create(:country => germany, :name => "Rheinböllen", :area_code => "6764") + AreaCode.create(:country => germany, :name => "Gemünden Hunsrück", :area_code => "6765") + AreaCode.create(:country => germany, :name => "Kisselbach", :area_code => "6766") + AreaCode.create(:country => germany, :name => "St Goarshausen", :area_code => "6771") + AreaCode.create(:country => germany, :name => "Nastätten", :area_code => "6772") + AreaCode.create(:country => germany, :name => "Kamp-Bornhofen", :area_code => "6773") + AreaCode.create(:country => germany, :name => "Kaub", :area_code => "6774") + AreaCode.create(:country => germany, :name => "Strüth Taunus", :area_code => "6775") + AreaCode.create(:country => germany, :name => "Dachsenhausen", :area_code => "6776") + AreaCode.create(:country => germany, :name => "Idar-Oberstein", :area_code => "6781") + AreaCode.create(:country => germany, :name => "Birkenfeld Nahe", :area_code => "6782") + AreaCode.create(:country => germany, :name => "Baumholder", :area_code => "6783") + AreaCode.create(:country => germany, :name => "Weierbach", :area_code => "6784") + AreaCode.create(:country => germany, :name => "Herrstein", :area_code => "6785") + AreaCode.create(:country => germany, :name => "Kempfeld", :area_code => "6786") + AreaCode.create(:country => germany, :name => "Niederbrombach", :area_code => "6787") + AreaCode.create(:country => germany, :name => "Sien", :area_code => "6788") + AreaCode.create(:country => germany, :name => "Heimbach Nahe", :area_code => "6789") + AreaCode.create(:country => germany, :name => "Völklingen-Lauterbach", :area_code => "6802") + AreaCode.create(:country => germany, :name => "Mandelbachtal-Ommersheim", :area_code => "6803") + AreaCode.create(:country => germany, :name => "Mandelbachtal", :area_code => "6804") + AreaCode.create(:country => germany, :name => "Kleinblittersdorf", :area_code => "6805") + AreaCode.create(:country => germany, :name => "Heusweiler", :area_code => "6806") + AreaCode.create(:country => germany, :name => "Grossrosseln", :area_code => "6809") + AreaCode.create(:country => germany, :name => "Saarbrücken", :area_code => "681") + AreaCode.create(:country => germany, :name => "Neunkirchen Saar", :area_code => "6821") + AreaCode.create(:country => germany, :name => "Ottweiler", :area_code => "6824") + AreaCode.create(:country => germany, :name => "Illingen Saar", :area_code => "6825") + AreaCode.create(:country => germany, :name => "Bexbach", :area_code => "6826") + AreaCode.create(:country => germany, :name => "Eppelborn", :area_code => "6827") + AreaCode.create(:country => germany, :name => "Saarlouis", :area_code => "6831") + AreaCode.create(:country => germany, :name => "Beckingen-Reimsbach", :area_code => "6832") + AreaCode.create(:country => germany, :name => "Rehlingen-Siersburg", :area_code => "6833") + AreaCode.create(:country => germany, :name => "Bous", :area_code => "6834") + AreaCode.create(:country => germany, :name => "Beckingen", :area_code => "6835") + AreaCode.create(:country => germany, :name => "Überherrn", :area_code => "6836") + AreaCode.create(:country => germany, :name => "Wallerfangen", :area_code => "6837") + AreaCode.create(:country => germany, :name => "Saarwellingen", :area_code => "6838") + AreaCode.create(:country => germany, :name => "Homburg Saar", :area_code => "6841") + AreaCode.create(:country => germany, :name => "Blieskastel", :area_code => "6842") + AreaCode.create(:country => germany, :name => "Gersheim", :area_code => "6843") + AreaCode.create(:country => germany, :name => "Blieskastel-Altheim", :area_code => "6844") + AreaCode.create(:country => germany, :name => "Homburg-Einöd", :area_code => "6848") + AreaCode.create(:country => germany, :name => "Kirkel", :area_code => "6849") + AreaCode.create(:country => germany, :name => "St Wendel", :area_code => "6851") + AreaCode.create(:country => germany, :name => "Nohfelden", :area_code => "6852") + AreaCode.create(:country => germany, :name => "Marpingen", :area_code => "6853") + AreaCode.create(:country => germany, :name => "Oberthal Saar", :area_code => "6854") + AreaCode.create(:country => germany, :name => "Freisen", :area_code => "6855") + AreaCode.create(:country => germany, :name => "St Wendel-Niederkirchen", :area_code => "6856") + AreaCode.create(:country => germany, :name => "Namborn", :area_code => "6857") + AreaCode.create(:country => germany, :name => "Ottweiler-Fürth", :area_code => "6858") + AreaCode.create(:country => germany, :name => "Merzig", :area_code => "6861") + AreaCode.create(:country => germany, :name => "Mettlach", :area_code => "6864") + AreaCode.create(:country => germany, :name => "Mettlach-Orscholz", :area_code => "6865") + AreaCode.create(:country => germany, :name => "Perl-Nennig", :area_code => "6866") + AreaCode.create(:country => germany, :name => "Perl", :area_code => "6867") + AreaCode.create(:country => germany, :name => "Mettlach-Tünsdorf", :area_code => "6868") + AreaCode.create(:country => germany, :name => "Merzig-Silwingen", :area_code => "6869") + AreaCode.create(:country => germany, :name => "Wadern", :area_code => "6871") + AreaCode.create(:country => germany, :name => "Losheim am See", :area_code => "6872") + AreaCode.create(:country => germany, :name => "Nonnweiler", :area_code => "6873") + AreaCode.create(:country => germany, :name => "Wadern-Nunkirchen", :area_code => "6874") + AreaCode.create(:country => germany, :name => "Nonnweiler-Primstal", :area_code => "6875") + AreaCode.create(:country => germany, :name => "Weiskirchen Saar", :area_code => "6876") + AreaCode.create(:country => germany, :name => "Lebach", :area_code => "6881") + AreaCode.create(:country => germany, :name => "Schmelz Saar", :area_code => "6887") + AreaCode.create(:country => germany, :name => "Lebach-Steinbach", :area_code => "6888") + AreaCode.create(:country => germany, :name => "Saarbrücken-Ensheim", :area_code => "6893") + AreaCode.create(:country => germany, :name => "St Ingbert", :area_code => "6894") + AreaCode.create(:country => germany, :name => "Sulzbach Saar", :area_code => "6897") + AreaCode.create(:country => germany, :name => "Völklingen", :area_code => "6898") + AreaCode.create(:country => germany, :name => "Frankfurt am Main", :area_code => "69") + AreaCode.create(:country => germany, :name => "Kirchheim unter Teck", :area_code => "7021") + AreaCode.create(:country => germany, :name => "Nürtingen", :area_code => "7022") + AreaCode.create(:country => germany, :name => "Weilheim an der Teck", :area_code => "7023") + AreaCode.create(:country => germany, :name => "Wendlingen am Neckar", :area_code => "7024") + AreaCode.create(:country => germany, :name => "Neuffen", :area_code => "7025") + AreaCode.create(:country => germany, :name => "Lenningen", :area_code => "7026") + AreaCode.create(:country => germany, :name => "Böblingen", :area_code => "7031") + AreaCode.create(:country => germany, :name => "Herrenberg", :area_code => "7032") + AreaCode.create(:country => germany, :name => "Weil Der Stadt", :area_code => "7033") + AreaCode.create(:country => germany, :name => "Ehningen", :area_code => "7034") + AreaCode.create(:country => germany, :name => "Mühlacker", :area_code => "7041") + AreaCode.create(:country => germany, :name => "Vaihingen an der Enz", :area_code => "7042") + AreaCode.create(:country => germany, :name => "Maulbronn", :area_code => "7043") + AreaCode.create(:country => germany, :name => "Mönsheim", :area_code => "7044") + AreaCode.create(:country => germany, :name => "Oberderdingen", :area_code => "7045") + AreaCode.create(:country => germany, :name => "Zaberfeld", :area_code => "7046") + AreaCode.create(:country => germany, :name => "Calw", :area_code => "7051") + AreaCode.create(:country => germany, :name => "Bad Liebenzell", :area_code => "7052") + AreaCode.create(:country => germany, :name => "Bad Teinach-Zavelstein", :area_code => "7053") + AreaCode.create(:country => germany, :name => "Wildberg Württ", :area_code => "7054") + AreaCode.create(:country => germany, :name => "Neuweiler Kr Calw", :area_code => "7055") + AreaCode.create(:country => germany, :name => "Gechingen", :area_code => "7056") + AreaCode.create(:country => germany, :name => "Beilstein Württ", :area_code => "7062") + AreaCode.create(:country => germany, :name => "Bad Wimpfen", :area_code => "7063") + AreaCode.create(:country => germany, :name => "Bad Rappenau-Bonfeld", :area_code => "7066") + AreaCode.create(:country => germany, :name => "Tübingen", :area_code => "7071") + AreaCode.create(:country => germany, :name => "Gomaringen", :area_code => "7072") + AreaCode.create(:country => germany, :name => "Ammerbuch", :area_code => "7073") + AreaCode.create(:country => germany, :name => "Bad Wildbad", :area_code => "7081") + AreaCode.create(:country => germany, :name => "Neuenbürg Württ", :area_code => "7082") + AreaCode.create(:country => germany, :name => "Bad Herrenalb", :area_code => "7083") + AreaCode.create(:country => germany, :name => "Schömberg b Neuenbürg", :area_code => "7084") + AreaCode.create(:country => germany, :name => "Enzklösterle", :area_code => "7085") + AreaCode.create(:country => germany, :name => "Stuttgart", :area_code => "711") + AreaCode.create(:country => germany, :name => "Reutlingen", :area_code => "7121") + AreaCode.create(:country => germany, :name => "St Johann Württ", :area_code => "7122") + AreaCode.create(:country => germany, :name => "Metzingen Württ", :area_code => "7123") + AreaCode.create(:country => germany, :name => "Trochtelfingen Hohenz", :area_code => "7124") + AreaCode.create(:country => germany, :name => "Bad Urach", :area_code => "7125") + AreaCode.create(:country => germany, :name => "Burladingen-Melchingen", :area_code => "7126") + AreaCode.create(:country => germany, :name => "Neckartenzlingen", :area_code => "7127") + AreaCode.create(:country => germany, :name => "Sonnenbühl", :area_code => "7128") + AreaCode.create(:country => germany, :name => "Lichtenstein Württ", :area_code => "7129") + AreaCode.create(:country => germany, :name => "Löwenstein Württ", :area_code => "7130") + AreaCode.create(:country => germany, :name => "Heilbronn Neckar", :area_code => "7131") + AreaCode.create(:country => germany, :name => "Neckarsulm", :area_code => "7132") + AreaCode.create(:country => germany, :name => "Lauffen am Neckar", :area_code => "7133") + AreaCode.create(:country => germany, :name => "Weinsberg", :area_code => "7134") + AreaCode.create(:country => germany, :name => "Brackenheim", :area_code => "7135") + AreaCode.create(:country => germany, :name => "Bad Friedrichshall", :area_code => "7136") + AreaCode.create(:country => germany, :name => "Schwaigern", :area_code => "7138") + AreaCode.create(:country => germany, :name => "Neuenstadt am Kocher", :area_code => "7139") + AreaCode.create(:country => germany, :name => "Ludwigsburg Württ", :area_code => "7141") + AreaCode.create(:country => germany, :name => "Bietigheim-Bissingen", :area_code => "7142") + AreaCode.create(:country => germany, :name => "Besigheim", :area_code => "7143") + AreaCode.create(:country => germany, :name => "Marbach am Neckar", :area_code => "7144") + AreaCode.create(:country => germany, :name => "Markgröningen", :area_code => "7145") + AreaCode.create(:country => germany, :name => "Remseck am Neckar", :area_code => "7146") + AreaCode.create(:country => germany, :name => "Sachsenheim Württ", :area_code => "7147") + AreaCode.create(:country => germany, :name => "Grossbottwar", :area_code => "7148") + AreaCode.create(:country => germany, :name => "Korntal-Münchingen", :area_code => "7150") + AreaCode.create(:country => germany, :name => "Waiblingen", :area_code => "7151") + AreaCode.create(:country => germany, :name => "Leonberg Württ", :area_code => "7152") + AreaCode.create(:country => germany, :name => "Plochingen", :area_code => "7153") + AreaCode.create(:country => germany, :name => "Kornwestheim", :area_code => "7154") + AreaCode.create(:country => germany, :name => "Ditzingen", :area_code => "7156") + AreaCode.create(:country => germany, :name => "Waldenbuch", :area_code => "7157") + AreaCode.create(:country => germany, :name => "Neuhausen auf den Fildern", :area_code => "7158") + AreaCode.create(:country => germany, :name => "Renningen", :area_code => "7159") + AreaCode.create(:country => germany, :name => "Göppingen", :area_code => "7161") + AreaCode.create(:country => germany, :name => "Süßen", :area_code => "7162") + AreaCode.create(:country => germany, :name => "Ebersbach an der Fils", :area_code => "7163") + AreaCode.create(:country => germany, :name => "Boll Kr Göppingen", :area_code => "7164") + AreaCode.create(:country => germany, :name => "Göppingen-Hohenstaufen", :area_code => "7165") + AreaCode.create(:country => germany, :name => "Adelberg", :area_code => "7166") + AreaCode.create(:country => germany, :name => "Schwäbisch Gmünd", :area_code => "7171") + AreaCode.create(:country => germany, :name => "Lorch Württ", :area_code => "7172") + AreaCode.create(:country => germany, :name => "Heubach", :area_code => "7173") + AreaCode.create(:country => germany, :name => "Mögglingen", :area_code => "7174") + AreaCode.create(:country => germany, :name => "Leinzell", :area_code => "7175") + AreaCode.create(:country => germany, :name => "Spraitbach", :area_code => "7176") + AreaCode.create(:country => germany, :name => "Schorndorf Württ", :area_code => "7181") + AreaCode.create(:country => germany, :name => "Welzheim", :area_code => "7182") + AreaCode.create(:country => germany, :name => "Rudersberg Württ", :area_code => "7183") + AreaCode.create(:country => germany, :name => "Kaisersbach", :area_code => "7184") + AreaCode.create(:country => germany, :name => "Backnang", :area_code => "7191") + AreaCode.create(:country => germany, :name => "Murrhardt", :area_code => "7192") + AreaCode.create(:country => germany, :name => "Sulzbach an der Murr", :area_code => "7193") + AreaCode.create(:country => germany, :name => "Spiegelberg", :area_code => "7194") + AreaCode.create(:country => germany, :name => "Winnenden", :area_code => "7195") + AreaCode.create(:country => germany, :name => "Karlsbad", :area_code => "7202") + AreaCode.create(:country => germany, :name => "Walzbachtal", :area_code => "7203") + AreaCode.create(:country => germany, :name => "Malsch-Völkersbach", :area_code => "7204") + AreaCode.create(:country => germany, :name => "Karlsruhe", :area_code => "721") + AreaCode.create(:country => germany, :name => "Forbach-Hundsbach", :area_code => "7220") + AreaCode.create(:country => germany, :name => "Baden-Baden", :area_code => "7221") + AreaCode.create(:country => germany, :name => "Rastatt", :area_code => "7222") + AreaCode.create(:country => germany, :name => "Bühl Baden", :area_code => "7223") + AreaCode.create(:country => germany, :name => "Gernsbach", :area_code => "7224") + AreaCode.create(:country => germany, :name => "Gaggenau", :area_code => "7225") + AreaCode.create(:country => germany, :name => "Bühl-Sand", :area_code => "7226") + AreaCode.create(:country => germany, :name => "Lichtenau Baden", :area_code => "7227") + AreaCode.create(:country => germany, :name => "Forbach", :area_code => "7228") + AreaCode.create(:country => germany, :name => "Iffezheim", :area_code => "7229") + AreaCode.create(:country => germany, :name => "Pforzheim", :area_code => "7231") + AreaCode.create(:country => germany, :name => "Königsbach-Stein", :area_code => "7232") + AreaCode.create(:country => germany, :name => "Niefern-Öschelbronn", :area_code => "7233") + AreaCode.create(:country => germany, :name => "Tiefenbronn", :area_code => "7234") + AreaCode.create(:country => germany, :name => "Unterreichenbach Kr Calw", :area_code => "7235") + AreaCode.create(:country => germany, :name => "Keltern", :area_code => "7236") + AreaCode.create(:country => germany, :name => "Neulingen Enzkreis", :area_code => "7237") + AreaCode.create(:country => germany, :name => "Pfinztal", :area_code => "7240") + AreaCode.create(:country => germany, :name => "Rheinstetten", :area_code => "7242") + AreaCode.create(:country => germany, :name => "Ettlingen", :area_code => "7243") + AreaCode.create(:country => germany, :name => "Weingarten Baden", :area_code => "7244") + AreaCode.create(:country => germany, :name => "Durmersheim", :area_code => "7245") + AreaCode.create(:country => germany, :name => "Malsch Kr Karlsruhe", :area_code => "7246") + AreaCode.create(:country => germany, :name => "Linkenheim-Hochstetten", :area_code => "7247") + AreaCode.create(:country => germany, :name => "Marxzell", :area_code => "7248") + AreaCode.create(:country => germany, :name => "Stutensee", :area_code => "7249") + AreaCode.create(:country => germany, :name => "Kraichtal", :area_code => "7250") + AreaCode.create(:country => germany, :name => "Bruchsal", :area_code => "7251") + AreaCode.create(:country => germany, :name => "Bretten", :area_code => "7252") + AreaCode.create(:country => germany, :name => "Bad Schönborn", :area_code => "7253") + AreaCode.create(:country => germany, :name => "Waghäusel", :area_code => "7254") + AreaCode.create(:country => germany, :name => "Graben-Neudorf", :area_code => "7255") + AreaCode.create(:country => germany, :name => "Philippsburg", :area_code => "7256") + AreaCode.create(:country => germany, :name => "Bruchsal-Untergrombach", :area_code => "7257") + AreaCode.create(:country => germany, :name => "Oberderdingen-Flehingen", :area_code => "7258") + AreaCode.create(:country => germany, :name => "Östringen-Odenheim", :area_code => "7259") + AreaCode.create(:country => germany, :name => "Sinsheim-Hilsbach", :area_code => "7260") + AreaCode.create(:country => germany, :name => "Sinsheim", :area_code => "7261") + AreaCode.create(:country => germany, :name => "Eppingen", :area_code => "7262") + AreaCode.create(:country => germany, :name => "Waibstadt", :area_code => "7263") + AreaCode.create(:country => germany, :name => "Bad Rappenau", :area_code => "7264") + AreaCode.create(:country => germany, :name => "Angelbachtal", :area_code => "7265") + AreaCode.create(:country => germany, :name => "Kirchardt", :area_code => "7266") + AreaCode.create(:country => germany, :name => "Gemmingen", :area_code => "7267") + AreaCode.create(:country => germany, :name => "Bad Rappenau-Obergimpern", :area_code => "7268") + AreaCode.create(:country => germany, :name => "Sulzfeld Baden", :area_code => "7269") + AreaCode.create(:country => germany, :name => "Wörth am Rhein", :area_code => "7271") + AreaCode.create(:country => germany, :name => "Rülzheim", :area_code => "7272") + AreaCode.create(:country => germany, :name => "Hagenbach Pfalz", :area_code => "7273") + AreaCode.create(:country => germany, :name => "Germersheim", :area_code => "7274") + AreaCode.create(:country => germany, :name => "Kandel", :area_code => "7275") + AreaCode.create(:country => germany, :name => "Herxheim bei Landau Pfalz", :area_code => "7276") + AreaCode.create(:country => germany, :name => "Wörth-Büchelberg", :area_code => "7277") + AreaCode.create(:country => germany, :name => "Roggenburg", :area_code => "7300") + AreaCode.create(:country => germany, :name => "Pfaffenhofen a d Roth", :area_code => "7302") + AreaCode.create(:country => germany, :name => "Illertissen", :area_code => "7303") + AreaCode.create(:country => germany, :name => "Blaustein Württ", :area_code => "7304") + AreaCode.create(:country => germany, :name => "Erbach Donau", :area_code => "7305") + AreaCode.create(:country => germany, :name => "Vöhringen Iller", :area_code => "7306") + AreaCode.create(:country => germany, :name => "Senden Iller", :area_code => "7307") + AreaCode.create(:country => germany, :name => "Nersingen", :area_code => "7308") + AreaCode.create(:country => germany, :name => "Weissenhorn", :area_code => "7309") + AreaCode.create(:country => germany, :name => "Ulm Donau", :area_code => "731") + AreaCode.create(:country => germany, :name => "Heidenheim a d Brenz", :area_code => "7321") + AreaCode.create(:country => germany, :name => "Giengen a d Brenz", :area_code => "7322") + AreaCode.create(:country => germany, :name => "Gerstetten", :area_code => "7323") + AreaCode.create(:country => germany, :name => "Herbrechtingen", :area_code => "7324") + AreaCode.create(:country => germany, :name => "Sontheim a d Brenz", :area_code => "7325") + AreaCode.create(:country => germany, :name => "Neresheim", :area_code => "7326") + AreaCode.create(:country => germany, :name => "Dischingen", :area_code => "7327") + AreaCode.create(:country => germany, :name => "Königsbronn", :area_code => "7328") + AreaCode.create(:country => germany, :name => "Steinheim am Albuch", :area_code => "7329") + AreaCode.create(:country => germany, :name => "Geislingen an der Steige", :area_code => "7331") + AreaCode.create(:country => germany, :name => "Lauterstein", :area_code => "7332") + AreaCode.create(:country => germany, :name => "Laichingen", :area_code => "7333") + AreaCode.create(:country => germany, :name => "Deggingen", :area_code => "7334") + AreaCode.create(:country => germany, :name => "Wiesensteig", :area_code => "7335") + AreaCode.create(:country => germany, :name => "Lonsee", :area_code => "7336") + AreaCode.create(:country => germany, :name => "Nellingen Alb", :area_code => "7337") + AreaCode.create(:country => germany, :name => "Neenstetten", :area_code => "7340") + AreaCode.create(:country => germany, :name => "Buch b Illertissen", :area_code => "7343") + AreaCode.create(:country => germany, :name => "Blaubeuren", :area_code => "7344") + AreaCode.create(:country => germany, :name => "Langenau Württ", :area_code => "7345") + AreaCode.create(:country => germany, :name => "Illerkirchberg", :area_code => "7346") + AreaCode.create(:country => germany, :name => "Dietenheim", :area_code => "7347") + AreaCode.create(:country => germany, :name => "Beimerstetten", :area_code => "7348") + AreaCode.create(:country => germany, :name => "Biberach an der Riß", :area_code => "7351") + AreaCode.create(:country => germany, :name => "Ochsenhausen", :area_code => "7352") + AreaCode.create(:country => germany, :name => "Schwendi", :area_code => "7353") + AreaCode.create(:country => germany, :name => "Erolzheim", :area_code => "7354") + AreaCode.create(:country => germany, :name => "Hochdorf Riß", :area_code => "7355") + AreaCode.create(:country => germany, :name => "Schemmerhofen", :area_code => "7356") + AreaCode.create(:country => germany, :name => "Attenweiler", :area_code => "7357") + AreaCode.create(:country => germany, :name => "Eberhardzell-Füramoos", :area_code => "7358") + AreaCode.create(:country => germany, :name => "Aalen", :area_code => "7361") + AreaCode.create(:country => germany, :name => "Bopfingen", :area_code => "7362") + AreaCode.create(:country => germany, :name => "Lauchheim", :area_code => "7363") + AreaCode.create(:country => germany, :name => "Oberkochen", :area_code => "7364") + AreaCode.create(:country => germany, :name => "Essingen Württ", :area_code => "7365") + AreaCode.create(:country => germany, :name => "Abtsgmünd", :area_code => "7366") + AreaCode.create(:country => germany, :name => "Aalen-Ebnat", :area_code => "7367") + AreaCode.create(:country => germany, :name => "Riedlingen Württ", :area_code => "7371") + AreaCode.create(:country => germany, :name => "Zwiefalten", :area_code => "7373") + AreaCode.create(:country => germany, :name => "Uttenweiler", :area_code => "7374") + AreaCode.create(:country => germany, :name => "Obermarchtal", :area_code => "7375") + AreaCode.create(:country => germany, :name => "Langenenslingen", :area_code => "7376") + AreaCode.create(:country => germany, :name => "Münsingen", :area_code => "7381") + AreaCode.create(:country => germany, :name => "Römerstein", :area_code => "7382") + AreaCode.create(:country => germany, :name => "Münsingen-Buttenhausen", :area_code => "7383") + AreaCode.create(:country => germany, :name => "Schelklingen-Hütten", :area_code => "7384") + AreaCode.create(:country => germany, :name => "Gomadingen", :area_code => "7385") + AreaCode.create(:country => germany, :name => "Hayingen", :area_code => "7386") + AreaCode.create(:country => germany, :name => "Hohenstein Württ", :area_code => "7387") + AreaCode.create(:country => germany, :name => "Pfronstetten", :area_code => "7388") + AreaCode.create(:country => germany, :name => "Heroldstatt", :area_code => "7389") + AreaCode.create(:country => germany, :name => "Ehingen Donau", :area_code => "7391") + AreaCode.create(:country => germany, :name => "Laupheim", :area_code => "7392") + AreaCode.create(:country => germany, :name => "Munderkingen", :area_code => "7393") + AreaCode.create(:country => germany, :name => "Schelklingen", :area_code => "7394") + AreaCode.create(:country => germany, :name => "Ehingen-Dächingen", :area_code => "7395") + AreaCode.create(:country => germany, :name => "Fluorn-Winzeln", :area_code => "7402") + AreaCode.create(:country => germany, :name => "Dunningen", :area_code => "7403") + AreaCode.create(:country => germany, :name => "Epfendorf", :area_code => "7404") + AreaCode.create(:country => germany, :name => "Rottweil", :area_code => "741") + AreaCode.create(:country => germany, :name => "Deisslingen", :area_code => "7420") + AreaCode.create(:country => germany, :name => "Schramberg", :area_code => "7422") + AreaCode.create(:country => germany, :name => "Oberndorf am Neckar", :area_code => "7423") + AreaCode.create(:country => germany, :name => "Spaichingen", :area_code => "7424") + AreaCode.create(:country => germany, :name => "Trossingen", :area_code => "7425") + AreaCode.create(:country => germany, :name => "Gosheim", :area_code => "7426") + AreaCode.create(:country => germany, :name => "Schömberg b Balingen", :area_code => "7427") + AreaCode.create(:country => germany, :name => "Rosenfeld", :area_code => "7428") + AreaCode.create(:country => germany, :name => "Egesheim", :area_code => "7429") + AreaCode.create(:country => germany, :name => "Albstadt-Ebingen", :area_code => "7431") + AreaCode.create(:country => germany, :name => "Albstadt-Tailfingen", :area_code => "7432") + AreaCode.create(:country => germany, :name => "Balingen", :area_code => "7433") + AreaCode.create(:country => germany, :name => "Winterlingen", :area_code => "7434") + AreaCode.create(:country => germany, :name => "Albstadt-Laufen", :area_code => "7435") + AreaCode.create(:country => germany, :name => "Messstetten-Oberdigisheim", :area_code => "7436") + AreaCode.create(:country => germany, :name => "Bad Rippoldsau", :area_code => "7440") + AreaCode.create(:country => germany, :name => "Freudenstadt", :area_code => "7441") + AreaCode.create(:country => germany, :name => "Baiersbronn", :area_code => "7442") + AreaCode.create(:country => germany, :name => "Dornstetten", :area_code => "7443") + AreaCode.create(:country => germany, :name => "Alpirsbach", :area_code => "7444") + AreaCode.create(:country => germany, :name => "Pfalzgrafenweiler", :area_code => "7445") + AreaCode.create(:country => germany, :name => "Lossburg", :area_code => "7446") + AreaCode.create(:country => germany, :name => "Baiersbronn-Schwarzenberg", :area_code => "7447") + AreaCode.create(:country => germany, :name => "Seewald", :area_code => "7448") + AreaCode.create(:country => germany, :name => "Baiersbronn-Obertal", :area_code => "7449") + AreaCode.create(:country => germany, :name => "Horb am Neckar", :area_code => "7451") + AreaCode.create(:country => germany, :name => "Nagold", :area_code => "7452") + AreaCode.create(:country => germany, :name => "Altensteig Württ", :area_code => "7453") + AreaCode.create(:country => germany, :name => "Sulz am Neckar", :area_code => "7454") + AreaCode.create(:country => germany, :name => "Dornhan", :area_code => "7455") + AreaCode.create(:country => germany, :name => "Haiterbach", :area_code => "7456") + AreaCode.create(:country => germany, :name => "Rottenburg-Ergenzingen", :area_code => "7457") + AreaCode.create(:country => germany, :name => "Ebhausen", :area_code => "7458") + AreaCode.create(:country => germany, :name => "Nagold-Hochdorf", :area_code => "7459") + AreaCode.create(:country => germany, :name => "Tuttlingen", :area_code => "7461") + AreaCode.create(:country => germany, :name => "Immendingen", :area_code => "7462") + AreaCode.create(:country => germany, :name => "Mühlheim an der Donau", :area_code => "7463") + AreaCode.create(:country => germany, :name => "Talheim Kr Tuttlingen", :area_code => "7464") + AreaCode.create(:country => germany, :name => "Emmingen-Liptingen", :area_code => "7465") + AreaCode.create(:country => germany, :name => "Beuron", :area_code => "7466") + AreaCode.create(:country => germany, :name => "Neuhausen ob Eck", :area_code => "7467") + AreaCode.create(:country => germany, :name => "Hechingen", :area_code => "7471") + AreaCode.create(:country => germany, :name => "Rottenburg am Neckar", :area_code => "7472") + AreaCode.create(:country => germany, :name => "Mössingen", :area_code => "7473") + AreaCode.create(:country => germany, :name => "Haigerloch", :area_code => "7474") + AreaCode.create(:country => germany, :name => "Burladingen", :area_code => "7475") + AreaCode.create(:country => germany, :name => "Bisingen", :area_code => "7476") + AreaCode.create(:country => germany, :name => "Jungingen b Hechingen", :area_code => "7477") + AreaCode.create(:country => germany, :name => "Hirrlingen", :area_code => "7478") + AreaCode.create(:country => germany, :name => "Horb-Dettingen", :area_code => "7482") + AreaCode.create(:country => germany, :name => "Horb-Mühringen", :area_code => "7483") + AreaCode.create(:country => germany, :name => "Simmersfeld", :area_code => "7484") + AreaCode.create(:country => germany, :name => "Empfingen", :area_code => "7485") + AreaCode.create(:country => germany, :name => "Horb-Altheim", :area_code => "7486") + AreaCode.create(:country => germany, :name => "Wolpertswende", :area_code => "7502") + AreaCode.create(:country => germany, :name => "Wilhelmsdorf Württ", :area_code => "7503") + AreaCode.create(:country => germany, :name => "Horgenzell", :area_code => "7504") + AreaCode.create(:country => germany, :name => "Fronreute", :area_code => "7505") + AreaCode.create(:country => germany, :name => "Wangen-Leupolz", :area_code => "7506") + AreaCode.create(:country => germany, :name => "Ravensburg", :area_code => "751") + AreaCode.create(:country => germany, :name => "Bodnegg", :area_code => "7520") + AreaCode.create(:country => germany, :name => "Wangen im Allgäu", :area_code => "7522") + AreaCode.create(:country => germany, :name => "Bad Waldsee", :area_code => "7524") + AreaCode.create(:country => germany, :name => "Aulendorf", :area_code => "7525") + AreaCode.create(:country => germany, :name => "Wolfegg", :area_code => "7527") + AreaCode.create(:country => germany, :name => "Neukirch b Tettnang", :area_code => "7528") + AreaCode.create(:country => germany, :name => "Waldburg Württ", :area_code => "7529") + AreaCode.create(:country => germany, :name => "Konstanz", :area_code => "7531") + AreaCode.create(:country => germany, :name => "Meersburg", :area_code => "7532") + AreaCode.create(:country => germany, :name => "Allensbach", :area_code => "7533") + AreaCode.create(:country => germany, :name => "Reichenau Baden", :area_code => "7534") + AreaCode.create(:country => germany, :name => "Friedrichshafen", :area_code => "7541") + AreaCode.create(:country => germany, :name => "Tettnang", :area_code => "7542") + AreaCode.create(:country => germany, :name => "Kressbronn am Bodensee", :area_code => "7543") + AreaCode.create(:country => germany, :name => "Markdorf", :area_code => "7544") + AreaCode.create(:country => germany, :name => "Immenstaad am Bodensee", :area_code => "7545") + AreaCode.create(:country => germany, :name => "Oberteuringen", :area_code => "7546") + AreaCode.create(:country => germany, :name => "Überlingen Bodensee", :area_code => "7551") + AreaCode.create(:country => germany, :name => "Pfullendorf", :area_code => "7552") + AreaCode.create(:country => germany, :name => "Salem Baden", :area_code => "7553") + AreaCode.create(:country => germany, :name => "Heiligenberg Baden", :area_code => "7554") + AreaCode.create(:country => germany, :name => "Deggenhausertal", :area_code => "7555") + AreaCode.create(:country => germany, :name => "Uhldingen-Mühlhofen", :area_code => "7556") + AreaCode.create(:country => germany, :name => "Herdwangen-Schönach", :area_code => "7557") + AreaCode.create(:country => germany, :name => "Illmensee", :area_code => "7558") + AreaCode.create(:country => germany, :name => "Leutkirch im Allgäu", :area_code => "7561") + AreaCode.create(:country => germany, :name => "Isny im Allgäu", :area_code => "7562") + AreaCode.create(:country => germany, :name => "Kisslegg", :area_code => "7563") + AreaCode.create(:country => germany, :name => "Bad Wurzach", :area_code => "7564") + AreaCode.create(:country => germany, :name => "Aichstetten Kr Ravensburg", :area_code => "7565") + AreaCode.create(:country => germany, :name => "Argenbühl", :area_code => "7566") + AreaCode.create(:country => germany, :name => "Leutkirch-Friesenhofen", :area_code => "7567") + AreaCode.create(:country => germany, :name => "Bad Wurzach-Hauerz", :area_code => "7568") + AreaCode.create(:country => germany, :name => "Isny-Eisenbach", :area_code => "7569") + AreaCode.create(:country => germany, :name => "Sigmaringen-Gutenstein", :area_code => "7570") + AreaCode.create(:country => germany, :name => "Sigmaringen", :area_code => "7571") + AreaCode.create(:country => germany, :name => "Mengen Württ", :area_code => "7572") + AreaCode.create(:country => germany, :name => "Stetten am kalten Markt", :area_code => "7573") + AreaCode.create(:country => germany, :name => "Gammertingen", :area_code => "7574") + AreaCode.create(:country => germany, :name => "Messkirch", :area_code => "7575") + AreaCode.create(:country => germany, :name => "Krauchenwies", :area_code => "7576") + AreaCode.create(:country => germany, :name => "Veringenstadt", :area_code => "7577") + AreaCode.create(:country => germany, :name => "Wald Hohenz", :area_code => "7578") + AreaCode.create(:country => germany, :name => "Schwenningen Baden", :area_code => "7579") + AreaCode.create(:country => germany, :name => "Saulgau", :area_code => "7581") + AreaCode.create(:country => germany, :name => "Bad Buchau", :area_code => "7582") + AreaCode.create(:country => germany, :name => "Bad Schussenried", :area_code => "7583") + AreaCode.create(:country => germany, :name => "Altshausen", :area_code => "7584") + AreaCode.create(:country => germany, :name => "Ostrach", :area_code => "7585") + AreaCode.create(:country => germany, :name => "Herbertingen", :area_code => "7586") + AreaCode.create(:country => germany, :name => "Hosskirch", :area_code => "7587") + AreaCode.create(:country => germany, :name => "Oberried Breisgau", :area_code => "7602") + AreaCode.create(:country => germany, :name => "Freiburg im Breisgau", :area_code => "761") + AreaCode.create(:country => germany, :name => "Schopfheim-Gersbach", :area_code => "7620") + AreaCode.create(:country => germany, :name => "Lörrach", :area_code => "7621") + AreaCode.create(:country => germany, :name => "Schopfheim", :area_code => "7622") + AreaCode.create(:country => germany, :name => "Rheinfelden Baden", :area_code => "7623") + AreaCode.create(:country => germany, :name => "Grenzach-Wyhlen", :area_code => "7624") + AreaCode.create(:country => germany, :name => "Zell im Wiesental", :area_code => "7625") + AreaCode.create(:country => germany, :name => "Kandern", :area_code => "7626") + AreaCode.create(:country => germany, :name => "Steinen Kr Lörrach", :area_code => "7627") + AreaCode.create(:country => germany, :name => "Efringen-Kirchen", :area_code => "7628") + AreaCode.create(:country => germany, :name => "Tegernau Baden", :area_code => "7629") + AreaCode.create(:country => germany, :name => "Müllheim Baden", :area_code => "7631") + AreaCode.create(:country => germany, :name => "Badenweiler", :area_code => "7632") + AreaCode.create(:country => germany, :name => "Staufen im Breisgau", :area_code => "7633") + AreaCode.create(:country => germany, :name => "Sulzburg", :area_code => "7634") + AreaCode.create(:country => germany, :name => "Schliengen", :area_code => "7635") + AreaCode.create(:country => germany, :name => "Münstertal Schwarzwald", :area_code => "7636") + AreaCode.create(:country => germany, :name => "Emmendingen", :area_code => "7641") + AreaCode.create(:country => germany, :name => "Endingen Kaiserstuh", :area_code => "7642") + AreaCode.create(:country => germany, :name => "Herbolzheim Breisgau", :area_code => "7643") + AreaCode.create(:country => germany, :name => "Kenzingen", :area_code => "7644") + AreaCode.create(:country => germany, :name => "Freiamt", :area_code => "7645") + AreaCode.create(:country => germany, :name => "Weisweil Breisgau", :area_code => "7646") + AreaCode.create(:country => germany, :name => "Titisee-Neustadt", :area_code => "7651") + AreaCode.create(:country => germany, :name => "Hinterzarten", :area_code => "7652") + AreaCode.create(:country => germany, :name => "Lenzkirch", :area_code => "7653") + AreaCode.create(:country => germany, :name => "Löffingen", :area_code => "7654") + AreaCode.create(:country => germany, :name => "Feldberg-Altglashütten", :area_code => "7655") + AreaCode.create(:country => germany, :name => "Schluchsee", :area_code => "7656") + AreaCode.create(:country => germany, :name => "Eisenbach Hochschwarzwald", :area_code => "7657") + AreaCode.create(:country => germany, :name => "St Peter Schwarzw", :area_code => "7660") + AreaCode.create(:country => germany, :name => "Kirchzarten", :area_code => "7661") + AreaCode.create(:country => germany, :name => "Vogtsburg im Kaiserstuh", :area_code => "7662") + AreaCode.create(:country => germany, :name => "Eichstetten", :area_code => "7663") + AreaCode.create(:country => germany, :name => "Freiburg-Tiengen", :area_code => "7664") + AreaCode.create(:country => germany, :name => "March Breisgau", :area_code => "7665") + AreaCode.create(:country => germany, :name => "Denzlingen", :area_code => "7666") + AreaCode.create(:country => germany, :name => "Breisach am Rhein", :area_code => "7667") + AreaCode.create(:country => germany, :name => "Ihringen", :area_code => "7668") + AreaCode.create(:country => germany, :name => "St Märgen", :area_code => "7669") + AreaCode.create(:country => germany, :name => "Todtnau", :area_code => "7671") + AreaCode.create(:country => germany, :name => "St Blasien", :area_code => "7672") + AreaCode.create(:country => germany, :name => "Schönau im Schwarzwald", :area_code => "7673") + AreaCode.create(:country => germany, :name => "Todtmoos", :area_code => "7674") + AreaCode.create(:country => germany, :name => "Bernau Baden", :area_code => "7675") + AreaCode.create(:country => germany, :name => "Feldberg Schwarzwald", :area_code => "7676") + AreaCode.create(:country => germany, :name => "Waldkirch Breisgau", :area_code => "7681") + AreaCode.create(:country => germany, :name => "Elzach", :area_code => "7682") + AreaCode.create(:country => germany, :name => "Simonswald", :area_code => "7683") + AreaCode.create(:country => germany, :name => "Glottertal", :area_code => "7684") + AreaCode.create(:country => germany, :name => "Gutach-Bleibach", :area_code => "7685") + AreaCode.create(:country => germany, :name => "Blumberg Baden", :area_code => "7702") + AreaCode.create(:country => germany, :name => "Bonndorf im Schwarzwald", :area_code => "7703") + AreaCode.create(:country => germany, :name => "Geisingen Baden", :area_code => "7704") + AreaCode.create(:country => germany, :name => "Wolterdingen Schwarzw", :area_code => "7705") + AreaCode.create(:country => germany, :name => "Oberbaldingen", :area_code => "7706") + AreaCode.create(:country => germany, :name => "Bräunlingen", :area_code => "7707") + AreaCode.create(:country => germany, :name => "Geisingen-Leipferdingen", :area_code => "7708") + AreaCode.create(:country => germany, :name => "Wutach", :area_code => "7709") + AreaCode.create(:country => germany, :name => "Donaueschingen", :area_code => "771") + AreaCode.create(:country => germany, :name => "Schwenningen a Neckar", :area_code => "7720") + AreaCode.create(:country => germany, :name => "Villingen i Schwarzw", :area_code => "7721") + AreaCode.create(:country => germany, :name => "Triberg im Schwarzwald", :area_code => "7722") + AreaCode.create(:country => germany, :name => "Furtwangen im Schwarzwald", :area_code => "7723") + AreaCode.create(:country => germany, :name => "St Georgen im Schwarzwald", :area_code => "7724") + AreaCode.create(:country => germany, :name => "Königsfeld im Schwarzwald", :area_code => "7725") + AreaCode.create(:country => germany, :name => "Bad Dürrheim", :area_code => "7726") + AreaCode.create(:country => germany, :name => "Vöhrenbach", :area_code => "7727") + AreaCode.create(:country => germany, :name => "Niedereschach", :area_code => "7728") + AreaCode.create(:country => germany, :name => "Tennenbronn", :area_code => "7729") + AreaCode.create(:country => germany, :name => "Singen Hohentwiel", :area_code => "7731") + AreaCode.create(:country => germany, :name => "Radolfzell am Bodensee", :area_code => "7732") + AreaCode.create(:country => germany, :name => "Engen Hegau", :area_code => "7733") + AreaCode.create(:country => germany, :name => "Gailingen", :area_code => "7734") + AreaCode.create(:country => germany, :name => "Öhningen", :area_code => "7735") + AreaCode.create(:country => germany, :name => "Tengen", :area_code => "7736") + AreaCode.create(:country => germany, :name => "Steisslingen", :area_code => "7738") + AreaCode.create(:country => germany, :name => "Hilzingen", :area_code => "7739") + AreaCode.create(:country => germany, :name => "Tiengen Hochrhein", :area_code => "7741") + AreaCode.create(:country => germany, :name => "Klettgau", :area_code => "7742") + AreaCode.create(:country => germany, :name => "Ühlingen-Birkendorf", :area_code => "7743") + AreaCode.create(:country => germany, :name => "Stühlingen", :area_code => "7744") + AreaCode.create(:country => germany, :name => "Jestetten", :area_code => "7745") + AreaCode.create(:country => germany, :name => "Wutöschingen", :area_code => "7746") + AreaCode.create(:country => germany, :name => "Berau", :area_code => "7747") + AreaCode.create(:country => germany, :name => "Grafenhausen Hochschwarzw", :area_code => "7748") + AreaCode.create(:country => germany, :name => "Waldshut", :area_code => "7751") + AreaCode.create(:country => germany, :name => "Albbruck", :area_code => "7753") + AreaCode.create(:country => germany, :name => "Görwihl", :area_code => "7754") + AreaCode.create(:country => germany, :name => "Weilheim Kr Waldshut", :area_code => "7755") + AreaCode.create(:country => germany, :name => "Bad Säckingen", :area_code => "7761") + AreaCode.create(:country => germany, :name => "Wehr Baden", :area_code => "7762") + AreaCode.create(:country => germany, :name => "Murg", :area_code => "7763") + AreaCode.create(:country => germany, :name => "Herrischried", :area_code => "7764") + AreaCode.create(:country => germany, :name => "Rickenbach Hotzenw", :area_code => "7765") + AreaCode.create(:country => germany, :name => "Stockach", :area_code => "7771") + AreaCode.create(:country => germany, :name => "Bodman-Ludwigshafen", :area_code => "7773") + AreaCode.create(:country => germany, :name => "Eigeltingen", :area_code => "7774") + AreaCode.create(:country => germany, :name => "Mühlingen", :area_code => "7775") + AreaCode.create(:country => germany, :name => "Sauldorf", :area_code => "7777") + AreaCode.create(:country => germany, :name => "Oberkirch Baden", :area_code => "7802") + AreaCode.create(:country => germany, :name => "Gengenbach", :area_code => "7803") + AreaCode.create(:country => germany, :name => "Oppenau", :area_code => "7804") + AreaCode.create(:country => germany, :name => "Appenweier", :area_code => "7805") + AreaCode.create(:country => germany, :name => "Bad Peterstal-Griesbach", :area_code => "7806") + AreaCode.create(:country => germany, :name => "Neuried Ortenaukreis", :area_code => "7807") + AreaCode.create(:country => germany, :name => "Hohberg b Offenburg", :area_code => "7808") + AreaCode.create(:country => germany, :name => "Offenburg", :area_code => "781") + AreaCode.create(:country => germany, :name => "Lahr Schwarzwald", :area_code => "7821") + AreaCode.create(:country => germany, :name => "Ettenheim", :area_code => "7822") + AreaCode.create(:country => germany, :name => "Seelbach Schutter", :area_code => "7823") + AreaCode.create(:country => germany, :name => "Schwanau", :area_code => "7824") + AreaCode.create(:country => germany, :name => "Kippenheim", :area_code => "7825") + AreaCode.create(:country => germany, :name => "Schuttertal", :area_code => "7826") + AreaCode.create(:country => germany, :name => "Hausach", :area_code => "7831") + AreaCode.create(:country => germany, :name => "Haslach im Kinzigtal", :area_code => "7832") + AreaCode.create(:country => germany, :name => "Hornberg Schwarzwaldbahn", :area_code => "7833") + AreaCode.create(:country => germany, :name => "Wolfach", :area_code => "7834") + AreaCode.create(:country => germany, :name => "Zell am Harmersbach", :area_code => "7835") + AreaCode.create(:country => germany, :name => "Schiltach", :area_code => "7836") + AreaCode.create(:country => germany, :name => "Oberharmersbach", :area_code => "7837") + AreaCode.create(:country => germany, :name => "Nordrach", :area_code => "7838") + AreaCode.create(:country => germany, :name => "Schapbach", :area_code => "7839") + AreaCode.create(:country => germany, :name => "Achern", :area_code => "7841") + AreaCode.create(:country => germany, :name => "Kappelrodeck", :area_code => "7842") + AreaCode.create(:country => germany, :name => "Renchen", :area_code => "7843") + AreaCode.create(:country => germany, :name => "Rheinau", :area_code => "7844") + AreaCode.create(:country => germany, :name => "Kehl", :area_code => "7851") + AreaCode.create(:country => germany, :name => "Willstätt", :area_code => "7852") + AreaCode.create(:country => germany, :name => "Kehl-Bodersweier", :area_code => "7853") + AreaCode.create(:country => germany, :name => "Kehl-Goldscheuer", :area_code => "7854") + AreaCode.create(:country => germany, :name => "Mainhardt", :area_code => "7903") + AreaCode.create(:country => germany, :name => "Ilshofen", :area_code => "7904") + AreaCode.create(:country => germany, :name => "Langenburg", :area_code => "7905") + AreaCode.create(:country => germany, :name => "Braunsbach", :area_code => "7906") + AreaCode.create(:country => germany, :name => "Schwäbisch Hall-Sulzdorf", :area_code => "7907") + AreaCode.create(:country => germany, :name => "Schwäbisch Hall", :area_code => "791") + AreaCode.create(:country => germany, :name => "Boxberg Baden", :area_code => "7930") + AreaCode.create(:country => germany, :name => "Bad Mergentheim", :area_code => "7931") + AreaCode.create(:country => germany, :name => "Niederstetten Württ", :area_code => "7932") + AreaCode.create(:country => germany, :name => "Creglingen", :area_code => "7933") + AreaCode.create(:country => germany, :name => "Weikersheim", :area_code => "7934") + AreaCode.create(:country => germany, :name => "Schrozberg", :area_code => "7935") + AreaCode.create(:country => germany, :name => "Schrozberg-Bartenstein", :area_code => "7936") + AreaCode.create(:country => germany, :name => "Dörzbach", :area_code => "7937") + AreaCode.create(:country => germany, :name => "Mulfingen Jagst", :area_code => "7938") + AreaCode.create(:country => germany, :name => "Schrozberg-Spielbach", :area_code => "7939") + AreaCode.create(:country => germany, :name => "Künzelsau", :area_code => "7940") + AreaCode.create(:country => germany, :name => "Öhringen", :area_code => "7941") + AreaCode.create(:country => germany, :name => "Neuenstein Württ", :area_code => "7942") + AreaCode.create(:country => germany, :name => "Schöntal Jagst", :area_code => "7943") + AreaCode.create(:country => germany, :name => "Kupferzell", :area_code => "7944") + AreaCode.create(:country => germany, :name => "Wüstenrot", :area_code => "7945") + AreaCode.create(:country => germany, :name => "Bretzfeld", :area_code => "7946") + AreaCode.create(:country => germany, :name => "Forchtenberg", :area_code => "7947") + AreaCode.create(:country => germany, :name => "Öhringen-Ohrnberg", :area_code => "7948") + AreaCode.create(:country => germany, :name => "Pfedelbach-Untersteinbach", :area_code => "7949") + AreaCode.create(:country => germany, :name => "Schnelldorf", :area_code => "7950") + AreaCode.create(:country => germany, :name => "Crailsheim", :area_code => "7951") + AreaCode.create(:country => germany, :name => "Gerabronn", :area_code => "7952") + AreaCode.create(:country => germany, :name => "Blaufelden", :area_code => "7953") + AreaCode.create(:country => germany, :name => "Kirchberg an der Jagst", :area_code => "7954") + AreaCode.create(:country => germany, :name => "Wallhausen Württ", :area_code => "7955") + AreaCode.create(:country => germany, :name => "Kressberg", :area_code => "7957") + AreaCode.create(:country => germany, :name => "Rot Am See-Brettheim", :area_code => "7958") + AreaCode.create(:country => germany, :name => "Frankenhardt", :area_code => "7959") + AreaCode.create(:country => germany, :name => "Ellwangen Jagst", :area_code => "7961") + AreaCode.create(:country => germany, :name => "Fichtenau", :area_code => "7962") + AreaCode.create(:country => germany, :name => "Adelmannsfelden", :area_code => "7963") + AreaCode.create(:country => germany, :name => "Stödtlen", :area_code => "7964") + AreaCode.create(:country => germany, :name => "Ellwangen-Röhlingen", :area_code => "7965") + AreaCode.create(:country => germany, :name => "Unterschneidheim", :area_code => "7966") + AreaCode.create(:country => germany, :name => "Jagstzell", :area_code => "7967") + AreaCode.create(:country => germany, :name => "Gaildorf", :area_code => "7971") + AreaCode.create(:country => germany, :name => "Gschwend b Gaildorf", :area_code => "7972") + AreaCode.create(:country => germany, :name => "Obersontheim", :area_code => "7973") + AreaCode.create(:country => germany, :name => "Bühlerzell", :area_code => "7974") + AreaCode.create(:country => germany, :name => "Untergröningen", :area_code => "7975") + AreaCode.create(:country => germany, :name => "Sulzbach-Laufen", :area_code => "7976") + AreaCode.create(:country => germany, :name => "Oberrot b Gaildorf", :area_code => "7977") + AreaCode.create(:country => germany, :name => "Weyarn", :area_code => "8020") + AreaCode.create(:country => germany, :name => "Waakirchen", :area_code => "8021") + AreaCode.create(:country => germany, :name => "Tegernsee", :area_code => "8022") + AreaCode.create(:country => germany, :name => "Bayrischzell", :area_code => "8023") + AreaCode.create(:country => germany, :name => "Holzkirchen", :area_code => "8024") + AreaCode.create(:country => germany, :name => "Miesbach", :area_code => "8025") + AreaCode.create(:country => germany, :name => "Hausham", :area_code => "8026") + AreaCode.create(:country => germany, :name => "Dietramszell", :area_code => "8027") + AreaCode.create(:country => germany, :name => "Fischbachau", :area_code => "8028") + AreaCode.create(:country => germany, :name => "Kreuth b Tegernsee", :area_code => "8029") + AreaCode.create(:country => germany, :name => "Rosenheim Oberbay", :area_code => "8031") + AreaCode.create(:country => germany, :name => "Rohrdorf Kr Rosenheim", :area_code => "8032") + AreaCode.create(:country => germany, :name => "Oberaudorf", :area_code => "8033") + AreaCode.create(:country => germany, :name => "Brannenburg", :area_code => "8034") + AreaCode.create(:country => germany, :name => "Raubling", :area_code => "8035") + AreaCode.create(:country => germany, :name => "Stephanskirchen Simssee", :area_code => "8036") + AreaCode.create(:country => germany, :name => "Vogtareuth", :area_code => "8038") + AreaCode.create(:country => germany, :name => "Rott a Inn", :area_code => "8039") + AreaCode.create(:country => germany, :name => "Bad Tölz", :area_code => "8041") + AreaCode.create(:country => germany, :name => "Lenggries", :area_code => "8042") + AreaCode.create(:country => germany, :name => "Jachenau", :area_code => "8043") + AreaCode.create(:country => germany, :name => "Lenggries-Fall", :area_code => "8045") + AreaCode.create(:country => germany, :name => "Bad Heilbrunn", :area_code => "8046") + AreaCode.create(:country => germany, :name => "Prien a Chiemsee", :area_code => "8051") + AreaCode.create(:country => germany, :name => "Aschau i Chiemgau", :area_code => "8052") + AreaCode.create(:country => germany, :name => "Bad Endorf", :area_code => "8053") + AreaCode.create(:country => germany, :name => "Breitbrunn a Chiemsee", :area_code => "8054") + AreaCode.create(:country => germany, :name => "Halfing", :area_code => "8055") + AreaCode.create(:country => germany, :name => "Eggstätt", :area_code => "8056") + AreaCode.create(:country => germany, :name => "Aschau-Sachrang", :area_code => "8057") + AreaCode.create(:country => germany, :name => "Bad Aibling", :area_code => "8061") + AreaCode.create(:country => germany, :name => "Bruckmühl Mangfall", :area_code => "8062") + AreaCode.create(:country => germany, :name => "Feldkirchen-Westerham", :area_code => "8063") + AreaCode.create(:country => germany, :name => "Au b Bad Aibling", :area_code => "8064") + AreaCode.create(:country => germany, :name => "Tuntenhausen-Schönau", :area_code => "8065") + AreaCode.create(:country => germany, :name => "Bad Feilnbach", :area_code => "8066") + AreaCode.create(:country => germany, :name => "Tuntenhausen", :area_code => "8067") + AreaCode.create(:country => germany, :name => "Wasserburg a Inn", :area_code => "8071") + AreaCode.create(:country => germany, :name => "Haag i OB", :area_code => "8072") + AreaCode.create(:country => germany, :name => "Gars a Inn", :area_code => "8073") + AreaCode.create(:country => germany, :name => "Schnaitsee", :area_code => "8074") + AreaCode.create(:country => germany, :name => "Amerang", :area_code => "8075") + AreaCode.create(:country => germany, :name => "Pfaffing", :area_code => "8076") + AreaCode.create(:country => germany, :name => "Dorfen Stadt", :area_code => "8081") + AreaCode.create(:country => germany, :name => "Schwindegg", :area_code => "8082") + AreaCode.create(:country => germany, :name => "Isen", :area_code => "8083") + AreaCode.create(:country => germany, :name => "Taufkirchen Vils", :area_code => "8084") + AreaCode.create(:country => germany, :name => "Sankt Wolfgang", :area_code => "8085") + AreaCode.create(:country => germany, :name => "Buchbach Oberbay", :area_code => "8086") + AreaCode.create(:country => germany, :name => "Kirchseeon", :area_code => "8091") + AreaCode.create(:country => germany, :name => "Grafing b München", :area_code => "8092") + AreaCode.create(:country => germany, :name => "Glonn Kr Ebersberg", :area_code => "8093") + AreaCode.create(:country => germany, :name => "Steinhöring", :area_code => "8094") + AreaCode.create(:country => germany, :name => "Aying", :area_code => "8095") + AreaCode.create(:country => germany, :name => "Höhenkirchen-Siegertsbrunn", :area_code => "8102") + AreaCode.create(:country => germany, :name => "Sauerlach", :area_code => "8104") + AreaCode.create(:country => germany, :name => "Gilching", :area_code => "8105") + AreaCode.create(:country => germany, :name => "Vaterstetten", :area_code => "8106") + AreaCode.create(:country => germany, :name => "Hallbergmoos", :area_code => "811") + AreaCode.create(:country => germany, :name => "Markt Schwaben", :area_code => "8121") + AreaCode.create(:country => germany, :name => "Erding", :area_code => "8122") + AreaCode.create(:country => germany, :name => "Moosinning", :area_code => "8123") + AreaCode.create(:country => germany, :name => "Forstern Oberbay", :area_code => "8124") + AreaCode.create(:country => germany, :name => "Dachau", :area_code => "8131") + AreaCode.create(:country => germany, :name => "Haimhausen Oberbay", :area_code => "8133") + AreaCode.create(:country => germany, :name => "Odelzhausen", :area_code => "8134") + AreaCode.create(:country => germany, :name => "Sulzemoos", :area_code => "8135") + AreaCode.create(:country => germany, :name => "Markt Indersdorf", :area_code => "8136") + AreaCode.create(:country => germany, :name => "Petershausen", :area_code => "8137") + AreaCode.create(:country => germany, :name => "Schwabhausen b Dachau", :area_code => "8138") + AreaCode.create(:country => germany, :name => "Röhrmoos", :area_code => "8139") + AreaCode.create(:country => germany, :name => "Fürstenfeldbruck", :area_code => "8141") + AreaCode.create(:country => germany, :name => "Olching", :area_code => "8142") + AreaCode.create(:country => germany, :name => "Inning a Ammersee", :area_code => "8143") + AreaCode.create(:country => germany, :name => "Grafrath", :area_code => "8144") + AreaCode.create(:country => germany, :name => "Mammendorf", :area_code => "8145") + AreaCode.create(:country => germany, :name => "Moorenweis", :area_code => "8146") + AreaCode.create(:country => germany, :name => "Starnberg", :area_code => "8151") + AreaCode.create(:country => germany, :name => "Herrsching a Ammersee", :area_code => "8152") + AreaCode.create(:country => germany, :name => "Wessling", :area_code => "8153") + AreaCode.create(:country => germany, :name => "Feldafing", :area_code => "8157") + AreaCode.create(:country => germany, :name => "Tutzing", :area_code => "8158") + AreaCode.create(:country => germany, :name => "Freising", :area_code => "8161") + AreaCode.create(:country => germany, :name => "Neufahrn b Freising", :area_code => "8165") + AreaCode.create(:country => germany, :name => "Allershausen Oberbay", :area_code => "8166") + AreaCode.create(:country => germany, :name => "Zolling", :area_code => "8167") + AreaCode.create(:country => germany, :name => "Attenkirchen", :area_code => "8168") + AreaCode.create(:country => germany, :name => "Straßlach-Dingharting", :area_code => "8170") + AreaCode.create(:country => germany, :name => "Wolfratshausen", :area_code => "8171") + AreaCode.create(:country => germany, :name => "Egling b Wolfratshausen", :area_code => "8176") + AreaCode.create(:country => germany, :name => "Münsing Starnberger See", :area_code => "8177") + AreaCode.create(:country => germany, :name => "Icking", :area_code => "8178") + AreaCode.create(:country => germany, :name => "Eurasburg a d Loisach", :area_code => "8179") + AreaCode.create(:country => germany, :name => "Landsberg a Lech", :area_code => "8191") + AreaCode.create(:country => germany, :name => "Schondorf a Ammersee", :area_code => "8192") + AreaCode.create(:country => germany, :name => "Geltendorf", :area_code => "8193") + AreaCode.create(:country => germany, :name => "Vilgertshofen", :area_code => "8194") + AreaCode.create(:country => germany, :name => "Weil Kr Landsberg a Lech", :area_code => "8195") + AreaCode.create(:country => germany, :name => "Pürgen", :area_code => "8196") + AreaCode.create(:country => germany, :name => "Althegnenberg", :area_code => "8202") + AreaCode.create(:country => germany, :name => "Grossaitingen", :area_code => "8203") + AreaCode.create(:country => germany, :name => "Mickhausen", :area_code => "8204") + AreaCode.create(:country => germany, :name => "Dasing", :area_code => "8205") + AreaCode.create(:country => germany, :name => "Egling a d Paar", :area_code => "8206") + AreaCode.create(:country => germany, :name => "Affing", :area_code => "8207") + AreaCode.create(:country => germany, :name => "Eurasburg b Augsburg", :area_code => "8208") + AreaCode.create(:country => germany, :name => "Augsburg", :area_code => "821") + AreaCode.create(:country => germany, :name => "Günzburg", :area_code => "8221") + AreaCode.create(:country => germany, :name => "Burgau Schwab", :area_code => "8222") + AreaCode.create(:country => germany, :name => "Ichenhausen", :area_code => "8223") + AreaCode.create(:country => germany, :name => "Offingen Donau", :area_code => "8224") + AreaCode.create(:country => germany, :name => "Jettingen-Scheppach", :area_code => "8225") + AreaCode.create(:country => germany, :name => "Bibertal", :area_code => "8226") + AreaCode.create(:country => germany, :name => "Gablingen", :area_code => "8230") + AreaCode.create(:country => germany, :name => "Königsbrunn b Augsburg", :area_code => "8231") + AreaCode.create(:country => germany, :name => "Schwabmünchen", :area_code => "8232") + AreaCode.create(:country => germany, :name => "Kissing", :area_code => "8233") + AreaCode.create(:country => germany, :name => "Bobingen", :area_code => "8234") + AreaCode.create(:country => germany, :name => "Fischach", :area_code => "8236") + AreaCode.create(:country => germany, :name => "Aindling", :area_code => "8237") + AreaCode.create(:country => germany, :name => "Gessertshausen", :area_code => "8238") + AreaCode.create(:country => germany, :name => "Langenneufnach", :area_code => "8239") + AreaCode.create(:country => germany, :name => "Buchloe", :area_code => "8241") + AreaCode.create(:country => germany, :name => "Fuchstal", :area_code => "8243") + AreaCode.create(:country => germany, :name => "Türkheim Wertach", :area_code => "8245") + AreaCode.create(:country => germany, :name => "Waal", :area_code => "8246") + AreaCode.create(:country => germany, :name => "Bad Wörishofen", :area_code => "8247") + AreaCode.create(:country => germany, :name => "Lamerdingen", :area_code => "8248") + AreaCode.create(:country => germany, :name => "Ettringen Wertach", :area_code => "8249") + AreaCode.create(:country => germany, :name => "Hilgertshausen-Tandern", :area_code => "8250") + AreaCode.create(:country => germany, :name => "Aichach", :area_code => "8251") + AreaCode.create(:country => germany, :name => "Schrobenhausen", :area_code => "8252") + AreaCode.create(:country => germany, :name => "Pöttmes", :area_code => "8253") + AreaCode.create(:country => germany, :name => "Altomünster", :area_code => "8254") + AreaCode.create(:country => germany, :name => "Inchenhofen", :area_code => "8257") + AreaCode.create(:country => germany, :name => "Sielenbach", :area_code => "8258") + AreaCode.create(:country => germany, :name => "Schiltberg", :area_code => "8259") + AreaCode.create(:country => germany, :name => "Mindelheim", :area_code => "8261") + AreaCode.create(:country => germany, :name => "Mittelneufnach", :area_code => "8262") + AreaCode.create(:country => germany, :name => "Breitenbrunn Schwab", :area_code => "8263") + AreaCode.create(:country => germany, :name => "Pfaffenhausen Schwab", :area_code => "8265") + AreaCode.create(:country => germany, :name => "Kirchheim i Schw", :area_code => "8266") + AreaCode.create(:country => germany, :name => "Dirlewang", :area_code => "8267") + AreaCode.create(:country => germany, :name => "Tussenhausen", :area_code => "8268") + AreaCode.create(:country => germany, :name => "Unteregg b Mindelheim", :area_code => "8269") + AreaCode.create(:country => germany, :name => "Meitingen", :area_code => "8271") + AreaCode.create(:country => germany, :name => "Wertingen", :area_code => "8272") + AreaCode.create(:country => germany, :name => "Nordendorf", :area_code => "8273") + AreaCode.create(:country => germany, :name => "Buttenwiesen", :area_code => "8274") + AreaCode.create(:country => germany, :name => "Baar Schwaben", :area_code => "8276") + AreaCode.create(:country => germany, :name => "Thannhausen Schwab", :area_code => "8281") + AreaCode.create(:country => germany, :name => "Krumbach Schwaben", :area_code => "8282") + AreaCode.create(:country => germany, :name => "Neuburg a d Kammel", :area_code => "8283") + AreaCode.create(:country => germany, :name => "Ziemetshausen", :area_code => "8284") + AreaCode.create(:country => germany, :name => "Burtenbach", :area_code => "8285") + AreaCode.create(:country => germany, :name => "Zusmarshausen", :area_code => "8291") + AreaCode.create(:country => germany, :name => "Dinkelscherben", :area_code => "8292") + AreaCode.create(:country => germany, :name => "Welden b Augsburg", :area_code => "8293") + AreaCode.create(:country => germany, :name => "Horgau", :area_code => "8294") + AreaCode.create(:country => germany, :name => "Altenmünster Schwab", :area_code => "8295") + AreaCode.create(:country => germany, :name => "Villenbach", :area_code => "8296") + AreaCode.create(:country => germany, :name => "Görisried", :area_code => "8302") + AreaCode.create(:country => germany, :name => "Waltenhofen", :area_code => "8303") + AreaCode.create(:country => germany, :name => "Wildpoldsried", :area_code => "8304") + AreaCode.create(:country => germany, :name => "Ronsberg", :area_code => "8306") + AreaCode.create(:country => germany, :name => "Kempten Allgäu", :area_code => "831") + AreaCode.create(:country => germany, :name => "Missen-Wilhams", :area_code => "8320") + AreaCode.create(:country => germany, :name => "Sonthofen", :area_code => "8321") + AreaCode.create(:country => germany, :name => "Oberstdorf", :area_code => "8322") + AreaCode.create(:country => germany, :name => "Immenstadt i Allgäu", :area_code => "8323") + AreaCode.create(:country => germany, :name => "Hindelang", :area_code => "8324") + AreaCode.create(:country => germany, :name => "Oberstaufen-Thalkirchdorf", :area_code => "8325") + AreaCode.create(:country => germany, :name => "Fischen i Allgäu", :area_code => "8326") + AreaCode.create(:country => germany, :name => "Rettenberg", :area_code => "8327") + AreaCode.create(:country => germany, :name => "Balderschwang", :area_code => "8328") + AreaCode.create(:country => germany, :name => "Riezlern (Österreich)", :area_code => "8329") + AreaCode.create(:country => germany, :name => "Legau", :area_code => "8330") + AreaCode.create(:country => germany, :name => "Memmingen", :area_code => "8331") + AreaCode.create(:country => germany, :name => "Ottobeuren", :area_code => "8332") + AreaCode.create(:country => germany, :name => "Babenhausen Schwab", :area_code => "8333") + AreaCode.create(:country => germany, :name => "Bad Grönenbach", :area_code => "8334") + AreaCode.create(:country => germany, :name => "Fellheim", :area_code => "8335") + AreaCode.create(:country => germany, :name => "Erkheim", :area_code => "8336") + AreaCode.create(:country => germany, :name => "Altenstadt Iller", :area_code => "8337") + AreaCode.create(:country => germany, :name => "Böhen", :area_code => "8338") + AreaCode.create(:country => germany, :name => "Baisweil", :area_code => "8340") + AreaCode.create(:country => germany, :name => "Kaufbeuren", :area_code => "8341") + AreaCode.create(:country => germany, :name => "Marktoberdorf", :area_code => "8342") + AreaCode.create(:country => germany, :name => "Aitrang", :area_code => "8343") + AreaCode.create(:country => germany, :name => "Westendorf b Kaufbeuren", :area_code => "8344") + AreaCode.create(:country => germany, :name => "Stöttwang", :area_code => "8345") + AreaCode.create(:country => germany, :name => "Pforzen", :area_code => "8346") + AreaCode.create(:country => germany, :name => "Friesenried", :area_code => "8347") + AreaCode.create(:country => germany, :name => "Bidingen", :area_code => "8348") + AreaCode.create(:country => germany, :name => "Stötten a Auerberg", :area_code => "8349") + AreaCode.create(:country => germany, :name => "Nesselwang", :area_code => "8361") + AreaCode.create(:country => germany, :name => "Füssen", :area_code => "8362") + AreaCode.create(:country => germany, :name => "Pfronten", :area_code => "8363") + AreaCode.create(:country => germany, :name => "Seeg", :area_code => "8364") + AreaCode.create(:country => germany, :name => "Wertach", :area_code => "8365") + AreaCode.create(:country => germany, :name => "Oy-Mittelberg", :area_code => "8366") + AreaCode.create(:country => germany, :name => "Roßhaupten Forggensee", :area_code => "8367") + AreaCode.create(:country => germany, :name => "Halblech", :area_code => "8368") + AreaCode.create(:country => germany, :name => "Rückholz", :area_code => "8369") + AreaCode.create(:country => germany, :name => "Wiggensbach", :area_code => "8370") + AreaCode.create(:country => germany, :name => "Obergünzburg", :area_code => "8372") + AreaCode.create(:country => germany, :name => "Altusried", :area_code => "8373") + AreaCode.create(:country => germany, :name => "Dietmannsried", :area_code => "8374") + AreaCode.create(:country => germany, :name => "Weitnau", :area_code => "8375") + AreaCode.create(:country => germany, :name => "Sulzberg Allgäu", :area_code => "8376") + AreaCode.create(:country => germany, :name => "Unterthingau", :area_code => "8377") + AreaCode.create(:country => germany, :name => "Buchenberg b Kempten", :area_code => "8378") + AreaCode.create(:country => germany, :name => "Waltenhofen-Oberdorf", :area_code => "8379") + AreaCode.create(:country => germany, :name => "Achberg", :area_code => "8380") + AreaCode.create(:country => germany, :name => "Lindenberg i Allgäu", :area_code => "8381") + AreaCode.create(:country => germany, :name => "Lindau Bodensee", :area_code => "8382") + AreaCode.create(:country => germany, :name => "Grünenbach Allgäu", :area_code => "8383") + AreaCode.create(:country => germany, :name => "Röthenbach Allgäu", :area_code => "8384") + AreaCode.create(:country => germany, :name => "Hergatz", :area_code => "8385") + AreaCode.create(:country => germany, :name => "Oberstaufen", :area_code => "8386") + AreaCode.create(:country => germany, :name => "Weiler-Simmerberg", :area_code => "8387") + AreaCode.create(:country => germany, :name => "Hergensweiler", :area_code => "8388") + AreaCode.create(:country => germany, :name => "Weissensberg", :area_code => "8389") + AreaCode.create(:country => germany, :name => "Markt Rettenbach", :area_code => "8392") + AreaCode.create(:country => germany, :name => "Holzgünz", :area_code => "8393") + AreaCode.create(:country => germany, :name => "Lautrach", :area_code => "8394") + AreaCode.create(:country => germany, :name => "Tannheim Württ", :area_code => "8395") + AreaCode.create(:country => germany, :name => "Münchsmünster", :area_code => "8402") + AreaCode.create(:country => germany, :name => "Pförring", :area_code => "8403") + AreaCode.create(:country => germany, :name => "Oberdolling", :area_code => "8404") + AreaCode.create(:country => germany, :name => "Stammham b Ingolstadt", :area_code => "8405") + AreaCode.create(:country => germany, :name => "Böhmfeld", :area_code => "8406") + AreaCode.create(:country => germany, :name => "Grossmehring", :area_code => "8407") + AreaCode.create(:country => germany, :name => "Ingolstadt Donau", :area_code => "841") + AreaCode.create(:country => germany, :name => "Eichstätt Bay", :area_code => "8421") + AreaCode.create(:country => germany, :name => "Dollnstein", :area_code => "8422") + AreaCode.create(:country => germany, :name => "Titting", :area_code => "8423") + AreaCode.create(:country => germany, :name => "Nassenfels", :area_code => "8424") + AreaCode.create(:country => germany, :name => "Walting Kr Eichstätt", :area_code => "8426") + AreaCode.create(:country => germany, :name => "Wellheim", :area_code => "8427") + AreaCode.create(:country => germany, :name => "Neuburg a d Donau", :area_code => "8431") + AreaCode.create(:country => germany, :name => "Burgheim", :area_code => "8432") + AreaCode.create(:country => germany, :name => "Königsmoos", :area_code => "8433") + AreaCode.create(:country => germany, :name => "Rennertshofen", :area_code => "8434") + AreaCode.create(:country => germany, :name => "Ehekirchen", :area_code => "8435") + AreaCode.create(:country => germany, :name => "Pfaffenhofen a d Ilm", :area_code => "8441") + AreaCode.create(:country => germany, :name => "Wolnzach", :area_code => "8442") + AreaCode.create(:country => germany, :name => "Hohenwart Paar", :area_code => "8443") + AreaCode.create(:country => germany, :name => "Schweitenkirchen", :area_code => "8444") + AreaCode.create(:country => germany, :name => "Gerolsbach", :area_code => "8445") + AreaCode.create(:country => germany, :name => "Pörnbach", :area_code => "8446") + AreaCode.create(:country => germany, :name => "Ingolstadt-Zuchering", :area_code => "8450") + AreaCode.create(:country => germany, :name => "Geisenfeld", :area_code => "8452") + AreaCode.create(:country => germany, :name => "Reichertshofen Oberbay", :area_code => "8453") + AreaCode.create(:country => germany, :name => "Karlshuld", :area_code => "8454") + AreaCode.create(:country => germany, :name => "Lenting", :area_code => "8456") + AreaCode.create(:country => germany, :name => "Vohburg a d Donau", :area_code => "8457") + AreaCode.create(:country => germany, :name => "Gaimersheim", :area_code => "8458") + AreaCode.create(:country => germany, :name => "Manching", :area_code => "8459") + AreaCode.create(:country => germany, :name => "Berching-Holnstein", :area_code => "8460") + AreaCode.create(:country => germany, :name => "Beilngries", :area_code => "8461") + AreaCode.create(:country => germany, :name => "Berching", :area_code => "8462") + AreaCode.create(:country => germany, :name => "Greding", :area_code => "8463") + AreaCode.create(:country => germany, :name => "Dietfurt a d Altmühl", :area_code => "8464") + AreaCode.create(:country => germany, :name => "Kipfenberg", :area_code => "8465") + AreaCode.create(:country => germany, :name => "Denkendorf Oberbay", :area_code => "8466") + AreaCode.create(:country => germany, :name => "Kinding", :area_code => "8467") + AreaCode.create(:country => germany, :name => "Altmannstein-Pondorf", :area_code => "8468") + AreaCode.create(:country => germany, :name => "Freystadt-Burggriesbach", :area_code => "8469") + AreaCode.create(:country => germany, :name => "Thyrnau", :area_code => "8501") + AreaCode.create(:country => germany, :name => "Fürstenzell", :area_code => "8502") + AreaCode.create(:country => germany, :name => "Neuhaus a Inn", :area_code => "8503") + AreaCode.create(:country => germany, :name => "Tittling", :area_code => "8504") + AreaCode.create(:country => germany, :name => "Hutthurm", :area_code => "8505") + AreaCode.create(:country => germany, :name => "Bad Höhenstadt", :area_code => "8506") + AreaCode.create(:country => germany, :name => "Neuburg a Inn", :area_code => "8507") + AreaCode.create(:country => germany, :name => "Ruderting", :area_code => "8509") + AreaCode.create(:country => germany, :name => "Passau", :area_code => "851") + AreaCode.create(:country => germany, :name => "Pocking", :area_code => "8531") + AreaCode.create(:country => germany, :name => "Griesbach i Rottal", :area_code => "8532") + AreaCode.create(:country => germany, :name => "Rotthalmünster", :area_code => "8533") + AreaCode.create(:country => germany, :name => "Tettenweis", :area_code => "8534") + AreaCode.create(:country => germany, :name => "Haarbach", :area_code => "8535") + AreaCode.create(:country => germany, :name => "Kößlarn", :area_code => "8536") + AreaCode.create(:country => germany, :name => "Bad Füssing-Aigen", :area_code => "8537") + AreaCode.create(:country => germany, :name => "Pocking-Hartkirchen", :area_code => "8538") + AreaCode.create(:country => germany, :name => "Vilshofen Niederbay", :area_code => "8541") + AreaCode.create(:country => germany, :name => "Ortenburg", :area_code => "8542") + AreaCode.create(:country => germany, :name => "Aidenbach", :area_code => "8543") + AreaCode.create(:country => germany, :name => "Eging a See", :area_code => "8544") + AreaCode.create(:country => germany, :name => "Hofkirchen Bay", :area_code => "8545") + AreaCode.create(:country => germany, :name => "Windorf-Otterskirchen", :area_code => "8546") + AreaCode.create(:country => germany, :name => "Osterhofen-Gergweis", :area_code => "8547") + AreaCode.create(:country => germany, :name => "Vilshofen-Sandbach", :area_code => "8548") + AreaCode.create(:country => germany, :name => "Vilshofen-Pleinting", :area_code => "8549") + AreaCode.create(:country => germany, :name => "Philippsreut", :area_code => "8550") + AreaCode.create(:country => germany, :name => "Freyung", :area_code => "8551") + AreaCode.create(:country => germany, :name => "Grafenau Niederbay", :area_code => "8552") + AreaCode.create(:country => germany, :name => "Spiegelau", :area_code => "8553") + AreaCode.create(:country => germany, :name => "Schönberg Niederbay", :area_code => "8554") + AreaCode.create(:country => germany, :name => "Perlesreut", :area_code => "8555") + AreaCode.create(:country => germany, :name => "Haidmühle", :area_code => "8556") + AreaCode.create(:country => germany, :name => "Mauth", :area_code => "8557") + AreaCode.create(:country => germany, :name => "Hohenau Niederbay", :area_code => "8558") + AreaCode.create(:country => germany, :name => "Pfarrkirchen Niederbay", :area_code => "8561") + AreaCode.create(:country => germany, :name => "Triftern", :area_code => "8562") + AreaCode.create(:country => germany, :name => "Bad Birnbach Rottal", :area_code => "8563") + AreaCode.create(:country => germany, :name => "Johanniskirchen", :area_code => "8564") + AreaCode.create(:country => germany, :name => "Dietersburg-Baumgarten", :area_code => "8565") + AreaCode.create(:country => germany, :name => "Simbach a Inn", :area_code => "8571") + AreaCode.create(:country => germany, :name => "Tann Niederbay", :area_code => "8572") + AreaCode.create(:country => germany, :name => "Ering", :area_code => "8573") + AreaCode.create(:country => germany, :name => "Wittibreut", :area_code => "8574") + AreaCode.create(:country => germany, :name => "Waldkirchen Niederbay", :area_code => "8581") + AreaCode.create(:country => germany, :name => "Röhrnbach", :area_code => "8582") + AreaCode.create(:country => germany, :name => "Neureichenau", :area_code => "8583") + AreaCode.create(:country => germany, :name => "Breitenberg Niederbay", :area_code => "8584") + AreaCode.create(:country => germany, :name => "Grainet", :area_code => "8585") + AreaCode.create(:country => germany, :name => "Hauzenberg", :area_code => "8586") + AreaCode.create(:country => germany, :name => "Obernzell", :area_code => "8591") + AreaCode.create(:country => germany, :name => "Wegscheid Niederbay", :area_code => "8592") + AreaCode.create(:country => germany, :name => "Untergriesbach", :area_code => "8593") + AreaCode.create(:country => germany, :name => "Traunstein", :area_code => "861") + AreaCode.create(:country => germany, :name => "Trostberg", :area_code => "8621") + AreaCode.create(:country => germany, :name => "Tacherting- Peterskirchen", :area_code => "8622") + AreaCode.create(:country => germany, :name => "Kirchweidach", :area_code => "8623") + AreaCode.create(:country => germany, :name => "Obing", :area_code => "8624") + AreaCode.create(:country => germany, :name => "Kienberg Oberbay", :area_code => "8628") + AreaCode.create(:country => germany, :name => "Palling", :area_code => "8629") + AreaCode.create(:country => germany, :name => "Oberneukirchen", :area_code => "8630") + AreaCode.create(:country => germany, :name => "Mühldorf a Inn", :area_code => "8631") + AreaCode.create(:country => germany, :name => "Tüßling", :area_code => "8633") + AreaCode.create(:country => germany, :name => "Garching a d Alz", :area_code => "8634") + AreaCode.create(:country => germany, :name => "Pleiskirchen", :area_code => "8635") + AreaCode.create(:country => germany, :name => "Ampfing", :area_code => "8636") + AreaCode.create(:country => germany, :name => "Lohkirchen", :area_code => "8637") + AreaCode.create(:country => germany, :name => "Waldkraiburg", :area_code => "8638") + AreaCode.create(:country => germany, :name => "Neumarkt-Sankt Veit", :area_code => "8639") + AreaCode.create(:country => germany, :name => "Reit Im Winkl", :area_code => "8640") + AreaCode.create(:country => germany, :name => "Grassau Kr Traunstein", :area_code => "8641") + AreaCode.create(:country => germany, :name => "Übersee", :area_code => "8642") + AreaCode.create(:country => germany, :name => "Schleching", :area_code => "8649") + AreaCode.create(:country => germany, :name => "Marktschellenberg", :area_code => "8650") + AreaCode.create(:country => germany, :name => "Bad Reichenhall", :area_code => "8651") + AreaCode.create(:country => germany, :name => "Berchtesgaden", :area_code => "8652") + AreaCode.create(:country => germany, :name => "Freilassing", :area_code => "8654") + AreaCode.create(:country => germany, :name => "Anger", :area_code => "8656") + AreaCode.create(:country => germany, :name => "Ramsau b Berchtesgaden", :area_code => "8657") + AreaCode.create(:country => germany, :name => "Grabenstätt Chiemsee", :area_code => "8661") + AreaCode.create(:country => germany, :name => "Siegsdorf Kr Traunstein", :area_code => "8662") + AreaCode.create(:country => germany, :name => "Ruhpolding", :area_code => "8663") + AreaCode.create(:country => germany, :name => "Chieming", :area_code => "8664") + AreaCode.create(:country => germany, :name => "Inzell", :area_code => "8665") + AreaCode.create(:country => germany, :name => "Teisendorf", :area_code => "8666") + AreaCode.create(:country => germany, :name => "Seeon-Seebruck", :area_code => "8667") + AreaCode.create(:country => germany, :name => "Traunreut", :area_code => "8669") + AreaCode.create(:country => germany, :name => "Reischach Kr Altötting", :area_code => "8670") + AreaCode.create(:country => germany, :name => "Altötting", :area_code => "8671") + AreaCode.create(:country => germany, :name => "Burghausen Salzach", :area_code => "8677") + AreaCode.create(:country => germany, :name => "Marktl", :area_code => "8678") + AreaCode.create(:country => germany, :name => "Burgkirchen a d Alz", :area_code => "8679") + AreaCode.create(:country => germany, :name => "Waging a See", :area_code => "8681") + AreaCode.create(:country => germany, :name => "Laufen Salzach", :area_code => "8682") + AreaCode.create(:country => germany, :name => "Tittmoning", :area_code => "8683") + AreaCode.create(:country => germany, :name => "Fridolfing", :area_code => "8684") + AreaCode.create(:country => germany, :name => "Kirchanschöring", :area_code => "8685") + AreaCode.create(:country => germany, :name => "Petting", :area_code => "8686") + AreaCode.create(:country => germany, :name => "Taching-Tengling", :area_code => "8687") + AreaCode.create(:country => germany, :name => "Wörth a d Isar", :area_code => "8702") + AreaCode.create(:country => germany, :name => "Essenbach", :area_code => "8703") + AreaCode.create(:country => germany, :name => "Altdorf-Pfettrach", :area_code => "8704") + AreaCode.create(:country => germany, :name => "Altfraunhofen", :area_code => "8705") + AreaCode.create(:country => germany, :name => "Vilsheim", :area_code => "8706") + AreaCode.create(:country => germany, :name => "Adlkofen", :area_code => "8707") + AreaCode.create(:country => germany, :name => "Weihmichl-Unterneuhausen", :area_code => "8708") + AreaCode.create(:country => germany, :name => "Eching Niederbay", :area_code => "8709") + AreaCode.create(:country => germany, :name => "Landshut", :area_code => "871") + AreaCode.create(:country => germany, :name => "Eggenfelden", :area_code => "8721") + AreaCode.create(:country => germany, :name => "Gangkofen", :area_code => "8722") + AreaCode.create(:country => germany, :name => "Arnstorf", :area_code => "8723") + AreaCode.create(:country => germany, :name => "Massing", :area_code => "8724") + AreaCode.create(:country => germany, :name => "Wurmannsquick", :area_code => "8725") + AreaCode.create(:country => germany, :name => "Schönau Niederbay", :area_code => "8726") + AreaCode.create(:country => germany, :name => "Falkenberg Niederbay", :area_code => "8727") + AreaCode.create(:country => germany, :name => "Geratskirchen", :area_code => "8728") + AreaCode.create(:country => germany, :name => "Dingolfing", :area_code => "8731") + AreaCode.create(:country => germany, :name => "Frontenhausen", :area_code => "8732") + AreaCode.create(:country => germany, :name => "Mengkofen", :area_code => "8733") + AreaCode.create(:country => germany, :name => "Reisbach Niederbay", :area_code => "8734") + AreaCode.create(:country => germany, :name => "Gangkofen-Kollbach", :area_code => "8735") + AreaCode.create(:country => germany, :name => "Vilsbiburg", :area_code => "8741") + AreaCode.create(:country => germany, :name => "Velden Vils", :area_code => "8742") + AreaCode.create(:country => germany, :name => "Geisenhausen", :area_code => "8743") + AreaCode.create(:country => germany, :name => "Gerzen", :area_code => "8744") + AreaCode.create(:country => germany, :name => "Bodenkirchen", :area_code => "8745") + AreaCode.create(:country => germany, :name => "Mainburg", :area_code => "8751") + AreaCode.create(:country => germany, :name => "Au i d Hallertau", :area_code => "8752") + AreaCode.create(:country => germany, :name => "Elsendorf Niederbay", :area_code => "8753") + AreaCode.create(:country => germany, :name => "Volkenschwand", :area_code => "8754") + AreaCode.create(:country => germany, :name => "Nandlstadt", :area_code => "8756") + AreaCode.create(:country => germany, :name => "Moosburg a d Isar", :area_code => "8761") + AreaCode.create(:country => germany, :name => "Wartenberg Oberbay", :area_code => "8762") + AreaCode.create(:country => germany, :name => "Mauern Kr Freising", :area_code => "8764") + AreaCode.create(:country => germany, :name => "Bruckberg Niederbay", :area_code => "8765") + AreaCode.create(:country => germany, :name => "Gammelsdorf", :area_code => "8766") + AreaCode.create(:country => germany, :name => "Ergoldsbach", :area_code => "8771") + AreaCode.create(:country => germany, :name => "Mallersdorf-Pfaffenberg", :area_code => "8772") + AreaCode.create(:country => germany, :name => "Neufahrn i NB", :area_code => "8773") + AreaCode.create(:country => germany, :name => "Bayerbach b Ergoldsbach", :area_code => "8774") + AreaCode.create(:country => germany, :name => "Rottenburg a d Laaber", :area_code => "8781") + AreaCode.create(:country => germany, :name => "Pfeffenhausen", :area_code => "8782") + AreaCode.create(:country => germany, :name => "Rohr i NB", :area_code => "8783") + AreaCode.create(:country => germany, :name => "Hohenthann", :area_code => "8784") + AreaCode.create(:country => germany, :name => "Rottenburg-Oberroning", :area_code => "8785") + AreaCode.create(:country => germany, :name => "Seeshaupt", :area_code => "8801") + AreaCode.create(:country => germany, :name => "Huglfing", :area_code => "8802") + AreaCode.create(:country => germany, :name => "Peissenberg", :area_code => "8803") + AreaCode.create(:country => germany, :name => "Hohenpeissenberg", :area_code => "8805") + AreaCode.create(:country => germany, :name => "Utting a Ammersee", :area_code => "8806") + AreaCode.create(:country => germany, :name => "Dießen a Ammersee", :area_code => "8807") + AreaCode.create(:country => germany, :name => "Pähl", :area_code => "8808") + AreaCode.create(:country => germany, :name => "Wessobrunn", :area_code => "8809") + AreaCode.create(:country => germany, :name => "Weilheim i OB", :area_code => "881") + AreaCode.create(:country => germany, :name => "Garmisch-Partenkirchen", :area_code => "8821") + AreaCode.create(:country => germany, :name => "Oberammergau", :area_code => "8822") + AreaCode.create(:country => germany, :name => "Mittenwald", :area_code => "8823") + AreaCode.create(:country => germany, :name => "Oberau Loisach", :area_code => "8824") + AreaCode.create(:country => germany, :name => "Krün", :area_code => "8825") + AreaCode.create(:country => germany, :name => "Murnau a Staffelsee", :area_code => "8841") + AreaCode.create(:country => germany, :name => "Bad Kohlgrub", :area_code => "8845") + AreaCode.create(:country => germany, :name => "Uffing a Staffelsee", :area_code => "8846") + AreaCode.create(:country => germany, :name => "Obersöchering", :area_code => "8847") + AreaCode.create(:country => germany, :name => "Kochel a See", :area_code => "8851") + AreaCode.create(:country => germany, :name => "Penzberg", :area_code => "8856") + AreaCode.create(:country => germany, :name => "Benediktbeuern", :area_code => "8857") + AreaCode.create(:country => germany, :name => "Kochel-Walchensee", :area_code => "8858") + AreaCode.create(:country => germany, :name => "Bernbeuren", :area_code => "8860") + AreaCode.create(:country => germany, :name => "Schongau", :area_code => "8861") + AreaCode.create(:country => germany, :name => "Steingaden Oberbay", :area_code => "8862") + AreaCode.create(:country => germany, :name => "Rottenbuch Oberbay", :area_code => "8867") + AreaCode.create(:country => germany, :name => "Schwabsoien", :area_code => "8868") + AreaCode.create(:country => germany, :name => "Kinsau", :area_code => "8869") + AreaCode.create(:country => germany, :name => "München", :area_code => "89") + AreaCode.create(:country => germany, :name => "Donauwörth", :area_code => "906") + AreaCode.create(:country => germany, :name => "Tapfheim", :area_code => "9070") + AreaCode.create(:country => germany, :name => "Dillingen a d Donau", :area_code => "9071") + AreaCode.create(:country => germany, :name => "Lauingen Donau", :area_code => "9072") + AreaCode.create(:country => germany, :name => "Gundelfingen a d Donau", :area_code => "9073") + AreaCode.create(:country => germany, :name => "Höchstädt a d Donau", :area_code => "9074") + AreaCode.create(:country => germany, :name => "Glött", :area_code => "9075") + AreaCode.create(:country => germany, :name => "Wittislingen", :area_code => "9076") + AreaCode.create(:country => germany, :name => "Bachhagel", :area_code => "9077") + AreaCode.create(:country => germany, :name => "Mertingen", :area_code => "9078") + AreaCode.create(:country => germany, :name => "Harburg Schwaben", :area_code => "9080") + AreaCode.create(:country => germany, :name => "Nördlingen", :area_code => "9081") + AreaCode.create(:country => germany, :name => "Oettingen i Bay", :area_code => "9082") + AreaCode.create(:country => germany, :name => "Möttingen", :area_code => "9083") + AreaCode.create(:country => germany, :name => "Bissingen Schwab", :area_code => "9084") + AreaCode.create(:country => germany, :name => "Alerheim", :area_code => "9085") + AreaCode.create(:country => germany, :name => "Fremdingen", :area_code => "9086") + AreaCode.create(:country => germany, :name => "Marktoffingen", :area_code => "9087") + AreaCode.create(:country => germany, :name => "Mönchsdeggingen", :area_code => "9088") + AreaCode.create(:country => germany, :name => "Bissingen-Unterringingen", :area_code => "9089") + AreaCode.create(:country => germany, :name => "Rain Lech", :area_code => "9090") + AreaCode.create(:country => germany, :name => "Monheim Schwab", :area_code => "9091") + AreaCode.create(:country => germany, :name => "Wemding", :area_code => "9092") + AreaCode.create(:country => germany, :name => "Polsingen", :area_code => "9093") + AreaCode.create(:country => germany, :name => "Tagmersheim", :area_code => "9094") + AreaCode.create(:country => germany, :name => "Marxheim", :area_code => "9097") + AreaCode.create(:country => germany, :name => "Kaisheim", :area_code => "9099") + AreaCode.create(:country => germany, :name => "Langenzenn", :area_code => "9101") + AreaCode.create(:country => germany, :name => "Wilhermsdorf", :area_code => "9102") + AreaCode.create(:country => germany, :name => "Cadolzburg", :area_code => "9103") + AreaCode.create(:country => germany, :name => "Emskirchen", :area_code => "9104") + AreaCode.create(:country => germany, :name => "Grosshabersdorf", :area_code => "9105") + AreaCode.create(:country => germany, :name => "Markt Erlbach", :area_code => "9106") + AreaCode.create(:country => germany, :name => "Trautskirchen", :area_code => "9107") + AreaCode.create(:country => germany, :name => "Nürnberg", :area_code => "911") + AreaCode.create(:country => germany, :name => "Leinburg", :area_code => "9120") + AreaCode.create(:country => germany, :name => "Schwabach", :area_code => "9122") + AreaCode.create(:country => germany, :name => "Lauf a d Pegnitz", :area_code => "9123") + AreaCode.create(:country => germany, :name => "Eckental", :area_code => "9126") + AreaCode.create(:country => germany, :name => "Rosstal Mittelfr", :area_code => "9127") + AreaCode.create(:country => germany, :name => "Feucht", :area_code => "9128") + AreaCode.create(:country => germany, :name => "Wendelstein", :area_code => "9129") + AreaCode.create(:country => germany, :name => "Erlangen", :area_code => "9131") + AreaCode.create(:country => germany, :name => "Herzogenaurach", :area_code => "9132") + AreaCode.create(:country => germany, :name => "Baiersdorf Mittelfr", :area_code => "9133") + AreaCode.create(:country => germany, :name => "Neunkirchen a Brand", :area_code => "9134") + AreaCode.create(:country => germany, :name => "Heßdorf Mittelfr", :area_code => "9135") + AreaCode.create(:country => germany, :name => "Weißenburg i Bay", :area_code => "9141") + AreaCode.create(:country => germany, :name => "Treuchtlingen", :area_code => "9142") + AreaCode.create(:country => germany, :name => "Pappenheim Mittelfr", :area_code => "9143") + AreaCode.create(:country => germany, :name => "Pleinfeld", :area_code => "9144") + AreaCode.create(:country => germany, :name => "Solnhofen", :area_code => "9145") + AreaCode.create(:country => germany, :name => "Markt Berolzheim", :area_code => "9146") + AreaCode.create(:country => germany, :name => "Nennslingen", :area_code => "9147") + AreaCode.create(:country => germany, :name => "Ettenstatt", :area_code => "9148") + AreaCode.create(:country => germany, :name => "Weissenburg-Suffersheim", :area_code => "9149") + AreaCode.create(:country => germany, :name => "Hersbruck", :area_code => "9151") + AreaCode.create(:country => germany, :name => "Hartenstein Mittelfr", :area_code => "9152") + AreaCode.create(:country => germany, :name => "Schnaittach", :area_code => "9153") + AreaCode.create(:country => germany, :name => "Pommelsbrunn", :area_code => "9154") + AreaCode.create(:country => germany, :name => "Simmelsdorf", :area_code => "9155") + AreaCode.create(:country => germany, :name => "Neuhaus a d Pegnitz", :area_code => "9156") + AreaCode.create(:country => germany, :name => "Alfeld Mittelfr", :area_code => "9157") + AreaCode.create(:country => germany, :name => "Offenhausen Mittelfr", :area_code => "9158") + AreaCode.create(:country => germany, :name => "Neustadt a d Aisch", :area_code => "9161") + AreaCode.create(:country => germany, :name => "Scheinfeld", :area_code => "9162") + AreaCode.create(:country => germany, :name => "Dachsbach", :area_code => "9163") + AreaCode.create(:country => germany, :name => "Langenfeld Mittelfr", :area_code => "9164") + AreaCode.create(:country => germany, :name => "Sugenheim", :area_code => "9165") + AreaCode.create(:country => germany, :name => "Münchsteinach", :area_code => "9166") + AreaCode.create(:country => germany, :name => "Oberscheinfeld", :area_code => "9167") + AreaCode.create(:country => germany, :name => "Schwanstetten", :area_code => "9170") + AreaCode.create(:country => germany, :name => "Roth Mittelfr", :area_code => "9171") + AreaCode.create(:country => germany, :name => "Georgensgmünd", :area_code => "9172") + AreaCode.create(:country => germany, :name => "Thalmässing", :area_code => "9173") + AreaCode.create(:country => germany, :name => "Hilpoltstein", :area_code => "9174") + AreaCode.create(:country => germany, :name => "Spalt", :area_code => "9175") + AreaCode.create(:country => germany, :name => "Allersberg", :area_code => "9176") + AreaCode.create(:country => germany, :name => "Heideck", :area_code => "9177") + AreaCode.create(:country => germany, :name => "Abenberg Mittelfr", :area_code => "9178") + AreaCode.create(:country => germany, :name => "Freystadt", :area_code => "9179") + AreaCode.create(:country => germany, :name => "Pyrbaum", :area_code => "9180") + AreaCode.create(:country => germany, :name => "Neumarkt i d Opf", :area_code => "9181") + AreaCode.create(:country => germany, :name => "Velburg", :area_code => "9182") + AreaCode.create(:country => germany, :name => "Burgthann", :area_code => "9183") + AreaCode.create(:country => germany, :name => "Deining Oberpf", :area_code => "9184") + AreaCode.create(:country => germany, :name => "Mühlhausen Oberpf", :area_code => "9185") + AreaCode.create(:country => germany, :name => "Lauterhofen Oberpf", :area_code => "9186") + AreaCode.create(:country => germany, :name => "Altdorf b Nürnberg", :area_code => "9187") + AreaCode.create(:country => germany, :name => "Postbauer-Heng", :area_code => "9188") + AreaCode.create(:country => germany, :name => "Berg b Neumarkt i d Opf", :area_code => "9189") + AreaCode.create(:country => germany, :name => "Heroldsbach", :area_code => "9190") + AreaCode.create(:country => germany, :name => "Forchheim Oberfr", :area_code => "9191") + AreaCode.create(:country => germany, :name => "Gräfenberg", :area_code => "9192") + AreaCode.create(:country => germany, :name => "Höchstadt a d Aisch", :area_code => "9193") + AreaCode.create(:country => germany, :name => "Ebermannstadt", :area_code => "9194") + AreaCode.create(:country => germany, :name => "Adelsdorf Mittelfr", :area_code => "9195") + AreaCode.create(:country => germany, :name => "Wiesenttal", :area_code => "9196") + AreaCode.create(:country => germany, :name => "Egloffstein", :area_code => "9197") + AreaCode.create(:country => germany, :name => "Heiligenstadt i Ofr", :area_code => "9198") + AreaCode.create(:country => germany, :name => "Kunreuth", :area_code => "9199") + AreaCode.create(:country => germany, :name => "Gesees", :area_code => "9201") + AreaCode.create(:country => germany, :name => "Waischenfeld", :area_code => "9202") + AreaCode.create(:country => germany, :name => "Neudrossenfeld", :area_code => "9203") + AreaCode.create(:country => germany, :name => "Plankenfels", :area_code => "9204") + AreaCode.create(:country => germany, :name => "Vorbach", :area_code => "9205") + AreaCode.create(:country => germany, :name => "Mistelgau-Obernsees", :area_code => "9206") + AreaCode.create(:country => germany, :name => "Königsfeld Oberfr", :area_code => "9207") + AreaCode.create(:country => germany, :name => "Bindlach", :area_code => "9208") + AreaCode.create(:country => germany, :name => "Emtmannsberg", :area_code => "9209") + AreaCode.create(:country => germany, :name => "Bayreuth", :area_code => "921") + AreaCode.create(:country => germany, :name => "Kasendorf-Azendorf", :area_code => "9220") + AreaCode.create(:country => germany, :name => "Kulmbach", :area_code => "9221") + AreaCode.create(:country => germany, :name => "Presseck", :area_code => "9222") + AreaCode.create(:country => germany, :name => "Rugendorf", :area_code => "9223") + AreaCode.create(:country => germany, :name => "Stadtsteinach", :area_code => "9225") + AreaCode.create(:country => germany, :name => "Neuenmarkt", :area_code => "9227") + AreaCode.create(:country => germany, :name => "Thurnau", :area_code => "9228") + AreaCode.create(:country => germany, :name => "Mainleus", :area_code => "9229") + AreaCode.create(:country => germany, :name => "Marktredwitz", :area_code => "9231") + AreaCode.create(:country => germany, :name => "Wunsiedel", :area_code => "9232") + AreaCode.create(:country => germany, :name => "Arzberg Oberfr", :area_code => "9233") + AreaCode.create(:country => germany, :name => "Neusorg", :area_code => "9234") + AreaCode.create(:country => germany, :name => "Thierstein", :area_code => "9235") + AreaCode.create(:country => germany, :name => "Nagel", :area_code => "9236") + AreaCode.create(:country => germany, :name => "Röslau", :area_code => "9238") + AreaCode.create(:country => germany, :name => "Pegnitz", :area_code => "9241") + AreaCode.create(:country => germany, :name => "Gößweinstein", :area_code => "9242") + AreaCode.create(:country => germany, :name => "Pottenstein", :area_code => "9243") + AreaCode.create(:country => germany, :name => "Betzenstein", :area_code => "9244") + AreaCode.create(:country => germany, :name => "Obertrubach", :area_code => "9245") + AreaCode.create(:country => germany, :name => "Pegnitz-Trockau", :area_code => "9246") + AreaCode.create(:country => germany, :name => "Münchberg", :area_code => "9251") + AreaCode.create(:country => germany, :name => "Helmbrechts", :area_code => "9252") + AreaCode.create(:country => germany, :name => "Weissenstadt", :area_code => "9253") + AreaCode.create(:country => germany, :name => "Gefrees", :area_code => "9254") + AreaCode.create(:country => germany, :name => "Marktleugast", :area_code => "9255") + AreaCode.create(:country => germany, :name => "Stammbach", :area_code => "9256") + AreaCode.create(:country => germany, :name => "Zell Oberfr", :area_code => "9257") + AreaCode.create(:country => germany, :name => "Wilhelmsthal Oberfr", :area_code => "9260") + AreaCode.create(:country => germany, :name => "Kronach", :area_code => "9261") + AreaCode.create(:country => germany, :name => "Wallenfels", :area_code => "9262") + AreaCode.create(:country => germany, :name => "Ludwigsstadt", :area_code => "9263") + AreaCode.create(:country => germany, :name => "Küps", :area_code => "9264") + AreaCode.create(:country => germany, :name => "Pressig", :area_code => "9265") + AreaCode.create(:country => germany, :name => "Mitwitz", :area_code => "9266") + AreaCode.create(:country => germany, :name => "Nordhalben", :area_code => "9267") + AreaCode.create(:country => germany, :name => "Teuschnitz", :area_code => "9268") + AreaCode.create(:country => germany, :name => "Tettau Kr Kronach", :area_code => "9269") + AreaCode.create(:country => germany, :name => "Creussen", :area_code => "9270") + AreaCode.create(:country => germany, :name => "Thurnau-Alladorf", :area_code => "9271") + AreaCode.create(:country => germany, :name => "Fichtelberg", :area_code => "9272") + AreaCode.create(:country => germany, :name => "Bad Berneck i Fichtelgebirge", :area_code => "9273") + AreaCode.create(:country => germany, :name => "Hollfeld", :area_code => "9274") + AreaCode.create(:country => germany, :name => "Speichersdorf", :area_code => "9275") + AreaCode.create(:country => germany, :name => "Bischofsgrün", :area_code => "9276") + AreaCode.create(:country => germany, :name => "Warmensteinach", :area_code => "9277") + AreaCode.create(:country => germany, :name => "Weidenberg", :area_code => "9278") + AreaCode.create(:country => germany, :name => "Mistelgau", :area_code => "9279") + AreaCode.create(:country => germany, :name => "Selbitz Oberfr", :area_code => "9280") + AreaCode.create(:country => germany, :name => "Hof Saale", :area_code => "9281") + AreaCode.create(:country => germany, :name => "Naila", :area_code => "9282") + AreaCode.create(:country => germany, :name => "Rehau", :area_code => "9283") + AreaCode.create(:country => germany, :name => "Schwarzenbach a d Saale", :area_code => "9284") + AreaCode.create(:country => germany, :name => "Kirchenlamitz", :area_code => "9285") + AreaCode.create(:country => germany, :name => "Oberkotzau", :area_code => "9286") + AreaCode.create(:country => germany, :name => "Selb", :area_code => "9287") + AreaCode.create(:country => germany, :name => "Bad Steben", :area_code => "9288") + AreaCode.create(:country => germany, :name => "Schwarzenbach a Wald", :area_code => "9289") + AreaCode.create(:country => germany, :name => "Konradsreuth", :area_code => "9292") + AreaCode.create(:country => germany, :name => "Berg Oberfr", :area_code => "9293") + AreaCode.create(:country => germany, :name => "Regnitzlosau", :area_code => "9294") + AreaCode.create(:country => germany, :name => "Töpen", :area_code => "9295") + AreaCode.create(:country => germany, :name => "Rottendorf Unterfr", :area_code => "9302") + AreaCode.create(:country => germany, :name => "Eibelstadt", :area_code => "9303") + AreaCode.create(:country => germany, :name => "Estenfeld", :area_code => "9305") + AreaCode.create(:country => germany, :name => "Kist", :area_code => "9306") + AreaCode.create(:country => germany, :name => "Altertheim", :area_code => "9307") + AreaCode.create(:country => germany, :name => "Würzburg", :area_code => "931") + AreaCode.create(:country => germany, :name => "Kitzingen", :area_code => "9321") + AreaCode.create(:country => germany, :name => "Iphofen", :area_code => "9323") + AreaCode.create(:country => germany, :name => "Dettelbach", :area_code => "9324") + AreaCode.create(:country => germany, :name => "Kleinlangheim", :area_code => "9325") + AreaCode.create(:country => germany, :name => "Markt Einersheim", :area_code => "9326") + AreaCode.create(:country => germany, :name => "Ochsenfurt", :area_code => "9331") + AreaCode.create(:country => germany, :name => "Marktbreit", :area_code => "9332") + AreaCode.create(:country => germany, :name => "Sommerhausen", :area_code => "9333") + AreaCode.create(:country => germany, :name => "Giebelstadt", :area_code => "9334") + AreaCode.create(:country => germany, :name => "Aub Kr Würzburg", :area_code => "9335") + AreaCode.create(:country => germany, :name => "Bütthard", :area_code => "9336") + AreaCode.create(:country => germany, :name => "Gaukönigshofen", :area_code => "9337") + AreaCode.create(:country => germany, :name => "Röttingen Unterfr", :area_code => "9338") + AreaCode.create(:country => germany, :name => "Ippesheim", :area_code => "9339") + AreaCode.create(:country => germany, :name => "Königheim-Brehmen", :area_code => "9340") + AreaCode.create(:country => germany, :name => "Tauberbischofsheim", :area_code => "9341") + AreaCode.create(:country => germany, :name => "Wertheim", :area_code => "9342") + AreaCode.create(:country => germany, :name => "Lauda-Königshofen", :area_code => "9343") + AreaCode.create(:country => germany, :name => "Gerchsheim", :area_code => "9344") + AreaCode.create(:country => germany, :name => "Külsheim Baden", :area_code => "9345") + AreaCode.create(:country => germany, :name => "Grünsfeld", :area_code => "9346") + AreaCode.create(:country => germany, :name => "Wittighausen", :area_code => "9347") + AreaCode.create(:country => germany, :name => "Werbach-Gamburg", :area_code => "9348") + AreaCode.create(:country => germany, :name => "Werbach-Wenkheim", :area_code => "9349") + AreaCode.create(:country => germany, :name => "Eussenheim-Hundsbach", :area_code => "9350") + AreaCode.create(:country => germany, :name => "Gemünden a Main", :area_code => "9351") + AreaCode.create(:country => germany, :name => "Lohr a Main", :area_code => "9352") + AreaCode.create(:country => germany, :name => "Karlstadt", :area_code => "9353") + AreaCode.create(:country => germany, :name => "Rieneck", :area_code => "9354") + AreaCode.create(:country => germany, :name => "Frammersbach", :area_code => "9355") + AreaCode.create(:country => germany, :name => "Burgsinn", :area_code => "9356") + AreaCode.create(:country => germany, :name => "Gräfendorf Bay", :area_code => "9357") + AreaCode.create(:country => germany, :name => "Gössenheim", :area_code => "9358") + AreaCode.create(:country => germany, :name => "Karlstadt-Wiesenfeld", :area_code => "9359") + AreaCode.create(:country => germany, :name => "Thüngen", :area_code => "9360") + AreaCode.create(:country => germany, :name => "Arnstein Unterfr", :area_code => "9363") + AreaCode.create(:country => germany, :name => "Zellingen", :area_code => "9364") + AreaCode.create(:country => germany, :name => "Rimpar", :area_code => "9365") + AreaCode.create(:country => germany, :name => "Geroldshausen Unterfr", :area_code => "9366") + AreaCode.create(:country => germany, :name => "Unterpleichfeld", :area_code => "9367") + AreaCode.create(:country => germany, :name => "Uettingen", :area_code => "9369") + AreaCode.create(:country => germany, :name => "Miltenberg", :area_code => "9371") + AreaCode.create(:country => germany, :name => "Klingenberg a Main", :area_code => "9372") + AreaCode.create(:country => germany, :name => "Amorbach", :area_code => "9373") + AreaCode.create(:country => germany, :name => "Eschau", :area_code => "9374") + AreaCode.create(:country => germany, :name => "Freudenberg Baden", :area_code => "9375") + AreaCode.create(:country => germany, :name => "Collenberg", :area_code => "9376") + AreaCode.create(:country => germany, :name => "Freudenberg-Boxtal", :area_code => "9377") + AreaCode.create(:country => germany, :name => "Eichenbühl-Riedern", :area_code => "9378") + AreaCode.create(:country => germany, :name => "Volkach", :area_code => "9381") + AreaCode.create(:country => germany, :name => "Gerolzhofen", :area_code => "9382") + AreaCode.create(:country => germany, :name => "Wiesentheid", :area_code => "9383") + AreaCode.create(:country => germany, :name => "Schwanfeld", :area_code => "9384") + AreaCode.create(:country => germany, :name => "Kolitzheim", :area_code => "9385") + AreaCode.create(:country => germany, :name => "Prosselsheim", :area_code => "9386") + AreaCode.create(:country => germany, :name => "Marktheidenfeld", :area_code => "9391") + AreaCode.create(:country => germany, :name => "Faulbach Unterfr", :area_code => "9392") + AreaCode.create(:country => germany, :name => "Rothenfels Unterfr", :area_code => "9393") + AreaCode.create(:country => germany, :name => "Esselbach", :area_code => "9394") + AreaCode.create(:country => germany, :name => "Triefenstein", :area_code => "9395") + AreaCode.create(:country => germany, :name => "Urspringen b Lohr", :area_code => "9396") + AreaCode.create(:country => germany, :name => "Wertheim-Dertingen", :area_code => "9397") + AreaCode.create(:country => germany, :name => "Birkenfeld b Würzburg", :area_code => "9398") + AreaCode.create(:country => germany, :name => "Neutraubling", :area_code => "9401") + AreaCode.create(:country => germany, :name => "Regenstauf", :area_code => "9402") + AreaCode.create(:country => germany, :name => "Donaustauf", :area_code => "9403") + AreaCode.create(:country => germany, :name => "Nittendorf", :area_code => "9404") + AreaCode.create(:country => germany, :name => "Bad Abbach", :area_code => "9405") + AreaCode.create(:country => germany, :name => "Mintraching", :area_code => "9406") + AreaCode.create(:country => germany, :name => "Wenzenbach", :area_code => "9407") + AreaCode.create(:country => germany, :name => "Altenthann", :area_code => "9408") + AreaCode.create(:country => germany, :name => "Pielenhofen", :area_code => "9409") + AreaCode.create(:country => germany, :name => "Regensburg", :area_code => "941") + AreaCode.create(:country => germany, :name => "Feldkirchen Niederbay", :area_code => "9420") + AreaCode.create(:country => germany, :name => "Straubing", :area_code => "9421") + AreaCode.create(:country => germany, :name => "Bogen Niederbay", :area_code => "9422") + AreaCode.create(:country => germany, :name => "Geiselhöring", :area_code => "9423") + AreaCode.create(:country => germany, :name => "Strasskirchen", :area_code => "9424") + AreaCode.create(:country => germany, :name => "Oberschneiding", :area_code => "9426") + AreaCode.create(:country => germany, :name => "Leiblfing", :area_code => "9427") + AreaCode.create(:country => germany, :name => "Kirchroth", :area_code => "9428") + AreaCode.create(:country => germany, :name => "Rain Niederbay", :area_code => "9429") + AreaCode.create(:country => germany, :name => "Schwandorf", :area_code => "9431") + AreaCode.create(:country => germany, :name => "Nabburg", :area_code => "9433") + AreaCode.create(:country => germany, :name => "Bodenwöhr", :area_code => "9434") + AreaCode.create(:country => germany, :name => "Schwarzenfeld", :area_code => "9435") + AreaCode.create(:country => germany, :name => "Nittenau", :area_code => "9436") + AreaCode.create(:country => germany, :name => "Fensterbach", :area_code => "9438") + AreaCode.create(:country => germany, :name => "Neunburg-Kemnath", :area_code => "9439") + AreaCode.create(:country => germany, :name => "Kelheim", :area_code => "9441") + AreaCode.create(:country => germany, :name => "Riedenburg", :area_code => "9442") + AreaCode.create(:country => germany, :name => "Abensberg", :area_code => "9443") + AreaCode.create(:country => germany, :name => "Siegenburg", :area_code => "9444") + AreaCode.create(:country => germany, :name => "Neustadt a d Donau", :area_code => "9445") + AreaCode.create(:country => germany, :name => "Altmannstein", :area_code => "9446") + AreaCode.create(:country => germany, :name => "Essing", :area_code => "9447") + AreaCode.create(:country => germany, :name => "Hausen Niederbay", :area_code => "9448") + AreaCode.create(:country => germany, :name => "Schierling", :area_code => "9451") + AreaCode.create(:country => germany, :name => "Langquaid", :area_code => "9452") + AreaCode.create(:country => germany, :name => "Thalmassing", :area_code => "9453") + AreaCode.create(:country => germany, :name => "Aufhausen Oberpf", :area_code => "9454") + AreaCode.create(:country => germany, :name => "Roding", :area_code => "9461") + AreaCode.create(:country => germany, :name => "Falkenstein Oberpf", :area_code => "9462") + AreaCode.create(:country => germany, :name => "Wald Oberpf", :area_code => "9463") + AreaCode.create(:country => germany, :name => "Walderbach", :area_code => "9464") + AreaCode.create(:country => germany, :name => "Neukirchen-Balbini", :area_code => "9465") + AreaCode.create(:country => germany, :name => "Stamsried", :area_code => "9466") + AreaCode.create(:country => germany, :name => "Michelsneukirchen", :area_code => "9467") + AreaCode.create(:country => germany, :name => "Zell Oberpf", :area_code => "9468") + AreaCode.create(:country => germany, :name => "Roding-Neubäu", :area_code => "9469") + AreaCode.create(:country => germany, :name => "Burglengenfeld", :area_code => "9471") + AreaCode.create(:country => germany, :name => "Hohenfels Oberpf", :area_code => "9472") + AreaCode.create(:country => germany, :name => "Kallmünz", :area_code => "9473") + AreaCode.create(:country => germany, :name => "Schmidmühlen", :area_code => "9474") + AreaCode.create(:country => germany, :name => "Sünching", :area_code => "9480") + AreaCode.create(:country => germany, :name => "Pfatter", :area_code => "9481") + AreaCode.create(:country => germany, :name => "Wörth a d Donau", :area_code => "9482") + AreaCode.create(:country => germany, :name => "Brennberg", :area_code => "9484") + AreaCode.create(:country => germany, :name => "Hemau", :area_code => "9491") + AreaCode.create(:country => germany, :name => "Parsberg", :area_code => "9492") + AreaCode.create(:country => germany, :name => "Beratzhausen", :area_code => "9493") + AreaCode.create(:country => germany, :name => "Breitenbrunn Oberpf", :area_code => "9495") + AreaCode.create(:country => germany, :name => "Seubersdorf i d Opf", :area_code => "9497") + AreaCode.create(:country => germany, :name => "Laaber", :area_code => "9498") + AreaCode.create(:country => germany, :name => "Painten", :area_code => "9499") + AreaCode.create(:country => germany, :name => "Frensdorf", :area_code => "9502") + AreaCode.create(:country => germany, :name => "Oberhaid Oberfr", :area_code => "9503") + AreaCode.create(:country => germany, :name => "Stadelhofen", :area_code => "9504") + AreaCode.create(:country => germany, :name => "Litzendorf", :area_code => "9505") + AreaCode.create(:country => germany, :name => "Bamberg", :area_code => "951") + AreaCode.create(:country => germany, :name => "Hassfurt", :area_code => "9521") + AreaCode.create(:country => germany, :name => "Eltmann", :area_code => "9522") + AreaCode.create(:country => germany, :name => "Hofheim i Ufr", :area_code => "9523") + AreaCode.create(:country => germany, :name => "Zeil a Main", :area_code => "9524") + AreaCode.create(:country => germany, :name => "Königsberg i Bay", :area_code => "9525") + AreaCode.create(:country => germany, :name => "Riedbach", :area_code => "9526") + AreaCode.create(:country => germany, :name => "Knetzgau", :area_code => "9527") + AreaCode.create(:country => germany, :name => "Donnersdorf", :area_code => "9528") + AreaCode.create(:country => germany, :name => "Oberaurach", :area_code => "9529") + AreaCode.create(:country => germany, :name => "Ebern", :area_code => "9531") + AreaCode.create(:country => germany, :name => "Maroldsweisach", :area_code => "9532") + AreaCode.create(:country => germany, :name => "Untermerzbach", :area_code => "9533") + AreaCode.create(:country => germany, :name => "Burgpreppach", :area_code => "9534") + AreaCode.create(:country => germany, :name => "Pfarrweisach", :area_code => "9535") + AreaCode.create(:country => germany, :name => "Kirchlauter", :area_code => "9536") + AreaCode.create(:country => germany, :name => "Schesslitz", :area_code => "9542") + AreaCode.create(:country => germany, :name => "Hirschaid", :area_code => "9543") + AreaCode.create(:country => germany, :name => "Baunach", :area_code => "9544") + AreaCode.create(:country => germany, :name => "Buttenheim", :area_code => "9545") + AreaCode.create(:country => germany, :name => "Burgebrach", :area_code => "9546") + AreaCode.create(:country => germany, :name => "Zapfendorf", :area_code => "9547") + AreaCode.create(:country => germany, :name => "Mühlhausen Mittelfr", :area_code => "9548") + AreaCode.create(:country => germany, :name => "Lisberg", :area_code => "9549") + AreaCode.create(:country => germany, :name => "Burgwindheim", :area_code => "9551") + AreaCode.create(:country => germany, :name => "Burghaslach", :area_code => "9552") + AreaCode.create(:country => germany, :name => "Ebrach Oberfr", :area_code => "9553") + AreaCode.create(:country => germany, :name => "Untersteinbach Unterfr", :area_code => "9554") + AreaCode.create(:country => germany, :name => "Schlüsselfeld-Aschbach", :area_code => "9555") + AreaCode.create(:country => germany, :name => "Geiselwind", :area_code => "9556") + AreaCode.create(:country => germany, :name => "Grub a Forst", :area_code => "9560") + AreaCode.create(:country => germany, :name => "Coburg", :area_code => "9561") + AreaCode.create(:country => germany, :name => "Sonnefeld", :area_code => "9562") + AreaCode.create(:country => germany, :name => "Rödental", :area_code => "9563") + AreaCode.create(:country => germany, :name => "Bad Rodach", :area_code => "9564") + AreaCode.create(:country => germany, :name => "Untersiemau", :area_code => "9565") + AreaCode.create(:country => germany, :name => "Meeder", :area_code => "9566") + AreaCode.create(:country => germany, :name => "Seßlach-Gemünda", :area_code => "9567") + AreaCode.create(:country => germany, :name => "Neustadt b Coburg", :area_code => "9568") + AreaCode.create(:country => germany, :name => "Sesslach", :area_code => "9569") + AreaCode.create(:country => germany, :name => "Lichtenfels Bay", :area_code => "9571") + AreaCode.create(:country => germany, :name => "Burgkunstadt", :area_code => "9572") + AreaCode.create(:country => germany, :name => "Staffelstein Oberfr", :area_code => "9573") + AreaCode.create(:country => germany, :name => "Marktzeuln", :area_code => "9574") + AreaCode.create(:country => germany, :name => "Weismain", :area_code => "9575") + AreaCode.create(:country => germany, :name => "Lichtenfels-Isling", :area_code => "9576") + AreaCode.create(:country => germany, :name => "Neustadt a d Waldnaab", :area_code => "9602") + AreaCode.create(:country => germany, :name => "Floss", :area_code => "9603") + AreaCode.create(:country => germany, :name => "Wernberg-Köblitz", :area_code => "9604") + AreaCode.create(:country => germany, :name => "Weiherhammer", :area_code => "9605") + AreaCode.create(:country => germany, :name => "Pfreimd", :area_code => "9606") + AreaCode.create(:country => germany, :name => "Luhe-Wildenau", :area_code => "9607") + AreaCode.create(:country => germany, :name => "Kohlberg Oberpf", :area_code => "9608") + AreaCode.create(:country => germany, :name => "Weiden i d Opf", :area_code => "961") + AreaCode.create(:country => germany, :name => "Amberg Oberpf", :area_code => "9621") + AreaCode.create(:country => germany, :name => "Hirschau Oberpf", :area_code => "9622") + AreaCode.create(:country => germany, :name => "Ensdorf Oberpf", :area_code => "9624") + AreaCode.create(:country => germany, :name => "Kastl b Amberg", :area_code => "9625") + AreaCode.create(:country => germany, :name => "Hohenburg", :area_code => "9626") + AreaCode.create(:country => germany, :name => "Freudenberg Oberpf", :area_code => "9627") + AreaCode.create(:country => germany, :name => "Ursensollen", :area_code => "9628") + AreaCode.create(:country => germany, :name => "Tirschenreuth", :area_code => "9631") + AreaCode.create(:country => germany, :name => "Waldsassen", :area_code => "9632") + AreaCode.create(:country => germany, :name => "Mitterteich", :area_code => "9633") + AreaCode.create(:country => germany, :name => "Wiesau", :area_code => "9634") + AreaCode.create(:country => germany, :name => "Bärnau", :area_code => "9635") + AreaCode.create(:country => germany, :name => "Plößberg", :area_code => "9636") + AreaCode.create(:country => germany, :name => "Falkenberg Oberpf", :area_code => "9637") + AreaCode.create(:country => germany, :name => "Neualbenreuth", :area_code => "9638") + AreaCode.create(:country => germany, :name => "Mähring", :area_code => "9639") + AreaCode.create(:country => germany, :name => "Grafenwöhr", :area_code => "9641") + AreaCode.create(:country => germany, :name => "Kemnath Stadt", :area_code => "9642") + AreaCode.create(:country => germany, :name => "Auerbach i d Opf", :area_code => "9643") + AreaCode.create(:country => germany, :name => "Pressath", :area_code => "9644") + AreaCode.create(:country => germany, :name => "Eschenbach i d Opf", :area_code => "9645") + AreaCode.create(:country => germany, :name => "Freihung", :area_code => "9646") + AreaCode.create(:country => germany, :name => "Kirchenthumbach", :area_code => "9647") + AreaCode.create(:country => germany, :name => "Neustadt a Kulm", :area_code => "9648") + AreaCode.create(:country => germany, :name => "Vohenstrauss", :area_code => "9651") + AreaCode.create(:country => germany, :name => "Waidhaus", :area_code => "9652") + AreaCode.create(:country => germany, :name => "Eslarn", :area_code => "9653") + AreaCode.create(:country => germany, :name => "Pleystein", :area_code => "9654") + AreaCode.create(:country => germany, :name => "Tännesberg", :area_code => "9655") + AreaCode.create(:country => germany, :name => "Moosbach b Vohenstrauß", :area_code => "9656") + AreaCode.create(:country => germany, :name => "Waldthurn", :area_code => "9657") + AreaCode.create(:country => germany, :name => "Georgenberg", :area_code => "9658") + AreaCode.create(:country => germany, :name => "Leuchtenberg", :area_code => "9659") + AreaCode.create(:country => germany, :name => "Sulzbach-Rosenberg", :area_code => "9661") + AreaCode.create(:country => germany, :name => "Vilseck", :area_code => "9662") + AreaCode.create(:country => germany, :name => "Neukirchen b Sulzbach-Rosenberg", :area_code => "9663") + AreaCode.create(:country => germany, :name => "Hahnbach", :area_code => "9664") + AreaCode.create(:country => germany, :name => "Königstein Oberpf", :area_code => "9665") + AreaCode.create(:country => germany, :name => "Illschwang", :area_code => "9666") + AreaCode.create(:country => germany, :name => "Oberviechtach", :area_code => "9671") + AreaCode.create(:country => germany, :name => "Neunburg vorm Wald", :area_code => "9672") + AreaCode.create(:country => germany, :name => "Tiefenbach Oberpf", :area_code => "9673") + AreaCode.create(:country => germany, :name => "Schönsee", :area_code => "9674") + AreaCode.create(:country => germany, :name => "Altendorf a Nabburg", :area_code => "9675") + AreaCode.create(:country => germany, :name => "Winklarn", :area_code => "9676") + AreaCode.create(:country => germany, :name => "Oberviechtach-Pullenried", :area_code => "9677") + AreaCode.create(:country => germany, :name => "Windischeschenbach", :area_code => "9681") + AreaCode.create(:country => germany, :name => "Erbendorf", :area_code => "9682") + AreaCode.create(:country => germany, :name => "Friedenfels", :area_code => "9683") + AreaCode.create(:country => germany, :name => "Sandberg Unterfr", :area_code => "9701") + AreaCode.create(:country => germany, :name => "Euerdorf", :area_code => "9704") + AreaCode.create(:country => germany, :name => "Bad Bocklet", :area_code => "9708") + AreaCode.create(:country => germany, :name => "Bad Kissingen", :area_code => "971") + AreaCode.create(:country => germany, :name => "Üchtelhausen", :area_code => "9720") + AreaCode.create(:country => germany, :name => "Schweinfurt", :area_code => "9721") + AreaCode.create(:country => germany, :name => "Werneck", :area_code => "9722") + AreaCode.create(:country => germany, :name => "Röthlein", :area_code => "9723") + AreaCode.create(:country => germany, :name => "Stadtlauringen", :area_code => "9724") + AreaCode.create(:country => germany, :name => "Poppenhausen Unterfr", :area_code => "9725") + AreaCode.create(:country => germany, :name => "Euerbach", :area_code => "9726") + AreaCode.create(:country => germany, :name => "Schonungen-Marktsteinach", :area_code => "9727") + AreaCode.create(:country => germany, :name => "Wülfershausen Unterfr", :area_code => "9728") + AreaCode.create(:country => germany, :name => "Grettstadt", :area_code => "9729") + AreaCode.create(:country => germany, :name => "Hammelburg", :area_code => "9732") + AreaCode.create(:country => germany, :name => "Münnerstadt", :area_code => "9733") + AreaCode.create(:country => germany, :name => "Burkardroth", :area_code => "9734") + AreaCode.create(:country => germany, :name => "Massbach", :area_code => "9735") + AreaCode.create(:country => germany, :name => "Oberthulba", :area_code => "9736") + AreaCode.create(:country => germany, :name => "Wartmannsroth", :area_code => "9737") + AreaCode.create(:country => germany, :name => "Rottershausen", :area_code => "9738") + AreaCode.create(:country => germany, :name => "Bad Brückenau", :area_code => "9741") + AreaCode.create(:country => germany, :name => "Kalbach Rhön", :area_code => "9742") + AreaCode.create(:country => germany, :name => "Zeitlofs-Detter", :area_code => "9744") + AreaCode.create(:country => germany, :name => "Wildflecken", :area_code => "9745") + AreaCode.create(:country => germany, :name => "Zeitlofs", :area_code => "9746") + AreaCode.create(:country => germany, :name => "Geroda Bay", :area_code => "9747") + AreaCode.create(:country => germany, :name => "Motten", :area_code => "9748") + AreaCode.create(:country => germany, :name => "Oberbach Unterfr", :area_code => "9749") + AreaCode.create(:country => germany, :name => "Bad Königshofen i Grabfeld", :area_code => "9761") + AreaCode.create(:country => germany, :name => "Saal a d Saale", :area_code => "9762") + AreaCode.create(:country => germany, :name => "Sulzdorf a d Lederhecke", :area_code => "9763") + AreaCode.create(:country => germany, :name => "Höchheim", :area_code => "9764") + AreaCode.create(:country => germany, :name => "Trappstadt", :area_code => "9765") + AreaCode.create(:country => germany, :name => "Grosswenkheim", :area_code => "9766") + AreaCode.create(:country => germany, :name => "Bad Neustadt a d Saale", :area_code => "9771") + AreaCode.create(:country => germany, :name => "Bischofsheim a d Rhön", :area_code => "9772") + AreaCode.create(:country => germany, :name => "Unsleben", :area_code => "9773") + AreaCode.create(:country => germany, :name => "Oberelsbach", :area_code => "9774") + AreaCode.create(:country => germany, :name => "Schönau a d Brend", :area_code => "9775") + AreaCode.create(:country => germany, :name => "Mellrichstadt", :area_code => "9776") + AreaCode.create(:country => germany, :name => "Ostheim v d Rhön", :area_code => "9777") + AreaCode.create(:country => germany, :name => "Fladungen", :area_code => "9778") + AreaCode.create(:country => germany, :name => "Nordheim v d Rhön", :area_code => "9779") + AreaCode.create(:country => germany, :name => "Ansbach-Katterbach", :area_code => "9802") + AreaCode.create(:country => germany, :name => "Colmberg", :area_code => "9803") + AreaCode.create(:country => germany, :name => "Aurach", :area_code => "9804") + AreaCode.create(:country => germany, :name => "Burgoberbach", :area_code => "9805") + AreaCode.create(:country => germany, :name => "Ansbach", :area_code => "981") + AreaCode.create(:country => germany, :name => "Lehrberg", :area_code => "9820") + AreaCode.create(:country => germany, :name => "Bechhofen a d Heide", :area_code => "9822") + AreaCode.create(:country => germany, :name => "Leutershausen", :area_code => "9823") + AreaCode.create(:country => germany, :name => "Dietenhofen", :area_code => "9824") + AreaCode.create(:country => germany, :name => "Herrieden", :area_code => "9825") + AreaCode.create(:country => germany, :name => "Weidenbach Mittelfr", :area_code => "9826") + AreaCode.create(:country => germany, :name => "Lichtenau Mittelfr", :area_code => "9827") + AreaCode.create(:country => germany, :name => "Rügland", :area_code => "9828") + AreaCode.create(:country => germany, :name => "Flachslanden", :area_code => "9829") + AreaCode.create(:country => germany, :name => "Gunzenhausen", :area_code => "9831") + AreaCode.create(:country => germany, :name => "Wassertrüdingen", :area_code => "9832") + AreaCode.create(:country => germany, :name => "Heidenheim Mittelfr", :area_code => "9833") + AreaCode.create(:country => germany, :name => "Theilenhofen", :area_code => "9834") + AreaCode.create(:country => germany, :name => "Ehingen Mittelfr", :area_code => "9835") + AreaCode.create(:country => germany, :name => "Gunzenhausen-Cronheim", :area_code => "9836") + AreaCode.create(:country => germany, :name => "Haundorf", :area_code => "9837") + AreaCode.create(:country => germany, :name => "Bad Windsheim", :area_code => "9841") + AreaCode.create(:country => germany, :name => "Uffenheim", :area_code => "9842") + AreaCode.create(:country => germany, :name => "Burgbernheim", :area_code => "9843") + AreaCode.create(:country => germany, :name => "Obernzenn", :area_code => "9844") + AreaCode.create(:country => germany, :name => "Oberdachstetten", :area_code => "9845") + AreaCode.create(:country => germany, :name => "Ipsheim", :area_code => "9846") + AreaCode.create(:country => germany, :name => "Ergersheim", :area_code => "9847") + AreaCode.create(:country => germany, :name => "Simmershofen", :area_code => "9848") + AreaCode.create(:country => germany, :name => "Dinkelsbühl", :area_code => "9851") + AreaCode.create(:country => germany, :name => "Feuchtwangen", :area_code => "9852") + AreaCode.create(:country => germany, :name => "Wilburgstetten", :area_code => "9853") + AreaCode.create(:country => germany, :name => "Wittelshofen", :area_code => "9854") + AreaCode.create(:country => germany, :name => "Dentlein a Forst", :area_code => "9855") + AreaCode.create(:country => germany, :name => "Dürrwangen", :area_code => "9856") + AreaCode.create(:country => germany, :name => "Schopfloch Mittelfr", :area_code => "9857") + AreaCode.create(:country => germany, :name => "Rothenburg ob der Tauber", :area_code => "9861") + AreaCode.create(:country => germany, :name => "Adelshofen Mittelfr", :area_code => "9865") + AreaCode.create(:country => germany, :name => "Geslau", :area_code => "9867") + AreaCode.create(:country => germany, :name => "Schillingsfürst", :area_code => "9868") + AreaCode.create(:country => germany, :name => "Wettringen Mittelfr", :area_code => "9869") + AreaCode.create(:country => germany, :name => "Windsbach", :area_code => "9871") + AreaCode.create(:country => germany, :name => "Heilsbronn", :area_code => "9872") + AreaCode.create(:country => germany, :name => "Abenberg-Wassermungenau", :area_code => "9873") + AreaCode.create(:country => germany, :name => "Neuendettelsau", :area_code => "9874") + AreaCode.create(:country => germany, :name => "Wolframs-Eschenbach", :area_code => "9875") + AreaCode.create(:country => germany, :name => "Rohr Mittelfr", :area_code => "9876") + AreaCode.create(:country => germany, :name => "Hengersberg Bay", :area_code => "9901") + AreaCode.create(:country => germany, :name => "Schöllnach", :area_code => "9903") + AreaCode.create(:country => germany, :name => "Lalling", :area_code => "9904") + AreaCode.create(:country => germany, :name => "Bernried Niederbay", :area_code => "9905") + AreaCode.create(:country => germany, :name => "Mariaposching", :area_code => "9906") + AreaCode.create(:country => germany, :name => "Zenting", :area_code => "9907") + AreaCode.create(:country => germany, :name => "Schöfweg", :area_code => "9908") + AreaCode.create(:country => germany, :name => "Deggendorf", :area_code => "991") + AreaCode.create(:country => germany, :name => "Bischofsmais", :area_code => "9920") + AreaCode.create(:country => germany, :name => "Regen", :area_code => "9921") + AreaCode.create(:country => germany, :name => "Zwiesel", :area_code => "9922") + AreaCode.create(:country => germany, :name => "Teisnach", :area_code => "9923") + AreaCode.create(:country => germany, :name => "Bodenmais", :area_code => "9924") + AreaCode.create(:country => germany, :name => "Bayerisch Eisenstein", :area_code => "9925") + AreaCode.create(:country => germany, :name => "Frauenau", :area_code => "9926") + AreaCode.create(:country => germany, :name => "Kirchberg Wald", :area_code => "9927") + AreaCode.create(:country => germany, :name => "Kirchdorf i Wald", :area_code => "9928") + AreaCode.create(:country => germany, :name => "Ruhmannsfelden", :area_code => "9929") + AreaCode.create(:country => germany, :name => "Plattling", :area_code => "9931") + AreaCode.create(:country => germany, :name => "Osterhofen", :area_code => "9932") + AreaCode.create(:country => germany, :name => "Wallersdorf", :area_code => "9933") + AreaCode.create(:country => germany, :name => "Stephansposching", :area_code => "9935") + AreaCode.create(:country => germany, :name => "Wallerfing", :area_code => "9936") + AreaCode.create(:country => germany, :name => "Oberpöring", :area_code => "9937") + AreaCode.create(:country => germany, :name => "Moos Niederbay", :area_code => "9938") + AreaCode.create(:country => germany, :name => "Kötzting", :area_code => "9941") + AreaCode.create(:country => germany, :name => "Viechtach", :area_code => "9942") + AreaCode.create(:country => germany, :name => "Lam Oberpf", :area_code => "9943") + AreaCode.create(:country => germany, :name => "Miltach", :area_code => "9944") + AreaCode.create(:country => germany, :name => "Arnbruck", :area_code => "9945") + AreaCode.create(:country => germany, :name => "Hohenwarth b Kötzing", :area_code => "9946") + AreaCode.create(:country => germany, :name => "Neukirchen b Hl Blut", :area_code => "9947") + AreaCode.create(:country => germany, :name => "Eschlkam", :area_code => "9948") + AreaCode.create(:country => germany, :name => "Landau a d Isar", :area_code => "9951") + AreaCode.create(:country => germany, :name => "Eichendorf", :area_code => "9952") + AreaCode.create(:country => germany, :name => "Pilsting", :area_code => "9953") + AreaCode.create(:country => germany, :name => "SimbachNiederbay", :area_code => "9954") + AreaCode.create(:country => germany, :name => "Mamming", :area_code => "9955") + AreaCode.create(:country => germany, :name => "Eichendorf-Aufhausen", :area_code => "9956") + AreaCode.create(:country => germany, :name => "Mitterfels", :area_code => "9961") + AreaCode.create(:country => germany, :name => "Schwarzach Niederbay", :area_code => "9962") + AreaCode.create(:country => germany, :name => "Konzell", :area_code => "9963") + AreaCode.create(:country => germany, :name => "Stallwang", :area_code => "9964") + AreaCode.create(:country => germany, :name => "Sankt Englmar", :area_code => "9965") + AreaCode.create(:country => germany, :name => "Wiesenfelden", :area_code => "9966") + AreaCode.create(:country => germany, :name => "Cham", :area_code => "9971") + AreaCode.create(:country => germany, :name => "Waldmünchen", :area_code => "9972") + AreaCode.create(:country => germany, :name => "Furth i Wald", :area_code => "9973") + AreaCode.create(:country => germany, :name => "Traitsching", :area_code => "9974") + AreaCode.create(:country => germany, :name => "Waldmünchen-Geigant", :area_code => "9975") + AreaCode.create(:country => germany, :name => "Rötz", :area_code => "9976") + AreaCode.create(:country => germany, :name => "Arnschwang", :area_code => "9977") + AreaCode.create(:country => germany, :name => "Schönthal Oberpf", :area_code => "9978") +end \ No newline at end of file diff --git a/lib/tasks/populate_area_codes_pl.rake b/lib/tasks/populate_area_codes_pl.rake new file mode 100644 index 0000000..a3f725a --- /dev/null +++ b/lib/tasks/populate_area_codes_pl.rake @@ -0,0 +1,59 @@ +# encoding: UTF-8 + +desc "Populate database with Polish pre 2005 (now defunct) area codes" +task :areacodes_poland => :environment do + if ! poland = Country.where( :name => 'Poland' ).first + $stderr.puts "Error. Country not found." + exit 1 + end + + AreaCode.create(:country => poland, :name => "Biała Podlaska", :area_code => "83") + AreaCode.create(:country => poland, :name => "Białystok", :area_code => "85") + AreaCode.create(:country => poland, :name => "Bielsko-Biała", :area_code => "33") + AreaCode.create(:country => poland, :name => "Bydgoszcz", :area_code => "52") + AreaCode.create(:country => poland, :name => "Chełm", :area_code => "82") + AreaCode.create(:country => poland, :name => "Ciechanów", :area_code => "23") + AreaCode.create(:country => poland, :name => "Częstochowa", :area_code => "34") + AreaCode.create(:country => poland, :name => "Elbląg", :area_code => "55") + AreaCode.create(:country => poland, :name => "Gdańsk", :area_code => "58") + AreaCode.create(:country => poland, :name => "Gorzów Wielkopolski", :area_code => "95") + AreaCode.create(:country => poland, :name => "Jelenia Góra", :area_code => "75") + AreaCode.create(:country => poland, :name => "Kalisz", :area_code => "62") + AreaCode.create(:country => poland, :name => "Katowice", :area_code => "32") + AreaCode.create(:country => poland, :name => "Kielce", :area_code => "41") + AreaCode.create(:country => poland, :name => "Konin", :area_code => "63") + AreaCode.create(:country => poland, :name => "Koszalin", :area_code => "94") + AreaCode.create(:country => poland, :name => "Kraków", :area_code => "12") + AreaCode.create(:country => poland, :name => "Krosno", :area_code => "13") + AreaCode.create(:country => poland, :name => "Legnica", :area_code => "76") + AreaCode.create(:country => poland, :name => "Leszno", :area_code => "65") + AreaCode.create(:country => poland, :name => "Łódź", :area_code => "42") + AreaCode.create(:country => poland, :name => "Łomża", :area_code => "86") + AreaCode.create(:country => poland, :name => "Lublin", :area_code => "81") + AreaCode.create(:country => poland, :name => "Nowy Sącz", :area_code => "18") + AreaCode.create(:country => poland, :name => "Olsztyn", :area_code => "89") + AreaCode.create(:country => poland, :name => "Opole", :area_code => "77") + AreaCode.create(:country => poland, :name => "Ostrołęka", :area_code => "29") + AreaCode.create(:country => poland, :name => "Piła", :area_code => "67") + AreaCode.create(:country => poland, :name => "Piotrków Trybunalski", :area_code => "44") + AreaCode.create(:country => poland, :name => "Płock", :area_code => "24") + AreaCode.create(:country => poland, :name => "Poznań", :area_code => "61") + AreaCode.create(:country => poland, :name => "Przemyśl", :area_code => "16") + AreaCode.create(:country => poland, :name => "Radom", :area_code => "48") + AreaCode.create(:country => poland, :name => "Rzeszów", :area_code => "17") + AreaCode.create(:country => poland, :name => "Siedlce", :area_code => "25") + AreaCode.create(:country => poland, :name => "Sieradz", :area_code => "43") + AreaCode.create(:country => poland, :name => "Skierniewice", :area_code => "46") + AreaCode.create(:country => poland, :name => "Słupsk", :area_code => "59") + AreaCode.create(:country => poland, :name => "Suwałki", :area_code => "87") + AreaCode.create(:country => poland, :name => "Szczecin", :area_code => "91") + AreaCode.create(:country => poland, :name => "Tarnobrzeg", :area_code => "15") + AreaCode.create(:country => poland, :name => "Tarnów", :area_code => "14") + AreaCode.create(:country => poland, :name => "Toruń", :area_code => "56") + AreaCode.create(:country => poland, :name => "Wałbrzych", :area_code => "74") + AreaCode.create(:country => poland, :name => "Warszawa", :area_code => "22") + AreaCode.create(:country => poland, :name => "Włocławek", :area_code => "54") + AreaCode.create(:country => poland, :name => "Wrocław", :area_code => "71") + AreaCode.create(:country => poland, :name => "Zamość", :area_code => "84") + AreaCode.create(:country => poland, :name => "Zielona Góra", :area_code => "68") +end diff --git a/lib/tasks/populate_country_codes.rake b/lib/tasks/populate_country_codes.rake new file mode 100644 index 0000000..1129f81 --- /dev/null +++ b/lib/tasks/populate_country_codes.rake @@ -0,0 +1,244 @@ +# encoding: UTF-8 + +desc "Populate database with country codes" +task :country_codes => :environment do + + Country.create(:name => "American Samoa", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Anguilla", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Antigua and Barbuda", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Bahamas", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Barbados", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Bermuda", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "British Virgin Islands", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Canada", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Cayman Islands", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Dominica", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Dominican Republic", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Grenada", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Guam", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Jamaica", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Montserrat", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Northern Mariana Islands", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Puerto Rico", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Saint Kitts and Nevis", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Saint Lucia", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Saint Vincent and the Grenadines", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Trinidad and Tobago", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Turks and Caicos Islands", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "United States of America", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "United States Virgin Islands", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + Country.create(:name => "Egypt", :country_code => "20", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Morocco", :country_code => "212", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Algeria", :country_code => "213", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Tunisia", :country_code => "216", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Libya", :country_code => "218", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Gambia", :country_code => "220", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Senegal", :country_code => "221", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Mauritania", :country_code => "222", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Mali", :country_code => "223", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Guinea", :country_code => "224", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Côte d'Ivoire", :country_code => "225", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Burkina Faso", :country_code => "226", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Niger", :country_code => "227", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Togolese Republic", :country_code => "228", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Benin", :country_code => "229", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Mauritius", :country_code => "230", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Liberia", :country_code => "231", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Sierra Leone", :country_code => "232", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Ghana", :country_code => "233", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Nigeria", :country_code => "234", :international_call_prefix => "009", :trunk_prefix => "" ) + Country.create(:name => "Chad", :country_code => "235", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Central African Republic", :country_code => "236", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Cameroon", :country_code => "237", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Cape Verde", :country_code => "238", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Sao Tome and Principe", :country_code => "239", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Equatorial Guinea", :country_code => "240", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Gabonese Republic", :country_code => "241", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Congo", :country_code => "242", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Democratic Republic of the Congo", :country_code => "243", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Angola", :country_code => "244", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Guinea-Bissau", :country_code => "245", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Diego Garcia", :country_code => "246", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Ascension", :country_code => "247", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Seychelles", :country_code => "248", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Sudan", :country_code => "249", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Rwanda", :country_code => "250", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Ethiopia", :country_code => "251", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Somali Democratic Republic", :country_code => "252", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Djibouti", :country_code => "253", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Kenya", :country_code => "254", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Tanzania", :country_code => "255", :international_call_prefix => "000", :trunk_prefix => "" ) + Country.create(:name => "Uganda", :country_code => "256", :international_call_prefix => "000", :trunk_prefix => "" ) + Country.create(:name => "Burundi", :country_code => "257", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Mozambique", :country_code => "258", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Zambia", :country_code => "260", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Madagascar", :country_code => "261", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Reunion", :country_code => "262", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Zimbabwe", :country_code => "263", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Namibia", :country_code => "264", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Malawi", :country_code => "265", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Lesotho", :country_code => "266", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Botswana", :country_code => "267", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Swaziland", :country_code => "268", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Comoros", :country_code => "269", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Mayotte", :country_code => "269", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "South Africa", :country_code => "27", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Saint Helena", :country_code => "290", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Eritrea", :country_code => "291", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Aruba", :country_code => "297", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Faroe Islands", :country_code => "298", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Greenland", :country_code => "299", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Greece", :country_code => "30", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Netherlands", :country_code => "31", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Belgium", :country_code => "32", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "France", :country_code => "33", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Spain", :country_code => "34", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Gibraltar", :country_code => "350", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Portugal", :country_code => "351", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Luxembourg", :country_code => "352", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Ireland", :country_code => "353", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Iceland", :country_code => "354", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Albania", :country_code => "355", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Malta", :country_code => "356", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Cyprus", :country_code => "357", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Finland", :country_code => "358", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Bulgaria", :country_code => "359", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Hungary", :country_code => "36", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Lithuania", :country_code => "370", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Latvia", :country_code => "371", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Estonia", :country_code => "372", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Moldova", :country_code => "373", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Armenia", :country_code => "374", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Belarus", :country_code => "375", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Andorra", :country_code => "376", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Monaco", :country_code => "377", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "San Marino", :country_code => "378", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Vatican City State", :country_code => "379", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Ukraine", :country_code => "380", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Serbia and Montenegro", :country_code => "381", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Croatia", :country_code => "385", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Slovenia", :country_code => "386", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Bosnia and Herzegovina", :country_code => "387", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Group of countries, shared code", :country_code => "388", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "The Former Yugoslav Republic of Macedonia", :country_code => "389", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Italy", :country_code => "39", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Vatican City State", :country_code => "39", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Romania", :country_code => "40", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Switzerland", :country_code => "41", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Czech Republic", :country_code => "420", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Slovak Republic", :country_code => "421", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Liechtenstein", :country_code => "423", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Austria", :country_code => "43", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "United Kingdom of Great Britain and Northern Ireland", :country_code => "44", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Denmark", :country_code => "45", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Sweden", :country_code => "46", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Norway", :country_code => "47", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Poland", :country_code => "48", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Germany", :country_code => "49", :international_call_prefix => "00", :trunk_prefix => "0" ) + Country.create(:name => "Falkland Islands", :country_code => "500", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Belize", :country_code => "501", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Guatemala", :country_code => "502", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "El Salvador", :country_code => "503", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Honduras", :country_code => "504", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Nicaragua", :country_code => "505", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Costa Rica", :country_code => "506", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Panama", :country_code => "507", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Saint Pierre and Miquelon", :country_code => "508", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Haiti", :country_code => "509", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Peru", :country_code => "51", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Mexico", :country_code => "52", :international_call_prefix => "00", :trunk_prefix => "01" ) + Country.create(:name => "Cuba", :country_code => "53", :international_call_prefix => "119", :trunk_prefix => "" ) + Country.create(:name => "Argentine Republic", :country_code => "54", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Brazil", :country_code => "55", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Chile", :country_code => "56", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Colombia", :country_code => "57", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Venezuela", :country_code => "58", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Guadeloupe", :country_code => "590", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Bolivia", :country_code => "591", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Guyana", :country_code => "592", :international_call_prefix => "001", :trunk_prefix => "" ) + Country.create(:name => "Ecuador", :country_code => "593", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "French Guiana", :country_code => "594", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Paraguay", :country_code => "595", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Martinique", :country_code => "596", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Suriname", :country_code => "597", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Uruguay", :country_code => "598", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Netherlands Antilles", :country_code => "599", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Malaysia", :country_code => "60", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Australia", :country_code => "61", :international_call_prefix => "0011", :trunk_prefix => "" ) + Country.create(:name => "Indonesia", :country_code => "62", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Philippines", :country_code => "63", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "New Zealand", :country_code => "64", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Singapore", :country_code => "65", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Thailand", :country_code => "66", :international_call_prefix => "001", :trunk_prefix => "" ) + Country.create(:name => "Democratic Republic of Timor-Leste", :country_code => "670", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Australian External Territories", :country_code => "672", :international_call_prefix => "0011", :trunk_prefix => "" ) + Country.create(:name => "Brunei Darussalam", :country_code => "673", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Nauru", :country_code => "674", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Papua New Guinea", :country_code => "675", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Tonga", :country_code => "676", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Solomon Islands", :country_code => "677", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Vanuatu", :country_code => "678", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Fiji", :country_code => "679", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Palau", :country_code => "680", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Wallis and Futuna", :country_code => "681", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Cook Islands", :country_code => "682", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Niue", :country_code => "683", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Samoa", :country_code => "685", :international_call_prefix => "0", :trunk_prefix => "" ) + Country.create(:name => "Kiribati", :country_code => "686", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "New Caledonia", :country_code => "687", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Tuvalu", :country_code => "688", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "French Polynesia", :country_code => "689", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Tokelau", :country_code => "690", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Micronesia", :country_code => "691", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Marshall Islands", :country_code => "692", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Kazakhstan", :country_code => "7", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Russian Federation", :country_code => "7", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "International Freephone Service", :country_code => "800", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "International Shared Cost Service", :country_code => "808", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Japan", :country_code => "81", :international_call_prefix => "010", :trunk_prefix => "" ) + Country.create(:name => "Korea", :country_code => "82", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Viet Nam", :country_code => "84", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Democratic People's Republic of Korea", :country_code => "850", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Hong Kong, China", :country_code => "852", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Macao, China", :country_code => "853", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Cambodia", :country_code => "855", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Lao People's Democratic Republic", :country_code => "856", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "China", :country_code => "86", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Inmarsat SNAC", :country_code => "870", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Inmarsat", :country_code => "871", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Inmarsat", :country_code => "872", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Inmarsat", :country_code => "873", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Inmarsat", :country_code => "874", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Universal Personal Telecommunication Service", :country_code => "878", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Bangladesh", :country_code => "880", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Turkey", :country_code => "90", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "India", :country_code => "91", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Pakistan", :country_code => "92", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Afghanistan", :country_code => "93", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Sri Lanka", :country_code => "94", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Myanmar", :country_code => "95", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Maldives", :country_code => "960", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Lebanon", :country_code => "961", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Jordan", :country_code => "962", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Syrian Arab Republic", :country_code => "963", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Iraq", :country_code => "964", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Kuwait", :country_code => "965", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Saudi Arabia", :country_code => "966", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Yemen", :country_code => "967", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Oman", :country_code => "968", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "United Arab Emirates", :country_code => "971", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Israel", :country_code => "972", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Bahrain", :country_code => "973", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Qatar", :country_code => "974", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Bhutan", :country_code => "975", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Mongolia", :country_code => "976", :international_call_prefix => "001", :trunk_prefix => "" ) + Country.create(:name => "Nepal", :country_code => "977", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "International Premium Rate Service", :country_code => "979", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Iran", :country_code => "98", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Tajikistan", :country_code => "992", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Turkmenistan", :country_code => "993", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Azerbaijani Republic", :country_code => "994", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Georgia", :country_code => "995", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Kyrgyz Republic", :country_code => "996", :international_call_prefix => "00", :trunk_prefix => "" ) + Country.create(:name => "Uzbekistan", :country_code => "998", :international_call_prefix => "00", :trunk_prefix => "" ) +end diff --git a/lib/tasks/send_fax_notifications.rake b/lib/tasks/send_fax_notifications.rake new file mode 100644 index 0000000..039c509 --- /dev/null +++ b/lib/tasks/send_fax_notifications.rake @@ -0,0 +1,49 @@ +# encoding: UTF-8 + +desc "Import inbound fax" + +task :send_fax_notifications => :environment do + FaxDocument.where(:state => 'received').each do |fax_document| + TIFF_FUFFIX = ".tiff" + PDF_SUFFIX = ".pdf" + TMP_DIR = "/tmp/" + + tiff_file = File.basename(fax_document.tiff.to_s) + + if !File.exists?( "#{TMP_DIR}#{tiff_file}" ) + fax_document.state = 'unsuccessful' + fax_document.save + next + end + + paper_size = "letter" + pdf_file = "#{TMP_DIR}#{File.basename(tiff_file, TIFF_FUFFIX)}#{PDF_SUFFIX}" + + system "tiff2pdf \\ + -o \"#{pdf_file}\" \\ + -p #{paper_size} \\ + -a \"#{fax_document.remote_station_id}\" \\ + -c \"AMOOMA Gemeinschaft version #{GEMEINSCHAFT_VERSION}\" \\ + -t \"#{fax_document.remote_station_id}\" \"#{TMP_DIR}#{tiff_file}\"" + + if !File.exists?( pdf_file ) + fax_document.state = 'unsuccessful' + fax_document.save + next + end + + fax_document.document = File.open(pdf_file) + fax_document.state = 'successful' + + if fax_document.save + Notifications.new_fax(fax_document).deliver + File.delete("#{TMP_DIR}#{tiff_file}"); + File.delete(pdf_file); + fax_document.tiff = nil + fax_document.save + else + fax_document.state = 'unsuccessful' + fax_document.save + end + end +end diff --git a/lib/tasks/send_voicemail_notifications.rake b/lib/tasks/send_voicemail_notifications.rake new file mode 100644 index 0000000..214d832 --- /dev/null +++ b/lib/tasks/send_voicemail_notifications.rake @@ -0,0 +1,52 @@ +# encoding: UTF-8 + +desc "Import inbound voicemail" + +task :send_voicemail_notifications => :environment do + VoicemailMessage.where(:notification => nil).each do |message| + + message.notification = false + message.save + if !File.exists?( message.file_path ) + $stderr.puts "File \"#{message.file_path}\" does not exist" + next + end + + sip_account = SipAccount.where(:auth_name => message.username).first + if ! sip_account + $stderr.puts "SipAccount \"#{message.username}\" does not exist" + next + end + + user = sip_account.sip_accountable + if user.class != User + next + end + + if user.email.blank? + $stderr.puts "no email address" + next + end + + voicemail_settings = sip_account.voicemail_setting + if !voicemail_settings + voicemail_settings = VoicemailSetting.new(:notify => user.send_voicemail_as_email_attachment, :attachment => user.send_voicemail_as_email_attachment, :mark_read => user.send_voicemail_as_email_attachment) + end + + message.notification = voicemail_settings.notify + if voicemail_settings.notify + if Notifications.new_voicemail(message, voicemail_settings.attachment).deliver + if voicemail_settings.purge + message.delete + next + end + message.save + if voicemail_settings.mark_read + message.mark_read + end + end + else + message.save + end + end +end diff --git a/lib/templates/erb/scaffold/_form.html.erb b/lib/templates/erb/scaffold/_form.html.erb new file mode 100644 index 0000000..24a1768 --- /dev/null +++ b/lib/templates/erb/scaffold/_form.html.erb @@ -0,0 +1,13 @@ +<%%= simple_form_for(@<%= singular_table_name %>) do |f| %> + <%%= f.error_notification %> + +
    + <%- attributes.each do |attribute| -%> + <%%= f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %> %> + <%- end -%> +
    + +
    + <%%= f.button :submit %> +
    +<%% end %> diff --git a/lib/uacsta.rb b/lib/uacsta.rb new file mode 100644 index 0000000..9303092 --- /dev/null +++ b/lib/uacsta.rb @@ -0,0 +1,83 @@ +class Uacsta + + def send(sip_account, domain, body) + require 'freeswitch_event' + + event = FreeswitchEvent.new("NOTIFY") + event.add_header("profile", "gemeinschaft") + event.add_header("event-string", "uaCSTA") + event.add_header("user", sip_account) + event.add_header("host", domain) + event.add_header("content-type", "application/csta+xml") + event.add_body(body); + + return event.fire(); + end + + def make_call(sip_account, domain, number) + body = ' + + ' + sip_account.to_s + ' + ' + number.to_s + ' + doNotPrompt + ' + + self.send(sip_account, domain, body); + end + + def answer_call(sip_account, domain) + body = ' + + + ' + sip_account + ' + + ' + + self.send(sip_account, domain, body) + end + + def set_microphone_mute(sip_account, domain, value) + body = ' + + ' + sip_account + ' + 1 + ' + value.to_s + ' + ' + + self.send(sip_account, domain, body) + end + + def set_speaker_volume(sip_account, domain, value) + body = ' + + ' + sip_account + ' + 1 + ' + value.to_s + ' + ' + + self.send(sip_account, domain, body) + end + + def set_do_not_disturb(sip_account, domain, value) + body = ' + + ' + sip_account + ' + ' + value.to_s + ' + ' + + self.send(sip_account, domain, body) + end + + def set_forwarding(sip_account, domain, forwarding_type, number, activate) + forwarding_types = [ "forwardImmediate", "forwardBusy", "forwardNoAns" ] + body = ' + + ' + sip_account + ' + ' + forwarding_types[forwarding_type.to_i] + ' + ' + number.to_s + ' + ' + activate.to_s + ' + ' + + self.send(sip_account, domain, body) + end +end diff --git a/log/.gitkeep b/log/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/misc/TODO-Liste.txt b/misc/TODO-Liste.txt new file mode 100644 index 0000000..e69de29 diff --git a/misc/etc/cron.d/logout_phones b/misc/etc/cron.d/logout_phones new file mode 100644 index 0000000..86b0ffd --- /dev/null +++ b/misc/etc/cron.d/logout_phones @@ -0,0 +1,3 @@ +# Logout tagged phones +23 1 * * * root /opt/GS5/script/logout_phones.sh + diff --git a/misc/etc/ssl/amooma/server.pem b/misc/etc/ssl/amooma/server.pem new file mode 100644 index 0000000..d34e8db --- /dev/null +++ b/misc/etc/ssl/amooma/server.pem @@ -0,0 +1,36 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDC9G3px4ew18PHIm8HJ3yXc9rxqM5uSn1qhjdoWM0zC0Qcue9k +V+5ZUq356yjBbs5wXi3SEWfucXxhnwnzeIqvMeO6y0BiUVsClbqziRCho/hgHPTJ +tZzjt6Mpl3D/9yeFKbah5lJ5qNm0T00ybpcSXC7w2Xv9ckji1DDtGo62fQIDAQAB +AoGAHM0jl9AEednGcJrjsDjjLTTOebkolh6nHJ+re9zyo8HcVCob9cUPz15pmWxm +Xv1RvkQLnOc5ZX6ak4l9XNzIEAvQXNRFXwCOyfpffx/8QhfrG0v2G+K2QG52VxQj +tqnRdLf8HEhCmrJCMvMEAuQkAiirIMTFcaaP1CBbCilr8nkCQQDnSYxEfXMYi4iq +9Xjwn8Ayh1koXFUY+5/0u9SGqzTeTxW1QN2hGhehsd0vlv4cJppcuL4Z+2VYqLQc +zXDZo/MLAkEA18kSHLp+HCd1BW/JEoIQqWlTw6SRx+IsUN7UmnSZS4C+UPRbtq5I +nzgzonZufOEmzoMdwbe9EHAl087f0UfxlwJBAKNIBhGYKvgqEdr3n2Dotuw1J1la +De2sPpmtPPWxyoojdOTYHV8Np59MjSV6yHyhOBq7heGb3EmCGF25H7FWkE8CQGUN +aakAgPxoUfn4zp4XQPxFMhAF6qtDtOMuZzvp7LwaD4ZT2PtlBOdjZ3LmqXlb61N8 +vZuxkx22l1BoqhIU8gMCQQDJsQr5y8UWamYZrNv5YRNnm8aGgJ83Gx3n5b8bKqjh +TM8hqJfFTIfHr90GhHyok1aVkjF+sUtydX1R85IHTDz5 +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIDfjCCAuegAwIBAgIJAKG1XaHFZ4gEMA0GCSqGSIb3DQEBBQUAMIGHMQswCQYD +VQQGEwJERTEYMBYGA1UECBMPUmhlaW5sYW5kLVBmYWx6MRAwDgYDVQQHEwdOZXV3 +aWVkMRQwEgYDVQQKEwtBTU9PTUEgR21iSDEXMBUGA1UEAxMOR2VtZWluc2NoYWZ0 +IDQxHTAbBgkqhkiG9w0BCQEWDmluZm9AYW1vb21hLmRlMB4XDTExMDcyMjE0NDAy +OFoXDTIxMDcxOTE0NDAyOFowgYcxCzAJBgNVBAYTAkRFMRgwFgYDVQQIEw9SaGVp +bmxhbmQtUGZhbHoxEDAOBgNVBAcTB05ldXdpZWQxFDASBgNVBAoTC0FNT09NQSBH +bWJIMRcwFQYDVQQDEw5HZW1laW5zY2hhZnQgNDEdMBsGCSqGSIb3DQEJARYOaW5m +b0BhbW9vbWEuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAML0benHh7DX +w8cibwcnfJdz2vGozm5KfWqGN2hYzTMLRBy572RX7llSrfnrKMFuznBeLdIRZ+5x +fGGfCfN4iq8x47rLQGJRWwKVurOJEKGj+GAc9Mm1nOO3oymXcP/3J4UptqHmUnmo +2bRPTTJulxJcLvDZe/1ySOLUMO0ajrZ9AgMBAAGjge8wgewwHQYDVR0OBBYEFATl +qWtGbyeBIN9mR/4GV9jO7ON7MIG8BgNVHSMEgbQwgbGAFATlqWtGbyeBIN9mR/4G +V9jO7ON7oYGNpIGKMIGHMQswCQYDVQQGEwJERTEYMBYGA1UECBMPUmhlaW5sYW5k +LVBmYWx6MRAwDgYDVQQHEwdOZXV3aWVkMRQwEgYDVQQKEwtBTU9PTUEgR21iSDEX +MBUGA1UEAxMOR2VtZWluc2NoYWZ0IDQxHTAbBgkqhkiG9w0BCQEWDmluZm9AYW1v +b21hLmRlggkAobVdocVniAQwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOB +gQCBIgWoP8YiP6tm8rhb81k6myP4ONO4vOaUz9bsadHDWNCTjiQxvo4uVYqTMLKa +Bc7S0VpyvSg7/eGsSWxIUwdn6dUPdo51juGnnJ9dK9DuiNPHb0HP3UJo1gCWgs1v +EnVGfKDdu9FfdNcQtIb28UfF8Pw8WA6mmhQOOh0M9d3ayQ== +-----END CERTIFICATE----- diff --git a/misc/etc/ssl/amooma/server_cert.pem b/misc/etc/ssl/amooma/server_cert.pem new file mode 100644 index 0000000..021ad28 --- /dev/null +++ b/misc/etc/ssl/amooma/server_cert.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDfjCCAuegAwIBAgIJAKG1XaHFZ4gEMA0GCSqGSIb3DQEBBQUAMIGHMQswCQYD +VQQGEwJERTEYMBYGA1UECBMPUmhlaW5sYW5kLVBmYWx6MRAwDgYDVQQHEwdOZXV3 +aWVkMRQwEgYDVQQKEwtBTU9PTUEgR21iSDEXMBUGA1UEAxMOR2VtZWluc2NoYWZ0 +IDQxHTAbBgkqhkiG9w0BCQEWDmluZm9AYW1vb21hLmRlMB4XDTExMDcyMjE0NDAy +OFoXDTIxMDcxOTE0NDAyOFowgYcxCzAJBgNVBAYTAkRFMRgwFgYDVQQIEw9SaGVp +bmxhbmQtUGZhbHoxEDAOBgNVBAcTB05ldXdpZWQxFDASBgNVBAoTC0FNT09NQSBH +bWJIMRcwFQYDVQQDEw5HZW1laW5zY2hhZnQgNDEdMBsGCSqGSIb3DQEJARYOaW5m +b0BhbW9vbWEuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAML0benHh7DX +w8cibwcnfJdz2vGozm5KfWqGN2hYzTMLRBy572RX7llSrfnrKMFuznBeLdIRZ+5x +fGGfCfN4iq8x47rLQGJRWwKVurOJEKGj+GAc9Mm1nOO3oymXcP/3J4UptqHmUnmo +2bRPTTJulxJcLvDZe/1ySOLUMO0ajrZ9AgMBAAGjge8wgewwHQYDVR0OBBYEFATl +qWtGbyeBIN9mR/4GV9jO7ON7MIG8BgNVHSMEgbQwgbGAFATlqWtGbyeBIN9mR/4G +V9jO7ON7oYGNpIGKMIGHMQswCQYDVQQGEwJERTEYMBYGA1UECBMPUmhlaW5sYW5k +LVBmYWx6MRAwDgYDVQQHEwdOZXV3aWVkMRQwEgYDVQQKEwtBTU9PTUEgR21iSDEX +MBUGA1UEAxMOR2VtZWluc2NoYWZ0IDQxHTAbBgkqhkiG9w0BCQEWDmluZm9AYW1v +b21hLmRlggkAobVdocVniAQwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOB +gQCBIgWoP8YiP6tm8rhb81k6myP4ONO4vOaUz9bsadHDWNCTjiQxvo4uVYqTMLKa +Bc7S0VpyvSg7/eGsSWxIUwdn6dUPdo51juGnnJ9dK9DuiNPHb0HP3UJo1gCWgs1v +EnVGfKDdu9FfdNcQtIb28UfF8Pw8WA6mmhQOOh0M9d3ayQ== +-----END CERTIFICATE----- + diff --git a/misc/etc/ssl/amooma/server_key.pem b/misc/etc/ssl/amooma/server_key.pem new file mode 100644 index 0000000..0c8e74e --- /dev/null +++ b/misc/etc/ssl/amooma/server_key.pem @@ -0,0 +1,16 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDC9G3px4ew18PHIm8HJ3yXc9rxqM5uSn1qhjdoWM0zC0Qcue9k +V+5ZUq356yjBbs5wXi3SEWfucXxhnwnzeIqvMeO6y0BiUVsClbqziRCho/hgHPTJ +tZzjt6Mpl3D/9yeFKbah5lJ5qNm0T00ybpcSXC7w2Xv9ckji1DDtGo62fQIDAQAB +AoGAHM0jl9AEednGcJrjsDjjLTTOebkolh6nHJ+re9zyo8HcVCob9cUPz15pmWxm +Xv1RvkQLnOc5ZX6ak4l9XNzIEAvQXNRFXwCOyfpffx/8QhfrG0v2G+K2QG52VxQj +tqnRdLf8HEhCmrJCMvMEAuQkAiirIMTFcaaP1CBbCilr8nkCQQDnSYxEfXMYi4iq +9Xjwn8Ayh1koXFUY+5/0u9SGqzTeTxW1QN2hGhehsd0vlv4cJppcuL4Z+2VYqLQc +zXDZo/MLAkEA18kSHLp+HCd1BW/JEoIQqWlTw6SRx+IsUN7UmnSZS4C+UPRbtq5I +nzgzonZufOEmzoMdwbe9EHAl087f0UfxlwJBAKNIBhGYKvgqEdr3n2Dotuw1J1la +De2sPpmtPPWxyoojdOTYHV8Np59MjSV6yHyhOBq7heGb3EmCGF25H7FWkE8CQGUN +aakAgPxoUfn4zp4XQPxFMhAF6qtDtOMuZzvp7LwaD4ZT2PtlBOdjZ3LmqXlb61N8 +vZuxkx22l1BoqhIU8gMCQQDJsQr5y8UWamYZrNv5YRNnm8aGgJ83Gx3n5b8bKqjh +TM8hqJfFTIfHr90GhHyok1aVkjF+sUtydX1R85IHTDz5 +-----END RSA PRIVATE KEY----- + diff --git a/misc/example/apache-gs5.conf b/misc/example/apache-gs5.conf new file mode 100644 index 0000000..ef81952 --- /dev/null +++ b/misc/example/apache-gs5.conf @@ -0,0 +1,24 @@ + + LoadModule passenger_module /usr/local/rvm/gems/ruby-1.9.2-p290/gems/passenger-3.0.11/ext/apache2/mod_passenger.so + PassengerRoot /usr/local/rvm/gems/ruby-1.9.2-p290/gems/passenger-3.0.11 + PassengerRuby /usr/local/rvm/wrappers/ruby-1.9.2-p290/ruby + + + + + ErrorLog "|/usr/bin/logger -t apache -i -p local6.notice" + CustomLog "|/usr/bin/logger -t apache -i -p local6.notice" combined + + + DocumentRoot /opt/GS5/public + PassengerAppRoot /opt/GS5 + RailsEnv development + + AllowOverride all + Options -MultiViews + Options FollowSymLinks + + SSLEngine on + SSLCertificateFile /etc/ssl/amooma/server_cert.pem + SSLCertificateKeyFile /etc/ssl/amooma/server_key.pem + diff --git a/misc/example/nginx b/misc/example/nginx new file mode 100644 index 0000000..ccb2bbb --- /dev/null +++ b/misc/example/nginx @@ -0,0 +1,73 @@ +#!/bin/sh + +##################################################################### +# nginx +# Start Script +# (c) AMOOMA GmbH 2012 +##################################################################### + +### BEGIN INIT INFO +# Provides: nginx +# Required-Start: freeswitch +# Required-Stop: freeswitch +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: starts nginx +# Description: starts nginx +# +### END INIT INFO + +DAEMON=/opt/nginx/sbin/nginx +EXECUTABLE=`basename 'nginx'` +NAME=nginx +DESC=nginx +ARGS="" + +if ! [ -x $DAEMON ] ; then + echo "ERROR: $DAEMON not found" + exit 1 +fi + +set -e + +. /lib/lsb/init-functions + +case "$1" in + start) + echo -n "Starting $DESC: " + start-stop-daemon --start --quiet --pidfile /opt/nginx/logs/$NAME.pid \ + --exec $DAEMON -- $DAEMON_OPTS + echo "$NAME." + ;; + stop) + echo -n "Stopping $DESC: " + start-stop-daemon --stop --quiet --pidfile /opt/nginx/logs/$NAME.pid \ + --exec $DAEMON + echo "$NAME." + ;; + restart|force-reload) + echo -n "Restarting $DESC: " + start-stop-daemon --stop --quiet --pidfile \ + /opt/nginx/logs/$NAME.pid --exec $DAEMON + sleep 1 + start-stop-daemon --start --quiet --pidfile \ + /opt/nginx/logs/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS + echo "$NAME." + ;; + reload) + echo -n "Reloading $DESC configuration: " + start-stop-daemon --stop --signal HUP --quiet --pidfile /opt/nginx/logs/$NAME.pid \ + --exec $DAEMON + echo "$NAME." + ;; + status) + status_of_proc -p /opt/nginx/logs/$NAME.pid "$DAEMON" nginx + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|reload|force-reload|status}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/misc/example/xml-interface.txt b/misc/example/xml-interface.txt new file mode 100644 index 0000000..9f05540 --- /dev/null +++ b/misc/example/xml-interface.txt @@ -0,0 +1,25 @@ +User anlegen +============ + +echo '2222MeyerFritz+49 228 1234567665544+49 171 123456+49 228 1234444fritz.meier@example.com1234562010-11-22T07:09:07.5256939example.jpg' | curl -X POST -H 'Content-type: text/xml' -d @- http://0.0.0.0:3000/api/rows + +Userdaten abrufen +================= +curl -H 'Content-type: text/xml' http://0.0.0.0:3000/api/rows/1.xml + +User löschen +============ + +curl -i -H "Accept: application/xml" -X DELETE http://0.0.0.0:3000/api/rows/1 + +If only the user name is known: +curl -i -H "Accept: application/xml" -X DELETE http://0.0.0.0:3000/api/rows/999999?user_name=12345 + + +User updaten +============ + +curl -i -X PUT -H 'Content-Type: application/xml' -d '+49 228 5555555665544' http://localhost:3000/api/rows/1 + +If only the user name is known: +curl -i -X PUT -H 'Content-Type: application/xml' -d '+49 228 5555555665544' http://localhost:3000/api/rows/999999?user_name=12345 \ No newline at end of file diff --git a/misc/freeswitch/conf/freeswitch.xml b/misc/freeswitch/conf/freeswitch.xml new file mode 100644 index 0000000..04369a7 --- /dev/null +++ b/misc/freeswitch/conf/freeswitch.xml @@ -0,0 +1,759 @@ + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + +
    +
    diff --git a/misc/freeswitch/scripts/acd_wait.lua b/misc/freeswitch/scripts/acd_wait.lua new file mode 100644 index 0000000..fd16bea --- /dev/null +++ b/misc/freeswitch/scripts/acd_wait.lua @@ -0,0 +1,45 @@ +-- Gemeinschaft 5: acd call handler +-- (c) AMOOMA GmbH 2012 +-- + +local caller_uuid = argv[1]; +local acd_id = tonumber(argv[2]); +local timeout = tonumber(argv[3]); +local retry_timeout = tonumber(argv[4]); +local acd_caller_id = tonumber(argv[5]); + +-- initialize logging +require 'common.log' +local log = common.log.Log:new{ prefix = '### [' .. caller_uuid .. '] ' }; + +if not acd_id then + log:error('ACD_WAIT - automaticcalldistributor=', acd_id, ' not specified'); + return; +end + +-- connect to database +require 'common.database' +local database = common.database.Database:new{ log = log }:connect(); +if not database:connected() then + log:critical('ACD_WAIT - database connect failed'); + database:release(); + return; +end + +require 'dialplan.acd' +local acd = dialplan.acd.AutomaticCallDistributor:new{ log = log, database = database }:find_by_id(acd_id); + +if not acd then + log:error('ACD_WAIT - automaticcalldistributor=', acd_id, ' not found'); + database:release(); + return; +end + +log:debug('ACD_WAIT ', acd_id, ' - start'); +acd:wait_turn(caller_uuid, acd_caller_id, timeout, retry_timeout); +log:debug('ACD_WAIT ', acd_id, ' - end'); + +-- release database +if database then + database:release(); +end diff --git a/misc/freeswitch/scripts/common/call_forwarding.lua b/misc/freeswitch/scripts/common/call_forwarding.lua new file mode 100644 index 0000000..3942d05 --- /dev/null +++ b/misc/freeswitch/scripts/common/call_forwarding.lua @@ -0,0 +1,47 @@ +-- Gemeinschaft 5 module: call forwarding class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +CallForwarding = {} + +-- Create CallForwarding object +function CallForwarding.new(self, arg, object) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self + self.log = arg.log; + self.database = arg.database; + self.record = arg.record; + self.domain = arg.domain; + return object; +end + +-- Find call forwarding by id +function CallForwarding.find_by_id(self, id) + local sql_query = 'SELECT * FROM `call_forwards` WHERE `id`= ' .. tonumber(id) .. ' LIMIT 1'; + local record = nil + + self.database:query(sql_query, function(entry) + record = entry; + end) + + if record then + call_forwarding = CallForwarding:new(self) + call_forwarding.record = record + return call_forwarding + end + + return nil +end + +function CallForwarding.presence_set(self, presence_state) + require 'dialplan.presence' + local presence = dialplan.presence.Presence:new(); + + presence:init{log = self.log, accounts = { 'f-cftg-' .. tostring(self.record.id) }, domain = self.domain, uuid = 'call_forwarding_' .. tostring(self.record.id)}; + + return presence:set(presence_state); +end diff --git a/misc/freeswitch/scripts/common/call_history.lua b/misc/freeswitch/scripts/common/call_history.lua new file mode 100644 index 0000000..c5bc0bf --- /dev/null +++ b/misc/freeswitch/scripts/common/call_history.lua @@ -0,0 +1,140 @@ +-- Gemeinschaft 5 module: call_history class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + + +function camelize_type(account_type) + ACCOUNT_TYPES = { + sipaccount = 'SipAccount', + conference = 'Conference', + faxaccount = 'FaxAccount', + callthrough = 'Callthrough', + huntgroup = 'HuntGroup', + automaticcalldistributor = 'AutomaticCallDistributor', + } + + return ACCOUNT_TYPES[account_type] or account_type; +end + + +CallHistory = {} + +-- Create CallHistory object +function CallHistory.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.class = 'callhistory'; + self.log = arg.log; + self.database = arg.database; + return object; +end + + +function CallHistory.insert_entry(self, call_history) + local keys = {} + local values = {} + + call_history.created_at = 'NOW()'; + call_history.updated_at = 'NOW()'; + + for key, value in pairs(call_history) do + table.insert(keys, key); + table.insert(values, value); + end + + local sql_query = 'INSERT INTO `call_histories` (`' .. table.concat(keys, "`, `") .. '`) VALUES (' .. table.concat(values, ", ") .. ')'; + local result = self.database:query(sql_query); + if not result then + self.log:error('[', call_history.caller_channel_uuid, '] CALL_HISTORY_SAVE - SQL: ', sql_query); + end + return result; +end + + +function CallHistory.insert_event(self, uuid, account_type, account_id, entry_type, event) + require 'common.str' + local call_history = {} + + call_history.entry_type = common.str.to_sql(entry_type); + call_history.call_historyable_type = common.str.to_sql(camelize_type(account_type)); + call_history.call_historyable_id = common.str.to_sql(account_id); + call_history.caller_channel_uuid = common.str.to_sql(uuid); + call_history.duration = common.str.to_sql(event:getHeader('variable_billsec')); + call_history.caller_id_number = common.str.to_sql(event:getHeader('variable_effective_caller_id_number')); + call_history.caller_id_name = common.str.to_sql(event:getHeader('variable_effective_caller_id_name')); + call_history.callee_id_number = common.str.to_sql(event:getHeader('variable_effective_callee_id_number')); + call_history.callee_id_name = common.str.to_sql(event:getHeader('variable_effective_callee_id_name')); + call_history.result = common.str.to_sql(event:getHeader('variable_hangup_cause')); + call_history.start_stamp = 'FROM_UNIXTIME(' .. math.floor(common.str.to_i(event:getHeader('Caller-Channel-Created-Time')) / 1000000) .. ')'; + call_history.caller_account_type = common.str.to_sql(camelize_type(event:getHeader('variable_gs_caller_account_type') or event:getHeader('variable_gs_account_type'))); + call_history.caller_account_id = common.str.to_sql(event:getHeader('variable_gs_caller_account_id') or event:getHeader('variable_gs_account_id')); + call_history.auth_account_type = common.str.to_sql(camelize_type(event:getHeader('variable_gs_auth_account_type'))); + call_history.auth_account_id = common.str.to_sql(event:getHeader('variable_gs_auth_account_id')); + call_history.callee_account_type = common.str.to_sql(camelize_type(event:getHeader('variable_gs_destination_type'))); + call_history.callee_account_id = common.str.to_sql(event:getHeader('variable_gs_destination_id')); + call_history.destination_number = common.str.to_sql(event:getHeader('variable_gs_destination_number')); + call_history.forwarding_service = common.str.to_sql(event:getHeader('variable_gs_forwarding_service')); + + if common.str.to_s(event:getHeader('variable_gs_call_service')) == 'pickup' then + call_history.forwarding_service = common.str.to_sql('pickup'); + end + + self.log:info('[', uuid,'] CALL_HISTORY_SAVE ', entry_type,' - account: ', account_type, '=', account_id, + ', caller: ', call_history.caller_id_number, ' ', call_history.caller_id_name, + ', callee: ', call_history.callee_id_number, ' ', call_history.callee_id_name, + ', result: ', call_history.result + ); + + return self:insert_entry(call_history); +end + + +function CallHistory.insert_forwarded(self, uuid, account_type, account_id, caller, destination, result) + require 'common.str' + + local call_history = {} + + call_history.entry_type = common.str.to_sql('forwarded'); + call_history.call_historyable_type = common.str.to_sql(camelize_type(account_type)); + call_history.call_historyable_id = common.str.to_sql(account_id); + call_history.caller_channel_uuid = common.str.to_sql(uuid); + + call_history.duration = common.str.to_sql(caller:to_i('billsec')); + call_history.caller_id_number = common.str.to_sql(caller.caller_id_number); + call_history.caller_id_name = common.str.to_sql(caller.caller_id_name); + call_history.callee_id_number = common.str.to_sql(caller.callee_id_number); + call_history.callee_id_name = common.str.to_sql(caller.callee_id_name); + call_history.result = common.str.to_sql(result.cause or 'UNSPECIFIED'); + call_history.start_stamp = 'FROM_UNIXTIME(' .. math.floor(caller:to_i('created_time') / 1000000) .. ')'; + + if caller.account then + call_history.caller_account_type = common.str.to_sql(camelize_type(caller.account.class)); + call_history.caller_account_id = common.str.to_sql(caller.account.id); + end + + if caller.auth_account then + call_history.auth_account_type = common.str.to_sql(camelize_type(caller.auth_account.class)); + call_history.auth_account_id = common.str.to_sql(caller.auth_account.id); + end + + if destination then + call_history.callee_account_type = common.str.to_sql(camelize_type(destination.type)); + call_history.callee_account_id = common.str.to_sql(destination.id); + call_history.destination_number = common.str.to_sql(destination.number); + end + + call_history.forwarding_service = common.str.to_sql(caller.forwarding_service); + + self.log:info('CALL_HISTORY_SAVE forwarded - account: ', account_type, '=', account_id, + ', service: ', call_history.forwarding_service, + ', caller: ', call_history.caller_id_number, ' ', call_history.caller_id_name, + ', callee: ', call_history.callee_id_number, ' ', call_history.callee_id_name, + ', result: ', call_history.result + ); + + return self:insert_entry(call_history); +end diff --git a/misc/freeswitch/scripts/common/conference.lua b/misc/freeswitch/scripts/common/conference.lua new file mode 100644 index 0000000..d2bf829 --- /dev/null +++ b/misc/freeswitch/scripts/common/conference.lua @@ -0,0 +1,239 @@ +-- Gemeinschaft 5 module: conference class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +Conference = {} + +MEMBERS_MAX = 100; +PIN_LENGTH_MAX = 10; +PIN_LENGTH_MIN = 2; +PIN_TIMEOUT = 4000; +ANNOUNCEMENT_MAX_LEN = 10 +ANNOUNCEMENT_SILENCE_THRESHOLD = 500 +ANNOUNCEMENT_SILENCE_LEN = 3 + +-- create conference object +function Conference.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.class = 'conference'; + self.log = arg.log; + self.database = arg.database; + self.record = arg.record; + self.max_members = 0; + return object; +end + +-- find conference by id +function Conference.find_by_id(self, id) + local sql_query = 'SELECT * FROM `conferences` WHERE `id`= ' .. tonumber(id) .. ' LIMIT 1'; + local conference = nil; + + self.database:query(sql_query, function(conference_entry) + conference = Conference:new(self); + conference.record = conference_entry; + conference.id = tonumber(conference_entry.id); + conference.uuid = conference_entry.uuid; + conference.max_members = tonumber(conference.record.max_members) or MEMBERS_MAX; + end) + + return conference; +end + +-- find invitee by phone numbers +function Conference.find_invitee_by_numbers(self, phone_numbers) + if not self.record then + return false + end + + local sql_query = string.format( + "SELECT `conference_invitees`.`pin` AS `pin`, `conference_invitees`.`speaker` AS `speaker`, `conference_invitees`.`moderator` AS `moderator` " .. + "FROM `conference_invitees` JOIN `phone_numbers` ON `phone_numbers`.`phone_numberable_id` = `conference_invitees`.`id` " .. + "WHERE `phone_numbers`.`phone_numberable_type` = 'ConferenceInvitee' AND `conference_invitees`.`conference_id` = %d " .. + "AND `phone_numbers`.`number` IN ('%s') LIMIT 1", self.record.id, table.concat(phone_numbers, "','")); + + local invitee = nil; + + self.database:query(sql_query, function(conference_entry) + invitee = conference_entry; + end) + + return invitee; +end + +function Conference.count(self) + return tonumber(self.caller:result('conference ' .. self.record.id .. ' list count')) or 0; +end + +-- Try to enter a conference +function Conference.enter(self, caller, domain) + local cause = "NORMAL_CLEARING"; + local pin = nil; + local flags = {'waste'}; + + self.caller = caller; + + require "common.phone_number" + local phone_number_class = common.phone_number.PhoneNumber:new{log = self.log, database = self.database} + local phone_numbers = phone_number_class:list_by_owner(self.record.id, "Conference"); + + -- Set conference presence + require "dialplan.presence" + local presence = dialplan.presence.Presence:new(); + presence:init{ log = log, accounts = phone_numbers, domain = domain, uuid = "conference_" .. self.record.id }; + + local conference_count = self:count(); + + -- Check if conference is full + if conference_count >= self.max_members then + presence:early(); + self.log:debug(string.format("full conference %s (\"%s\"), members: %d, members allowed: %d", self.record.id, self.record.name, conference_count, self.max_members)); + + if (tonumber(self.record.conferenceable_id) == caller.account_owner_id) + and (self.record.conferenceable_type == caller.account_owner_type) then + self.log:debug("Allow owner of this conterence to enter a full conference"); + else + cause = "CALL_REJECTED"; + caller:hangup(cause); + return cause; + end; + end + + -- Check if conference is within time frame + if self.record.start and self.record['end'] then + local d = {} + _,_,d.year,d.month,d.day,d.hour,d.min,d.sec=string.find(self.record.start, "(%d+)-(%d+)-(%d+) (%d+):(%d+):(%d+)"); + + local conference_start = os.time(d); + _,_,d.year,d.month,d.day,d.hour,d.min,d.sec=string.find(self.record['end'], "(%d+)-(%d+)-(%d+) (%d+):(%d+):(%d+)"); + local conference_end = os.time(d); + local now = os.time(os.date("!*t", os.time())); + + log:debug("conference - open: " .. os.date("%c",conference_start) .. " by " .. os.date("%c",conference_end) .. ", now: " .. os.date("%c",now)); + + if now < conference_start or now > conference_end then + cause = "CALL_REJECTED"; + caller:hangup(cause); + return cause; + end + end + + require 'common.str' + -- Owner ist always moderator + if (tonumber(self.record.conferenceable_id) == caller.account_owner_id) and (self.record.conferenceable_type == caller.account_owner_type) then + table.insert(flags, 'moderator'); + log:debug("is owner - conference: " .. self.record.id .. ", owner: " .. caller.account_owner_type .. ":" .. caller.account_owner_id); + else + local invitee = self:find_invitee_by_numbers(caller.caller_phone_numbers); + + if not common.str.to_b(self.record.open_for_anybody) and not invitee then + log:debug(string.format("conference %s (\"%s\"), caller %s not allowed to enter this conference", self.record.id, self.record.name, caller.caller_phone_number)); + cause = "CALL_REJECTED"; + caller:hangup(cause); + return cause; + end + + if invitee then + log:debug("conference " .. self.record.id .. " member invited - speaker: " .. invitee.speaker .. ", moderator: " .. invitee.moderator); + if common.str.to_b(invitee.moderator) then + table.insert(flags, 'moderator'); + end + if not common.str.to_b(invitee.speaker) then + table.insert(flags, 'mute'); + end + pin = invitee.pin; + else + log:debug("conference " .. self.record.id .. " caller not invited"); + end + end + + if not pin and self.record.pin then + pin = self.record.pin + end + + caller:answer(); + caller:sleep(1000); + caller.session:streamFile('conference/conf-welcome.wav'); + + if pin and pin ~= "" then + local digits = ""; + for i = 1, 3, 1 do + if digits == pin then + break + elseif digits ~= "" then + caller.session:streamFile('conference/conf-bad-pin.wav'); + end + digits = caller.session:read(PIN_LENGTH_MIN, PIN_LENGTH_MAX, 'conference/conf-enter_conf_pin.wav', PIN_TIMEOUT, '#'); + end + if digits ~= pin then + caller.session:streamFile("conference/conf-goodbye.wav"); + return "CALL_REJECTED"; + end + end + + self.log:debug(string.format("entering conference %s - name: \"%s\", flags: %s, members: %d, max. members: %d", + self.record.id, self.record.name, table.concat(flags, ','), conference_count, self.max_members)); + + -- Members count will be incremented in a few milliseconds, set presence + if (conference_count + 1) >= self.max_members then + presence:early(); + else + presence:confirmed(); + end + + -- Enter the conference + local name_file = nil; + + -- Record caller's name + if common.str.to_b(self.record.announce_new_member_by_name) or common.str.to_b(self.record.announce_left_member_by_name) then + local uid = session:get_uuid(); + name_file = "/tmp/conference_caller_name_" .. uid .. ".wav"; + caller.session:streamFile("voicemail/vm-record_name1.wav"); + caller.session:execute("playback", "tone_stream://%(1000,0,500)"); + session:recordFile(name_file, ANNOUNCEMENT_MAX_LEN, ANNOUNCEMENT_SILENCE_THRESHOLD, ANNOUNCEMENT_SILENCE_LEN); + caller.session:streamFile(name_file); + end + + -- Play entering caller's name if recorded + if name_file and (self:count() > 0) and common.str.to_b(self.record.announce_new_member_by_name) then + caller.session:execute('set',"result=${conference(" .. self.record.id .. " play ".. name_file .. ")}"); + caller.session:execute('set',"result=${conference(" .. self.record.id .. " play conference/conf-has_joined.wav)}"); + else + -- Ensure a surplus "#" digit is not passed to the conference + caller.session:read(1, 1, '', 1000, "#"); + end + + local result = caller.session:execute('conference', self.record.id .. "@profile_" .. self.record.id .. "++flags{" .. table.concat(flags, '|') .. "}"); + self.log:debug('exited conference - result: ' .. tostring(result)); + caller.session:streamFile("conference/conf-goodbye.wav") + + -- Play leaving caller's name if recorded + if name_file then + if (self:count() > 0) and common.str.to_b(self.record.announce_left_member_by_name) then + if (self:count() == 1) then + caller.session:sleep(3000); + end + caller.session:execute('set',"result=${conference(" .. self.record.id .. " play ".. name_file .. ")}"); + caller.session:execute('set',"result=${conference(" .. self.record.id .. " play conference/conf-has_left.wav)}"); + end + os.remove(name_file); + end + + -- Set presence according to member count + conference_count = self:count(); + if conference_count >= self.max_members then + presence:early(); + elseif conference_count > 0 then + presence:confirmed(); + else + presence:terminated(); + end + + cause = "NORMAL_CLEARING"; + caller.session:hangup(cause); + return cause; +end diff --git a/misc/freeswitch/scripts/common/configuration_file.lua b/misc/freeswitch/scripts/common/configuration_file.lua new file mode 100644 index 0000000..67e1f3b --- /dev/null +++ b/misc/freeswitch/scripts/common/configuration_file.lua @@ -0,0 +1,70 @@ +-- Gemeinschaft 5 module: configuration file +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +function ignore_comments(line) + return line:gsub(';+([^;]*)', function(entry) + return ''; + end); +end + +-- parse configuration +function parse(lines, filter_section_name) + require 'common.str' + local section = {} + local root = { [true] = section } + + for line in lines do + if line then + local ignore_line = false; + line = ignore_comments(line); + + line:gsub('^%s*%[(.-)%]%s*$', function(section_name) + if tostring(section_name):match('%=false$') then + section = {} + else + root[common.str.strip(section_name)] = {}; + section = root[common.str.strip(section_name)]; + end + ignore_line = true; + end); + + if not ignore_line then + key, value = common.str.partition(line, '='); + if value and key and not common.str.strip(key):match('%s') then + section[common.str.strip(key)] = common.str.strip(value); + else + line = common.str.strip(line); + if not common.str.blank(line) then + if line:match(',') then + table.insert(section, common.str.strip_to_a(line, ',')); + else + table.insert(section, line); + end + end + end + end + end + end + + if filter_section_name == false then + root[true] = nil; + elseif filter_section_name then + return root[filter_section_name]; + end + + return root; +end + +-- retrieve configuration from file +function get(file_name, filter_section_name) + local file = io.open(file_name); + + if file then + local result = parse(file:lines(), filter_section_name); + file:close(); + return result; + end +end diff --git a/misc/freeswitch/scripts/common/database.lua b/misc/freeswitch/scripts/common/database.lua new file mode 100644 index 0000000..3692f84 --- /dev/null +++ b/misc/freeswitch/scripts/common/database.lua @@ -0,0 +1,151 @@ +-- Gemeinschaft 5 module: database class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +Database = {} + +DATABASE_DRIVER = 'mysql' + +function Database.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.class = 'database'; + self.log = arg.log; + self.conn = nil; + return object; +end + + +function Database.connect(self, database_name, user_name, password, host_name) + local database_driver = nil; + if not (database_name and user_name and password) then + require 'common.configuration_file' + local config = common.configuration_file.get('/opt/freeswitch/scripts/ini/database.ini'); + if config then + database_driver = config[true].driver + database_name = config[database_driver].database + user_name = config[database_driver].user + password = config[database_driver].password + host_name = config[database_driver].host + end + end + + host_name = host_name or 'localhost'; + database_driver = database_driver or DATABASE_DRIVER; + + if database_driver == 'mysql' then + require "luasql.mysql" + self.env = luasql.mysql(); + elseif database_driver == 'odbc' then + require "luasql.odbc" + self.env = luasql.odbc(); + end + + self.conn = self.env:connect(database_name, user_name, password, host_name); + self.conn_id = tostring(self.conn); + self.database_name = database_name; + self.user_name = user_name; + self.password = password; + self.host_name = host_name; + + -- self.log:debug('DATABASE_CONNECT - connection: ', self.conn_id, ', environment: ', self.env); + + return self; +end + + +function Database.reconnect(self) + self.conn = self.env:connect(self.database_name, self.user_name, self.password, self.host_name); + self.conn_id = tostring(self.conn); + + if self.log then + self.log:info('DATABASE_RECONNECT - connection: ', self.conn_id, ', environment: ', self.env); + end + + return self; +end + + +function Database.connected(self) + return self.conn; +end + + +function Database.query(self, sql_query, call_function) + local cursor = self.conn:execute(sql_query); + + if cursor == nil and not self.conn:execute('SELECT @@VERSION') then + if self.log then + self.log:error('DATABASE_QUERY - lost connection: ', self.conn_id, ', environment: ', self.env, ', query: ', sql_query); + end + self:reconnect(); + + if call_function then + cursor = self.conn:execute(sql_query); + self.log:notice('DATABASE_QUERY - retry: ', sql_query); + end + end + + if cursor and call_function then + repeat + row = cursor:fetch({}, 'a'); + if row then + call_function(row); + end + until not row; + end + + if type(cursor) == 'userdata' then + cursor:close(); + end + + return cursor; +end + + +function Database.query_return_value(self, sql_query) + local cursor = self.conn:execute(sql_query); + + if cursor == nil and not self.conn:execute('SELECT @@VERSION') then + if self.log then + self.log:error('DATABASE_QUERY - lost connection: ', self.conn_id, ', environment: ', self.env, ', query: ', sql_query); + end + self:reconnect(); + cursor = self.conn:execute(sql_query); + self.log:notice('DATABASE_QUERY - retry: ', sql_query); + end + + if type(cursor) == 'userdata' then + local row = cursor:fetch({}, 'n'); + cursor:close(); + + if not row then + return row; + else + return row[1]; + end + end + + return cursor; +end + + +function Database.last_insert_id(self) + return self:query_return_value('SELECT LAST_INSERT_ID()'); +end + + +function Database.release(self, sql_query, call_function) + if self.conn then + self.conn:close(); + end + if self.env then + self.env:close(); + end + + -- self.log:debug('DATABASE_RELEASE - connection: ', self.conn_id, ', status: ', self.env, ', ', self.conn); +end diff --git a/misc/freeswitch/scripts/common/fapi.lua b/misc/freeswitch/scripts/common/fapi.lua new file mode 100644 index 0000000..0a05155 --- /dev/null +++ b/misc/freeswitch/scripts/common/fapi.lua @@ -0,0 +1,80 @@ +-- Gemeinschaft 5 module: FS api class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +FApi = {} + +-- create fapi object +function FApi.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.class = 'fapi'; + self.log = arg.log; + self.uuid = arg.uuid; + self.fs_api = freeswitch.API(); + return object; +end + + +function FApi.return_result(self, result, positive, negative, unspecified) + if not result then + return negative; + end + result = tostring(result); + + if result:match('^-ERR') then + return negative; + elseif result:match('^_undef_') then + return negative; + elseif result:match('^+OK') then + return positive; + else + return unspecified; + end +end + + +function FApi.sleep(self, value) + freeswitch.msleep(value); +end + + +function FApi.channel_exists(self, uuid) + require 'common.str' + uuid = uuid or self.uuid; + return common.str.to_b(freeswitch.API():execute('uuid_exists', tostring(uuid))); +end + + +function FApi.get_variable(self, variable_name) + local result = freeswitch.API():execute('uuid_getvar', tostring(self.uuid) .. ' ' .. tostring(variable_name)); + return self:return_result(result, result, nil, result); +end + + +function FApi.set_variable(self, variable_name, value) + value = value or ''; + + local result = freeswitch.API():execute('uuid_setvar', tostring(self.uuid) .. ' ' .. tostring(variable_name) .. ' ' .. tostring(value)); + return self:return_result(result, true); +end + + +function FApi.continue(self) + local result = freeswitch.API():execute('break', tostring(self.uuid)); + return self:return_result(result, true, false); +end + +function FApi.create_uuid(self, uuid) + local result = self.fs_api:execute('create_uuid', uuid); + return result; +end + +function FApi.execute(self, function_name, function_parameters) + local result = self.fs_api:execute(function_name, function_parameters); + return self:return_result(result, true); +end diff --git a/misc/freeswitch/scripts/common/ipcalc.lua b/misc/freeswitch/scripts/common/ipcalc.lua new file mode 100644 index 0000000..5c19d20 --- /dev/null +++ b/misc/freeswitch/scripts/common/ipcalc.lua @@ -0,0 +1,27 @@ +-- Gemeinschaft 5 module: ip calculation functions +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +function ipv4_to_i(ip_address_str) + local octet4, octet3, octet2, octet1 = ip_address_str:match('(%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)'); + if octet4 and octet3 and octet2 and octet1 then + return (2^24*octet4 + 2^16*octet3 + 2^8*octet2 + octet1); + end +end + +function ipv4_to_network_netmask(ip_address_str) + local octet4, octet3, octet2, octet1, netmask = ip_address_str:match('(%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)/(%d%d?)'); + if octet4 and octet3 and octet2 and octet1 and netmask then + return (2^24*octet4 + 2^16*octet3 + 2^8*octet2 + octet1), tonumber(netmask); + end +end + +function ipv4_network(ip_address, netmask) + return math.floor(ip_address / 2^(32-netmask)); +end + +function ipv4_in_network(ip_address, network, netmask) + return ipv4_network(ip_address, netmask) == ipv4_network(network, netmask); +end diff --git a/misc/freeswitch/scripts/common/log.lua b/misc/freeswitch/scripts/common/log.lua new file mode 100644 index 0000000..d0d13dc --- /dev/null +++ b/misc/freeswitch/scripts/common/log.lua @@ -0,0 +1,69 @@ +-- Gemeinschaft 5 module: log +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +Log = {} + +-- Create logger object +function Log.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.prefix = arg.prefix or '### '; + + self.level_console = arg.level_console or 0; + self.level_alert = arg.level_alert or 1; + self.level_critical = arg.level_critical or 2; + self.level_error = arg.level_error or 3; + self.level_warning = arg.level_warning or 4; + self.level_notice = arg.level_notice or 5; + self.level_info = arg.level_info or 6; + self.level_debug = arg.level_debug or 7; + + return object; +end + +function Log.message(self, log_level, message_arguments ) + local message = tostring(self.prefix); + for index, value in pairs(message_arguments) do + if type(index) == 'number' then + message = message .. tostring(value); + end + end + freeswitch.consoleLog(log_level, message .. '\n'); +end + +function Log.console(self, ...) + self:message(self.level_console, arg); +end + +function Log.alert(self, ...) + self:message(self.level_alert, arg); +end + +function Log.critical(self, ...) + self:message(self.level_critical, arg); +end + +function Log.error(self, ...) + self:message(self.level_error, arg); +end + +function Log.warning(self, ...) + self:message(self.level_warning, arg); +end + +function Log.notice(self, ...) + self:message(self.level_notice, arg); +end + +function Log.info(self, ...) + self:message(self.level_info, arg); +end + +function Log.debug(self, ...) + self:message(self.level_debug, arg); +end diff --git a/misc/freeswitch/scripts/common/node.lua b/misc/freeswitch/scripts/common/node.lua new file mode 100644 index 0000000..544ede9 --- /dev/null +++ b/misc/freeswitch/scripts/common/node.lua @@ -0,0 +1,73 @@ +-- CommonModule: Node +-- +module(...,package.seeall) + +Node = {} + +-- Create Node object +function Node.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self) + self.__index = self + self.log = arg.log + self.database = arg.database + self.record = arg.record + self.session = arg.session + return object +end + +-- Find Node account by name +function Node.find_by_id(self, node_id) + + if not tonumber(node_id) then + return nil + end + + local sql_query = 'SELECT * FROM `gs_nodes` WHERE `id`= ' .. node_id .. ' LIMIT 1'; + local record = nil + + self.database:query(sql_query, function(node_entry) + record = node_entry + end) + + if record then + local node_object = Node:new(self); + node_object.record = record + + return node_object + end + + return nil +end + +-- Find Node account by name +function Node.find_by_address(self, address) + local sql_query = 'SELECT * FROM `gs_nodes` WHERE `ip_address`= "' .. tostring(address):gsub('[^A-F0-9%.%:]', '') .. '" LIMIT 1'; + local record = nil + + self.database:query(sql_query, function(node_entry) + record = node_entry + end) + + if record then + local node_object = Node:new(self); + node_object.record = record + + return node_object + end + + return nil +end + +-- List Nodes +function Node.all(self) + local sql_query = 'SELECT * FROM `gs_nodes`'; + nodes = {}; + + self.database:query(sql_query, function(node_entry) + nodes[tonumber(node_entry.id)] = node_entry; + end) + + return nodes +end \ No newline at end of file diff --git a/misc/freeswitch/scripts/common/phone_number.lua b/misc/freeswitch/scripts/common/phone_number.lua new file mode 100644 index 0000000..f4f4bfe --- /dev/null +++ b/misc/freeswitch/scripts/common/phone_number.lua @@ -0,0 +1,359 @@ +-- Gemeinschaft 5 module: phone number class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +PhoneNumber = {} + +PHONE_NUMBER_INTERNAL_TYPES = { 'SipAccount', 'Conference', 'FaxAccount', 'Callthrough', 'HuntGroup', 'AutomaticCallDistributor' } + +-- create phone number object +function PhoneNumber.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.class = 'phonenumber'; + self.log = arg.log; + self.database = arg.database; + self.record = arg.record; + self.domain = arg.domain; + self.DEFAULT_CALL_FORWARDING_DEPTH = 20; + return object; +end + +-- find phone number by id +function PhoneNumber.find_by_id(self, id) + local sql_query = 'SELECT * FROM `phone_numbers` WHERE `id`= ' .. tonumber(id) .. ' LIMIT 1'; + + local phone_number = nil; + + self.database:query(sql_query, function(number_entry) + phone_number = PhoneNumber:new(self); + phone_number.record = number_entry; + phone_number.id = tonumber(number_entry.id); + phone_number.uuid = number_entry.uuid; + end) + + return phone_number; +end + +-- find phone number by number +function PhoneNumber.find_by_number(self, number, phone_numberable_types) + require 'common.str' + + phone_numberable_types = phone_numberable_types or PHONE_NUMBER_INTERNAL_TYPES + + local sql_query = 'SELECT * FROM `phone_numbers` \ + WHERE `number`= ' .. common.str.to_sql(number) .. ' \ + AND `phone_numberable_type` IN ("' .. table.concat(phone_numberable_types, '","') .. '") \ + AND `state` = "active" LIMIT 1'; + + local phone_number = nil; + + self.database:query(sql_query, function(number_entry) + phone_number = PhoneNumber:new(self); + phone_number.record = number_entry; + end) + + return phone_number; +end + +-- Find numbers by owner id and type +function PhoneNumber.find_all_by_owner(self, owner_id, owner_type) + local sql_query = 'SELECT * FROM `phone_numbers` WHERE `phone_numberable_type`="' .. owner_type .. '" AND `phone_numberable_id`= ' .. tonumber(owner_id) ..' ORDER BY `position`'; + local phone_numbers = {} + + self.database:query(sql_query, function(number_entry) + phone_numbers[tonumber(number_entry.id)] = PhoneNumber:new(self); + phone_numbers[tonumber(number_entry.id)].record = number_entry; + end) + + return phone_numbers; +end + +-- List numbers by owner id and type +function PhoneNumber.list_by_owner(self, owner_id, owner_type) + local sql_query = 'SELECT * FROM `phone_numbers` WHERE `phone_numberable_type`="' .. owner_type .. '" AND `phone_numberable_id`= ' .. tonumber(owner_id) ..' ORDER BY `position`'; + local phone_numbers = {} + + self.database:query(sql_query, function(number_entry) + table.insert(phone_numbers, number_entry.number) + end) + + return phone_numbers; +end + +-- List numbers by same owner +function PhoneNumber.list_by_same_owner(self, number, owner_types) + local phone_number = self:find_by_number(number, owner_types) + + if phone_number then + return self:list_by_owner(phone_number.record.phone_numberable_id, phone_number.record.phone_numberable_type); + end +end + +-- Retrieve call forwarding +function PhoneNumber.call_forwarding(self, sources) + require 'common.str' + + sources = sources or {}; + table.insert(sources, ''); + + local sql_query = 'SELECT \ + `a`.`destination` AS `number`, \ + `a`.`call_forwardable_id` AS `id`, \ + `a`.`call_forwardable_type` AS `type`, \ + `a`.`timeout`, `a`.`depth`, \ + `b`.`value` AS `service` \ + FROM `call_forwards` `a` JOIN `call_forward_cases` `b` ON `a`.`call_forward_case_id` = `b`.`id` \ + WHERE `a`.`phone_number_id`= ' .. tonumber(self.record.id) .. ' \ + AND `a`.`active` IS TRUE \ + AND (`a`.`source` IS NULL OR `a`.`source` IN ("' .. table.concat( sources, '","') .. '"))'; + + local call_forwarding = {} + + self.database:query(sql_query, function(forwarding_entry) + call_forwarding[forwarding_entry.service] = forwarding_entry; + self.log:debug('CALL_FORWARDING_GET - PhoneNumber=', self.record.id, '/', self.record.uuid, '@', self.record.gs_node_id, + ', number: ', self.record.number, + ', service: ', forwarding_entry.service, + ', destination: ',forwarding_entry.type, '=', forwarding_entry.id, + ', number: ', forwarding_entry.number); + end) + + return call_forwarding; +end + + +function PhoneNumber.call_forwarding_effective(self, service, source) + local conditions = {} + table.insert(conditions, '`phone_number_id` = ' .. self.record.id); + + if source then + table.insert(conditions, '`source` = "' .. source); + else + table.insert(conditions, '(`source` = "" OR `source` IS NULL)'); + end + + if service then + table.insert(conditions, '`call_forward_case_id` IN (SELECT `id` FROM `call_forward_cases` WHERE `value` = "' .. service .. '")'); + end + + -- get call forwarding entry + local sql_query = 'SELECT `destination`,`active`,`timeout`,`call_forwardable_type`, `call_forwardable_id` FROM `call_forwards` WHERE ' .. table.concat(conditions, ' AND ') .. ' ORDER BY `active` DESC LIMIT 1'; + local call_forwarding = nil; + + self.database:query(sql_query, function(entry) + call_forwarding = entry; + end) + + return call_forwarding; +end + + +function PhoneNumber.call_forwarding_off(self, service, source, delete) + local conditions = {} + table.insert(conditions, '`phone_number_id` = ' .. self.record.id); + + if source then + table.insert(conditions, '`source` = "' .. source); + else + table.insert(conditions, '(`source` = "" OR `source` IS NULL)'); + end + + if service then + table.insert(conditions, '`call_forward_case_id` IN (SELECT `id` FROM `call_forward_cases` WHERE `value` = "' .. service .. '")'); + end + + self.log:info('PHONE_NUMBER_CALL_FORWARDING_OFF - service: ', service, ', number: ', self.record.number); + + local call_forwarding_ids = {} + + local sql_query = 'SELECT `id` FROM `call_forwards` WHERE ' .. table.concat(conditions, ' AND '); + self.database:query(sql_query, function(record) + table.insert(call_forwarding_ids, record.id); + end) + + require 'common.call_forwarding' + local call_forwarding_class = common.call_forwarding.CallForwarding:new{ log = self.log, database = self.database, domain = self.domain }; + + for index, call_forwarding_id in ipairs(call_forwarding_ids) do + if tonumber(call_forwarding_id) then + local call_forwarding = call_forwarding_class:find_by_id(call_forwarding_id); + call_forwarding:presence_set('terminated'); + end + end + + -- set call forwarding entry inactive + local sql_query = 'UPDATE `call_forwards` SET `active` = FALSE, `updated_at` = NOW() WHERE ' .. table.concat(conditions, ' AND '); + + local call_forwards = {}; + + -- or delete call forwarding entry + if delete then + sql_query = 'SELECT * FROM `call_forwards` WHERE ' .. table.concat(conditions, ' AND '); + self.database:query(sql_query, function(forwarding_entry) + table.insert(call_forwards, forwarding_entry) + end) + sql_query = 'DELETE FROM `call_forwards` WHERE ' .. table.concat(conditions, ' AND '); + end + + if not self.database:query(sql_query) then + self.log:notice('PHONE_NUMBER_CALL_FORWARDING_OFF - call forwarding could not be deactivated - number: ', self.record.number); + return false; + end + + if delete then + require 'common.sync_log' + local sync_log_class = common.sync_log.SyncLog:new{ log = self.log, database = self.database, homebase_ip_address = '' } + + for index, call_forward in ipairs(call_forwards) do + sync_log_class:insert('CallForward', call_forward, 'destroy', nil); + end + end + + return true; +end + + +function PhoneNumber.call_forwarding_on(self, service, destination, destination_type, timeout, source) + require 'common.str' + if call_forwarding_service == 'noanswer' then + timeout = tonumber(timeout) or '30'; + else + timeout = 'NULL'; + end + + if source then + sql_query = 'SELECT `id`, `destination`, `call_forwardable_type`, `call_forward_case_id` FROM `call_forwards` \ + WHERE `phone_number_id` = ' .. self.record.id .. ' \ + AND `call_forward_case_id` IN (SELECT `id` FROM `call_forward_cases` WHERE `value` = "' .. service .. '") \ + AND `source` = "' .. source .. '" AND `phone_number_id` = ' .. self.record.id .. ' ORDER BY `active` DESC LIMIT 1'; + else + sql_query = 'SELECT `id`, `destination`, `call_forwardable_type`, `call_forward_case_id` FROM `call_forwards` \ + WHERE `phone_number_id` = ' .. self.record.id .. ' \ + AND `call_forward_case_id` IN (SELECT `id` FROM `call_forward_cases` WHERE `value` = "' .. service .. '") \ + AND (`source` = "" OR `source` IS NULL) AND `phone_number_id` = ' .. self.record.id .. ' ORDER BY `active` DESC LIMIT 1'; + end + + destination_type = destination_type or ''; + destination = destination or ''; + local service_id = nil; + local entry_id = 'NULL'; + + self.database:query(sql_query, function(record) + entry_id = record.id; + service_id = record.call_forward_case_id; + if common.str.blank(destination) then + if not common.str.blank(record.call_forwardable_type) then + destination_type = common.str.downcase(record.call_forwardable_type); + end + if not common.str.blank(record.destination) then + destination = record.destination; + end + end + end) + + if destination == '' and destination_type:lower() ~= 'voicemail' then + self.log:notice('PHONE_NUMBER_CALL_FORWARDING_ON - destination not specified - destination: ', destination, ', type: ', destination_type,', number: ' .. self.record.number); + return false; + end + + if destination_type == '' then + destination_type = 'PhoneNumber'; + end + + self.log:info('PHONE_NUMBER_CALL_FORWARDING_ON - service: ', service, ', number: ', self.record.number, ', destination: ', destination, ', type: ', destination_type, ', timeout: ', timeout); + + if not service_id then + sql_query = 'SELECT `id` FROM `call_forward_cases` WHERE `value` = "' .. service .. '"'; + self.database:query(sql_query, function(record) + service_id = tonumber(record.id); + end); + end + + sql_query = 'REPLACE INTO `call_forwards` \ + (`active`, `uuid`, `depth`, `updated_at`, `id`, `phone_number_id`, `call_forward_case_id`, `destination`, `call_forwardable_type`, `timeout`) \ + VALUES \ + (TRUE, UUID(), ' .. self.DEFAULT_CALL_FORWARDING_DEPTH .. ', NOW(), ' .. entry_id .. ', ' .. self.record.id .. ', ' .. service_id .. ', "' .. destination .. '", "' .. destination_type .. '", ' .. timeout .. ')' + + if not self.database:query(sql_query) then + self.log:error('PHONE_NUMBER_CALL_FORWARDING_ON - could not be activated - destination: ', destination, ', type: ', destination_type,', number: ' .. self.record.number); + return false; + end + + require 'common.call_forwarding' + local call_forwarding_class = common.call_forwarding.CallForwarding:new{ log = self.log, database = self.database, domain = self.domain }; + if tonumber(entry_id) then + local call_forwarding = call_forwarding_class:find_by_id(entry_id); + end + + if call_forwarding then + if destination_type:lower() == 'voicemail' then + call_forwarding:presence_set('early'); + else + call_forwarding:presence_set('confirmed'); + end + end + + return true; +end + + +function PhoneNumber.call_forwarding_toggle(self, service, source) + local call_forwarding = self:call_forwarding_effective(service, source); + + -- no call_forwarding entry: all forwarding is deactivated + if not call_forwarding then + return false; + end + + if tostring(call_forwarding.active) == '1' then + if self:call_forwarding_off(service, source) then + return {destination = call_forwarding.destination, destination_type = call_forwarding.destination_type, active = false}; + end + end + + if self:call_forwarding_on(service, call_forwarding.destination, call_forwarding.destination_type, call_forwarding.timeout, source) then + return {destination = call_forwarding.destination, destination_type = call_forwarding.destination_type, active = true}; + end + + return nil; +end + + +function PhoneNumber.call_forwarding_presence_set(self, presence_state, service) + service = service or 'always'; + local dialplan_function = 'f-cfutg'; + + if service == 'assistant' then + dialplan_function = 'f-cfatg'; + end + + require "dialplan.presence" + local presence = dialplan.presence.Presence:new(); + + presence:init{log = self.log, accounts = { dialplan_function .. '-' .. tostring(self.record.id) }, domain = self.domain, uuid = 'call_forwarding_number_' .. tostring(self.record.id)}; + + return presence:set(presence_state); +end + + +-- Retrieve ringtone +function PhoneNumber.ringtone(self, id) + id = id or self.record.id; + if not id then + return false; + end + + local sql_query = "SELECT * FROM `ringtones` WHERE `ringtoneable_type` = \"PhoneNumber\" AND `ringtoneable_id`=" .. self.record.id .. " LIMIT 1"; + local ringtone = nil; + + self.database:query(sql_query, function(entry) + ringtone = entry; + end) + + return ringtone; +end diff --git a/misc/freeswitch/scripts/common/routing_tables.lua b/misc/freeswitch/scripts/common/routing_tables.lua new file mode 100644 index 0000000..34d0143 --- /dev/null +++ b/misc/freeswitch/scripts/common/routing_tables.lua @@ -0,0 +1,66 @@ +-- Gemeinschaft 5 module: routing table functions +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +function expand_variables(line, variables_list) + variables_list = variables_list or {}; + + return (line:gsub('{([%a%d_]+)}', function(captured) + return variables_list[captured] or ''; + end)) +end + + +function match_route(entry, search_str, variables_list) + if not entry or not search_str then + return { error = 'No input values' }; + end + + local result = nil; + local success = nil; + success, result = pcall(string.find, search_str, entry[1]); + + if not success then + return { error = result, line = line } + elseif result then + local route = { + pattern = entry[1], + value = search_str:gsub(entry[1], expand_variables(entry[#entry], variables_list)), + } + + for index = 2, #entry-1 do + local attribute = entry[index]:match('^(.-)%s*='); + if attribute then + route[attribute] = entry[index]:match('=%s*(.-)$'); + end + end + + return route; + end + + return {}; +end + + +function match_caller_id(entry, search_str, variables_list) + if not entry or not search_str then + return { error = 'No input values' }; + end + local result = nil; + local success = nil; + success, result = pcall(string.find, search_str, entry[1]); + if not success then + return { error = result, line = line } + elseif result then + return { + value = search_str:gsub(entry[1], expand_variables(entry[4], variables_list)), + class = entry[2], + endpoint = entry[3], + pattern = entry[1], + } + end + + return {}; +end diff --git a/misc/freeswitch/scripts/common/sip_account.lua b/misc/freeswitch/scripts/common/sip_account.lua new file mode 100644 index 0000000..28a00df --- /dev/null +++ b/misc/freeswitch/scripts/common/sip_account.lua @@ -0,0 +1,137 @@ +-- Gemeinschaft 5 module: sip account class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +SipAccount = {} + +-- Create SipAccount object +function SipAccount.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.class = 'sipaccount'; + self.log = arg.log; + self.database = arg.database; + self.record = arg.record; + return object; +end + + +function SipAccount.find_by_sql(self, where) + local sql_query = 'SELECT \ + `a`.`id`, \ + `a`.`uuid`, \ + `a`.`auth_name`, \ + `a`.`caller_name`, \ + `a`.`password`, \ + `a`.`voicemail_pin`, \ + `a`.`tenant_id`, \ + `a`.`sip_domain_id`, \ + `a`.`call_waiting`, \ + `a`.`clir`, \ + `a`.`clip`, \ + `a`.`clip_no_screening`, \ + `a`.`sip_accountable_type`, \ + `a`.`sip_accountable_id`, \ + `a`.`hotdeskable`, \ + `a`.`gs_node_id`, \ + `b`.`host` \ + FROM `sip_accounts` `a` JOIN `sip_domains` `b` ON `a`.`sip_domain_id` = `b`.`id` \ + WHERE ' .. where .. ' LIMIT 1'; + + local sip_account = nil; + self.database:query(sql_query, function(account_entry) + sip_account = SipAccount:new(self); + sip_account.record = account_entry; + sip_account.id = tonumber(account_entry.id); + sip_account.uuid = account_entry.uuid; + end) + + return sip_account; +end + + +-- find sip account by id +function SipAccount.find_by_id(self, id) + local sql_query = '`a`.`id`= ' .. tonumber(id); + return self:find_by_sql(sql_query); +end + +-- find sip account by uuid +function SipAccount.find_by_uuid(self, uuid) + local sql_query = '`a`.`uuid`= "' .. uuid .. '"'; + return self:find_by_sql(sql_query); +end + +-- Find SIP Account by auth_name +function SipAccount.find_by_auth_name(self, auth_name, domain) + local sql_query = '`a`.`auth_name`= "' .. auth_name .. '"'; + + if domain then + sql_query = sql_query .. ' AND `b`.`host` = "' .. domain .. '"'; + end + + return self:find_by_sql(sql_query); +end + +-- retrieve Phone Numbers for SIP Account +function SipAccount.phone_numbers(self, id) + id = id or self.record.id; + if not id then + return false; + end + + local sql_query = "SELECT * FROM `phone_numbers` WHERE `phone_numberable_type` = \"SipAccount\" AND `phone_numberable_id`=" .. self.record.id; + local phone_numbers = {} + + self.database:query(sql_query, function(entry) + table.insert(phone_numbers,entry.number); + end) + + return phone_numbers; +end + +-- retrieve Ringtone for SIP Account +function SipAccount.ringtone(self, id) + id = id or self.record.id; + if not id then + return false; + end + + local sql_query = "SELECT * FROM `ringtones` WHERE `ringtoneable_type` = \"SipAccount\" AND `ringtoneable_id`=" .. self.record.id .. " LIMIT 1"; + local ringtone = nil; + + self.database:query(sql_query, function(entry) + ringtone = entry; + end) + + return ringtone; +end + +function SipAccount.send_text(self, text) + local event = freeswitch.Event("NOTIFY"); + event:addHeader("profile", "gemeinschaft"); + event:addHeader("event-string", "text"); + event:addHeader("user", self.record.auth_name); + event:addHeader("host", self.record.host); + event:addHeader("content-type", "text/plain"); + event:addBody(text); + event:fire(); +end + + +function SipAccount.call_state(self) + local state = nil + local sql_query = "SELECT `callstate` FROM `channels` \ + WHERE `name` LIKE (\"\%" .. self.record.auth_name .. "@%\") \ + OR `name` LIKE (\"\%" .. self.record.auth_name .. "@%\") LIMIT 1"; + + self.database:query(sql_query, function(channel_entry) + state = channel_entry.callstate; + end) + + return state; +end diff --git a/misc/freeswitch/scripts/common/str.lua b/misc/freeswitch/scripts/common/str.lua new file mode 100644 index 0000000..b19f299 --- /dev/null +++ b/misc/freeswitch/scripts/common/str.lua @@ -0,0 +1,136 @@ +-- Gemeinschaft 5 module: string functions +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +function try(array, arguments) + local argument = arguments:match('^(.-)%.') or arguments; + local remaining_arguments = arguments:match('%.(.-)$'); + + if argument and type(array) == 'table' then + if remaining_arguments then + if type(array[argument]) == 'table' then + return try(array[argument], remaining_arguments); + else + return nil; + end + else + return array[argument]; + end + end + + return nil; +end + +-- to number +function to_n(value) + value = tostring(value):gsub('[^%d%.%+%-]', ''); + return tonumber(value) or 0; +end + +-- to integer +function to_i(value) + return math.floor(to_n(value)); +end + +-- to string +function to_s(value) + if value == nil then + return ''; + end + + return tostring(value); +end + +-- to boolean +function to_b(value) + if type(value) == 'boolean' then + return value; + elseif tonumber(value) then + return (tonumber(value) > 0); + else + return (tostring(value) == 'yes' or tostring(value) == 'true'); + end +end + +-- to array +function to_a(line, separator) + line = line or ''; + separator = separator or ';'; + local result = {} + line:gsub('([^' .. separator .. ']+)', function(entry) + table.insert(result, entry); + end); + + return result; +end + +-- stripped to array +function strip_to_a(line, separator) + + local result = {} + line:gsub('([^' .. separator .. ']+)', function(entry) + table.insert(result, (entry:gsub('^%s+', ''):gsub('%s+$', ''))); + end); + + return result; +end + +-- downcase +function downcase(value) + if value == nil then + return ''; + end + + return tostring(value):lower(); +end + +-- remove special characters +function to_ascii(value) + return (to_s(value):gsub('[^A-Za-z0-9%-%_ %(%)]', '')); +end + +-- to SQL +function to_sql(value) + if type(value) == 'boolean' then + return tostring(value):upper(); + elseif type(value) == 'number' then + return tostring(value); + elseif type(value) == 'string' then + return '"' .. value:gsub('"', '\\"'):gsub("'", "\\'") .. '"'; + else + return 'NULL'; + end +end + +-- to JSON +function to_json(value) + if type(value) == 'boolean' then + return tostring(value):lower(); + elseif type(value) == 'number' then + return tostring(value); + elseif type(value) == 'string' then + return '"' .. value:gsub('"', '\\"'):gsub("'", "\\'") .. '"'; + else + return 'null'; + end +end + +-- remove leading/trailing whitespace +function strip(value) + return (tostring(value):gsub('^%s+', ''):gsub('%s+$', '')); +end + +-- split string +function partition(value, separator) + value = tostring(value); + separator = separator or ':' + + return value:match('^(.-)' .. separator), value:match(separator .. '(.-)$'); +end + +-- check if value is empty string or nil +function blank(value) + return (value == nil or to_s(value) == ''); +end diff --git a/misc/freeswitch/scripts/common/sync_log.lua b/misc/freeswitch/scripts/common/sync_log.lua new file mode 100644 index 0000000..05b0dcf --- /dev/null +++ b/misc/freeswitch/scripts/common/sync_log.lua @@ -0,0 +1,39 @@ +-- Gemeinschaft 5 module: sync log class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +SyncLog = {} + +-- create sync log object +function SyncLog.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.database = arg.database; + self.homebase_ip_address = arg.homebase_ip_address; + return object; +end + +-- create new entry +function SyncLog.insert(self, entry_name, entry_record, action, history_entries) + local content = {} + for key, value in pairs(entry_record) do + require 'common.str' + table.insert(content, '"'.. key ..'":' .. common.str.to_json(value)); + end + + local history = ''; + if action == 'update' then + history = 'Changed: ["' .. table.concat(history_entries, '","') .. '"]'; + end + + local sql_query = 'INSERT INTO `gs_cluster_sync_log_entries` (`waiting_to_be_synced`,`created_at`,`updated_at`,`class_name`,`action`,`content`,`history`,`homebase_ip_address`) \ + VALUES \ + (TRUE, NOW(), NOW(), \'' .. entry_name .. '\', \'' .. action .. '\', \'{' .. table.concat(content, ',') .. '}\', \'' .. history .. '\', \'' .. self.homebase_ip_address .. '\')'; + + return self.database:query(sql_query); +end diff --git a/misc/freeswitch/scripts/configuration.lua b/misc/freeswitch/scripts/configuration.lua new file mode 100644 index 0000000..906d3f8 --- /dev/null +++ b/misc/freeswitch/scripts/configuration.lua @@ -0,0 +1,229 @@ +-- Gemeinschaft 5 dynamic freeswitch configuration +-- (c) AMOOMA GmbH 2012 +-- + +function nodes(database, local_node_id) + local gateways_xml = ''; + + require 'common.node' + for node_id, node_record in pairs(common.node.Node:new{log=log, database=database}:all()) do + if node_id ~= local_node_id then + local node_parameters = {} + node_parameters['username'] = node_record.name; + node_parameters['password'] = 'gemeinschaft'; + node_parameters['proxy'] = node_record.ip_address; + node_parameters['register'] = 'false'; + log:debug('NODE_GATEWAY ', node_record.id, ' - name: ', node_record.name, ', address: ', node_record.ip_address); + gateways_xml = gateways_xml .. xml:gateway(node_record.name, node_parameters); + end + end + + return gateways_xml; +end + +function gateways(profile_name) + local gateways_xml = ''; + local gateways = common.configuration_file.get('/opt/freeswitch/scripts/ini/gateways.ini', false); + + if not gateways then + return ''; + end + + for sofia_gateway, gateway_parameters in pairs(gateways) do + if tostring(gateway_parameters.profile) == profile_name then + log:debug('GATEWAY - name: ', sofia_gateway, ', address: ', gateway_parameters.proxy); + gateways_xml = gateways_xml .. xml:gateway(sofia_gateway, gateway_parameters); + end + end + + return gateways_xml; +end + +function profile(database, sofia_ini, profile_name, index, domains, node_id) + local profile_parameters = sofia_ini['profile:' .. profile_name]; + + if not profile_parameters then + log:error('SOFIA_PROFILE ', index,' - name: ', profile_name, ' - no parameters'); + return ''; + end + -- set local bind address + if domains[index] then + profile_parameters['sip-ip'] = domains[index]['host']; + profile_parameters['rtp-ip'] = domains[index]['host']; + profile_parameters['force-register-domain'] = domains[index]['host']; + profile_parameters['force-subscription-domain'] = domains[index]['host']; + profile_parameters['force-register-db-domain'] = domains[index]['host']; + log:debug('SOFIA_PROFILE ', index,' - name: ', profile_name, ', domain: ', domains[index]['host'], ', sip_bind: ', profile_parameters['sip-ip'], ':', profile_parameters['sip-port']); + else + log:error('SOFIA_PROFILE ', index,' - name: ', profile_name, ' - no domains'); + end + + local gateways_xml = gateways(profile_name); + + if index == 1 then + gateways_xml = gateways_xml .. nodes(database, node_id); + end + + return xml:sofia_profile(profile_name, profile_parameters, gateways_xml); +end + +-- generate sofia.conf +function conf_sofia(database) + local sofia_profile = "gemeinschaft"; + + require 'common.configuration_file' + local sofia_ini = common.configuration_file.get('/opt/freeswitch/scripts/ini/sofia.ini'); + local dialplan_parameters = common.configuration_file.get('/opt/freeswitch/scripts/ini/dialplan.ini', 'parameters'); + + local local_node_id = tonumber(dialplan_parameters['node_id']) or 1; + + require 'configuration.sip' + local domains = configuration.sip.Sip:new{ log = log, database = database}:domains(); + + sofia_profiles_xml = ''; + for index, profile_name in ipairs(sofia_ini.profiles) do + sofia_profiles_xml = sofia_profiles_xml .. profile(database, sofia_ini, profile_name, index, domains, local_node_id); + end + + XML_STRING = xml:document(xml:sofia(sofia_ini.parameters, sofia_profiles_xml)) +end + +function conf_conference(database) + XML_STRING = xml:document(xml:conference()); + + require 'common.configuration_file' + local conference_ini = common.configuration_file.get('/opt/freeswitch/scripts/ini/conferences.ini'); + local conference_parameters = conference_ini.parameters; + + local event_name = params:getHeader("Event-Name") + if event_name == 'COMMAND' then + local conf_name = params:getHeader('conf_name'); + local profile_name = params:getHeader('profile_name'); + + if conf_name then + require 'common.conference' + conference = common.conference.Conference:new{log=log, database=database}:find_by_id(conf_name); + if conference then + log:debug('CONFIG_CONFERENCE ', conf_name, ' name: ', conference.record.name, ', profile: ', profile_name); + conference_parameters['caller-id-name'] = conference.record.name or ''; + XML_STRING = xml:document(xml:conference(xml:conference_profile(profile_name, conference_parameters))); + else + log:error('CONFIG_CONFERENCE ', conf_name, ' - conference not found'); + end + else + log:notice('CONFIG_CONFERENCE - no conference name'); + end + else + log:debug('CONFIG_CONFERENCE ', conf_name, ' - event: ', event_name); + end +end + + +function directory_sip_account(database) + local key = params:getHeader('key'); + local auth_name = params:getHeader('user'); + local domain = params:getHeader('domain'); + local purpose = params:getHeader('purpose'); + + if auth_name and auth_name ~= '' then + -- sip account or gateway + if string.len(auth_name) > 3 and auth_name:sub(1, 3) == 'gw+' then + local gateway_name = auth_name:sub(4); + domain = domain or freeswitch.API():execute('global_getvar', 'domain'); + require 'configuration.sip' + log:notice('DATABASE: ', database); + local sip_gateway = configuration.sip.Sip:new{ log = log, database = database}:find_gateway_by_name(gateway_name); + if sip_gateway ~= nil and next(sip_gateway) ~= nil then + log:debug('DIRECTORY_GATEWAY - name: ', gateway_name, ', auth_name: ', auth_name); + XML_STRING = xml:document(xml:directory(xml:gateway_user(sip_gateway, gateway_name, auth_name), domain)); + else + log:debug('DIRECTORY_GATEWAY - gateway not found - name: ', gateway_name, ', auth_name: ', auth_name); + end + else + require 'common.sip_account' + local sip_account = common.sip_account.SipAccount:new{ log = log, database = database}:find_by_auth_name(auth_name, domain); + if sip_account ~= nil then + if tostring(purpose) == 'publish-vm' then + log:debug('DIRECTORY_SIP_ACCOUNT - purpose: VoiceMail, auth_name: ', sip_account.record.auth_name, ', caller_name: ', sip_account.record.caller_name, ', domain: ', domain); + XML_STRING = xml:document(xml:directory(xml:group_default(xml:user(sip_account.record)), domain)); + else + log:debug('DIRECTORY_SIP_ACCOUNT - auth_name: ', sip_account.record.auth_name, ', caller_name: ', sip_account.record.caller_name, ', domain: ', domain); + XML_STRING = xml:document(xml:directory(xml:user(sip_account.record), domain)); + end + else + log:debug('DIRECTORY_SIP_ACCOUNT - sip account not found - auth_name: ', auth_name, ', domain: ', domain); + -- fake sip_account configuration + sip_account = { + auth_name = auth_name, + id = 0, + uuid = '', + password = tostring(math.random(0, 65534)), + voicemail_pin = '', + state = 'inactive', + caller_name = '', + sip_accountable_type = 'none', + sip_accountable_id = 0, + } + XML_STRING = xml:document(xml:directory(xml:user(sip_account), domain)) + end + end + elseif tostring(XML_REQUEST.key_name) == 'name' and tostring(XML_REQUEST.key_value) ~= '' then + log:debug('DOMAIN_DIRECTORY - domain: ', XML_REQUEST.key_value); + XML_STRING = xml:document(xml:directory(nil, XML_REQUEST.key_value)); + end +end + + +local log_identifier = XML_REQUEST.key_value or 'CONFIG'; + +-- set logger +require 'common.log' +log = common.log.Log:new(); +log.prefix = '#C# [' .. log_identifier .. '] '; + +-- return a valid xml document +require 'configuration.freeswitch_xml' +xml = configuration.freeswitch_xml.FreeSwitchXml:new(); +XML_STRING = xml:document(); + +local database = nil; + +-- log:debug('CONFIG_REQUEST section: ', XML_REQUEST.section, ', tag: ', XML_REQUEST.tag_name, ', key: ', XML_REQUEST.key_value); + +if XML_REQUEST.section == 'configuration' and XML_REQUEST.tag_name == 'configuration' then + -- database connection + require 'common.database' + database = common.database.Database:new{ log = log }:connect(); + if database:connected() == false then + log:error('CONFIG_REQUEST - cannot connect to Gemeinschaft database'); + return false; + end + + if XML_REQUEST.key_value == 'sofia.conf' then + conf_sofia(database); + elseif XML_REQUEST.key_value == "conference.conf" then + conf_conference(database); + end +elseif XML_REQUEST.section == 'directory' and XML_REQUEST.tag_name == '' then + log:debug('SIP_ACCOUNT_DIRECTORY - initialization phase'); +elseif XML_REQUEST.section == 'directory' and XML_REQUEST.tag_name == 'domain' then + if params == nil then + log:error('SIP_ACCOUNT_DIRECTORY - no parameters'); + return false; + end + + require 'common.database' + database = common.database.Database:new{ log = log }:connect(); + if not database:connected() then + log:error('CONFIG_REQUEST - cannot connect to Gemeinschaft database'); + return false; + end + directory_sip_account(database); +else + log:error('CONFIG_REQUEST - no configuration handler, section: ', XML_REQUEST.section, ', tag: ', XML_REQUEST.tag_name); +end + +-- ensure database handler is released on exit +if database then + database:release(); +end diff --git a/misc/freeswitch/scripts/configuration/freeswitch_xml.lua b/misc/freeswitch/scripts/configuration/freeswitch_xml.lua new file mode 100644 index 0000000..c81bf50 --- /dev/null +++ b/misc/freeswitch/scripts/configuration/freeswitch_xml.lua @@ -0,0 +1,307 @@ +-- ConfigurationModule: FreeSwitchXml +-- +module(...,package.seeall) + +FreeSwitchXml = {} + +-- Create FreeSwitchXml object +function FreeSwitchXml.new(self, object) + object = object or {} + setmetatable(object, self) + self.__index = self + return object +end + +function FreeSwitchXml.param(self, name, value) + return '' +end + +function FreeSwitchXml.variable(self, name, value) + return '' +end + +function FreeSwitchXml.document(self, sections_xml) + if type(sections_xml) == "string" then + sections_xml = { sections_xml } + elseif type(sections_xml) == "nil" then + sections_xml = { "" } + end + + local xml_string= +[[ + +]] .. table.concat(sections_xml, "\n") .. [[ + +]] + + return xml_string +end + +function FreeSwitchXml.directory(self, entries_xml, domain) + if type(entries_xml) == "string" then + entries_xml = { entries_xml } + elseif type(entries_xml) == "nil" then + entries_xml = { "" } + end + + local xml_string = +[[ +
    + + + + +]] .. table.concat(entries_xml, "\n") .. [[ + + +
    ]] + return xml_string +end + +function FreeSwitchXml.group_default(self, entries_xml) + if type(entries_xml) == "string" then + entries_xml = { entries_xml } + elseif type(entries_xml) == "nil" then + entries_xml = { "" } + end + + local xml_string = +[[ + + + +]] .. table.concat(entries_xml, "\n") .. [[ + + + +]] + return xml_string +end + +function FreeSwitchXml.user(self, user) + require 'common.configuration_file' + local params = common.configuration_file.get('/opt/freeswitch/scripts/ini/sip_accounts.ini', 'parameters'); + + params['password'] = user.password; + params['vm-password'] = user.voicemail_pin; + + local variables = { + user_context = "default", + gs_from_gateway = "false", + gs_account_id = user.id, + gs_account_uuid = user.uuid, + gs_account_type = "SipAccount", + gs_account_state = user.state, + gs_account_caller_name = user.caller_name, + gs_account_owner_type = user.sip_accountable_type, + gs_account_owner_id = user.sip_accountable_id + } + + local params_xml = {} + for name, value in pairs(params) do + params_xml[#params_xml+1] = self:param(name, value) + end + + local variables_xml = {} + for name, value in pairs(variables) do + variables_xml[#variables_xml+1] = self:variable(name, value) + end + + local xml_string = +[[ + + +]] .. table.concat(params_xml, "\n") .. [[ + + + +]] .. table.concat(variables_xml, "\n") .. [[ + + +]] + return xml_string +end + +function FreeSwitchXml.gateway_user(self, user, gateway_name, auth_name) + user.id = user.id or 0 + + local params = { + ['password'] = user.password, + } + + local variables = { + user_context = "default", + gs_from_gateway = "true", + gs_gateway_name = gateway_name, + gs_gateway_id = user.id + } + + local params_xml = {} + for name, value in pairs(params) do + params_xml[#params_xml+1] = self:param(name, value) + end + + local variables_xml = {} + for name, value in pairs(variables) do + variables_xml[#variables_xml+1] = self:variable(name, value) + end + + local xml_string = +[[ + + +]] .. table.concat(params_xml, "\n") .. [[ + + + +]] .. table.concat(variables_xml, "\n") .. [[ + + +]] + return xml_string +end + +function FreeSwitchXml.sofia(self, parameters, profiles_xml) + if type(profiles_xml) == "string" then + profiles_xml = { profiles_xml } + elseif type(profiles_xml) == "nil" then + profiles_xml = { "" } + end + + local params_xml = {} + for name, value in pairs(parameters) do + params_xml[#params_xml+1] = self:param(name, value) + end + + local xml_string = +[[ +
    + + +]] .. table.concat(params_xml, "\n") .. [[ + + + +]] .. table.concat(profiles_xml, "\n") .. [[ + + + +
    ]] + return xml_string +end + +function FreeSwitchXml.sofia_profile(self, profile_name, parameters, gateways_xml) + params_xml = {} + for name, value in pairs(parameters) do + params_xml[#params_xml+1] = self:param(name, value) + end + + if type(gateways_xml) == "string" then + gateways_xml = { gateways_xml } + elseif type(gateways_xml) == "nil" then + gateways_xml = { "" } + end + + local xml_string = +[[ + + + + +]] .. table.concat(gateways_xml, "\n") .. [[ + + + + + + +]] .. table.concat(params_xml, "\n") .. [[ + + +]] + return xml_string +end + +function FreeSwitchXml.gateway(self, gateway_name, parameters) + local params_xml = {} + if parameters then + for name, value in pairs(parameters) do + params_xml[#params_xml+1] = self:param(name, value) + end + end + + local xml_string = +[[ + +]] .. table.concat(params_xml, "\n") .. [[ + +]] + return xml_string +end + +function FreeSwitchXml.conference(self, profiles_xml) + if type(profiles_xml) == "string" then + profiles_xml = { profiles_xml } + elseif type(profiles_xml) == "nil" then + profiles_xml = { "" } + end + + local xml_string = +[[ +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]] .. table.concat(profiles_xml, "\n") .. [[ + + + +
    ]] + return xml_string +end + +function FreeSwitchXml.conference_profile(self, profile_name, parameters) + params_xml = {} + for name, value in pairs(parameters) do + params_xml[#params_xml+1] = self:param(name, value) + end + + local xml_string = +[[ + +]] .. table.concat(params_xml, "\n") .. [[ + +]] + return xml_string +end diff --git a/misc/freeswitch/scripts/configuration/sip.lua b/misc/freeswitch/scripts/configuration/sip.lua new file mode 100644 index 0000000..78143bc --- /dev/null +++ b/misc/freeswitch/scripts/configuration/sip.lua @@ -0,0 +1,37 @@ +-- Gemeinschaft 5 module: sip configuration class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +Sip = {} + +-- create sip configuration object +function Sip.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.database = arg.database; + self.record = arg.record; + return object; +end + +-- find gateway by name +function Sip.find_gateway_by_name(self, name) + require 'common.configuration_file' + return common.configuration_file.get('/opt/freeswitch/scripts/ini/gateways.ini', name); +end + +-- list sip domains +function Sip.domains(self) + local sql_query = 'SELECT * FROM `sip_domains`'; + local sip_domains = {} + + self.database:query(sql_query, function(sip_domain) + table.insert(sip_domains, sip_domain); + end) + + return sip_domains; +end diff --git a/misc/freeswitch/scripts/dialplan/access_authorizations.lua b/misc/freeswitch/scripts/dialplan/access_authorizations.lua new file mode 100644 index 0000000..dbacf20 --- /dev/null +++ b/misc/freeswitch/scripts/dialplan/access_authorizations.lua @@ -0,0 +1,52 @@ +-- CommonModule: AccessAuthorization +-- +module(...,package.seeall) + +AccessAuthorization = {} + +-- Create AccessAuthorization object +function AccessAuthorization.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self) + self.__index = self + self.log = arg.log + self.database = arg.database + self.record = arg.record + self.session = arg.session + return object +end + +-- Find AccessAuthorization by ID +function AccessAuthorization.find_by_id(self, id) + local sql_query = string.format("SELECT * FROM `access_authorizations` WHERE `id`=%d LIMIT 1", id) + local record = nil + + self.database:query(sql_query, function(access_authorization_entry) + record = access_authorization_entry + end) + + if record then + access_authorization = AccessAuthorization:new(self) + access_authorization.record = record + return access_authorization + end + + return nil +end + +-- list accessauthorization by owner +function AccessAuthorization.list_by_owner(self, owner_id, owner_type) + local sql_query = 'SELECT `a`.`id`, `a`.`name`, `a`.`login`, `a`.`pin`, `a`.`sip_account_id`, `b`.`number` AS `phone_number` \ + FROM `access_authorizations` `a` \ + LEFT JOIN `phone_numbers` `b` ON `b`.`phone_numberable_id` = `a`.`id` AND `b`.`phone_numberable_type` = "AccessAuthorization" \ + WHERE `a`.`access_authorizationable_type` = "' .. owner_type .. '" AND `access_authorizationable_id`= ' .. tonumber(owner_id); + + local access_authorizations = {} + + self.database:query(sql_query, function(access_authorization_entry) + table.insert(access_authorizations, access_authorization_entry); + end); + + return access_authorizations; +end diff --git a/misc/freeswitch/scripts/dialplan/acd.lua b/misc/freeswitch/scripts/dialplan/acd.lua new file mode 100644 index 0000000..563d836 --- /dev/null +++ b/misc/freeswitch/scripts/dialplan/acd.lua @@ -0,0 +1,484 @@ +-- Gemeinschaft 5 module: acd class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +AutomaticCallDistributor = {} + +local DEFAULT_AGENT_TIMEOUT = 20; +local DEFAULT_TIME_RES = 5; +local DEFAULT_WAIT_TIMEOUT = 360; +local DEFAULT_RETRY_TIME = 2; +local DEFAULT_MUSIC_ON_WAIT = 'tone_stream://%(2000,4000,440.0,480.0);loops=-1'; + +-- create acd object +function AutomaticCallDistributor.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.class = 'automaticcalldistributor'; + self.log = arg.log; + self.database = arg.database; + self.record = arg.record; + self.acd_caller_id = arg.acd_caller_id; + self.domain = arg.domain; + return object; +end + + +function AutomaticCallDistributor.find_by_sql(self, sql_query) + local acd = nil; + + require 'common.str' + + self.database:query(sql_query, function(entry) + acd = AutomaticCallDistributor:new(self); + acd.record = entry; + acd.id = tonumber(entry.id); + acd.uuid = entry.uuid; + acd.agent_timeout = tonumber(entry.agent_timeout) or DEFAULT_AGENT_TIMEOUT; + acd.announce_position = tonumber(entry.announce_position); + acd.announce_call_agents = common.str.to_s(entry.announce_call_agents); + acd.greeting = common.str.to_s(entry.greeting); + acd.goodbye = common.str.to_s(entry.goodbye); + acd.music = common.str.to_s(entry.music); + acd.strategy = common.str.to_s(entry.strategy); + acd.join = common.str.to_s(entry.join); + acd.leave = common.str.to_s(entry.leave); + end) + + return acd; +end + + +function AutomaticCallDistributor.find_by_id(self, id) + local sql_query = 'SELECT * FROM `automatic_call_distributors` WHERE `id`= '.. tonumber(id) .. ' LIMIT 1'; + return self:find_by_sql(sql_query); +end + + +function AutomaticCallDistributor.find_by_uuid(self, uuid) + local sql_query = 'SELECT * FROM `automatic_call_distributors` WHERE `uuid`= "'.. tostring(uuid) .. '" LIMIT 1'; + return self:find_by_sql(sql_query); +end + + +function AutomaticCallDistributor.callers_count(self) + return self.database:query_return_value('SELECT COUNT(*) FROM `acd_callers` `a` JOIN `channels` `b` ON `a`.`channel_uuid` = `b`.`uuid` WHERE `automatic_call_distributor_id` = ' .. self.id); +end + + +function AutomaticCallDistributor.caller_new(self, uuid) + local sql_query = 'INSERT INTO `acd_callers` \ + (`enter_time`, `created_at`, `updated_at`, `status`, `automatic_call_distributor_id`, `channel_uuid`) \ + VALUES (NOW(), NOW(), NOW(), "enter", ' .. self.id .. ', "' .. uuid .. '")'; + + if self.database:query(sql_query) then + self.acd_caller_id = self.database:last_insert_id(); + end +end + + +function AutomaticCallDistributor.caller_update(self, attributes) + local attributes_sql = { '`updated_at` = NOW()' }; + for key, value in pairs(attributes) do + table.insert(attributes_sql, '`' .. key .. '` = "' .. value .. '"'); + end + + local sql_query = 'UPDATE `acd_callers` \ + SET '.. table.concat(attributes_sql, ',') .. '\ + WHERE `id` = ' .. tonumber(self.acd_caller_id); + return self.database:query(sql_query); +end + + +function AutomaticCallDistributor.caller_delete(self, id) + id = id or self.acd_caller_id; + local sql_query = 'DELETE FROM `acd_callers` \ + WHERE `id` = ' .. tonumber(id); + return self.database:query(sql_query); +end + + +function AutomaticCallDistributor.agent_find_by_acd_and_destination(self, acd_id, destination_type, destination_id) + local sql_query = 'SELECT * FROM `acd_agents` \ + WHERE `automatic_call_distributor_id` = ' .. acd_id .. ' \ + AND `destination_type` = "' .. destination_type .. '" \ + AND `destination_id` = ' .. destination_id; + + local agent = nil; + self.database:query(sql_query, function(entry) + agent = entry; + end) + + return agent; +end + + +function AutomaticCallDistributor.agent_status_presence_set(self, agent_id, presence_state) + require "dialplan.presence" + local presence = dialplan.presence.Presence:new(); + + presence:init{log = self.log, accounts = { 'f-acdmtg-' .. tostring(agent_id) }, domain = self.domain, uuid = 'acd_agent_' .. tostring(agent_id)}; + return presence:set(presence_state); +end + + +function AutomaticCallDistributor.agent_status_get(self, agent_id) + local sql_query = 'SELECT `status` FROM `acd_agents` WHERE `id` = ' .. agent_id; + return self.database:query_return_value(sql_query); +end + + +function AutomaticCallDistributor.agent_status_toggle(self, agent_id, destination_type, destination_id) + local sql_query = 'UPDATE `acd_agents` SET `status` = IF(`status` = "active", "inactive", "active") \ + WHERE `id` = ' .. agent_id .. ' \ + AND `destination_type` = "' .. destination_type .. '" \ + AND `destination_id` = ' .. destination_id; + + if not self.database:query(sql_query) then + return nil; + end + + local status = self:agent_status_get(agent_id); + + if tostring(status) == 'active' then + self:agent_status_presence_set(agent_id, 'confirmed'); + else + self:agent_status_presence_set(agent_id, 'terminated'); + end + + return status; +end + + +function AutomaticCallDistributor.agents_active(self) + local sql_query = 'SELECT * FROM `acd_agents` \ + WHERE `status` = "active" AND destination_type != "SipAccount" AND `automatic_call_distributor_id` = ' .. tonumber(self.id); + + local agents = {} + self.database:query(sql_query, function(entry) + table.insert(agents, entry); + end); + + local sql_query = 'SELECT `a`.* FROM `acd_agents` `a` \ + JOIN `sip_accounts` `b` ON `a`.`destination_id` = `b`.`id` \ + JOIN `sip_registrations` `c` ON `b`.`auth_name` = `c`.`sip_user` \ + WHERE `a`.`status` = "active" AND `a`.destination_type = "SipAccount" AND `a`.`automatic_call_distributor_id` = ' .. tonumber(self.id); + + self.database:query(sql_query, function(entry) + table.insert(agents, entry); + end); + + return agents; +end + + +function AutomaticCallDistributor.agents_available(self, strategy) + local order_by = '`a`.`id` DESC'; + + if strategy then + if strategy == 'round_robin' then + order_by = '`a`.`last_call` ASC, `a`.`id` DESC'; + end + end + + local sql_query = 'SELECT `a`.`id`, `a`.`name`, `a`.`destination_type`, `a`.`destination_id`, `b`.`auth_name`, `b`.`gs_node_id`, `c`.`callstate` \ + FROM `acd_agents` `a` LEFT JOIN `sip_accounts` `b` ON `a`.`destination_id` = `b`.`id` \ + JOIN `sip_registrations` `d` ON `b`.`auth_name` = `d`.`sip_user` \ + LEFT JOIN `channels` `c` ON `c`.`name` LIKE CONCAT("%", `b`.`auth_name`, "@%") \ + WHERE `a`.`status` = "active" AND `a`.`destination_id` IS NOT NULL AND `a`.`automatic_call_distributor_id` = ' .. tonumber(self.id) .. ' \ + ORDER BY ' .. order_by; + + local accounts = {} + self.database:query(sql_query, function(entry) + if not entry.callstate then + table.insert(accounts, entry); + end + end); + + return accounts; +end + + +function AutomaticCallDistributor.agent_update_call(self, agent_id) + + local sql_query = 'UPDATE `acd_agents` \ + SET `last_call` = NOW(), `calls_answered` = IFNULL(`calls_answered`, 0) + 1 \ + WHERE `id` = ' .. tonumber(agent_id); + return self.database:query(sql_query); +end + + +function AutomaticCallDistributor.call_position(self) + local sql_query = 'SELECT COUNT(*) FROM `acd_callers` `a` JOIN `channels` `b` ON `a`.`channel_uuid` = `b`.`uuid` \ + WHERE `automatic_call_distributor_id` = ' .. tonumber(self.id) .. ' AND `status` = "waiting" AND `id` < ' .. tonumber(self.acd_caller_id); + + return tonumber(self.database:query_return_value(sql_query)); +end + + +function AutomaticCallDistributor.wait_turn(self, caller_uuid, acd_caller_id, timeout, retry_timeout) + self.acd_caller_id = acd_caller_id or self.acd_caller_id; + timeout = timeout or DEFAULT_WAIT_TIMEOUT; + local available_agents = {}; + local active_agents = {}; + local position = self:call_position(); + + self.log:info('ACD ', self.id, ' WAIT - timeout: ', timeout, ', res: ', DEFAULT_TIME_RES, ', retry_timeout: ', retry_timeout, ', position: ', position + 1); + + require 'common.fapi' + local fapi = common.fapi.FApi:new{ log = self.log, uuid = caller_uuid } + + local acd_status = nil; + local start_time = os.time(); + local exit_time = start_time + timeout; + + if tonumber(retry_timeout) then + self.log:info('ACD ', self.id, ' WAIT - retry_timeout: ', retry_timeout); + fapi:sleep(retry_timeout * 1000); + end + + while (exit_time > os.time() and fapi:channel_exists()) do + available_agents = self:agents_available(); + active_agents = self:agents_active(); + local current_position = self:call_position(); + + if position ~= current_position then + position = current_position; + self.log:info('ACD ', self.id, ' WAIT - agents: ', #available_agents, '/', #active_agents, ', position: ', position + 1, ', wait_time: ', os.time()-start_time); + + if tostring(self.announce_position) >= '0' and position > 0 then + acd_status = 'announce_position'; + fapi:set_variable('acd_position', position + 1); + break; + end + else + self.log:debug('ACD ', self.id, ' WAIT - agents: ', #available_agents, '/', #active_agents, ', position: ', position + 1, ', wait_time: ', os.time()-start_time); + end + + if #available_agents == 0 and self.leave:find('no_agents_available') then + acd_status = 'no_agents'; + break; + elseif #active_agents == 0 and self.leave:find('no_agents_active') then + acd_status = 'no_agents'; + break; + elseif position == 0 and #available_agents > 0 then + acd_status = 'call_agents'; + break; + end + + if tonumber(self.announce_position) and tonumber(self.announce_position) > 0 and tonumber(self.announce_position) <= os.time()-start_time then + acd_status = 'announce_position'; + fapi:set_variable('acd_position', position + 1); + break; + end + + fapi:sleep(DEFAULT_TIME_RES * 1000); + end + + if not acd_status then + if (exit_time <= os.time()) then + acd_status = 'timeout'; + else + acd_status = 'unspecified'; + end + end + + self.log:info('ACD ', self.id, ' WAIT END - status: ', acd_status, ', agents: ', #available_agents, '/', #active_agents, ', position: ', position + 1, ', wait_time: ', os.time()-start_time); + + fapi:set_variable('acd_status', acd_status); + if tostring(fapi:get_variable('acd_waiting')) == 'true' then + fapi:continue(); + end +end + + +function AutomaticCallDistributor.wait_play_music(self, caller, timeout, retry_timeout, music) + local result = caller:result('luarun(acd_wait.lua ' .. caller.uuid .. ' ' .. tostring(self.id) .. ' ' .. tostring(timeout) .. ' ' .. tostring(retry_timeout) .. ' ' .. self.acd_caller_id .. ')'); + if not tostring(result):match('^+OK') then + self.log:error('ACD ', self.id,' WAIT_PLAY_MUSIC - error starting acd thread'); + return 'error'; + end + + caller:set_variable('acd_waiting', true); + caller.session:streamFile(music or DEFAULT_MUSIC_ON_WAIT); + caller:set_variable('acd_waiting', false); + + local acd_status = caller:to_s('acd_status'); + if acd_status == '' then + acd_status = 'abandoned'; + end + + return acd_status; +end + + +function AutomaticCallDistributor.on_answer(self, destination) + self.log:info('ACD ', self.id, ' ANSWERED - agent: ', destination.type, '=', destination.id, '/', destination.uuid) + self:caller_update({status = 'answered'}); +end + + +function AutomaticCallDistributor.call_agents(self, dialplan_object, caller, destination) + local available_agents = self:agents_available(self.strategy); + + self.log:info('ACD ', self.id, ' CALL_AGENTS - strategy: ', self.strategy, ', available_agents: ', #available_agents); + + caller:set_variable('ring_ready', true); + + local destinations = {} + for index, agent in ipairs(available_agents) do + self.log:info('ACD ', self.id, ' AGENT - name: ', agent.name, ', destination: ', agent.destination_type, '=', agent.destination_id, '@', agent.gs_node_id, ', local_node: ', dialplan_object.node_id); + table.insert(destinations, dialplan_object:destination_new{ type = agent.destination_type, id = agent.destination_id, node_id = agent.gs_node_id, data = agent.id }); + end + + local result = { continue = false }; + local start_time = os.time(); + + require 'dialplan.sip_call' + if self.strategy == 'ring_all' then + result = dialplan.sip_call.SipCall:new{ log = self.log, database = self.database, caller = caller, calling_object = self, on_answer = self.on_answer }:fork(destinations, + { + callee_id_number = destination.number, + timeout = self.agent_timeout, + send_ringing = ( dialplan_object.send_ringing_to_gateways and caller.from_gateway ), + }); + self.log:info('ACD ', self.id, ' CALL_AGENTS - success, fork_index: ', result.fork_index); + if result.fork_index then + result.destination = destinations[result.fork_index]; + end + return result; + else + for index, destination in ipairs(destinations) do + if os.time() > (self.start_time + self.timeout) and caller.session:ready() then + self.log:info('ACD ', self.id, ' CALL_AGENTS - timeout'); + return { disposition = 'ACD_TIMEOUT', code = 480, phrase = 'Timeout' } + end + + self.log:info('ACD ', self.id, ' CALL_AGENT - ', destination.type, '=', destination.id, ', timeout: ', self.agent_timeout); + result = dialplan.sip_call.SipCall:new{ log = self.log, database = self.database, caller = caller, calling_object = self, on_answer = self.on_answer }:fork({ destination }, + { + callee_id_number = destination.number, + timeout = self.agent_timeout, + send_ringing = ( dialplan_object.send_ringing_to_gateways and caller.from_gateway ), + }); + if result.disposition == 'SUCCESS' then + self.log:info('ACD ', self.id, ' CALL_AGENTS - success, agent_id: ', destination.data); + self:agent_update_call(destination.data); + result.destination = destination; + return result; + end + end + end + + return { disposition = 'ACD_NO_AGENTS', code = 480, phrase = 'No active agents' } +end + + +function AutomaticCallDistributor.run(self, dialplan_object, caller, destination) + require 'common.str' + + local callers_count = self:callers_count(); + local active_agents = self:agents_active(); + local available_agents = self:agents_available(); + local position = self:call_position(); + + if self.leave:find('timeout') then + self.timeout = dialplan_object.dial_timeout_active; + else + self.timeout = 86400; + end + + self.log:info('ACD ', self.id,' - ', self.class, '=', self.id, '/', self.uuid, ', acd_caller=', self.acd_caller_id, ', callers: ', callers_count, ', agents: ', #available_agents, '/', #active_agents, ', position: ', position + 1, ', music: ', tostring(self.music)); + + if self.join == 'agents_active' and #active_agents == 0 then + self.log:info('ACD ', self.id, ' - no agents active'); + return { disposition = 'ACD_NO_AGENTS', code = 480, phrase = 'No agents' } + end + + if self.join == 'agents_available' and #available_agents == 0 then + self.log:info('ACD ', self.id, ' - no agents available'); + return { disposition = 'ACD_NO_AGENTS', code = 480, phrase = 'All agents busy' } + end + + if not common.str.blank(self.music) then + caller:set_variable('ringback', self.music); + else + self.music = false; + end + + if self.music then + caller.session:answer(); + else + caller:set_variable('instant_ringback', true); + end + + self.start_time = os.time(); + caller:sleep(500); + local acd_status = 'waiting'; + self:caller_update({status = acd_status}); + + local retry_timeout = nil; + local result = { disposition = 'ACD_NO_AGENTS', code = 480, phrase = 'No active agents' } + + if self.greeting then + caller.session:sayPhrase('acd_greeting', self.greeting); + end + + if self.announce_position then + local current_position = self:call_position(); + if tonumber(current_position) then + caller.session:sayPhrase('acd_announce_position_enter', tonumber(current_position) + 1); + end + end + + while acd_status == 'waiting' and caller.session:ready() do + acd_status = self:wait_play_music(caller, self.timeout - (os.time() - self.start_time), retry_timeout, self.music); + self.log:info('ACD ', self.id, ' PROCESS - status: ', acd_status, ', wait_time: ', (os.time() - self.start_time)); + + if not caller.session:ready() then + acd_status = 'abandoned'; + break; + elseif os.time() >= (self.start_time + self.timeout) then + acd_status = 'timeout'; + break; + elseif acd_status == 'no_agents' then + break; + elseif acd_status == 'call_agents' then + if self.announce_call_agents ~= '' then + caller.session:sayPhrase('acd_announce_call_agents', self.announce_call_agents); + end + + result = self:call_agents(dialplan_object, caller, destination); + self.log:info('ACD ', self.id, ' PROCESS - result: ', result.disposition, ', code: ', result.code, ', wait_time: ', (os.time() - self.start_time)); + + if result.disposition == 'SUCCESS' then + acd_status = 'success'; + break; + elseif os.time() < (self.start_time + self.timeout) then + acd_status = 'waiting'; + else + break; + end + elseif acd_status == 'announce_position' then + acd_status = 'waiting'; + if tostring(self.announce_position) == '0' then + caller.session:sayPhrase('acd_announce_position_change', caller:to_i('acd_position')); + else + caller.session:sayPhrase('acd_announce_position_periodic', caller:to_i('acd_position')); + end + end + + retry_timeout = tonumber(self.record.retry_timeout); + end + + if self.goodbye and caller.session:ready() then + caller.session:sayPhrase('acd_goodbye', self.goodbye); + end + self.log:info('ACD ', self.id, ' EXIT - status: ', acd_status, ', wait_time: ', (os.time() - self.start_time)); + + return result; +end diff --git a/misc/freeswitch/scripts/dialplan/callthrough.lua b/misc/freeswitch/scripts/dialplan/callthrough.lua new file mode 100644 index 0000000..69a0611 --- /dev/null +++ b/misc/freeswitch/scripts/dialplan/callthrough.lua @@ -0,0 +1,148 @@ +-- CommonModule: Callthrough +-- +module(...,package.seeall) + +Callthrough = {} + +-- Create Callthrough object +function Callthrough.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self) + self.__index = self + self.log = arg.log + self.database = arg.database + self.record = arg.record + self.access_authorizations = arg.access_authorizations + return object +end + +-- Find Callthrough by ID +function Callthrough.find_by_id(self, id) + local sql_query = string.format("SELECT * FROM `callthroughs` WHERE `id`=%d LIMIT 1", id) + local record = nil + + self.database:query(sql_query, function(callthrough_entry) + record = callthrough_entry + end) + + if record then + local callthrough = Callthrough:new(self); + callthrough.record = record + + require 'dialplan.access_authorizations' + callthrough.access_authorizations = dialplan.access_authorizations.AccessAuthorization:new{ log = self.log, database = self.database }:list_by_owner(record.id, 'Callthrough'); + return callthrough + end + + return nil +end + +function Callthrough.authenticate(self, caller) + local authorizations = {} + local logins = {} + local pins = {} + + caller:answer(); + caller:sleep(1000); + + if not self.access_authorizations or table.getn(self.access_authorizations) == 0 then + self.log:debug('CALLTHROUGH_AUTHENTICATE - authorization disabled'); + return true; + end + + self.log:debug('CALLTHROUGH_AUTHENTICATE - access_authorizations: ', #self.access_authorizations); + for index, authorization in ipairs(self.access_authorizations) do + if authorization.phone_number then + if authorization.phone_number == caller.caller_phone_number then + if authorization.pin and authorization.pin ~= "" then + if caller.session:read(authorization.pin:len(), authorization.pin:len(), "ivr/ivr-please_enter_pin_followed_by_pound.wav", 3000, "#") ~= authorization.pin then + self.log:debug("CALLTHROUGH_AUTHENTICATE - Wrong PIN"); + return false; + else + self.log:debug("CALLTHROUGH_AUTHENTICATE - Caller was authenticated by caller id: " .. caller.caller_phone_number .. " and PIN"); + return authorization; + end + end + self.log:debug("CALLTHROUGH_AUTHENTICATE - Caller was authenticated by caller id: " .. caller.caller_phone_number); + return authorization; + end + else + self.log:debug('CALLTHROUGH_AUTHENTICATE - access_authorization=', authorization.id); + if authorization.id then + authorizations[authorization.id] = authorization; + if authorization.login and authorization.login ~= "" then + logins[authorization.login] = authorization; + elseif authorization.pin and authorization.pin ~= "" then + pins[authorization.pin] = authorization; + end + end + end + end + + local login = nil; + local pin = nil; + + + if next(logins) ~= nil then + + caller.session:streamFile('ivr/ivr-please_enter_the.wav'); + caller.session:streamFile('ivr/ivr-id_number.wav'); + login = caller.session:read(2, 10, 'ivr/ivr-followed_by_pound.wav', 3000, '#'); + end + + if login and logins[tostring(login)] then + if not logins[tostring(login)].pin or logins[tostring(login)].pin == '' then + self.log:debug("CALLTHROUGH_AUTHENTICATE - Caller was authenticated by login: " .. login .. " without PIN"); + return logins[tostring(login)]; + end + pin = caller.session:read(2, 10, "ivr/ivr-please_enter_pin_followed_by_pound.wav", 3000, "#"); + if logins[tostring(login)].pin == pin then + self.log:debug("CALLTHROUGH_AUTHENTICATE - Caller was authenticated by login: " .. login .. " and PIN"); + return logins[tostring(login)]; + else + self.log:debug("CALLTHROUGH_AUTHENTICATE - Wrong PIN"); + return false + end + end + + if next(pins) ~= nil then + pin = caller.session:read(2, 10, "ivr/ivr-please_enter_pin_followed_by_pound.wav", 3000, "#"); + end + + self.log:debug("CALLTHROUGH_AUTHENTICATE - No such login, try PIN"); + + if pin and pins[tostring(pin)] then + self.log:debug("CALLTHROUGH_AUTHENTICATE - Caller was authenticated by PIN"); + return pins[tostring(pin)]; + end + + self.log:debug("CALLTHROUGH_AUTHENTICATE - No login, wrong PIN - giving up"); + + return false; +end + +function Callthrough.whitelist(self, number) + local sql_query = 'SELECT `id` FROM `whitelists` WHERE `whitelistable_type` = "Callthrough" AND `whitelistable_id` = ' .. self.record.id; + local whitelist_ids = {} + + self.database:query(sql_query, function(entry) + table.insert(whitelist_ids, entry.id); + end) + + if next(whitelist_ids) == nil then + return true; + end + + -- OPTIMIZE Make sure number contains only valid characters + local sql_query = 'SELECT `id` FROM `phone_numbers` WHERE \ + `number` = "' .. number .. '" AND \ + `phone_numberable_type` = "Whitelist" AND `phone_numberable_id` IN (' .. table.concat(whitelist_ids, ',') .. ') LIMIT 1'; + + local authorized = false + self.database:query(sql_query, function(entry) + authorized = true + end) + + return authorized; +end diff --git a/misc/freeswitch/scripts/dialplan/cdr.lua b/misc/freeswitch/scripts/dialplan/cdr.lua new file mode 100644 index 0000000..55a7889 --- /dev/null +++ b/misc/freeswitch/scripts/dialplan/cdr.lua @@ -0,0 +1,71 @@ +-- Gemeinschaft 5 module: cdr class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +Cdr = {} + +local DEFAULT_MEMBER_TIMEOUT = 20; + +-- Create Cdr object +function Cdr.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.database = arg.database; + return object; +end + + +function Cdr.save(self, caller, destination) + require 'common.str' + local cdr = {} + cdr.uuid = common.str.to_sql(caller.uuid); + cdr.bleg_uuid = common.str.to_sql(caller:to_s('bridge_uuid')); + cdr.dialed_number = common.str.to_sql(caller.called_number); + cdr.destination_number = common.str.to_sql(destination.number); + cdr.caller_id_number = common.str.to_sql(caller:to_s('effective_caller_id_number')); + cdr.caller_id_name = common.str.to_sql(caller:to_s('effective_caller_id_name')); + cdr.callee_id_number = common.str.to_sql(caller:to_s('effective_callee_id_number')); + cdr.callee_id_name = common.str.to_sql(caller:to_s('effective_callee_id_name')); + cdr.start_stamp = 'FROM_UNIXTIME(' .. math.floor(caller:to_i('created_time') / 1000000) .. ')'; + cdr.answer_stamp = 'FROM_UNIXTIME(' .. math.floor(caller:to_i('answered_time') / 1000000) .. ')'; + cdr.end_stamp = 'NOW()'; + cdr.duration = 'UNIX_TIMESTAMP(NOW()) - ' .. math.floor(caller:to_i('created_time') / 1000000); + cdr.hangup_cause = common.str.to_sql(caller.session:hangupCause()); + cdr.dialstatus = common.str.to_sql(caller:to_s('DIALSTATUS')); + cdr.forwarding_number = common.str.to_sql(caller.forwarding_number); + cdr.forwarding_service = common.str.to_sql(caller.forwarding_service); + + if caller.auth_account then + cdr.forwarding_account_id = common.str.to_sql(caller.auth_account.id); + cdr.forwarding_account_type = common.str.to_sql(caller.auth_account.class); + end + + if caller.account then + cdr.account_id = common.str.to_sql(caller.account.id); + cdr.account_type = common.str.to_sql(caller.account.class); + end + + if caller:to_i('answered_time') > 0 then + cdr.billsec = 'UNIX_TIMESTAMP(NOW()) - ' .. math.floor(caller:to_i('answered_time') / 1000000); + end + + cdr.bleg_account_id = common.str.to_sql(tonumber(destination.id)); + cdr.bleg_account_type = common.str.to_sql(destination.type); + + local keys = {} + local values = {} + + for key, value in pairs(cdr) do + table.insert(keys, key); + table.insert(values, value); + end + + local sql_query = 'INSERT INTO `cdrs` (`' .. table.concat(keys, "`, `") .. '`) VALUES (' .. table.concat(values, ", ") .. ')'; + self.log:info('CDR_SAVE - caller: ', cdr.account_type, '=', cdr.account_id, ', callee: ',cdr.bleg_account_type, '=', cdr.bleg_account_id,', dialstatus: ', cdr.dialstatus); + return self.database:query(sql_query); +end diff --git a/misc/freeswitch/scripts/dialplan/dialplan.lua b/misc/freeswitch/scripts/dialplan/dialplan.lua new file mode 100644 index 0000000..f4dca9e --- /dev/null +++ b/misc/freeswitch/scripts/dialplan/dialplan.lua @@ -0,0 +1,996 @@ +-- Gemeinschaft 5 module: dialplan class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +Dialplan = {} + +-- local constants +local CONFIG_FILE_NAME = '/opt/freeswitch/scripts/ini/dialplan.ini'; +local DIAL_TIMEOUT = 120; +local MAX_LOOPS = 20; +local DIALPLAN_FUNCTION_PATTERN = '^f[_%-].*'; +local CALL_FORWARDING_SERVICES = { + USER_BUSY = 'busy', + CALL_REJECTED = 'busy', + NO_ANSWER = 'noanswer', + USER_NOT_REGISTERED = 'offline', + HUNT_GROUP_EMPTY = 'offline', + ACD_NO_AGENTS = 'offline', + ACD_TIMEOUT = 'noanswer', +} + +-- create dialplan object +function Dialplan.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.database = arg.database; + self.caller = arg.caller; + + return object; +end + + +function Dialplan.domain_get(self, domain) + require 'common.str' + local global_domain = freeswitch.API():execute('global_getvar', 'domain'); + + if common.str.blank(global_domain) then + if common.str.blank(domain) then + require 'common.database' + local database = common.database.Database:new{ log = self.log }:connect(); + if not database:connected() then + self.log:error('[', uuid,'] DIALPLAN_DOMAIN - cannot connect to Gemeinschaft database'); + else + require 'configuration.sip' + local domains = configuration.sip.Sip:new{ log = self.log, database = database }:domains(); + if domains[1] then + domain = domains[1]['host']; + end + end + end + + if database then + database:release(); + end + + if not common.str.blank(domain) then + self.log:notice('DIALPLAN_DOMAIN - setting default domain: ', domain); + freeswitch.API():execute('global_setvar', 'domain=' .. tostring(domain)); + end + else + domain = global_domain; + end + + if common.str.blank(domain) then + self.log:error('DIALPLAN_DOMAIN - no domain found'); + end + + return domain; +end + + +function Dialplan.configuration_read(self, file_name) + require 'common.str' + require 'common.configuration_file' + + -- dialplan configuration + self.config = common.configuration_file.get(file_name or CONFIG_FILE_NAME); + self.node_id = common.str.to_i(self.config.parameters.node_id); + self.domain = self:domain_get(self.config.parameters.domain); + self.dial_timeout = tonumber(self.config.parameters.dial_timeout) or DIAL_TIMEOUT; + self.max_loops = tonumber(self.config.parameters.max_loops) or MAX_LOOPS; + self.user_image_url = common.str.to_s(self.config.parameters.user_image_url); + self.phone_book_entry_image_url = common.str.to_s(self.config.parameters.phone_book_entry_image_url); + self.phonebook_number_lookup = common.str.to_b(self.config.parameters.phonebook_number_lookup); + self.geo_number_lookup = common.str.to_b(self.config.parameters.geo_number_lookup); + self.default_language = self.config.parameters.default_language or 'en'; + self.send_ringing_to_gateways = common.str.to_b(self.config.parameters.send_ringing_to_gateways); + + if tonumber(self.config.parameters.default_ringtone) then + self.default_ringtone = 'http://amooma.de;info=Ringer' .. self.config.parameters.default_ringtone .. ';x-line-id=0'; + else + self.default_ringtone = 'http://amooma.de;info=Ringer1;x-line-id=0'; + end + + return (self.config ~= nil); +end + + +function Dialplan.hangup(self, code, phrase, cause) + if self.caller:ready() then + if tonumber(code) then + self.caller:respond(code, phrase or 'Thank you for flying Gemeinschaft5'); + end + self.caller:hangup(cause or 16); + else + self.log:info('HANGUP - caller sesson down - cause: ', self.caller.session:hangupCause()); + end +end + + +function Dialplan.check_auth(self) + local authenticated = false; + + require 'common.str' + if self.caller.from_node then + self.log:info('AUTH_FIRST_STAGE - node authenticated - node_id: ', self.caller.node_id); + authenticated = true; + elseif not common.str.blank(self.caller.auth_account_type) then + self.log:info('AUTH_FIRST_STAGE - sipaccount autheticated by name/password: ', self.caller.auth_account_type, '=', self.caller.account_id, '/', self.caller.account_uuid); + authenticated = true; + elseif self.caller.from_gateway then + self.log:info('AUTH_FIRST_STAGE - gateway autheticated by name/password: gateway=', self.caller.gateway_id, ', name: ', self.caller.gateway_name); + authenticated = true; + else + local gateways = common.configuration_file.get('/opt/freeswitch/scripts/ini/gateways.ini', false); + if not gateways then + return false; + end + for gateway, gateway_parameters in pairs(gateways) do + if common.str.to_s(gateway_parameters.proxy) == self.caller.sip_contact_host then + self.caller.gateway_name = gateway; + self.caller.from_gateway = true; + self.log:info('AUTH_FIRST_STAGE - gateway autheticated by ip: gateway=', self.caller.gateway_id, ', name: ', self.caller.gateway_name, ', ip: ', self.caller.sip_contact_host); + authenticated = true; + end + end + end + + return authenticated; +end + + +function Dialplan.check_auth_node(self) + require 'common.node' + local node = common.node.Node:new{ log = self.log, database = self.database }:find_by_address(self.caller.sip_contact_host); + + return (node ~= nil); +end + + +function Dialplan.check_auth_ip(self) + self.log:info('AUTH - node: ', self.caller.from_node, ', auth_account: ', self.caller.auth_account_type, ', gateway: ', self.caller.from_gateway); + require 'common.str' + if self.caller.from_node then + return true; + elseif not common.str.blank(self.caller.auth_account_type) then + return true; + elseif self.caller.from_gateway then + return true; + else + return nil; + end +end + + +function Dialplan.object_find(self, class, identifier, auth_name) + require 'common.str' + class = common.str.downcase(class); + + if class == 'user' then + require 'dialplan.user' + local user = nil; + if type(identifier) == 'number' then + user = dialplan.user.User:new{ log = self.log, database = self.database }:find_by_id(identifier); + else + user = dialplan.user.User:new{ log = self.log, database = self.database }:find_by_uuid(identifier); + end + + if user then + user.groups = user:list_groups(); + end + + return user; + elseif class == 'tenant' then + require 'dialplan.tenant' + local tenant = nil; + if type(identifier) == 'number' then + tenant = dialplan.tenant.Tenant:new{ log = self.log, database = self.database }:find_by_id(identifier); + else + tenant = dialplan.tenant.Tenant:new{ log = self.log, database = self.database }:find_by_uuid(identifier); + end + + return tenant; + elseif class == 'sipaccount' then + require 'common.sip_account' + local sip_account = nil; + if auth_name then + sip_account = common.sip_account.SipAccount:new{ log = self.log, database = self.database }:find_by_auth_name(auth_name, identifier); + elseif type(identifier) == 'number' then + sip_account = common.sip_account.SipAccount:new{ log = self.log, database = self.database }:find_by_id(identifier); + else + sip_account = common.sip_account.SipAccount:new{ log = self.log, database = self.database }:find_by_uuid(identifier); + end + if sip_account then + sip_account.owner = self:object_find(sip_account.record.sip_accountable_type, tonumber(sip_account.record.sip_accountable_id)); + end + return sip_account; + elseif class == 'huntgroup' then + require 'dialplan.hunt_group' + + local hunt_group = nil; + if type(identifier) == 'number' then + hunt_group = dialplan.hunt_group.HuntGroup:new{ log = self.log, database = self.database }:find_by_id(identifier); + else + hunt_group = dialplan.hunt_group.HuntGroup:new{ log = self.log, database = self.database }:find_by_uuid(identifier); + end + + if hunt_group then + hunt_group.owner = self:object_find('tenant', tonumber(hunt_group.record.tenant_id)); + end + + return hunt_group; + elseif class == 'automaticcalldistributor' then + require 'dialplan.acd' + + local acd = nil; + if type(identifier) == 'number' then + acd = dialplan.acd.AutomaticCallDistributor:new{ log = self.log, database = self.database, domain = self.domain }:find_by_id(identifier); + else + acd = dialplan.acd.AutomaticCallDistributor:new{ log = self.log, database = self.database, domain = self.domain }:find_by_uuid(identifier); + end + + if acd then + acd.owner = self:object_find(acd.record.automatic_call_distributorable_type, tonumber(acd.record.automatic_call_distributorable_id)); + end + + return acd; + elseif class == 'faxaccount' then + require 'dialplan.fax' + local fax_account = nil; + if type(identifier) == 'number' then + fax_account = dialplan.fax.Fax:new{ log = self.log, database = self.database }:find_by_id(identifier); + else + fax_account = dialplan.fax.Fax:new{ log = self.log, database = self.database }:find_by_uuid(identifier); + end + if fax_account then + fax_account.owner = self:object_find(fax_account.record.fax_accountable_type, tonumber(fax_account.record.fax_accountable_id)); + end + + return fax_account; + end +end + + +function Dialplan.retrieve_caller_data(self) + self.caller.caller_phone_numbers_hash = {} + + require 'common.str' + + local dialed_sip_user = self.caller:to_s('dialed_user'); + + -- TODO: Set auth_account on transfer initiated by calling party + if not common.str.blank(dialed_sip_user) then + self.caller.auth_account = self:object_find('sipaccount', self.caller:to_s('dialed_domain'), dialed_sip_user); + self.caller:set_auth_account(self.caller.auth_account); + elseif not common.str.blank(self.caller.auth_account_type) and not common.str.blank(self.caller.auth_account_uuid) then + self.caller.auth_account = self:object_find(self.caller.auth_account_type, self.caller.auth_account_uuid); + self.caller:set_auth_account(self.caller.auth_account); + end + + if self.caller.auth_account then + self.log:info('CALLER_DATA - auth account: ', self.caller.auth_account.class, '=', self.caller.auth_account.id, '/', self.caller.auth_account.uuid); + if self.caller.auth_account.owner then + self.log:info('CALLER_DATA - auth owner: ', self.caller.auth_account.owner.class, '=', self.caller.auth_account.owner.id, '/', self.caller.auth_account.owner.uuid); + else + self.log:error('CALLER_DATA - auth owner not found'); + end + else + self.log:info('CALLER_DATA - no data - unauthenticated call: ', self.caller.auth_account_type, '/', self.caller.auth_account_uuid); + end + + if not common.str.blank(self.caller.account_type) and not common.str.blank(self.caller.account_uuid) then + self.caller.account = self:object_find(self.caller.account_type, self.caller.account_uuid); + if self.caller.account then + require 'common.phone_number' + self.caller.caller_phone_numbers = common.phone_number.PhoneNumber:new{ log = self.log, database = self.database }:list_by_owner(self.caller.account.id, self.caller.account.class); + for index, caller_number in ipairs(self.caller.caller_phone_numbers) do + self.caller.caller_phone_numbers_hash[caller_number] = true; + end + self.log:info('CALLER_DATA - caller account: ', self.caller.account.class, '=', self.caller.account.id, '/', self.caller.account.uuid, ', phone_numbers: ', #self.caller.caller_phone_numbers); + if self.caller.account.owner then + self.log:info('CALLER_DATA - caller owner: ', self.caller.account.owner.class, '=', self.caller.account.owner.id, '/', self.caller.account.owner.uuid); + else + self.log:error('CALLER_DATA - caller owner not found'); + end + + if not self.caller.clir then + self.caller:set_caller_id(self.caller.caller_phone_numbers[1], self.caller.account.record.caller_name or self.caller.account.record.name); + end + else + self.log:error('CALLER_DATA - caller account not found: ', self.caller.account_type, '/', self.caller.account_uuid); + end + end +end + + +function Dialplan.destination_new(self, arg) + require 'common.str' + + local destination = { + number = arg.number or '', + type = arg.type or 'unknown', + id = common.str.to_i(arg.id), + uuid = arg.uuid or '', + phone_number = arg.phone_number, + node_id = common.str.to_i(arg.node_id), + call_forwarding = {}, + data = arg.data, + } + + destination.type = common.str.downcase(destination.type); + + if not common.str.blank(destination.number) then + if destination.type == 'unknown' and destination.number:find(DIALPLAN_FUNCTION_PATTERN) then + destination.type = 'dialplanfunction'; + elseif destination.type == 'phonenumber' or destination.type == 'unknown' then + require 'common.phone_number' + destination.phone_number = common.phone_number.PhoneNumber:new{ log = self.log, database = self.database }:find_by_number(destination.number); + + if destination.phone_number then + destination.type = common.str.downcase(destination.phone_number.record.phone_numberable_type); + destination.id = common.str.to_i(destination.phone_number.record.phone_numberable_id); + destination.uuid = common.str.to_s(destination.phone_number.record.phone_numberable_uuid); + destination.node_id = common.str.to_i(destination.phone_number.record.gs_node_id); + if self.caller then + destination.call_forwarding = destination.phone_number:call_forwarding(self.caller.caller_phone_numbers); + end + elseif destination.type == 'unknown' then + require 'common.sip_account' + destination.account = common.sip_account.SipAccount:new{ log = self.log, database = self.database }:find_by_auth_name(destination.number); + if destination.account then + destination.type = 'sipaccount'; + destination.id = common.str.to_i(destination.account.record.id); + destination.uuid = common.str.to_s(destination.account.record.uuid); + destination.node_id = common.str.to_i(destination.account.record.gs_node_id); + end + end + end + end + + if destination.node_id == 0 then + destination.node_id = self.node_id; + destination.node_local = true; + else + destination.node_local = (destination.node_id == self.node_id); + end + + self.log:info('DESTINATION_NEW - ', destination.type, '=', destination.id, '/', destination.uuid,'@', destination.node_id, ', number: ', destination.number); + + return destination; +end + + +function Dialplan.routes_get(self, destination) + require 'dialplan.route' + return dialplan.route.Route:new{ log = self.log, database = self.database, routing_table = self.routes }:outbound(self.caller, destination.number); +end + + +function Dialplan.set_caller_picture(self, entry_id, entry_type, image) + entry_type = entry_type:lower(); + if entry_type == 'user' then + require 'dialplan.user' + local user = dialplan.user.User:new{ log = self.log, database = self.database }:find_by_id(entry_id); + if user then + self.caller:set_variable('sip_h_Call-Info', '<' .. self.user_image_url .. '/' .. tonumber(entry_id) .. '/snom_caller_picture_' .. tostring(user.record.image) .. '>;purpose=icon'); + end + elseif entry_type == 'phonebookentry' and image then + self.caller:set_variable('sip_h_Call-Info', '<' .. self.phone_book_entry_image_url .. '/' .. tonumber(entry_id) .. '/snom_caller_picture_' .. tostring(image) .. '>;purpose=icon'); + end +end + + +function Dialplan.dial(self, destination) + require 'common.str' + destination.caller_id_number = destination.caller_id_number or self.caller.caller_phone_numbers[1]; + + if not self.caller.clir then + if destination.node_local and destination.type == 'sipaccount' then + local user_id = nil; + local tenant_id = nil; + + destination.account = self:object_find(destination.type, destination.id); + if destination.account then + if destination.account.class == 'sipaccount' then + destination.callee_id_name = destination.account.record.caller_name; + self.caller:set_callee_id(destination.number, destination.account.record.caller_name); + end + end + + if destination.account and destination.account.owner then + if destination.account.owner.class == 'user' then + user_id = destination.account.owner.id; + tenant_id = tonumber(destination.account.owner.record.current_tenant_id); + elseif destination.account.owner.class == 'tenant' then + tenant_id = destination.account.owner.id; + end + end + + if user_id or tenant_id then + require 'common.str' + local phone_book_entry = nil; + + if self.phonebook_number_lookup then + require 'dialplan.phone_book' + phone_book_entry = dialplan.phone_book.PhoneBook:new{ log = self.log, database = self.database }:find_entry_by_number_user_tenant(self.caller.caller_phone_numbers, user_id, tenant_id); + end + + if phone_book_entry then + self.log:info('PHONE_BOOK_ENTRY - phone_book=', phone_book_entry.phone_book_id, ' (', phone_book_entry.phone_book_name, '), caller_id_name: ', phone_book_entry.caller_id_name, ', ringtone: ', phone_book_entry.bellcore_id); + destination.caller_id_name = common.str.to_ascii(phone_book_entry.caller_id_name); + if tonumber(phone_book_entry.bellcore_id) then + self.log:debug('RINGTONE - phonebookentry, index: ', phone_book_entry.bellcore_id); + self.caller:export_variable('alert_info', 'http://amooma.de;info=Ringer' .. phone_book_entry.bellcore_id .. ';x-line-id=0'); + end + if phone_book_entry.image then + self:set_caller_picture(phone_book_entry.id, 'phonebookentry', phone_book_entry.image); + elseif self.caller.account and self.caller.account.owner then + self:set_caller_picture(self.caller.account.owner.id, self.caller.account.owner.class); + end + elseif self.caller.account and self.caller.account.owner then + self:set_caller_picture(self.caller.account.owner.id, self.caller.account.owner.class); + elseif self.geo_number_lookup then + require 'dialplan.geo_number' + local geo_number = dialplan.geo_number.GeoNumber:new{ log = self.log, database = self.database }:find(destination.caller_id_number); + if geo_number then + self.log:info('GEO_NUMBER - found: ', geo_number.name, ', ', geo_number.country); + if geo_number.name then + destination.caller_id_name = common.str.to_ascii(geo_number.name) .. ', ' .. common.str.to_ascii(geo_number.country); + else + destination.caller_id_name = common.str.to_ascii(geo_number.country); + end + end + end + end + end + self.caller:set_caller_id(destination.caller_id_number, destination.caller_id_name or self.caller.caller_id_name); + else + self.caller:set_caller_id('anonymous', 'Unknown'); + self.caller:set_privacy(true); + end + + local destinations = { destination }; + + if self.caller.forwarding_service == 'assistant' and self.caller.auth_account and self.caller.auth_account.class == 'sipaccount' then + self.caller.auth_account.type = self.caller.auth_account.class; + local forwarding_destination = self:destination_new( self.caller.auth_account ); + if forwarding_destination then + forwarding_destination.alert_info = 'http://amooma.com;info=Ringer0;x-line-id=0' + table.insert(destinations, forwarding_destination); + end + end + + if common.str.to_b(self.config.parameters.bypass_media) then + self.caller:set_variable('bypass_media', true); + end + + require 'dialplan.sip_call' + return dialplan.sip_call.SipCall:new{ log = self.log, database = self.database, caller = self.caller }:fork( + destinations, + { timeout = self.dial_timeout_active, + send_ringing = ( self.send_ringing_to_gateways and self.caller.from_gateway ), + bypass_media_network = self.config.parameters.bypass_media_network, + } + ); +end + + +function Dialplan.huntgroup(self, destination) + local hunt_group = self:object_find('huntgroup', tonumber(destination.id)); + + if not hunt_group then + self.log:error('DIALPLAN_HUNTGROUP - huntgroup not found'); + return { continue = true, code = 404, phrase = 'Huntgroup not found' } + end + + self.caller:set_callee_id(destination.number, hunt_group.record.name); + destination.caller_id_number = destination.caller_id_number or self.caller.caller_phone_numbers[1]; + + if not self.caller.clir then + self.caller:set_caller_id(destination.caller_id_number, tostring(hunt_group.record.name) .. ' '.. tostring(self.caller.caller_id_name)); + if self.caller.account and self.caller.account.owner then + self:set_caller_picture(self.caller.account.owner.id, self.caller.account.owner.class); + end + else + self.caller:set_caller_id('anonymous', tostring(hunt_group.record.name)); + self.caller:set_privacy(true); + end + + self.caller.auth_account = hunt_group; + self.caller:set_auth_account(self.caller.auth_account); + self.caller.forwarding_number = destination.number; + self.caller.forwarding_service = 'huntgroup'; + self.caller:set_variable('gs_forwarding_service', self.caller.forwarding_service); + self.caller:set_variable('gs_forwarding_number', self.caller.forwarding_number); + return hunt_group:run(self, self.caller, destination); +end + + +function Dialplan.acd(self, destination) + local acd = self:object_find('automaticcalldistributor', tonumber(destination.id)); + + if not acd then + self.log:error('DIALPLAN_ACD - acd not found'); + return { continue = true, code = 404, phrase = 'ACD not found' } + end + + self.caller:set_callee_id(destination.number, acd.record.name); + destination.caller_id_number = destination.caller_id_number or self.caller.caller_phone_numbers[1]; + + if not self.caller.clir then + self.caller:set_caller_id(destination.caller_id_number, tostring(acd.record.name) .. ' '.. tostring(self.caller.caller_id_name)); + if self.caller.account and self.caller.account.owner then + self:set_caller_picture(self.caller.account.owner.id, self.caller.account.owner.class); + end + else + self.caller:set_caller_id('anonymous', tostring(acd.record.name)); + self.caller:set_privacy(true); + end + + self.caller.auth_account = acd; + self.caller:set_auth_account(self.caller.auth_account); + self.caller.forwarding_number = destination.number; + self.caller.forwarding_service = 'automaticcalldistributor'; + self.caller:set_variable('gs_forwarding_service', self.caller.forwarding_service); + self.caller:set_variable('gs_forwarding_number', self.caller.forwarding_number); + + acd:caller_new(self.caller.uuid); + local result = acd:run(self, self.caller, destination); + acd:caller_delete(); + + return result; +end + + +function Dialplan.conference(self, destination) + -- call local conference + require 'common.conference' + conference = common.conference.Conference:new{ log = self.log, database = self.database }:find_by_id(destination.id); + + if not conference then + return { continue = false, code = 404, phrase = 'Conference not found' } + end + + local cause = conference:enter(self.caller, self.domain); + return { continue = false, cause = cause } +end + + +function Dialplan.faxaccount(self, destination) + require 'dialplan.fax' + local fax_account = dialplan.fax.Fax:new{ log = self.log, database = self.database }:find_by_id(destination.id); + + if not fax_account then + return { continue = false, code = 404, phrase = 'Fax not found' } + end + + self.log:info('FAX_RECEIVE start - fax_account=', fax_account.id, '/', fax_account.uuid, ', name: ', fax_account.record.name, ', station_id: ', fax_account.record.station_id); + + self.caller:set_caller_id(self.caller.caller_phone_number); + self.caller:set_callee_id(destination.number, fax_account.record.name); + + local fax_document = fax_account:receive(self.caller); + + if not fax_document then + self.log:error('FAX_RECEIVE - error receiving fax document - fax_account=', fax_account.id, '/', fax_account.uuid); + return { continue = false, code = 500, phrase = 'Error receiving fax' }; + end + + fax_document.caller_id_number = self.caller.caller_phone_number; + fax_document.caller_id_name = self.caller.caller_id_name; + fax_document.uuid = self.caller.uuid; + + self.log:info('FAX_RECEIVE end - success: ', fax_document.success, + ', remote: ', fax_document.remote_station_id, + ', pages: ', fax_document.transferred_pages, '/', fax_document.total_pages, + ', result: ', fax_document.result_code, ' ', fax_document.result_text); + + if fax_document.success then + self.log:notice('FAX_RECEIVE - saving fax document: ', fax_document.filename ); + if not fax_account:insert_document(fax_document) then + self.log:error('FAX_RECEIVE - error inserting fax document to database - fax_account=', fax_account.id, '/', fax_account.uuid, ', file: ', fax_document.filename); + end + end + + return { continue = false, code = 200, phrase = 'OK' } +end + + +function Dialplan.callthrough(self, destination) + -- Callthrough + require 'dialplan.callthrough' + callthrough = dialplan.callthrough.Callthrough:new{ log = self.log, database = self.database }:find_by_id(destination.id) + + if not callthrough then + self.log:error('CALLTHROUGH - no callthrough for destination number: ', destination.number); + return { continue = false, code = 404, phrase = 'Fax not found' } + end + self.log:info('CALLTHROUGH - number: ' .. destination.number .. ', name: ' .. callthrough.record.name); + + local authorization = callthrough:authenticate(self.caller); + + if not authorization then + self.log:notice('CALLTHROUGH - authentication failed'); + return { continue = false, code = 403, phrase = 'Authentication failed' } + end + + if type(authorization) == 'table' and tonumber(authorization.sip_account_id) and tonumber(authorization.sip_account_id) > 0 then + local auth_account = self:object_find('sipaccount', tonumber(authorization.sip_account_id)); + self.caller.forwarding_number = destination.number; + self.caller.forwarding_service = 'callthrough'; + self.caller:set_variable('gs_forwarding_service', self.caller.forwarding_service); + self.caller:set_variable('gs_forwarding_number', self.caller.forwarding_number); + + if auth_account then + self.caller.auth_account = auth_account; + self.caller:set_auth_account(self.caller.auth_account); + self.log:info('AUTH_ACCOUNT_UPDATE - account: ', self.caller.auth_account.class, '=', self.caller.auth_account.id, '/', self.caller.auth_account.uuid); + if self.caller.auth_account.owner then + self.log:info('AUTH_ACCOUNT_UPDATE - auth owner: ', self.caller.auth_account.owner.class, '=', self.caller.auth_account.owner.id, '/', self.caller.auth_account.owner.uuid); + else + self.log:error('AUTH_ACCOUNT_UPDATE - auth owner not found'); + end + self.log:info('CALLTHROUGH - use sip account: ', auth_account.id, ' (', auth_account.record.caller_name, ')'); + end + else + self.log:info('CALLTHROUGH - no sip account'); + end + + local destination_number = ''; + for i = 1, 3, 1 do + if destination_number ~= '' then + break; + end + destination_number = session:read(2, 16, "ivr/ivr-enter_destination_telephone_number.wav", 3000, "#"); + end + + if destination_number == '' then + self.log:debug("no callthrough destination - hangup call"); + return { continue = false, code = 404, phrase = 'No destination' } + end + + local route = dialplan.route.Route:new{ log = self.log, database = self.database, routing_table = self.routes }:prerouting(self.caller, destination_number); + if route and route.value then + destination_number = route.value; + end + + if not callthrough:whitelist(destination_number) then + self.log:debug('caller not authorized to call destination number: ' .. destination_number .. ' - hangup call'); + return { continue = false, code = 403, phrase = 'Unauthorized' } + end + + return { continue = true, code = 302, number = destination_number } +end + + +function Dialplan.voicemail(self, destination) + if not self.caller.auth_account or self.caller.auth_account.class ~= 'sipaccount' then + self.log:error('VOICEMAIL - incompatible destination'); + return { continue = false, code = 404, phrase = 'Mailbox not found' } + end + + require 'dialplan.voicemail' + local voicemail_account = dialplan.voicemail.Voicemail:new{ log = self.log, database = self.database }:find_by_sip_account_id(self.caller.auth_account.id); + + if not voicemail_account then + self.log:error('VOICEMAIL - no mailbox'); + return { continue = false, code = 404, phrase = 'Mailbox not found' } + end + + voicemail_account:leave(self.caller, self.caller.forwarding_number); + + if self.caller:to_s("voicemail_message_len") == '' then + self.log:info('VOICEMAIL - no message saved'); + end + + return { continue = false, code = 200 } +end + + +function Dialplan.dialplanfunction(self, destination) + require 'dialplan.functions' + return dialplan.functions.Functions:new{ log = self.log, database = self.database, domain = self.domain }:dialplan_function(self.caller, destination.number); +end + + +function Dialplan.switch(self, destination) + require 'common.str' + local result = nil; + self.dial_timeout_active = self.dial_timeout; + + if not destination.node_local then + return self:dial(destination); + end + + for service, call_forwarding in pairs(destination.call_forwarding) do + if self.caller.caller_phone_numbers_hash[call_forwarding.number] then + self.log:info('CALL_FORWARDING - caller number equals destination: ', call_forwarding.number,' - ignore service: ', service); + destination.call_forwarding[service] = nil; + end + end + + if destination.call_forwarding.noanswer then + self.dial_timeout_active = tonumber(destination.call_forwarding.noanswer.timeout) or self.dial_timeout; + end + + if destination.call_forwarding.always then + return { continue = true, call_forwarding = destination.call_forwarding.always } + elseif destination.call_forwarding.assistant then + if common.str.downcase(destination.call_forwarding.assistant.type) == 'huntgroup' then + require 'dialplan.hunt_group' + local hunt_group = dialplan.hunt_group.HuntGroup:new{ log = self.log, database = self.database }:find_by_id(destination.call_forwarding.assistant.id); + self.log:info('CALL_FORWARDING - huntgroup - auth_account: ', self.caller.auth_account_type, '=', self.caller.auth_account_uuid); + if hunt_group and (hunt_group:is_member_by_numbers(self.caller.caller_phone_numbers)) then + self.log:info('CALL_FORWARDING - caller is huntgroup member - ignore service: ', destination.call_forwarding.assistant.service); + else + return { continue = true, call_forwarding = destination.call_forwarding.assistant } + end + else + return { continue = true, call_forwarding = destination.call_forwarding.assistant } + end + end + + -- reset ringtone + self.caller:export_variable('alert_info', self.default_ringtone); + + if destination.phone_number then + local ringtone = destination.phone_number:ringtone(); + if ringtone and ringtone.bellcore_id then + self.log:debug('RINGTONE - ', ringtone.ringtoneable_type .. ', index: ' .. ringtone.bellcore_id); + self.caller:export_variable('alert_info', 'http://amooma.de;info=Ringer' .. tonumber(ringtone.bellcore_id) .. ';x-line-id=0'); + end + end + + if destination.type == 'sipaccount' then + result = self:dial(destination); + if CALL_FORWARDING_SERVICES[result.disposition] then + result.call_forwarding = destination.call_forwarding[CALL_FORWARDING_SERVICES[result.disposition]]; + if result.call_forwarding then + result.continue = true; + end + end + return result; + elseif destination.type == 'conference' then + return self:conference(destination); + elseif destination.type == 'faxaccount' then + return self:faxaccount(destination); + elseif destination.type == 'callthrough' then + return self:callthrough(destination); + elseif destination.type == 'huntgroup' then + result = self:huntgroup(destination); + if CALL_FORWARDING_SERVICES[result.disposition] then + result.call_forwarding = destination.call_forwarding[CALL_FORWARDING_SERVICES[result.disposition]]; + if result.call_forwarding then + result.continue = true; + end + end + return result; + elseif destination.type == 'automaticcalldistributor' then + result = self:acd(destination); + if CALL_FORWARDING_SERVICES[result.disposition] then + result.call_forwarding = destination.call_forwarding[CALL_FORWARDING_SERVICES[result.disposition]]; + if result.call_forwarding then + result.continue = true; + end + end + return result; + elseif destination.type == 'voicemail' then + return self:voicemail(destination); + elseif destination.type == 'dialplanfunction' then + return self:dialplanfunction(destination); + elseif not common.str.blank(destination.number) then + local result = { continue = false, code = 404, phrase = 'No route' } + local routes = self:routes_get(destination); + + if not routes or #routes == 0 then + self.log:notice('SWITCH - no route - number: ', destination.number); + return { continue = false, code = 404, phrase = 'No route' } + end + + destination.callee_id_number = destination.number; + destination.callee_id_name = nil; + + if self.phonebook_number_lookup then + require 'common.str' + local user_id = common.str.try(self.caller, 'account.owner.id'); + local tenant_id = common.str.try(self.caller, 'account.owner.record.current_tenant_id'); + + if user_id or tenant_id then + require 'dialplan.phone_book' + local phone_book_entry = dialplan.phone_book.PhoneBook:new{ log = self.log, database = self.database }:find_entry_by_number_user_tenant({ destination.number }, user_id, tenant_id); + if phone_book_entry then + self.log:info('PHONE_BOOK_ENTRY - phone_book=', phone_book_entry.phone_book_id, ' (', phone_book_entry.phone_book_name, '), callee_id_name: ', common.str.to_ascii(phone_book_entry.caller_id_name)); + destination.callee_id_name = common.str.to_ascii(phone_book_entry.caller_id_name); + end + end + end + + if self.geo_number_lookup and not destination.callee_id_name then + require 'dialplan.geo_number' + local geo_number = dialplan.geo_number.GeoNumber:new{ log = self.log, database = self.database }:find(destination.number); + if geo_number then + require 'common.str' + self.log:info('GEO_NUMBER - found: ', geo_number.name, ', ', geo_number.country); + if geo_number.name then + destination.callee_id_name = common.str.to_ascii(geo_number.name) .. ', ' .. common.str.to_ascii(geo_number.country); + else + destination.callee_id_name = common.str.to_ascii(geo_number.country); + end + end + end + + self.caller:set_callee_id(destination.callee_id_number, destination.callee_id_name); + + for index, route in ipairs(routes) do + if route.class == 'hangup' then + return { continue = false, code = route.endpoint, phrase = route.phrase, cause = route.value } + end + if route.class == 'forward' then + return { continue = true, call_forwarding = { number = route.value, service = 'route', type = 'phonenumber' }} + end + destination.gateway = route.endpoint; + destination.type = route.class; + destination.number = route.value; + destination.caller_id_number = route.caller_id_number; + destination.caller_id_name = route.caller_id_name; + result = self:dial(destination); + + if result.continue == false then + break; + end + + if common.str.to_b(self.routes.failover[tostring(result.code)]) == true then + self.log:info('SWITCH - failover - code: ', result.code); + elseif common.str.to_b(self.routes.failover[tostring(result.cause)]) == true then + self.log:info('SWITCH - failover - cause: ', result.cause); + else + self.log:info('SWITCH - no failover - cause: ', result.cause, ', code: ', result.code); + break; + end + end + + return result; + end + + self.log:error('SWITCH - destination not found - type: ', destination.type); + return { continue = true, code = 404, phrase = destination.type .. ' not found' } +end + + +function Dialplan.run(self, destination) + self.caller:set_variable('hangup_after_bridge', false); + self.caller:set_variable('ringback', self.config.parameters.ringback); + self.caller:set_variable('bridge_early_media', 'true'); + self.caller:set_variable('send_silence_when_idle', 0); + self.caller:set_variable('default_language', self.default_language); + self.caller:set_variable('gs_save_cdr', true); + self.caller:set_variable('gs_call_service', 'dial'); + self.caller.session:setAutoHangup(false); + + self.routes = common.configuration_file.get('/opt/freeswitch/scripts/ini/routes.ini'); + self.caller.domain_local = self.domain; + self:retrieve_caller_data(); + + if not destination or destination.type == 'unknown' then + require 'dialplan.route' + local route = nil; + + if self.caller.from_gateway then + local route_object = dialplan.route.Route:new{ log = self.log, database = self.database, routing_table = self.routes }; + route = route_object:inbound(self.caller, self.caller.destination_number); + local inbound_caller_id_number = route_object:inbound_cid_number(self.caller, self.caller.gateway_name, 'gateway'); + route_object.expandable.caller_id_number = inbound_caller_id_number; + local inbound_caller_id_name = route_object:inbound_cid_name(self.caller, self.caller.gateway_name, 'gateway'); + self.log:info('INBOUND_CALLER_ID_REWRITE - number: ', inbound_caller_id_number, ', name: ', inbound_caller_id_name); + self.caller.caller_id_number = inbound_caller_id_number or self.caller.caller_id_number; + self.caller.caller_id_name = inbound_caller_id_name or self.caller.caller_id_name; + self.caller.caller_phone_numbers[1] = self.caller.caller_id_number; + else + route = dialplan.route.Route:new{ log = self.log, database = self.database, routing_table = self.routes }:prerouting(self.caller, self.caller.destination_number); + end + + if route then + destination = self:destination_new{ number = route.value } + self.caller.destination_number = destination.number; + self.caller.destination = destination; + elseif not destination or destination.type == 'unknown' then + destination = self:destination_new{ number = self.caller.destination_number } + self.caller.destination = destination; + end + end + + self.log:info('DIALPLAN start - caller_id: ',self.caller.caller_id_number, ' "', self.caller.caller_id_name,'"', + ', number: ', destination.number); + + local result = { continue = false }; + local loop = self.caller.loop_count; + while self.caller:ready() and loop < self.max_loops do + loop = loop + 1; + self.caller.loop_count = loop; + + self.log:info('LOOP ', loop, + ' - destination: ', destination.type, '=', destination.id, '/', destination.uuid,'@', destination.node_id, + ', number: ', destination.number); + + self.caller:set_variable('gs_destination_type', destination.type); + self.caller:set_variable('gs_destination_id', destination.id); + self.caller:set_variable('gs_destination_uuid', destination.uuid); + self.caller:set_variable('gs_destination_number', destination.number); + self.caller:set_variable('gs_destination_node_local', destination.node_local); + + result = self:switch(destination); + result = result or { continue = false, code = 502, cause = 'DESTINATION_OUT_OF_ORDER', phrase = 'Destination out of order' } + + if result.call_service then + self.caller:set_variable('gs_call_service', result.call_service); + end + + if not result.continue then + break; + end + + if result.call_forwarding then + self.log:info('LOOP ', loop, ' CALL_FORWARDING - service: ', result.call_forwarding.service, + ', destination: ', result.call_forwarding.type, '=', result.call_forwarding.id, + ', number: ', result.call_forwarding.number); + + local auth_account = self:object_find(destination.type, destination.id); + self.caller.forwarding_number = destination.number; + self.caller.forwarding_service = result.call_forwarding.service; + self.caller:set_variable('gs_forwarding_service', self.caller.forwarding_service); + self.caller:set_variable('gs_forwarding_number', self.caller.forwarding_number); + + if auth_account then + self.caller.auth_account = auth_account; + self.caller:set_auth_account(self.caller.auth_account); + self.log:info('AUTH_ACCOUNT_UPDATE - account: ', self.caller.auth_account.class, '=', self.caller.auth_account.id, '/', self.caller.auth_account.uuid); + if self.caller.auth_account.owner then + self.log:info('AUTH_ACCOUNT_UPDATE - auth owner: ', self.caller.auth_account.owner.class, '=', self.caller.auth_account.owner.id, '/', self.caller.auth_account.owner.uuid); + else + self.log:error('AUTH_ACCOUNT_UPDATE - auth owner not found'); + end + end + + destination = self:destination_new(result.call_forwarding); + self.caller.destination = destination; + + if not result.no_cdr and auth_account then + require 'common.call_history' + common.call_history.CallHistory:new{ log = self.log, database = self.database }:insert_forwarded( + self.caller.uuid, + auth_account.class, + auth_account.id, + self.caller, + destination, + result + ); + end + end + + if result.number then + self.log:info('LOOP ', loop, ' NEW_DESTINATION_NUMBER - number: ', result.number ); + destination = self:destination_new{ number = result.number } + self.caller.destination = destination; + end + end + + if loop >= self.max_loops then + result = { continue = false, code = 483, cause = 'EXCHANGE_ROUTING_ERROR', phrase = 'Too many hops' } + end + + self.log:info('DIALPLAN end - caller_id: ',self.caller.caller_id_number, ' "', self.caller.caller_id_name,'"', + ', destination: ', destination.type, '=', destination.id, '/', destination.uuid,'@', destination.node_id, + ', number: ', destination.number, ', result: ', result.code, ' ', result.phrase); + + if self.caller:ready() then + self:hangup(result.code, result.phrase, result.cause); + end + + self.caller:set_variable('gs_save_cdr', not result.no_cdr); +end diff --git a/misc/freeswitch/scripts/dialplan/fax.lua b/misc/freeswitch/scripts/dialplan/fax.lua new file mode 100644 index 0000000..2a40620 --- /dev/null +++ b/misc/freeswitch/scripts/dialplan/fax.lua @@ -0,0 +1,232 @@ +-- Gemeinschaft 5 module: fax class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +FAX_DOCUMENTS_DIRECTORY = '/tmp/' +FAX_PARALLEL_MAX = 8; +Fax = {} + +-- Create Fax object +function Fax.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self) + self.__index = self + self.class = 'faxaccount'; + self.log = arg.log; + self.database = arg.database; + self.record = arg.record; + self.fax_directory = arg.fax_directory or FAX_DOCUMENTS_DIRECTORY; + return object; +end + +-- find fax account by id +function Fax.find_by_id(self, id) + local sql_query = 'SELECT * FROM `fax_accounts` WHERE `id` = ' .. tonumber(id) .. ' LIMIT 1'; + local fax_account = nil; + + self.database:query(sql_query, function(fax_entry) + fax_account = Fax:new(self); + fax_account.record = fax_entry; + fax_account.id = tonumber(fax_entry.id); + fax_account.uuid = fax_entry.uuid; + end) + + return fax_account; +end + + +-- find fax account by uuid +function Fax.find_by_uuid(self, uuid) + local sql_query = 'SELECT * FROM `fax_accounts` WHERE `uuid` = "' .. uuid .. '" LIMIT 1'; + local fax_account = nil; + + self.database:query(sql_query, function(fax_entry) + fax_account = Fax:new(self); + fax_account.record = fax_entry; + fax_account.id = tonumber(fax_entry.id); + fax_account.uuid = fax_entry.uuid; + end) + + return fax_account; +end + + +function Fax.destination_numbers(self, id) + local sql_query = 'SELECT `number` FROM `phone_numbers` WHERE `phone_numberable_type` = "FaxDocument" AND `phone_numberable_id` = ' .. tonumber(id); + local destination_numbers = {} + + self.database:query(sql_query, function(fax_entry) + table.insert(destination_numbers, fax_entry.number); + end) + + return destination_numbers; +end + +function Fax.destination_number(self, id) + local sql_query = 'SELECT `number` FROM `phone_numbers` WHERE `phone_numberable_type` = "FaxDocument" AND `phone_numberable_id`= ' .. tonumber(id) .. ' LIMIT 1'; + local destination_number = nil; + + self.database:query(sql_query, function(fax_entry) + destination_number = fax_entry.number; + end) + + return destination_number; +end + +-- List waiting fax documents +function Fax.queued_for_sending(self, limit) + limit = limit or FAX_PARALLEL_MAX; + local sql_query = 'SELECT * FROM `fax_documents` WHERE `state` IN ("queued_for_sending","unsuccessful") AND `retry_counter` > 0 ORDER BY `sent_at` ASC LIMIT ' .. limit; + local fax_documents = {} + self.database:query(sql_query, function(fax_entry) + fax_entry['destination_numbers'] = Fax:destination_numbers(fax_entry.id) + table.insert(fax_documents, fax_entry); + end) + + return fax_documents; +end + +-- Update fax document sending status +function Fax.document_update(self, id, params) + require 'common.str' + local params_sql = {} + + for name, value in pairs(params) do + table.insert(params_sql, '`' .. name .. '`=' .. common.str.to_sql(value)); + end + + if not params['sent_at'] then + table.insert(params_sql, '`sent_at`=NOW()'); + end + + if not params['updated_at'] then + table.insert(params_sql, '`updated_at`=NOW()'); + end + + local sql_query = 'UPDATE `fax_documents` SET ' .. table.concat(params_sql, ',') .. ' WHERE `id` = ' .. tonumber(id); + + return self.database:query(sql_query); +end + + +function Fax.get_parameters(self, caller) + local fax_parameters = { + bad_rows = caller:to_i('fax_bad_rows'), + total_pages = caller:to_i('fax_document_total_pages'), + transferred_pages = caller:to_i('fax_document_transferred_pages'), + ecm_requested = caller:to_b('fax_ecm_requested'), + ecm_used = caller:to_b('fax_ecm_used'), + filename = caller:to_s('fax_filename'), + image_resolution = caller:to_s('fax_image_resolution'), + image_size = caller:to_i('fax_image_size'), + local_station_id = caller:to_s('fax_local_station_id'), + result_code = caller:to_i('fax_result_code'), + result_text = caller:to_s('fax_result_text'), + remote_station_id = caller:to_s('fax_remote_station_id'), + success = caller:to_b('fax_success'), + transfer_rate = caller:to_i('fax_transfer_rate'), + v17_disabled = caller:to_b('fax_v17_disabled'), + } + + return fax_parameters; +end + +-- Receive Fax +function Fax.receive(self, caller, file_name) + file_name = file_name or self.fax_directory .. 'fax_in_' .. caller.uuid .. '.tiff'; + + caller:set_variable('fax_ident', self.record.station_id) + caller:set_variable('fax_verbose', 'false') + + caller:answer(); + local start_time = os.time(); + caller:execute('rxfax', file_name); + local record = self:get_parameters(caller); + record.transmission_time = os.time() - start_time; + return record; +end + +-- Send Fax +function Fax.send(self, caller, file_name) + caller:set_variable('fax_ident', self.record.station_id) + caller:set_variable('fax_header', self.record.name) + caller:set_variable('fax_verbose', 'false') + local start_time = os.time(); + caller:execute('txfax', file_name); + local record = self:get_parameters(caller); + record.transmission_time = os.time() - start_time; + return record; +end + +-- find fax document by id +function Fax.find_document_by_id(self, id) + local sql_query = 'SELECT * FROM `fax_documents` WHERE `id` = ' .. tonumber(id) .. ' LIMIT 1' + local record = nil + + self.database:query(sql_query, function(fax_entry) + record = fax_entry; + end); + + return record; +end + +-- save fax document to database +function Fax.insert_document(self, record) + require 'common.str' + local sql_query = 'INSERT INTO `fax_documents` ( \ + inbound, \ + retry_counter, \ + fax_resolution_id, \ + state, \ + transmission_time, \ + sent_at, \ + document_total_pages, \ + document_transferred_pages, \ + ecm_requested, \ + ecm_used, \ + image_resolution, \ + image_size, \ + local_station_id, \ + result_code, \ + remote_station_id, \ + success, \ + transfer_rate, \ + created_at, \ + updated_at, \ + fax_account_id, \ + caller_id_number, \ + caller_id_name, \ + tiff, \ + uuid \ + ) VALUES ( \ + true, \ + 0, \ + 1, \ + "received", \ + ' .. common.str.to_sql(record.transmission_time) .. ', \ + NOW(), \ + ' .. common.str.to_sql(record.total_pages) .. ', \ + ' .. common.str.to_sql(record.transferred_pages) .. ', \ + ' .. common.str.to_sql(record.ecm_requested) .. ', \ + ' .. common.str.to_sql(record.ecm_used) .. ', \ + ' .. common.str.to_sql(record.image_resolution) .. ', \ + ' .. common.str.to_sql(record.image_size) .. ', \ + ' .. common.str.to_sql(record.local_station_id) .. ', \ + ' .. common.str.to_sql(record.result_code) .. ', \ + ' .. common.str.to_sql(record.remote_station_id) .. ', \ + ' .. common.str.to_sql(record.success) .. ', \ + ' .. common.str.to_sql(record.transfer_rate) .. ', \ + NOW(), \ + NOW(), \ + ' .. common.str.to_sql(self.id) .. ', \ + ' .. common.str.to_sql(record.caller_id_number) .. ', \ + ' .. common.str.to_sql(record.caller_id_name) .. ', \ + ' .. common.str.to_sql(record.filename) .. ', \ + ' .. common.str.to_sql(record.uuid) .. ' \ + )'; + + return self.database:query(sql_query); +end diff --git a/misc/freeswitch/scripts/dialplan/functions.lua b/misc/freeswitch/scripts/dialplan/functions.lua new file mode 100644 index 0000000..c104f89 --- /dev/null +++ b/misc/freeswitch/scripts/dialplan/functions.lua @@ -0,0 +1,839 @@ +-- DialplanModule: Functions +-- +module(...,package.seeall) + +Functions = {} + +-- Create Functions object +function Functions.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self) + self.__index = self + self.log = arg.log + self.database = arg.database + self.domain = arg.domain + return object +end + +function Functions.ensure_caller_sip_account(self, caller) + if caller.account and caller.account.class == 'sipaccount' then + return caller.account; + end +end + +function Functions.dialplan_function(self, caller, dialed_number) + require 'common.str' + local parameters = common.str.to_a(dialed_number, '%-'); + if not parameters[2] then + return { continue = false, code = 484, phrase = 'Malformed function parameters', no_cdr = true }; + end + local fid = tostring(parameters[2]); + local result = { continue = false, code = 404, phrase = 'Function not found', no_cdr = true }; + + self.log:debug('DIALPLAN_DUNCTION - execute: ', dialed_number); + + if fid == "ta" then + result = self:transfer_all(caller, parameters[3]); + elseif fid == "in" then + result = self:intercept_extensions(caller, parameters[3]); + elseif fid == "ia" then + result = self:intercept_any_extension(caller, parameters[3]); + elseif fid == "anc" then + result = self:account_node_change(caller); + elseif fid == "li" then + result = self:user_login(caller, parameters[3], parameters[4]); + elseif fid == "lo" then + result = self:user_logout(caller); + elseif fid == "lir" then + result = self:user_login_redirect(caller, parameters[3], parameters[4]); + elseif fid == "loaon" then + result = self:user_auto_logout(caller, true); + elseif fid == "loaoff" then + result = self:user_auto_logout(caller, false); + elseif fid == "dcliroff" then + result = self:dial_clir_off(caller, parameters[3]); + elseif fid == "dcliron" then + result = self:dial_clir_on(caller, parameters[3]); + elseif fid == "clipon" then + result = self:clip_on(caller); + elseif fid == "clipoff" then + result = self:clip_off(caller); + elseif fid == "cwaoff" then + result = self:callwaiting_off(caller); + elseif fid == "cwaon" then + result = self:callwaiting_on(caller); + elseif fid == "cfoff" then + result = self:call_forwarding_off(caller); + elseif fid == "cfdel" then + result = self:call_forwarding_off(caller, nil, true); + elseif fid == "cfu" then + result = self:call_forwarding_on(caller, 'always', parameters[3], 'PhoneNumber'); + elseif fid == "cfuoff" then + result = self:call_forwarding_off(caller, 'always'); + elseif fid == "cfudel" then + result = self:call_forwarding_off(caller, 'always', true); + elseif fid == "cfutg" then + result = self:call_forwarding_toggle(caller, 'always', parameters[3]); + elseif fid == "cfn" then + result = self:call_forwarding_on(caller, 'noanswer', parameters[3], 'PhoneNumber', parameters[4]); + elseif fid == "cfnoff" then + result = self:call_forwarding_off(caller, 'noanswer'); + elseif fid == "cfndel" then + result = self:call_forwarding_off(caller, 'noanswer', true); + elseif fid == "cfo" then + result = self:call_forwarding_on(caller, 'offline', parameters[3], 'PhoneNumber'); + elseif fid == "cfooff" then + result = self:call_forwarding_off(caller, 'offline'); + elseif fid == "cfodel" then + result = self:call_forwarding_off(caller, 'offline', true); + elseif fid == "cfb" then + result = self:call_forwarding_on(caller, 'busy', parameters[3], 'PhoneNumber'); + elseif fid == "cfboff" then + result = self:call_forwarding_off(caller, 'busy'); + elseif fid == "cfbdel" then + result = self:call_forwarding_off(caller, 'busy', true); + elseif fid == "vmleave" then + result = self:voicemail_message_leave(caller, parameters[3]); + elseif fid == "vmcheck" then + result = self:voicemail_check(caller, parameters[3]); + elseif fid == "vmtg" then + result = self:call_forwarding_toggle(caller, nil, parameters[3]); + elseif fid == "acdmtg" then + result = self:acd_membership_toggle(caller, parameters[3], parameters[4]); + elseif fid == "e164" then + result = "+" .. tostring(parameters[3]); + elseif fid == "hangup" then + result = self:hangup(caller, parameters[3], parameters[4]); + end + + return result; +end + +-- Transfer all calls to a conference +function Functions.transfer_all(self, caller, destination_number) + self.log:info('TRANSFER_ALL - caller: ', caller.account_type, '/', caller.account_uuid, ' number: ', destination_number); + + local caller_sip_account = self:ensure_caller_sip_account(caller); + if not caller_sip_account then + self.log:error('TRANSFER_ALL - incompatible caller'); + return { continue = false, code = 403, phrase = 'Incompatible caller' } + end + + -- Query call and channel table for channel IDs + local sql_query = 'SELECT `b`.`name` AS `caller_chan_name`, `a`.`caller_uuid`, `a`.`callee_uuid` \ + FROM `calls` `a` JOIN `channels` `b` ON `a`.`caller_uuid` = `b`.`uuid` JOIN `channels` `c` \ + ON `a`.`callee_uuid` = `c`.`uuid` WHERE `b`.`name` LIKE ("%' .. caller_sip_account.record.auth_name .. '@%") \ + OR `c`.`name` LIKE ("%' .. caller_sip_account.record.auth_name .. '@%") LIMIT 100'; + + self.database:query(sql_query, function(call_entry) + local uid = nil + if call_entry.caller_chan_name:find(caller_sip_account.record.auth_name .. "@") then + uid = call_entry.callee_uuid; + self.log:debug("Transfering callee channel with uid: " .. uid); + else + uid = call_entry.caller_uuid; + self.log:debug("Transfering caller channel with uid: " .. uid); + end + freeswitch.API():execute("uuid_transfer", uid .. " " .. destination_number); + end) + + return destination_number; +end + +-- Intercept Extensions +function Functions.intercept_extensions(self, caller, destination_numbers) + if type(destination_numbers) == "string" then + destination_numbers = "\"" .. destination_numbers .. "\""; + else + destination_numbers = "\"" .. table.concat(destination_numbers, "\",\"") .. "\""; + end + + self.log:debug("Intercept call to number(s): " .. destination_numbers); + + if caller.account_type ~= "SipAccount" then + self.log:error("caller is not a SipAccount"); + return { continue = false, code = 403, phrase = 'Incompatible caller' } + end + + local sql_query = 'SELECT * FROM `channels` WHERE `callstate` IN ("EARLY", "ACTIVE") AND `dest` IN (' .. destination_numbers .. ') LIMIT 1'; + + self.database:query(sql_query, function(call_entry) + self.log:debug("intercepting call with uid: " .. call_entry.uuid); + caller:intercept(call_entry.uuid); + end) + + return nil; +end + +-- intercept call to destination (e.g. sip_account) +function Functions.intercept_destination(self, caller, destination) + self.log:debug("Intercept call to destination " .. destination); + local result = false; + local sql_query = 'SELECT `call_uuid`, `uuid` FROM `channels` WHERE `callstate` = "RINGING" AND `dest` = "' .. destination .. '" LIMIT 1'; + + caller:set_caller_id(caller.caller_phone_numbers[1] ,caller.caller_id_name); + self.database:query(sql_query, function(call_entry) + if call_entry.call_uuid and tostring(call_entry.call_uuid) then + self.log:debug("intercepting call - uuid: " .. call_entry.call_uuid); + caller:intercept(call_entry.call_uuid); + result = { continue = false, code = 200, call_service = 'pickup' } + require 'common.str' + require 'common.fapi' + local fapi = common.fapi.FApi:new{ log = self.log, uuid = call_entry.call_uuid } + if fapi:channel_exists() then + caller:set_caller_id( + common.str.to_s(fapi:get_variable('effective_caller_id_number')), + common.str.to_s(fapi:get_variable('effective_caller_id_name')) + ); + caller:set_callee_id( + common.str.to_s(fapi:get_variable('effective_callee_id_number')), + common.str.to_s(fapi:get_variable('effective_callee_id_name')) + ); + + caller:set_variable('gs_destination_type', fapi:get_variable('gs_destination_type')); + caller:set_variable('gs_destination_id', fapi:get_variable('gs_destination_id')); + caller:set_variable('gs_destination_uuid', fapi:get_variable('gs_destination_uuid')); + + caller:set_variable('gs_caller_account_type', fapi:get_variable('gs_account_type')); + caller:set_variable('gs_caller_account_id', fapi:get_variable('gs_account_id')); + caller:set_variable('gs_caller_account_uuid', fapi:get_variable('gs_account_uuid')); + + caller:set_variable('gs_auth_account_type', fapi:get_variable('gs_auth_account_type')); + caller:set_variable('gs_auth_account_id', fapi:get_variable('gs_auth_account_id')); + caller:set_variable('gs_auth_account_uuid', fapi:get_variable('gs_auth_account_uuid')); + end + else + self.log:error('FUNCTION - failed to intercept call - no caller uuid for callee uuid: ', call_entry.uuid); + end + end) + + return result; +end + +-- intercept call to owner of destination_number +function Functions.intercept_any_extension(self, caller, destination_number) + require 'common.phone_number' + local phone_number_object = common.phone_number.PhoneNumber:new{ log = self.log, database = self.database }:find_by_number(destination_number); + + if not phone_number_object or not phone_number_object.record then + self.log:notice("unallocated number: " .. tostring(destination_number)); + return false; + end + + if phone_number_object.record.phone_numberable_type == 'SipAccount' then + require "common.sip_account" + local sip_account_class = common.sip_account.SipAccount:new{ log = self.log, database = self.database } + local sip_account = sip_account_class:find_by_id(phone_number_object.record.phone_numberable_id) + if sip_account then + return self:intercept_destination(caller, sip_account.record.auth_name); + end + end +end + + +function Functions.account_node_change(self, caller) + self.log:info('NODE_CHANGE - caller: ', caller.account_type, '/', caller.account_uuid, ', caller_id: ', caller.caller_id_number); + + -- find caller's sip account + local caller_sip_account = caller.account; + if not caller_sip_account or not caller_sip_account.class == 'sipaccount' then + self.log:notice('LOGIN - caller sip_account not found'); + return { continue = false, code = 404, phrase = 'Account not found', no_cdr = true } + end + + require 'phones.phone' + local phone_class = phones.phone.Phone:new{log = self.log, database = self.database} + + -- logout caller phones if caller account is hot-deskable + local caller_phones = phone_class:find_all_hot_deskable_by_account(caller_sip_account.record.id); + for index, phone_caller in ipairs(caller_phones) do + phone_caller:logout(caller_sip_account.record.id); + end + + self:update_node_change(caller_sip_account, caller.local_node_id); + caller:answer(); + caller:send_display('Change successful'); + caller.session:sayPhrase('logged_in'); + + -- resync caller phones + for index, phone_caller in ipairs(caller_phones) do + local result = phone_caller:resync{ auth_name = caller_sip_account.auth_name, domain = caller.domain }; + self.log:info('NODE_CHANGE - resync phone - mac: ', phone_caller.record.mac_address, ', ip_address: ', phone_caller.record.ip_address, ', result: ', result); + end + + return { continue = false, code = 200, phrase = 'OK', no_cdr = true } +end + + +function Functions.user_login(self, caller, number, pin) + require 'common.str' + + local PHONE_NUMBER_LEN_MIN = 4; + local PHONE_NUMBER_LEN_MAX = 12; + local PIN_LEN_MIN = 4; + local PIN_LEN_MAX = 12; + + caller:set_variable('destination_number', 'f-li-' .. common.str.to_s(number) .. '-PIN'); + self.log:info('LOGIN - caller: ', caller.account_type, '/', caller.account_uuid, ', caller_id: ', caller.caller_id_number, ', number: ', number); + + if common.str.blank(number) then + number = caller.session:read(PHONE_NUMBER_LEN_MIN, PHONE_NUMBER_LEN_MAX, 'ivr/ivr-please_enter_extension_followed_by_pound.wav', 3000, '#'); + end + + -- find caller's sip account + local caller_sip_account = caller.account; + if not caller_sip_account or not caller_sip_account.class == 'sipaccount' then + self.log:notice('LOGIN - caller sip_account not found'); + return { continue = false, code = 404, phrase = 'Caller not found', no_cdr = true } + end + + require 'phones.phone' + local phone_class = phones.phone.Phone:new{log = self.log, database = self.database} + + local caller_phones = phone_class:find_all_hot_deskable_by_account(caller_sip_account.id); + local caller_phone = caller_phones[1]; + + if not caller_phone then + self.log:notice('LOGIN - caller phone not found or not hot-deskable'); + return { continue = false, code = 403, phrase = 'Phone not hot-deskable', no_cdr = true } + end + + require 'common.phone_number' + local phone_number = common.phone_number.PhoneNumber:new{log = self.log, database = self.database}:find_by_number(number, {"SipAccount"}); + + if not phone_number then + self.log:notice('LOGIN - number not found or not linked to a sip account - number: ', number); + return { continue = false, code = 404, phrase = 'Account not found', no_cdr = true } + end + + require 'common.sip_account' + local destination_sip_account = common.sip_account.SipAccount:new{ log = self.log, database = self.database }:find_by_id(phone_number.record.phone_numberable_id); + + if not destination_sip_account then + self.log:notice('LOGIN - account not found - ', phone_number.record.phone_numberable_type, '=', phone_number.record.phone_numberable_id, ', number: ', number); + return { continue = false, code = 404, phrase = 'Account not found', no_cdr = true } + end + + self.log:info('LOGIN - destination: ', phone_number.record.phone_numberable_type, '=', destination_sip_account.record.id, + ', caller_name: ', destination_sip_account.record.caller_name, ', hotdeskable: ', destination_sip_account.record.hotdeskable); + + if not common.str.to_b(destination_sip_account.record.hotdeskable) then + self.log:notice('LOGIN - destination sip_account not hot-deskable'); + return { continue = false, code = 404, phrase = 'Destination not hot-deskable', no_cdr = true } + end + + require 'dialplan.user' + local user = dialplan.user.User:new{ log = self.log, database = self.database }:find_by_id(destination_sip_account.record.sip_accountable_id); + + if common.str.blank(pin) then + pin = caller.session:read(PIN_LEN_MIN, PIN_LEN_MAX, 'ivr/ivr-please_enter_pin_followed_by_pound.wav', 3000, '#'); + end + + if not user then + self.log:notice('LOGIN - user not found - ', destination_sip_account.record.sip_accountable_type, '=',destination_sip_account.record.sip_accountable_id); + return { continue = false, code = 403, phrase = 'Authentication failed', no_cdr = true } + end + + if not user:check_pin(pin) then + self.log:notice('LOGIN - authentication failed'); + return { continue = false, code = 403, phrase = 'Authentication failed', no_cdr = true } + end + + -- logout caller phones if caller account is hot-deskable + if common.str.to_b(caller_sip_account.record.hotdeskable) then + for index, phone_caller in ipairs(caller_phones) do + phone_caller:logout(caller_sip_account.record.id); + end + end + + local destination_phones = phone_class:find_all_hot_deskable_by_account(destination_sip_account.record.id); + -- logout destination phones + for index, phone_destination in ipairs(destination_phones) do + phone_destination:logout(destination_sip_account.record.id); + end + + local result = caller_phone:login(destination_sip_account.record.id, destination_sip_account.record.sip_accountable_id, destination_sip_account.record.sip_accountable_type); + self.log:info('LOGIN - account login - mac: ', caller_phone.record.mac_address, ', ip_address: ', caller_phone.record.ip_address, ', result: ', result); + + if not result then + return { continue = false, code = 403, phrase = 'Login failed', no_cdr = true } + end + + caller:answer(); + caller:send_display('Login successful'); + + self:update_node_change(destination_sip_account, caller.local_node_id); + caller:sleep(1000); + + -- resync destination phones + for index, phone_destination in ipairs(destination_phones) do + local result = phone_destination:resync{ auth_name = destination_sip_account.auth_name, domain = caller.domain_local }; + self.log:info('LOGIN - resync destination phone - mac: ', phone_destination.record.mac_address, ', ip_address: ', phone_destination.record.ip_address, ', result: ', result); + end + + -- resync caller phones + for index, phone_caller in ipairs(caller_phones) do + local result = phone_caller:resync{ auth_name = caller_sip_account.auth_name, domain = caller.domain }; + self.log:info('LOGIN - resync caller phone - mac: ', phone_caller.record.mac_address, ', ip_address: ', phone_caller.record.ip_address, ', result: ', result); + end + + return { continue = false, code = 200, phrase = 'OK', no_cdr = true } +end + + +function Functions.user_logout(self, caller) + require 'common.str' + self.log:info('LOGOUT - caller: ', caller.account_type, '/', caller.account_uuid, ', caller_id: ', caller.caller_id_number); + + -- find caller's sip account + local caller_sip_account = caller.account; + if not caller_sip_account or not caller_sip_account.class == 'sipaccount' then + self.log:notice('LOGOUT - caller sip_account not found'); + return { continue = false, code = 404, phrase = 'Caller not found', no_cdr = true } + end + + if not common.str.to_b(caller_sip_account.record.hotdeskable) then + self.log:notice('LOGOUT - caller sip_account not hot-deskable'); + return { continue = false, code = 404, phrase = 'Caller not hot-deskable', no_cdr = true } + end + + require 'phones.phone' + local phone_class = phones.phone.Phone:new{log = self.log, database = self.database} + + local caller_phones = phone_class:find_all_hot_deskable_by_account(caller_sip_account.id); + + if caller_phones == 0 then + self.log:notice('LOGOUT - caller phones not found or not hot-deskable'); + return { continue = false, code = 403, phrase = 'Phone not hot-deskable', no_cdr = true } + end + + local result = false; + for index, phone_caller in ipairs(caller_phones) do + result = phone_caller:logout(caller_sip_account.record.id); + self.log:info('LOGOUT - account logout - mac: ', phone_caller.record.mac_address, ', ip_address: ', phone_caller.record.ip_address, ', result: ', result); + end + + caller:answer(); + caller:send_display('Logout successful'); + caller:sleep(1000); + + -- resync caller phones + for index, phone_caller in ipairs(caller_phones) do + local result = phone_caller:resync{ auth_name = caller_sip_account.auth_name, domain = caller.domain }; + self.log:info('LOGIN - resync caller phone - mac: ', phone_caller.record.mac_address, ', ip_address: ', phone_caller.record.ip_address, ', result: ', result); + end + + return { continue = false, code = 200, phrase = 'OK', no_cdr = true } +end + + +function Functions.update_node_change(self, sip_account, node_id) + require 'common.sync_log' + local sync_log_class = common.sync_log.SyncLog:new{ log = self.log, database = self.database, homebase_ip_address = sip_account.record.host } + + if tostring(sip_account.record.gs_node_id) ~= tostring(node_id) then + self.log:info('UPDATE_NODE - from: ', sip_account.record.gs_node_id, ', to: ', node_id, ', sipaccount=', sip_account.record.id, '/', sip_account.record.uuid, '@', node_id, ', caller_name: ', sip_account.record.caller_name); + sql_query = 'UPDATE `sip_accounts` SET `updated_at` = NOW(), `gs_node_id` = ' .. tonumber(node_id) .. ' WHERE id = ' .. tonumber(sip_account.record.id); + if self.database:query(sql_query) then + sync_log_class:insert('SipAccount', { uuid = sip_account.record.uuid, gs_node_id = tonumber(node_id), updated_at = os.date('!%Y-%m-%d %H:%M:%S %Z') }, 'update', { 'gs_node_id', 'updated_at' }); + end + end + + require 'common.phone_number' + local phone_numbers = common.phone_number.PhoneNumber:new{log = self.log, database = self.database}:find_all_by_owner(sip_account.record.id, 'SipAccount'); + for number_id, phone_number in pairs(phone_numbers) do + if tostring(phone_number.record.gs_node_id) ~= tostring(node_id) then + self.log:info('UPDATE_NODE - from: ', phone_number.record.gs_node_id, ', to: ', node_id, ', phonenumber=', phone_number.record.id, '/', phone_number.record.uuid, '@', node_id, ', number: ', phone_number.record.number); + sql_query = 'UPDATE `phone_numbers` SET `updated_at` = NOW(), `gs_node_id` = ' .. tonumber(node_id) .. ' WHERE id = ' .. tonumber(number_id); + + if self.database:query(sql_query) then + sync_log_class:insert('PhoneNumber', { uuid = phone_number.record.uuid, gs_node_id = tonumber(node_id), updated_at = os.date('!%Y-%m-%d %H:%M:%S %Z') }, 'update', { 'gs_node_id', 'updated_at' }); + end + end + end +end + + +function Functions.user_login_redirect(self, caller, phone_number, pin) + -- Remove PIN from destination_number + caller.session:setVariable("destination_number", "f-li-" .. tostring(phone_number) .. "-PIN"); + + -- Redirect to f-li function + caller.session:execute("redirect", "sip:f-li-" .. tostring(phone_number) .. "-" .. tostring(pin) .. "@" .. caller.domain); +end + +-- Set nightly_reboot flag +function Functions.user_auto_logout(self, caller, auto_logout) + local nightly_reboot = 'FALSE'; + if auto_logout then + nightly_reboot = 'TRUE'; + end + + -- Ensure a valid sip account + local caller_sip_account = caller.account; + if not caller_sip_account or not caller_sip_account.class == 'sipaccount' then + return { continue = false, code = 403, phrase = 'Incompatible caller', no_cdr = true } + end + + require "phones.phone" + local phone_class = phones.phone.Phone:new{log = self.log, database = self.database} + + -- Get caller phone + local caller_phone = phone_class:find_hot_deskable_by_account(caller_sip_account.id); + if not caller_phone then + self.log:notice("Caller phone not found or not hot-deskable"); + return { continue = false, code = 401, phrase = 'Phone not hot-deskable', no_cdr = true } + end + + log:debug("Hot-desking auto log off - caller phone: " .. caller_phone.record.id .. ", mac: " .. caller_phone.record.mac_address); + + sql_query = 'UPDATE `phones` SET `nightly_reboot` = ' .. nightly_reboot .. ' WHERE `id` = ' .. tonumber(caller_phone.record.id); + + if not self.database:query(sql_query) then + self.log:error('Hot-desking auto log off status could not be changed from ' .. tostring(caller_phone.record.nightly_reboot) .. ' to ' .. nightly_reboot); + return { continue = false, code = 401, phrase = 'Value could not be changed', no_cdr = true } + + end + + self.log:debug('Hot-desking auto log off changed from ' .. tostring(caller_phone.record.nightly_reboot) .. ' to ' .. nightly_reboot); + + caller:answer(); + caller:send_display('Logout successful'); + caller:sleep(1000); +end + +function Functions.dial_clir_off(self, caller, phone_number) + -- Ensure a valid sip account + local caller_sip_account = self:ensure_caller_sip_account(caller); + if not caller_sip_account then + return { continue = false, code = 403, phrase = 'Incompatible caller', no_cdr = true } + end + + caller.clir = false; + return { continue = true, number = phone_number } +end + +function Functions.dial_clir_on(self, caller, phone_number) + -- Ensure a valid sip account + local caller_sip_account = self:ensure_caller_sip_account(caller); + if not caller_sip_account then + return { continue = false, code = 403, phrase = 'Incompatible caller', no_cdr = true } + end + + caller.clir = true; + return { continue = true, number = phone_number } +end + +function Functions.callwaiting_on(self, caller) + -- Find caller's SipAccount + local caller_sip_account = self:ensure_caller_sip_account(caller); + if not caller_sip_account then + return { continue = false, code = 403, phrase = 'Incompatible caller', no_cdr = true } + end + + local sql_query = 'UPDATE `sip_accounts` SET `call_waiting` = TRUE WHERE `id` = ' .. caller_sip_account.record.id; + + if not self.database:query(sql_query) then + self.log:notice("Call Waiting could not be set"); + return { continue = false, code = 500, phrase = 'Call Waiting could not be set', no_cdr = true } + end + + caller:answer(); + caller:send_display('Call waiting on'); + caller:sleep(1000); + return { continue = false, code = 200, phrase = 'OK', no_cdr = true } +end + +function Functions.callwaiting_off(self, caller) + -- Find caller's SipAccount + local caller_sip_account = self:ensure_caller_sip_account(caller); + if not caller_sip_account then + return { continue = false, code = 403, phrase = 'Incompatible caller', no_cdr = true } + end + + local sql_query = 'UPDATE `sip_accounts` SET `call_waiting` = FALSE WHERE `id` = ' .. caller_sip_account.record.id; + + if not self.database:query(sql_query) then + self.log:notice("Call Waiting could not be set"); + return { continue = false, code = 500, phrase = 'Call Waiting could not be set', no_cdr = true } + end + + caller:answer(); + caller:send_display('Call waiting off'); + caller:sleep(1000); + return { continue = false, code = 200, phrase = 'OK', no_cdr = true } +end + +function Functions.clip_on(self, caller) + -- Find caller's SipAccount + local caller_sip_account = self:ensure_caller_sip_account(caller); + if not caller_sip_account then + return { continue = false, code = 403, phrase = 'Incompatible caller', no_cdr = true } + end + + local sql_query = 'UPDATE `sip_accounts` SET `clip` = TRUE WHERE `id` = ' .. caller_sip_account.record.id; + + if not self.database:query(sql_query) then + self.log:notice("CLIP could not be set"); + return { continue = false, code = 500, phrase = 'CLIP could not be set', no_cdr = true } + + end + + caller:answer(); + caller:send_display('CLIP on'); + caller:sleep(1000); + return { continue = false, code = 200, phrase = 'OK', no_cdr = true } +end + +function Functions.clip_off(self, caller) + -- Find caller's SipAccount + local caller_sip_account = self:ensure_caller_sip_account(caller); + if not caller_sip_account then + return { continue = false, code = 403, phrase = 'Incompatible caller', no_cdr = true } + end + + local sql_query = 'UPDATE `sip_accounts` SET `clip` = FALSE WHERE `id` = ' .. caller_sip_account.record.id; + + if not self.database:query(sql_query) then + self.log:notice("CLIP could not be set"); + return { continue = false, code = 500, phrase = 'CLIP could not be set', no_cdr = true } + + end + + caller:answer(); + caller:send_display('CLIP off'); + caller:sleep(1000); + return { continue = false, code = 200, phrase = 'OK', no_cdr = true } +end + + +function Functions.call_forwarding_off(self, caller, call_forwarding_service, delete) + local defaults = {log = self.log, database = self.database, domain = caller.domain} + + -- Find caller's SipAccount + local caller_sip_account = self:ensure_caller_sip_account(caller); + if not caller_sip_account then + return { continue = false, code = 403, phrase = 'Incompatible caller', no_cdr = true } + end + + require 'common.phone_number' + local phone_number_class = common.phone_number.PhoneNumber:new{ log = self.log, database = self.database, domain = caller.domain }; + local phone_numbers = phone_number_class:list_by_owner(caller_sip_account.record.id, 'SipAccount'); + + local success = false; + for index, phone_number in pairs(phone_numbers) do + phone_number_object = phone_number_class:find_by_number(phone_number); + if phone_number_object then + if phone_number_object:call_forwarding_off(call_forwarding_service, nil, delete) then + success = true; + end + end + end + + if not success then + self.log:notice("call forwarding could not be deactivated"); + return { continue = false, code = 500, phrase = 'Call Forwarding could not be deactivated', no_cdr = true } + + end + + caller:answer(); + caller:send_display('Call forwarding off'); + caller:sleep(1000); + return { continue = false, code = 200, phrase = 'OK', no_cdr = true } +end + + +function Functions.call_forwarding_on(self, caller, call_forwarding_service, destination, destination_type, timeout) + local defaults = {log = self.log, database = self.database, domain = caller.domain} + + if not call_forwarding_service then + self.log:notice('no call forwarding service specified'); + end + + -- Find caller's SipAccount + local caller_sip_account = self:ensure_caller_sip_account(caller); + if not caller_sip_account then + return { continue = false, code = 403, phrase = 'Incompatible caller', no_cdr = true } + end + + require "common.phone_number" + local phone_number_class = common.phone_number.PhoneNumber:new{ log = self.log, database = self.database, domain = caller.domain }; + local phone_numbers = phone_number_class:list_by_owner(caller_sip_account.record.id, 'SipAccount'); + + local success = false; + for index, phone_number in pairs(phone_numbers) do + phone_number_object = phone_number_class:find_by_number(phone_number); + if phone_number_object then + if phone_number_object:call_forwarding_on(call_forwarding_service, destination, timeout) then + success = true; + end + end + end + + if not success then + self.log:notice("call forwarding could not be activated"); + return { continue = false, code = 500, phrase = 'Call Forwarding could not be activated', no_cdr = true } + + end + + caller:answer(); + caller:send_display('Call forwarding on'); + caller:sleep(1000); + return { continue = false, code = 200, phrase = 'OK', no_cdr = true } +end + + +function Functions.call_forwarding_toggle(self, caller, call_forwarding_service, phone_number_id) + local defaults = {log = self.log, database = self.database, domain = caller.domain} + + -- Find caller's SipAccount + local caller_sip_account = self:ensure_caller_sip_account(caller); + if not caller_sip_account then + return { continue = false, code = 403, phrase = 'Incompatible caller', no_cdr = true } + end + + require "common.phone_number" + local phone_number_class = common.phone_number.PhoneNumber:new{ log = self.log, database = self.database, domain = caller.domain }; + local phone_numbers = phone_number_class:list_by_owner(caller_sip_account.record.id, 'SipAccount'); + + local result = nil; + for index, phone_number in pairs(phone_numbers) do + phone_number_object = phone_number_class:find_by_number(phone_number); + if phone_number_object then + if not result then + result = phone_number_object:call_forwarding_toggle(call_forwarding_service); + elseif result.active then + phone_number_object:call_forwarding_on(call_forwarding_service, result.destination, result.destination_type, result.timeout); + else + phone_number_object:call_forwarding_off(call_forwarding_service); + end + end + end + + if not result then + self.log:notice("call forwarding could not be toggled"); + return { continue = false, code = 500, phrase = 'Call Forwarding could not be toggled', no_cdr = true } + + end + + caller:answer(); + caller:send_display('Call forwarding toggled'); + caller:sleep(1000); + return { continue = false, code = 200, phrase = 'OK', no_cdr = true } +end + + +function Functions.voicemail_message_leave(self, caller, phone_number) + require 'dialplan.voicemail' + local voicemail_account = dialplan.voicemail.Voicemail:new{ log = self.log, database = self.database }:find_by_number(phone_number); + + if not voicemail_account then + return { continue = false, code = 404, phrase = 'Mailbox not found', no_cdr = true } + end + + voicemail_account:leave(caller, phone_number); + + if caller:to_s("voicemail_message_len") ~= '' then + voicemail_account:send_notify(caller); + else + self.log:debug("voicemail - no message saved"); + end + + return { continue = false, code = 200, phrase = 'OK' } +end + + +function Functions.voicemail_check(self, caller, phone_number) + local voicemail_account = nil; + local voicemail_authorized = false; + + require 'dialplan.voicemail' + + if phone_number then + voicemail_account = dialplan.voicemail.Voicemail:new{ log = self.log, database = self.database }:find_by_number(phone_number); + else + if caller.auth_account_type == 'SipAccount' then + voicemail_account = dialplan.voicemail.Voicemail:new{ log = self.log, database = self.database }:find_by_sip_account_id(caller.auth_account.id); + voicemail_authorized = true; + end + end + + if not voicemail_account then + return { continue = false, code = 404, phrase = 'Mailbox not found', no_cdr = true } + end + + voicemail_account:menu(caller, voicemail_authorized); + + return { continue = false, code = 200, phrase = 'OK', no_cdr = true } +end + + +function Functions.acd_membership_toggle(self, caller, agent_id, phone_number) + -- Find caller's SipAccount + local caller_sip_account = self:ensure_caller_sip_account(caller); + if not caller_sip_account then + return { continue = false, code = 403, phrase = 'Incompatible caller', no_cdr = true } + end + + require 'dialplan.acd' + local acd_class = dialplan.acd.AutomaticCallDistributor:new{ log = self.log, database = self.database, domain = self.domain }; + + self.log:info('ACD_MEMBERSHIP_TOGGLE - sipaccount=', caller_sip_account.id, '/', caller_sip_account.uuid, ', agent=', agent_id, ', ACD phone number: ', phone_number); + + if not tonumber(agent_id) or tonumber(agent_id) == 0 then + + if not phone_number then + self.log:notice('ACD_MEMBERSHIP_TOGGLE - neither agent_id nor phone_number specified'); + return { continue = false, code = 404, phrase = 'Agent not found', no_cdr = true } + end + + require "common.phone_number" + local phone_number_object = common.phone_number.PhoneNumber:new{ log = self.log, database = self.database, domain = caller.domain }:find_by_number(phone_number, {'AutomaticCallDistributor'}); + + if not phone_number_object or not tonumber(phone_number_object.record.phone_numberable_id) then + self.log:notice('ACD_MEMBERSHIP_TOGGLE - ACD not found'); + return { continue = false, code = 404, phrase = 'ACD not found', no_cdr = true } + end + + local agent = acd_class:agent_find_by_acd_and_destination(phone_number_object.record.phone_numberable_id, caller_sip_account.class, caller_sip_account.id); + + if not agent or not tonumber(agent.id) then + self.log:notice('ACD_MEMBERSHIP_TOGGLE - agent not found'); + return { continue = false, code = 404, phrase = 'Agent not found', no_cdr = true } + end + + agent_id = agent.id; + end + + local status = acd_class:agent_status_toggle(agent_id, 'sipaccount', caller_sip_account.id); + + if not status then + self.log:error('ACD_MEMBERSHIP_TOGGLE - error toggling ACD membership'); + return { continue = false, code = 500, phrase = 'Error toggling ACD membership', no_cdr = true } + end + + self.log:info('ACD_MEMBERSHIP_TOGGLE - sipaccount=', caller_sip_account.id, '/', caller_sip_account.uuid, ', agent=', agent_id, ', status: ', status); + + caller:answer(); + caller:send_display('ACD membership toggled: ' .. status); + caller:sleep(500); + caller.session:sayPhrase('acd_agent_status', tostring(status)); + return { continue = false, code = 200, phrase = 'OK', no_cdr = true } +end + +function Functions.hangup(self, caller, code, phrase) + require 'common.str' + + if not tonumber(code) then + code = 403; + phrase = 'Forbidden'; + end + + if common.str.blank(phrase) then + phrase = 'Hangup here'; + end + + self.log:info("FUNCTION_HANGUP code: ", code, ', phrase: ', phrase); + return { continue = false, code = code, phrase = phrase:gsub('_', ' '), no_cdr = true } +end diff --git a/misc/freeswitch/scripts/dialplan/geo_number.lua b/misc/freeswitch/scripts/dialplan/geo_number.lua new file mode 100644 index 0000000..06bfd62 --- /dev/null +++ b/misc/freeswitch/scripts/dialplan/geo_number.lua @@ -0,0 +1,89 @@ +-- Gemeinschaft 5 module: geonumber class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +GeoNumber = {} + +-- create phone_book object +function GeoNumber.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.class = 'geonumber'; + self.log = arg.log; + self.database = arg.database; + return object; +end + +function GeoNumber.country(self, phone_number) + if phone_number:match('^%+1') then + return { id = 0, name = 'NANP', country_code = '1' } + end + + local country_codes = {}; + for i = 2, 4, 1 do + table.insert(country_codes, phone_number:sub(2, i)); + end + + local sql_query = 'SELECT * FROM `countries` WHERE `country_code` IN ("' .. table.concat(country_codes, '","') .. '") ORDER BY LENGTH(`country_code`) DESC LIMIT 1'; + + local country = nil; + self.database:query(sql_query, function(entry) + country = entry; + end) + + return country; +end + + +function GeoNumber.area_code(self, phone_number, country_code) + local sql_query = nil; + local area_code = nil; + + if country_code == '1' then + area_code = {} + area_code.area_code, area_code.central_office_code, area_code.subscriber_number, area_code.extension = phone_number:match('%+1(%d%d%d)(%d%d%d)(%d%d%d%d)(%d*)'); + sql_query = 'SELECT `a`.`name`, `b`.`name` AS `country` FROM `area_codes` `a` \ + JOIN `countries` `b` ON `a`.`country_id` = `b`.`id` \ + WHERE `b`.`country_code` = "' .. tostring(country_code) .. '"\ + AND `a`.`area_code` = "' .. tostring(area_code.area_code) .. '" \ + AND `a`.`central_office_code` = "' .. tostring(area_code.central_office_code) .. '" LIMIT 1'; + else + local offset = #country_code; + area_codes = {}; + for i = (3 + offset), (6 + offset), 1 do + table.insert(area_codes, phone_number:sub((2 + offset), i)); + end + + sql_query = 'SELECT `a`.`name`, `b`.`name` AS `country` FROM `area_codes` `a` \ + JOIN `countries` `b` ON `a`.`country_id` = `b`.`id` \ + WHERE `b`.`country_code` = "' .. country_code .. '"\ + AND `a`.`area_code` IN ("' .. table.concat(area_codes, '","') .. '") ORDER BY LENGTH(`a`.`area_code`) DESC LIMIT 1'; + end + + self.database:query(sql_query, function(entry) + area_code = entry; + end) + + return area_code; +end + + +function GeoNumber.find(self, phone_number) + if not phone_number:match('^%+%d+') then + return nil; + end + + local country = self:country(phone_number); + if country then + local area_code = self:area_code(phone_number, country.country_code); + if area_code then + return area_code; + else + return { country = country.name }; + end + end +end diff --git a/misc/freeswitch/scripts/dialplan/hunt_group.lua b/misc/freeswitch/scripts/dialplan/hunt_group.lua new file mode 100644 index 0000000..87f86f1 --- /dev/null +++ b/misc/freeswitch/scripts/dialplan/hunt_group.lua @@ -0,0 +1,202 @@ +-- Gemeinschaft 5 module: hunt group class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +HuntGroup = {} + +local DEFAULT_MEMBER_TIMEOUT = 20; + +-- Create HuntGroup object +function HuntGroup.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.class = 'huntgroup'; + self.log = arg.log; + self.database = arg.database; + self.record = arg.record; + return object; +end + + +function HuntGroup.find_by_id(self, id) + local sql_query = 'SELECT * FROM `hunt_groups` WHERE `id`= '.. tonumber(id) .. ' LIMIT 1'; + local hunt_group = nil; + + self.database:query(sql_query, function(entry) + hunt_group = HuntGroup:new(self); + hunt_group.record = entry; + hunt_group.id = tonumber(entry.id); + hunt_group.uuid = entry.uuid; + end) + + return hunt_group; +end + + +function HuntGroup.find_by_uuid(self, uuid) + local sql_query = 'SELECT * FROM `hunt_groups` WHERE `id`= "'.. uuid .. '" LIMIT 1'; + local hunt_group = nil; + + self.database:query(sql_query, function(entry) + hunt_group = HuntGroup:new(self); + hunt_group.record = entry; + hunt_group.id = tonumber(entry.id); + hunt_group.uuid = entry.uuid; + end) + + return hunt_group; +end + + +function HuntGroup.list_active_members(self) + local sql_query = 'SELECT `a`.`number`, `b`.`name` \ + FROM `phone_numbers` `a` \ + LEFT JOIN `hunt_group_members` `b` ON `a`.`phone_numberable_type` = "huntgroupmember" AND `a`.`phone_numberable_id` = `b`.`id` \ + WHERE `a`.`phone_numberable_type` = "huntgroupmember" \ + AND `b`.`active` IS TRUE \ + AND `b`.`hunt_group_id` = ' .. self.record.id; + + local hunt_group_members = {} + + self.database:query(sql_query, function(hunt_group_members_entry) + table.insert(hunt_group_members, hunt_group_members_entry); + end) + + return hunt_group_members; +end + + +function HuntGroup.is_member_by_numbers(self, numbers) + local sql_query = 'SELECT `a`.`number`, `b`.`name` \ + FROM `phone_numbers` `a` \ + LEFT JOIN `hunt_group_members` `b` ON `a`.`phone_numberable_type` = "huntgroupmember" AND `a`.`phone_numberable_id` = `b`.`id` \ + WHERE `a`.`phone_numberable_type` = "huntgroupmember" \ + AND `b`.`active` IS TRUE \ + AND `b`.`hunt_group_id` = ' .. self.record.id .. '\ + AND `a`.`number` IN ("' .. table.concat( numbers, '","') .. '") LIMIT 1'; + + local hunt_group_member = false; + + self.database:query(sql_query, function(hunt_group_members_entry) + hunt_group_member = true; + end) + + return hunt_group_member; +end + + +function HuntGroup.run(self, dialplan_object, caller, destination) + local hunt_group_members = self:list_active_members(); + + if #hunt_group_members == 0 then + return { disposition = 'HUNT_GROUP_EMPTY', code = 480, phrase = 'No active users' } + end + + self.log:info('HUNTGROUP ', self.record.id, ' - name: ', self.record.name, ', strategy: ', self.record.strategy,', members: ', #hunt_group_members); + + local destinations = {} + for index, hunt_group_member in ipairs(hunt_group_members) do + local destination = dialplan_object:destination_new{ number = hunt_group_member.number }; + if destination.type == 'unknown' then + require 'dialplan.route' + local routes = dialplan.route.Route:new{ log = self.log, database = self.database, routing_table = dialplan_object.routes }:outbound(caller, destination.number); + if routes and #routes > 0 then + destination.callee_id_number = destination.number; + destination.callee_id_name = nil; + local route = routes[1]; + destination.gateway = route.endpoint; + destination.type = route.class; + destination.number = route.value; + destination.caller_id_number = route.caller_id_number; + destination.caller_id_name = route.caller_id_name; + table.insert(destinations, destination); + end + else + table.insert(destinations, destination); + end + end + + local forwarding_destination = nil; + if caller.forwarding_service == 'assistant' and caller.auth_account then + forwarding_destination = dialplan_object:destination_new{ type = caller.auth_account.class, id = caller.auth_account.id, number = forwarding_number } + forwarding_destination.alert_info = 'http://amooma.com;info=Ringer0;x-line-id=0'; + end + + local result = { continue = false }; + local start_time = os.time(); + if self.record.strategy == 'ring_recursively' then + local member_timeout = tonumber(self.record.seconds_between_jumps) or DEFAULT_MEMBER_TIMEOUT; + local run_queue = true; + while run_queue do + for index, member_destination in ipairs(destinations) do + local recursive_destinations = { member_destination } + if forwarding_destination then + table.insert(recursive_destinations, forwarding_destination); + end + require 'dialplan.sip_call' + result = dialplan.sip_call.SipCall:new{ log = self.log, database = self.database, caller = caller }:fork( recursive_destinations, { callee_id_number = destination.number, timeout = member_timeout }); + if result.disposition == 'SUCCESS' then + if result.fork_index then + result.destination = recursive_destinations[result.fork_index]; + end + run_queue = false; + break; + elseif os.time() > start_time + dialplan_object.dial_timeout_active then + run_queue = false; + break; + elseif not caller:ready() then + run_queue = false; + break; + end + end + if tostring(result.code) == '486' then + self.log:info('HUNTGROUP ', self.record.id, ' - all members busy'); + run_queue = false; + end + end + else + if forwarding_destination then + table.insert(destinations, forwarding_destination); + end + + require 'dialplan.sip_call' + result = dialplan.sip_call.SipCall:new{ log = self.log, database = self.database, caller = caller }:fork( destinations, + { + callee_id_number = destination.number, + timeout = dialplan_object.dial_timeout_active, + send_ringing = ( dialplan_object.send_ringing_to_gateways and caller.from_gateway ), + }); + if result.fork_index then + result.destination = destinations[result.fork_index]; + end + + return result; + end + + return result; +end + + +function HuntGroup.list_destination_numbers(self) + require "common.phone_number" + local phone_number_class = common.phone_number.PhoneNumber:new(defaults) + + local sql_query = string.format("SELECT * FROM `phone_numbers` WHERE `state`='active' AND `phone_numberable_type` = 'HuntGroupMember' AND `phone_numberable_id` IN ( \ + SELECT `id` FROM `hunt_group_members` WHERE `active` IS TRUE AND `hunt_group_id`=%d ) ORDER BY `position` ASC", tonumber(self.record.id)); + local phone_numbers = {} + + self.database:query(sql_query, function(hunt_group_number_entry) + local number_object = phone_number_class:find_by_number(hunt_group_number_entry.number) + if number_object and number_object.record then + table.insert(phone_numbers, {number = hunt_group_number_entry.number, destination_type = number_object.record.phone_numberable_type, destination_id = number_object.record.phone_numberable_id}); + else + table.insert(phone_numbers, {number = hunt_group_number_entry.number}); + end + end) + + return phone_numbers ; +end diff --git a/misc/freeswitch/scripts/dialplan/phone_book.lua b/misc/freeswitch/scripts/dialplan/phone_book.lua new file mode 100644 index 0000000..089f115 --- /dev/null +++ b/misc/freeswitch/scripts/dialplan/phone_book.lua @@ -0,0 +1,63 @@ +-- Gemeinschaft 5 module: phone book class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +PhoneBook = {} + +-- create phone_book object +function PhoneBook.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.class = 'phonebook'; + self.log = arg.log; + self.database = arg.database; + return object; +end + + +function PhoneBook.find_entry_by_number_user_tenant(self, numbers, user_id, tenant_id) + user_id = tonumber(user_id) or 0; + tenant_id = tonumber(tenant_id) or 0; + + if not numbers or #numbers == 0 then + return nil; + end + local numbers_sql = '"' .. table.concat(numbers, '","') .. '"'; + + local sql_query = 'SELECT `a`.`name` AS `number_name`, \ + `a`.`number`, \ + `b`.`id`, \ + `b`.`value_of_to_s`, \ + `b`.`phone_book_id`, \ + `b`.`image`, \ + `c`.`name` AS `phone_book_name`, \ + `d`.`bellcore_id` \ + FROM `phone_numbers` `a` \ + JOIN `phone_book_entries` `b` ON `a`.`phone_numberable_id` = `b`.`id` AND `a`.`phone_numberable_type` = "PhoneBookENtry" \ + JOIN `phone_books` `c` ON `b`.`phone_book_id` = `c`.`id` \ + LEFT JOIN `ringtones` `d` ON `a`.`id` = `d`.`ringtoneable_id` AND `d`.`ringtoneable_type` = "PhoneNumber" \ + WHERE ((`c`.`phone_bookable_type` = "User" AND `c`.`phone_bookable_id` = ' .. user_id .. ') \ + OR (`c`.`phone_bookable_type` = "Tenant" AND `c`.`phone_bookable_id` = ' .. tenant_id .. ')) \ + AND `a`.`number` IN (' .. numbers_sql .. ') \ + AND `a`.`state` = "active" \ + AND `b`.`state` = "active" \ + AND `c`.`state` = "active" \ + ORDER BY `c`.`phone_bookable_type` DESC LIMIT 1'; + + local phone_book_entry = nil; + + self.database:query(sql_query, function(entry) + phone_book_entry = entry; + if entry.number_name then + phone_book_entry.caller_id_name = tostring(entry.value_of_to_s) .. ' (' .. entry.number_name .. ')'; + else + phone_book_entry.caller_id_name = entry.value_of_to_s; + end + end) + + return phone_book_entry; +end diff --git a/misc/freeswitch/scripts/dialplan/presence.lua b/misc/freeswitch/scripts/dialplan/presence.lua new file mode 100644 index 0000000..234b908 --- /dev/null +++ b/misc/freeswitch/scripts/dialplan/presence.lua @@ -0,0 +1,84 @@ +-- Gemeinschaft 5 module: presence class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +Presence = {} + +-- Create Presence object +function Presence.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self) + self.__index = self + self.log = arg.log; + self.domain = arg.domain; + self.uuid = arg.uuid; + self.inbound = arg.inbound; + self.accounts = arg.accounts; + + return object +end + + +function Presence.init(self, arg) + self.log = arg.log or self.log; + self.domain = arg.domain or self.domain; + self.uuid = arg.uuid or self.uuid; + self.inbound = arg.inbound or self.inbound; + self.accounts = arg.accounts or self.accounts; +end + + +function Presence.set(self, state, caller_number) + if not self.accounts or #self.accounts == 0 then + return nil; + end + + state = state or "terminated"; + local direction = "outbound"; + + if self.inbound then + direction = "inbound"; + end + + for index, account in pairs(self.accounts) do + if account ~= '' then + local event = freeswitch.Event('PRESENCE_IN'); + event:addHeader('proto', 'sip'); + event:addHeader('from', account .. '@' .. self.domain); + event:addHeader('event_type', 'presence'); + event:addHeader('alt_event_type', 'dialog'); + event:addHeader('presence-call-direction', direction); + event:addHeader('answer-state', state); + event:addHeader('unique-id', self.uuid); + if caller_number then + if self.inbound then + event:addHeader('Caller-Destination-Number', caller_number); + else + event:addHeader('Other-Leg-Caller-ID-Number', caller_number); + end + end + event:fire(); + self.log:debug('PRESENCE - account: ' .. account .. '@' .. self.domain .. ', state: ' .. state .. ', direction: ' .. direction .. ', uid: ' ..self.uuid); + end + end + + return true; +end + + +function Presence.early(self, caller_number) + return self:set("early", caller_number); +end + + +function Presence.confirmed(self, caller_number) + return self:set("confirmed", caller_number); +end + + +function Presence.terminated(self, caller_number) + return self:set("terminated", caller_number); +end diff --git a/misc/freeswitch/scripts/dialplan/route.lua b/misc/freeswitch/scripts/dialplan/route.lua new file mode 100644 index 0000000..2243cbe --- /dev/null +++ b/misc/freeswitch/scripts/dialplan/route.lua @@ -0,0 +1,265 @@ +-- Gemeinschaft 5 module: routing class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +Route = {} + +-- create route object +function Route.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.database = arg.database; + self.routing_table = arg.routing_table; + self.expandable = arg.expandable or {}; + return object; +end + +-- find matching routes +function Route.prerouting(self, caller, number) + require 'common.routing_tables' + + for index, routing_entry in pairs(self.routing_table.prerouting) do + local route = common.routing_tables.match_route(routing_entry, number); + if route.error then + self.log:error('PREROUTE - error: ', route.error); + elseif route.value then + self.log:info('ROUTE_PREROUTING - called number: ', number, ', value: ', route.value, ', pattern: ', route.pattern); + return route; + end + end +end + +-- find matching routes +function Route.outbound(self, caller, number) + local routes = {}; + require 'common.routing_tables' + require 'common.str' + + local ignore_arguments = { + class=true, + endpoint=true, + pattern=true, + value=true, + group=true, + phrase=true, + } + + local clip_no_screening = common.str.try(caller, 'account.record.clip_no_screening'); + local caller_id_numbers = {} + if not common.str.blank(clip_no_screening) then + for index, number in ipairs(common.str.strip_to_a(clip_no_screening, ',')) do + table.insert(caller_id_numbers, number); + end + end + for index, number in ipairs(caller.caller_phone_numbers) do + table.insert(caller_id_numbers, number); + end + self.log:info('CALLER_ID_NUMBER - caller_id_numbers: ', table.concat(caller_id_numbers, ',')); + + for index, routing_entry in pairs(self.routing_table.outbound) do + local route = common.routing_tables.match_route(routing_entry, number); + if route.error then + self.log:error('ROUTE_OUTBOUND - error: ', route.error); + elseif route.value then + local valid_route = true; + + for argument, value in pairs(route) do + if not ignore_arguments[argument] then + local table_value = common.str.downcase(tostring(common.str.try(caller, argument))); + value = common.str.downcase(tostring(value)); + if table_value:match(value) then + self.log:info('ROUTE_OUTBOUND_POSITIVE - ', argument, '=', value, ' ~ ', table_value, ', pattern: ', route.pattern); + else + self.log:info('ROUTE_OUTBOUND_NEGATIVE - ', argument, '=', value, ' !~ ', table_value, ', pattern: ', route.pattern); + valid_route = false; + end + end + end + + if route.group then + if common.str.try(caller.auth_account, 'owner.groups.' .. tostring(route.group)) then + self.log:info('ROUTE_OUTBOUND_POSITIVE - group=', route.group, ', pattern: ', route.pattern); + else + self.log:info('ROUTE_OUTBOUND_NEGATIVE - group=', route.group, ', pattern: ', route.pattern); + valid_route = false; + end + end + + if route.cidn then + if caller.caller_id_number:match(route.cidn) then + self.log:info('ROUTE_OUTBOUND_POSITIVE - cidn=', route.cidn, ' ~ ', caller.caller_id_number,', pattern: ', route.pattern); + else + self.log:info('ROUTE_OUTBOUND_NEGATIVE - cidn=', route.cidn, ' !~ ', caller.caller_id_number, ', pattern: ', route.pattern); + valid_route = false; + end + end + + if valid_route then + if route.class ~= 'hangup' then + route.caller_id_number = self:outbound_cid_number(caller, caller_id_numbers, route.endpoint, route.class); + self.expandable.caller_id_number = route.caller_id_number; + route.caller_id_name = self:outbound_cid_name(caller, route.endpoint, route.class); + end + table.insert(routes, route); + self.log:info('ROUTE_OUTBOUND ', #routes,' - ', route.class, '=', route.endpoint, ', value: ', route.value, ', caller_id_number: ', route.caller_id_number, ', caller_id_name: ', route.caller_id_name); + end + end + end + + return routes; +end + + +function Route.inbound(self, caller, number) + require 'common.routing_tables' + + local ignore_arguments = { + class=true, + endpoint=true, + pattern=true, + value=true, + group=true, + phrase=true, + } + + for index, routing_entry in pairs(self.routing_table.inbound) do + local route = common.routing_tables.match_route(routing_entry, number); + if route.error then + self.log:error('ROUTE_INBOUND - error: ', route.error); + elseif route.value then + local valid_route = true; + + for argument, value in pairs(route) do + if not ignore_arguments[argument] then + local table_value = common.str.downcase(tostring(common.str.try(caller, argument))); + value = common.str.downcase(tostring(value)); + if table_value:match(value) then + self.log:info('ROUTE_INBOUND_POSITIVE - ', argument, '=', value, ' ~ ', table_value, ', pattern: ', route.pattern); + else + self.log:info('ROUTE_INBOUND_NEGATIVE - ', argument, '=', value, ' !~ ', table_value, ', pattern: ', route.pattern); + valid_route = false; + end + end + end + + if route.class and route.endpoint then + if route.class == 'gateway' and caller.gateway_name:match(route.endpoint) then + self.log:info('ROUTE_INBOUND_POSITIVE - ', route.class, '=', route.endpoint, ' ~ ', caller.gateway_name, ', pattern: ', route.pattern); + else + self.log:info('ROUTE_INBOUND_NEGATIVE - ', route.class, '=', route.endpoint, ' !~ ', caller.gateway_name, ', pattern: ', route.pattern); + valid_route = false; + end + end + + if valid_route then + self.log:info('ROUTE_INBOUND - called number: ', number, ', value: ', route.value, ', pattern: ', route.pattern); + return route; + end + end + end +end + +-- find caller id +function Route.caller_id(self, caller, cid_entry, search_str, endpoint, class) + local ignore_arguments = { + class=true, + endpoint=true, + pattern=true, + value=true, + group=true, + phrase=true, + } + + local route = common.routing_tables.match_route(cid_entry, search_str, self.expandable); + if route.error then + self.log:error('CALLER_ID - error: ', route.error); + elseif route.value then + local valid_route = true; + + for argument, value in pairs(route) do + if not ignore_arguments[argument] then + local table_value = common.str.downcase(tostring(common.str.try(caller, argument))); + value = common.str.downcase(tostring(value)); + if table_value:match(value) then + self.log:debug('CALLER_ID_POSITIVE - ', argument, '=', value, ' ~ ', table_value, ', pattern: ', route.pattern); + else + self.log:debug('CALLER_ID_NEGATIVE - ', argument, '=', value, ' !~ ', table_value, ', pattern: ', route.pattern); + valid_route = false; + end + end + end + + if route.group then + if common.str.try(caller.auth_account, 'owner.groups.' .. tostring(route.group)) then + self.log:debug('CALLER_ID_POSITIVE - group=', route.group, ', pattern: ', route.pattern); + else + self.log:debug('CALLER_ID_NEGATIVE - group=', route.group, ', pattern: ', route.pattern); + valid_route = false; + end + end + + endpoint = tostring(endpoint); + if route.class and route.endpoint then + if route.class == 'gateway' and endpoint:match(route.endpoint) then + self.log:debug('CALLER_ID_POSITIVE - ', route.class, '=', route.endpoint, ' ~ ', endpoint, ', pattern: ', route.pattern); + else + self.log:debug('CALLER_ID_NEGATIVE - ', route.class, '=', route.endpoint, ' !~ ', endpoint, ', pattern: ', route.pattern); + valid_route = false; + end + end + + if valid_route then + self.log:debug('CALLER_ID ', route.class, '=', route.endpoint, ', value: ', route.value); + return route.value; + end + end + + return nil; +end + +-- find matching caller id number +function Route.outbound_cid_number(self, caller, caller_id_numbers, endpoint, class) + for route_index, cid_entry in pairs(self.routing_table.outbound_cid_number) do + for index, number in ipairs(caller_id_numbers) do + local route = self:caller_id(caller, cid_entry, number, endpoint, class); + if route then + return route; + end + end + end +end + +-- find matching caller id name +function Route.outbound_cid_name(self, caller, endpoint, class) + for route_index, cid_entry in pairs(self.routing_table.outbound_cid_name) do + local route = self:caller_id(caller, cid_entry, caller.caller_id_name, endpoint, class); + if route then + return route; + end + end +end + +-- find matching caller id number +function Route.inbound_cid_number(self, caller, endpoint, class) + for route_index, cid_entry in pairs(self.routing_table.inbound_cid_number) do + local route = self:caller_id(caller, cid_entry, caller.caller_id_number, endpoint, class); + if route then + return route; + end + end +end + +-- find matching caller id name +function Route.inbound_cid_name(self, caller, endpoint, class) + for route_index, cid_entry in pairs(self.routing_table.inbound_cid_name) do + local route = self:caller_id(caller, cid_entry, caller.caller_id_name, endpoint, class); + if route then + return route; + end + end +end diff --git a/misc/freeswitch/scripts/dialplan/session.lua b/misc/freeswitch/scripts/dialplan/session.lua new file mode 100644 index 0000000..7174b24 --- /dev/null +++ b/misc/freeswitch/scripts/dialplan/session.lua @@ -0,0 +1,224 @@ +-- Gemeinschaft 5 module: caller session class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +Session = {} + +-- create session object +function Session.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.session = arg.session; + + if not self.session then + return nil; + end + + return object; +end + +function Session.init_channel_variables(self) + self.cause = "UNSPECIFIED" + + self.uuid = self.session:get_uuid(); + self.destination_number = self:expand_variables(self:to_s('destination_number')); + self.called_number = self.destination_number; + + self.caller_id_number = self:to_s('caller_id_number'); + self.caller_id_name = self:to_s('caller_id_name'); + self.caller_phone_number = self.caller_id_number; + self.caller_phone_numbers = {self.caller_id_number}; + + self.domain = self:to_s('domain_name'); + self.gateway_name = self:to_s('sip_gateway'); + self.from_gateway = self:to_b('gs_from_gateway'); + if self.from_gateway then + self.gateway_name = self:to_s('gs_gateway_name'); + elseif self.gateway_name ~= '' then + self.from_gateway = true; + end + + self.account_uuid = self:to_s('gs_account_uuid'); + self.account_type = self:to_s('gs_account_type'); + self.sip_contact_host = self:to_s('sip_contact_host'); + self.clir = self:to_b('gs_clir'); + self.call_timeout = self:to_i('gs_call_timeout'); + self.auth_account_type = self:to_s('gs_auth_account_type'); + self.auth_account_uuid = self:to_s('gs_auth_account_uuid'); + + self.node_id = self:to_i('sip_h_X-GS_node_id'); + self.loop_count = self:to_i('sip_h_X-GS_loop_count'); + + if self.node_id > 0 and self.node_id ~= self.local_node_id then + self.from_node = true; + else + self.from_node = false; + end + self:set_variable('gs_account_node_local', not self.from_node); + + if self.from_node then + self.account_uuid = self:to_s('sip_h_X-GS_account_uuid'); + self.account_type = self:to_s('sip_h_X-GS_account_type'); + self.auth_account_uuid = self:to_s('sip_h_X-GS_auth_account_uuid'); + self.auth_account_type = self:to_s('sip_h_X-GS_auth_account_type'); + end + + if self.auth_account_type == '' then + self.auth_account_type = self.account_type; + self.auth_account_uuid = self.account_uuid; + end + + self.forwarding_number = nil; + self.forwarding_service = nil; + + return true; +end + + +-- Cast channel variable to string +function Session.to_s(self, variable_name) + require 'common.str' + return common.str.to_s(self.session:getVariable(variable_name)); +end + +-- Cast channel variable to integer +function Session.to_i(self, variable_name) + require 'common.str' + return common.str.to_i(self.session:getVariable(variable_name)); +end + +-- Cast channel variable to boolean +function Session.to_b(self, variable_name) + require 'common.str' + return common.str.to_b(self.session:getVariable(variable_name)); +end + +-- Split channel variable to table +function Session.to_a(self, variable_name) + require 'common.str' + return common.str.to_a(self.session:getVariable(variable_name)); +end + +-- Check if session is active +function Session.ready(self, command, parameters) + return self.session:ready(); +end + +-- Wait milliseconds +function Session.sleep(self, milliseconds) + return self.session:sleep(milliseconds); +end + +-- Execute command +function Session.execute(self, command, parameters) + parameters = parameters or ''; + self.session:execute(command, parameters); +end + +-- Execute and return result +function Session.result(self, command_line) + self.session:execute('set', 'result=${' .. command_line .. '}'); + return self.session:getVariable('result'); +end + +-- Set cause code +function Session.set_cause(self, cause) + self.cause = cause +end + +-- Set channel variable +function Session.set_variable(self, name, value) + self.session:setVariable(name, tostring(value)); +end + +-- Set and export channel variable +function Session.export_variable(self, name, value) + self.session:execute('export', tostring(name) .. '=' .. tostring(value)); +end + +-- Set SIP header +function Session.set_header(self, name, value) + self.session:setVariable('sip_h_' .. name, tostring(value)); +end + +-- Hangup a call +function Session.hangup(self, cause) + return self.session:hangup(cause); +end + +-- Respond a call +function Session.respond(self, code, text) + self.session:execute('respond', tostring(code) .. ' ' .. text); + return self.session:hangupCause(); +end + +-- Answer a call +function Session.answer(self) + return self.session:answer(); +end + +function Session.intercept(self, uid) + self.session:execute("intercept", uid); +end + +function Session.send_display(self, ... ) + self:execute('send_display', table.concat( arg, '|')); +end + +-- Set caller ID +function Session.set_caller_id(self, number, name) + if number then + self.caller_id_number = tostring(number); + self.session:setVariable('effective_caller_id_number', tostring(number)) + end + if name then + self.caller_id_name = tostring(name); + self.session:setVariable('effective_caller_id_name', tostring(name)) + end +end + +-- Set callee ID +function Session.set_callee_id(self, number, name) + if number ~= nil then + self.callee_id_number = tostring(number); + self.session:execute('export', 'effective_callee_id_number=' .. number); + end + if name ~= nil then + self.callee_id_name = tostring(name); + self.session:execute('export', 'effective_callee_id_name=' .. name); + end +end + +-- Set caller Privacy header +function Session.set_privacy(self, privacy) + if privacy then + self.session:setVariable('cid_type', 'none'); + self.session:setVariable('sip_h_Privacy', 'id'); + else + self.session:setVariable('cid_type', 'none'); + self.session:setVariable('sip_h_Privacy', 'none'); + end +end + + +function Session.set_auth_account(self, auth_account) + if auth_account then + self:set_variable('gs_auth_account_type', auth_account.class); + self:set_variable('gs_auth_account_id', auth_account.id); + self:set_variable('gs_auth_account_uuid', auth_account.uuid); + end + + return auth_account; +end + + +function Session.expand_variables(self, line) + return (line:gsub('{([%a%d_-]+)}', function(captured) + return self.session:getVariable(captured) or ''; + end)) +end diff --git a/misc/freeswitch/scripts/dialplan/sip_call.lua b/misc/freeswitch/scripts/dialplan/sip_call.lua new file mode 100644 index 0000000..57f92c6 --- /dev/null +++ b/misc/freeswitch/scripts/dialplan/sip_call.lua @@ -0,0 +1,266 @@ +-- Gemeinschaft 5 module: sip call class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall); + +SipCall = {} + +-- Create SipCall object +function SipCall.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.session = arg.session; + self.record = arg.record; + self.database = arg.database; + self.domain = arg.domain; + self.caller = arg.caller; + self.on_answer = arg.on_answer; + self.calling_object = arg.calling_object; + return object; +end + + +function SipCall.wait_answer(self, caller_session, callee_session, timeout, start_time) + if caller_session:ready() and callee_session:ready() then + callee_session:waitForAnswer(caller_session); + end + + while true do + if not caller_session:ready() then + return 'ORIGINATOR_CANCEL'; + elseif not callee_session:ready() then + return 'UNSPECIFIED'; + elseif (os.time() - start_time) > timeout then + return 'NO_ANSWER'; + elseif callee_session:answered() then + return 'SUCCESS'; + end + + self.caller:sleep(500); + end +end + + +function SipCall.wait_hangup(self, caller_session, callee_session) + local hangup_on = { + CS_HANGUP = true, + CS_DESTROY = true, + } + + while true do + local state_caller = caller_session:getState(); + local state_callee = callee_session:getState(); + if hangup_on[state_caller] or hangup_on[state_callee] then + break; + end + caller_session:sleep(500); + end +end + + +function SipCall.call_waiting_busy(self, sip_account) + require 'common.str' + if common.str.to_b(sip_account.record.call_waiting) then + self.log:info('CALL_WAITING - status: enabled'); + return false; + else + local state = sip_account:call_state(); + self.log:info('CALL_WAITING - status: disabled, sip_account state: ', state); + return state; + end +end + + +function SipCall.fork(self, destinations, arg ) + local dial_strings = {} + + require 'common.sip_account' + local sip_account_class = common.sip_account.SipAccount:new{ log = self.log, database = self.database }; + + local call_result = { code = 404, phrase = 'No destination' }; + local some_destinations_busy = false; + + for index, destination in ipairs(destinations) do + local origination_variables = { 'gs_fork_index=' .. index } + + self.log:info('FORK ', index, '/', #destinations, ' - ', destination.type, '=', destination.id, '/', destination.gateway or destination.uuid, '@', destination.node_id, ', number: ', destination.number); + if not destination.node_local or destination.type == 'node' then + require 'common.node' + local node = nil; + if tonumber(destination.gateway) then + node = common.node.Node:new{ log = self.log, database = self.database }:find_by_id(tonumber(destination.gateway)); + else + node = common.node.Node:new{ log = self.log, database = self.database }:find_by_id(destination.node_id); + end + if node then + table.insert(origination_variables, 'sip_h_X-GS_node_id=' .. self.caller.local_node_id); + table.insert(dial_strings, '[' .. table.concat(origination_variables , ',') .. ']sofia/gateway/' .. node.record.name .. '/' .. destination.number); + end + elseif destination.type == 'sipaccount' then + local callee_id_params = ''; + local sip_account = sip_account_class:find_by_id(destination.id); + local call_waiting = self:call_waiting_busy(sip_account); + if not call_waiting then + destinations[index].numbers = sip_account:phone_numbers(); + + if not arg.callee_id_name then + table.insert(origination_variables, "effective_callee_id_name='" .. sip_account.record.caller_name .. "'"); + end + if not arg.callee_id_number then + table.insert(origination_variables, "effective_callee_id_number='" .. destination.number .. "'"); + end + if destination.alert_info then + table.insert(origination_variables, "alert_info='" .. destination.alert_info .. "'"); + end + table.insert(dial_strings, '[' .. table.concat(origination_variables , ',') .. ']user/' .. sip_account.record.auth_name); + else + some_destinations_busy = true; + call_result = { code = 486, phrase = 'User busy', disposition = 'USER_BUSY' }; + end + elseif destination.type == 'gateway' then + if destination.caller_id_number then + table.insert(origination_variables, "origination_caller_id_number='" .. destination.caller_id_number .. "'"); + end + if destination.caller_id_name then + table.insert(origination_variables, "origination_caller_id_name='" .. destination.caller_id_name .. "'"); + end + table.insert(dial_strings, '[' .. table.concat(origination_variables , ',') .. ']sofia/gateway/' .. destination.gateway .. '/' .. destination.number); + elseif destination.type == 'dial' then + if destination.caller_id_number then + table.insert(origination_variables, "origination_caller_id_number='" .. destination.caller_id_number .. "'"); + end + if destination.caller_id_name then + table.insert(origination_variables, "origination_caller_id_name='" .. destination.caller_id_name .. "'"); + end + table.insert(dial_strings, '[' .. table.concat(origination_variables , ',') .. ']' .. destination.number); + else + self.log:info('FORK ', index, '/', #destinations, ' - unhandled destination type: ', destination.type, ', number: ', destination.number); + end + end + + if #dial_strings == 0 then + self.log:notice('FORK - no active destinations - result: ', call_result.code, ' ', call_result.phrase); + return call_result; + end + + self.caller:set_callee_id(arg.callee_id_number, arg.callee_id_name); + self.caller:set_header('X-GS_account_uuid', self.caller.account_uuid); + self.caller:set_header('X-GS_account_type', self.caller.account_type); + self.caller:set_header('X-GS_auth_account_type', self.caller.auth_account_type); + self.caller:set_header('X-GS_auth_account_uuid', self.caller.auth_account_uuid); + self.caller:set_header('X-GS_loop_count', self.caller.loop_count); + + self.caller:set_variable('call_timeout', arg.timeout ); + self.log:info('FORK DIAL - destinations: ', #dial_strings, ', timeout: ', arg.timeout); + + if arg.send_ringing then + self.caller:execute('ring_ready'); + end + + local start_time = os.time(); + local session_callee = freeswitch.Session('{local_var_clobber=true}' .. table.concat(dial_strings, ','), self.caller.session); + self.log:debug('FORK SESSION_INIT - dial_time: ', os.time() - start_time); + local answer_result = self:wait_answer(self.caller.session, session_callee, arg.timeout, start_time); + local fork_index = nil; + self.log:info('FORK ANSWER - status: ', answer_result, ', dial_time: ', os.time() - start_time); + if answer_result == 'SUCCESS' then + session_callee:setAutoHangup(false); + fork_index = tonumber(session_callee:getVariable('gs_fork_index')) or 0; + local destination = destinations[fork_index]; + + if arg.bypass_media_network then + local callee_uuid = session_callee:get_uuid(); + + if callee_uuid and self.caller.uuid and freeswitch then + require 'common.ipcalc' + local callee_network_str = self.caller:to_s('bleg_network_addr'); + local caller_network_str = self.caller:to_s('network_addr'); + local callee_network_addr = common.ipcalc.ipv4_to_i(callee_network_str); + local caller_network_addr = common.ipcalc.ipv4_to_i(caller_network_str); + local network, netmask = common.ipcalc.ipv4_to_network_netmask(arg.bypass_media_network); + if network and netmask and callee_network_addr and caller_network_addr + and common.ipcalc.ipv4_in_network(callee_network_addr, network, netmask) + and common.ipcalc.ipv4_in_network(caller_network_addr, network, netmask) then + self.log:info('FORK ', fork_index, ' BYPASS_MEDIA - caller_ip: ', caller_network_str, + ', callee_ip: ', callee_network_str, + ', subnet: ', arg.bypass_media_network, + ', uuid: ', self.caller.uuid, ', bleg_uuid: ', callee_uuid); + freeswitch.API():execute('uuid_media', 'off ' .. self.caller.uuid); + freeswitch.API():execute('uuid_media', 'off ' .. callee_uuid); + end + end + end + + if self.on_answer then + self.on_answer(self.calling_object, destination); + end + + self.caller:set_variable('gs_destination_type', destination.type); + self.caller:set_variable('gs_destination_id', destination.id); + self.caller:set_variable('gs_destination_uuid', destination.uuid); + + self.log:info('FORK ', fork_index, + ' BRIDGE - destination: ', destination.type, '=', destination.id, '/', destination.uuid,'@', destination.node_id, + ', number: ', destination.number, + ', dial_time: ', os.time() - start_time); + freeswitch.bridge(self.caller.session, session_callee); + self:wait_hangup(self.caller.session, session_callee); + end + + -- if session_callee:ready() then + -- self.log:info('FORK - hangup destination channel'); + -- session_callee:hangup('ORIGINATOR_CANCEL'); + -- end + + call_result = {}; + call_result.disposition = session_callee:hangupCause(); + call_result.fork_index = fork_index; + + if some_destinations_busy and call_result.disposition == 'USER_NOT_REGISTERED' then + call_result.phrase = 'User busy'; + call_result.code = 486; + call_result.disposition = 'USER_BUSY'; + elseif call_result.disposition == 'USER_NOT_REGISTERED' then + call_result.phrase = 'User offline'; + call_result.code = 480; + elseif call_result.disposition == 'NO_ANSWER' then + call_result.phrase = 'No answer'; + call_result.code = 408; + elseif call_result.disposition == 'NORMAL_TEMPORARY_FAILURE' then + call_result.phrase = 'User offline'; + call_result.code = 480; + else + call_result.cause = self.caller:to_s('last_bridge_hangup_cause'); + call_result.code = self.caller:to_i('last_bridge_proto_specific_hangup_cause'); + call_result.phrase = self.caller:to_s('sip_hangup_phrase'); + end + + self.log:info('FORK EXIT - disposition: ', call_result.disposition, + ', cause: ', call_result.cause, + ', code: ', call_result.code, + ', phrase: ', call_result.phrase, + ', dial_time: ', os.time() - start_time); + + return call_result; +end + +-- Return call forwarding settngs +function SipCall.conditional_call_forwarding(self, cause, call_forwarding) + local condition_map = {USER_NOT_REGISTERED="offline", NO_ANSWER="noanswer", USER_BUSY="busy"} + local condition = condition_map[cause] + if call_forwarding and condition and call_forwarding[condition] then + log:debug('call forwarding on ' .. condition .. ' - destination: ' .. call_forwarding[condition].destination .. ', type: ' .. call_forwarding[condition].call_forwardable_type); + return call_forwarding[condition] + end +end + +function SipCall.set_callee_variables(self, sip_account) + self.session:setVariable("gs_callee_account_id", sip_account.id); + self.session:setVariable("gs_callee_account_type", "SipAccount"); + self.session:setVariable("gs_callee_account_owner_type", sip_account.sip_accountable_type); + self.session:setVariable("gs_callee_account_owner_id", sip_account.sip_accountable_id); +end diff --git a/misc/freeswitch/scripts/dialplan/tenant.lua b/misc/freeswitch/scripts/dialplan/tenant.lua new file mode 100644 index 0000000..8d6436c --- /dev/null +++ b/misc/freeswitch/scripts/dialplan/tenant.lua @@ -0,0 +1,51 @@ +-- Gemeinschaft 5 module: user class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +Tenant = {} + +-- Create Tenant object +function Tenant.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self) + self.__index = self; + self.class = 'tenant'; + self.log = arg.log; + self.database = arg.database; + self.record = arg.record; + return object; +end + +-- find tenant by id +function Tenant.find_by_id(self, id) + local sql_query = 'SELECT * FROM `tenants` WHERE `id`= ' .. tonumber(id) .. ' LIMIT 1'; + local tenant = nil; + + self.database:query(sql_query, function(account_entry) + tenant = Tenant:new(self); + tenant.record = account_entry; + tenant.id = tonumber(account_entry.id); + tenant.uuid = account_entry.uuid; + end); + + return tenant; +end + +-- find tenant by uuid +function Tenant.find_by_uuid(self, uuid) + tenant_id = tonumber(tenant_id) + local sql_query = 'SELECT * FROM `tenants` WHERE `id`= "' .. uuid .. '" LIMIT 1'; + local tenant = nil; + + self.database:query(sql_query, function(account_entry) + tenant = Tenant:new(self); + tenant.record = account_entry; + tenant.id = tonumber(account_entry.id); + tenant.uuid = account_entry.uuid; + end); + + return tenant; +end diff --git a/misc/freeswitch/scripts/dialplan/user.lua b/misc/freeswitch/scripts/dialplan/user.lua new file mode 100644 index 0000000..3b483c8 --- /dev/null +++ b/misc/freeswitch/scripts/dialplan/user.lua @@ -0,0 +1,91 @@ +-- Gemeinschaft 5 module: user class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +User = {} + +MAX_GROUP_MEMBERSHIPS = 256; + +-- create user object +function User.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.class = 'user'; + self.log = arg.log; + self.database = arg.database; + self.record = arg.record; + return object; +end + +-- find user by id +function User.find_by_id(self, id) + local sql_query = 'SELECT * FROM `users` WHERE `id`= ' .. tonumber(id) .. ' LIMIT 1'; + local user = nil; + + self.database:query(sql_query, function(account_entry) + user = User:new(self); + user.record = account_entry; + user.id = tonumber(account_entry.id); + user.uuid = account_entry.uuid; + end); + + return user; +end + +-- find user by uuid +function User.find_by_uuid(self, uuid) + local sql_query = 'SELECT * FROM `users` WHERE `id`= "' .. uuid .. '" LIMIT 1'; + local user = nil; + + self.database:query(sql_query, function(account_entry) + user = User:new(self); + user.record = account_entry; + user.id = tonumber(account_entry.id); + user.uuid = account_entry.uuid; + end); + + return user; +end + + +function User.list_groups(self, id) + require 'common.str' + id = id or self.id; + local sql_query = 'SELECT `b`.`name` FROM `user_group_memberships` `a` \ + JOIN `user_groups` `b` ON `a`.`user_group_id` = `b`.`id` \ + WHERE `a`.`state` = "active" AND `a`.`user_id`= ' .. tonumber(id) .. ' ORDER BY `b`.`position` LIMIT ' .. MAX_GROUP_MEMBERSHIPS; + + local groups = {}; + + self.database:query(sql_query, function(entry) + groups[common.str.downcase(entry.name)] = true; + end); + + return groups; +end + + +function User.check_pin(self, pin_to_check) + if not self.record then + return nil + end + + local str_to_hash = tostring(self.record.pin_salt) .. tostring(pin_to_check); + + local file = io.popen("echo -n " .. str_to_hash .. "|sha256sum"); + local pin_to_check_hash = file:read("*a"); + file:close(); + + pin_to_check_hash = pin_to_check_hash:sub(1, 64); + + if pin_to_check_hash == self.record.pin_hash then + return true; + end + + return false; +end + diff --git a/misc/freeswitch/scripts/dialplan/voicemail.lua b/misc/freeswitch/scripts/dialplan/voicemail.lua new file mode 100644 index 0000000..b9dab79 --- /dev/null +++ b/misc/freeswitch/scripts/dialplan/voicemail.lua @@ -0,0 +1,155 @@ +-- Gemeinschaft 5 module: voicemail class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +Voicemail = {} + +MESSAGE_LENGTH_MIN = 3; +MESSAGE_LENGTH_MAX = 120; +SILENCE_LENGTH_ABORT = 5; +SILENCE_LEVEL = 500; +BEEP = 'tone_stream://%(1000,0,500)'; +RECORD_FILE_PREFIX = '/tmp/voicemail_'; + +-- create voicemail object +function Voicemail.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.class = 'voicemail'; + self.log = arg.log; + self.database = arg.database; + self.record = arg.record; + return object +end + +-- find voicemail account by sip account id +function Voicemail.find_by_sip_account_id(self, id) + local sql_query = 'SELECT `a`.`id`, `a`.`uuid`, `a`.`auth_name`, `a`.`caller_name`, `b`.`name_path`, `b`.`greeting_path`, `a`.`voicemail_pin`, `b`.`password`, `c`.`host` AS `domain` \ + FROM `sip_accounts` `a` LEFT JOIN `voicemail_prefs` `b` ON `a`.`auth_name` = `b`.`username` \ + JOIN `sip_domains` `c` ON `a`.`sip_domain_id` = `c`.`id` \ + WHERE `a`.`id` = ' .. tonumber(id); + + local voicemail_account = nil; + self.database:query(sql_query, function(entry) + voicemail_account = Voicemail:new(self); + voicemail_account.record = entry; + voicemail_account.id = tonumber(entry.id); + voicemail_account.uuid = entry.uuid; + end) + + return voicemail_account; +end + +-- Find Voicemail account by name +function Voicemail.find_by_name(self, account_name) + id = tonumber(id) or 0; + local sql_query = string.format('SELECT * FROM `voicemail_prefs` WHERE `username`= "%s" LIMIT 1', account_name) + local record = nil + + self.database:query(sql_query, function(voicemail_entry) + record = voicemail_entry + end) + + if voicemail_account then + voicemail_account.account_name = account_name; + if record then + voicemail_account.name_path = record.name_path; + voicemail_account.greeting_path = record.greeting_path; + voicemail_account.password = record.password; + end + end + + return voicemail_account +end + +-- Find Voicemail account by name +function Voicemail.find_by_number(self, phone_number) + local sip_account = nil; + + require "common.phone_number" + local phone_number_class = common.phone_number.PhoneNumber:new{ log = self.log, database = self.database }; + local destination_number_object = phone_number_class:find_by_number(phone_number); + if destination_number_object and destination_number_object.record.phone_numberable_type == "SipAccount" then + return Voicemail:find_by_sip_account_id(destination_number_object.record.phone_numberable_id); + end + + return false; +end + + +function Voicemail.leave(self, caller, phone_number) + require 'common.str' + + self.log:info('VOICEMAIL_LEAVE - account=', self.record.id, '/', self.record.uuid, ', auth_name: ', self.record.auth_name, ', caller_name: ', self.record.caller_name); + + caller:set_callee_id(phone_number, self.record.caller_name); + caller:answer(); + caller:send_display(common.str.to_s(self.record.caller_name), common.str.to_s(phone_number)); + caller:sleep(1000); + + if not common.str.blank(self.record.greeting_path) then + caller.session:sayPhrase('voicemail_play_greeting', 'greeting:' .. tostring(self.record.greeting_path)); + elseif not common.str.blank(self.record.name_path) then + caller.session:sayPhrase('voicemail_play_greeting', 'name:' .. tostring(self.record.name_path)); + elseif not common.str.blank(phone_number) then + caller.session:sayPhrase('voicemail_play_greeting', (tostring(phone_number):gsub('[%D]', ''))); + end + + local record_file_name = RECORD_FILE_PREFIX .. caller.uuid .. '.wav'; + caller.session:streamFile(BEEP); + self.log:info('VOICEMAIL_LEAVE - recording to file: ', tostring(record_file_name)); + local result = caller.session:recordFile(record_file_name, MESSAGE_LENGTH_MAX, SILENCE_LEVEL, SILENCE_LENGTH_ABORT); + local duration = caller:to_i('record_seconds'); + + if duration >= MESSAGE_LENGTH_MIN then + self.log:info('VOICEMAIL_LEAVE - saving recorded message to voicemail, duration: ', duration); + require 'common.fapi' + common.fapi.FApi:new{ log = self.log, uuid = caller.uuid }:execute('vm_inject', + self.record.auth_name .. + '@' .. self.record.domain .. " '" .. + record_file_name .. "' '" .. + caller.caller_id_number .. "' '" .. + caller.caller_id_name .. "' '" .. + caller.uuid .. "'" + ); + caller:set_variable('voicemail_message_len', duration); + else + caller:set_variable('voicemail_message_len'); + end + os.remove(record_file_name); + return true; +end + + +function Voicemail.send_notify(self, caller) + self.log:debug('VOICEMAIL_NOTIFY - account: ' .. self.record.auth_name .. ", id: " .. tostring(caller.uuid)); + + local file = io.popen("/opt/GS5/script/voicemail_new.sh '" .. tostring(self.record.auth_name) .. "' '" .. tostring(caller.uuid) .. "' 2>&1"); + self.log:debug('VOICEMAIL_NOTIFY - result: ' .. tostring(file:read("*a"))); + file:close(); + + return true; +end + + +function Voicemail.menu(self, caller, authorized) + self.log:info('VOICEMAIL_MENU - account: ', self.record.auth_name); + + if authorized then + caller:set_variable('voicemail_authorized', true); + end + + caller:set_callee_id(phone_number, self.record.caller_name); + caller:answer(); + caller:send_display(common.str.to_s(self.record.caller_name), common.str.to_s(phone_number)); + + caller:sleep(1000); + caller:set_variable('skip_greeting', true); + caller:set_variable('skip_instructions', true); + + caller:execute('voicemail', 'check default ' .. self.record.domain .. ' ' .. self.record.auth_name); +end diff --git a/misc/freeswitch/scripts/dialplan_default.lua b/misc/freeswitch/scripts/dialplan_default.lua new file mode 100644 index 0000000..ee4a88f --- /dev/null +++ b/misc/freeswitch/scripts/dialplan_default.lua @@ -0,0 +1,64 @@ +-- Gemeinschaft 5 default dialplan +-- (c) AMOOMA GmbH 2012 +-- + + +function hangup_hook_caller(s, status, arg) + log:info('HANGUP_HOOK: ', status) + if tostring(status) == 'transfer' then + if start_caller and start_caller.destination then + log:info('CALL_TRANSFERRED - destination was: ', start_caller.destination.type, '=', start_caller.destination.id,', number: ' .. tostring(start_caller.destination.number) .. ', to: ' .. start_caller:to_s('sip_refer_to')); + start_caller.auth_account = start_dialplan:object_find(start_caller.destination.type, start_caller.destination.id); + start_caller.forwarding_number = start_caller.destination.number; + start_caller.forwarding_service = 'transfer'; + end + end +end + +-- initialize logging +require 'common.log' +log = common.log.Log:new{ prefix = '### [' .. session:get_uuid() .. '] ' }; + +-- caller session object +require 'dialplan.session' +start_caller = dialplan.session.Session:new{ log = log, session = session }; + +-- dialplan object +require 'dialplan.dialplan' + +start_dialplan = dialplan.dialplan.Dialplan:new{ log = log, caller = start_caller }; +start_dialplan:configuration_read(); +start_caller.local_node_id = start_dialplan.node_id; +start_caller:init_channel_variables(); + +-- session:execute('info','notice'); + +if not start_dialplan:check_auth() then + log:debug('AUTHENTICATION_REQUIRED - domain: ', start_dialplan.domain); + start_dialplan:hangup(407, start_dialplan.domain); + return false; +end + +-- connect to database +require 'common.database' +local database = common.database.Database:new{ log = log }:connect(); +if not database:connected() then + log:critical('DIALPLAN_DEFAULT - database connect failed'); + return; +end + +start_dialplan.database = database; + +if start_caller.from_node and not start_dialplan:check_auth_node() then + log:debug('AUTHENTICATION_REQUIRED_NODE - node_id: ', start_caller.node_id, ', domain: ', start_dialplan.domain); + start_dialplan:hangup(407, start_dialplan.domain); +else + start_destination = { type = 'unknown' } + start_caller.session:setHangupHook('hangup_hook_caller', 'destination_number'); + start_dialplan:run(start_destination); +end + +-- release database handle +if database then + database:release(); +end diff --git a/misc/freeswitch/scripts/event/call_history_save.lua b/misc/freeswitch/scripts/event/call_history_save.lua new file mode 100644 index 0000000..057ca16 --- /dev/null +++ b/misc/freeswitch/scripts/event/call_history_save.lua @@ -0,0 +1,74 @@ +-- Gemeinschaft 5 module: call_history event handler class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +function handler_class() + return CallHistorySave +end + +CallHistorySave = {} + + +function CallHistorySave.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.class = 'callhistorysave' + self.database = arg.database; + self.domain = arg.domain; + + return object; +end + + +function CallHistorySave.event_handlers(self) + return { CHANNEL_DESTROY = { [true] = self.channel_destroy } } +end + + +function CallHistorySave.channel_destroy(self, event) + local uuid = event:getHeader('Unique-ID'); + local direction = event:getHeader('variable_direction'); + + require 'common.str' + local save_cdr = common.str.to_b(event:getHeader('variable_gs_save_cdr')); + + if not save_cdr then + self.log:debug('[', uuid,'] CALL_HISTORY_SAVE - event: CHANNEL_DESTROY, direction: ', direction, ', save_cdr: ', save_cdr); + return false; + end + + require 'common.call_history' + call_history_class = common.call_history.CallHistory:new{ log = self.log, database = self.database } + + -- caller entry + local account_type = event:getHeader('variable_gs_account_type'); + local account_id = common.str.to_i(event:getHeader('variable_gs_account_id')); + + if account_type and account_id > 0 and common.str.to_b(event:getHeader('variable_gs_account_node_local')) then + call_history_class:insert_event(uuid, account_type, account_id, 'dialed', event); + else + self.log:info('[', uuid,'] CALL_HISTORY_SAVE - ignore caller entry - account: ', account_type, '=', account_id, ', local: ', event:getHeader('variable_gs_account_node_local')); + end + + -- callee entry + local account_type = event:getHeader('variable_gs_destination_type'); + local account_id = common.str.to_i(event:getHeader('variable_gs_destination_id')); + + if account_type and account_id > 0 + and common.str.to_b(event:getHeader('variable_gs_destination_node_local')) + and tostring(event:getHeader('variable_gs_call_service')) ~= 'pickup' then + + if tostring(event:getHeader('variable_endpoint_disposition')) == 'ANSWER' then + call_history_class:insert_event(uuid, account_type, account_id, 'received', event); + else + call_history_class:insert_event(uuid, account_type, account_id, 'missed', event); + end + else + self.log:info('[', uuid,'] CALL_HISTORY_SAVE - ignore callee entry - account: ', account_type, '=', account_id, ', local: ', event:getHeader('variable_gs_destination_node_local')); + end +end diff --git a/misc/freeswitch/scripts/event/cdr_save.lua b/misc/freeswitch/scripts/event/cdr_save.lua new file mode 100644 index 0000000..ed53aa3 --- /dev/null +++ b/misc/freeswitch/scripts/event/cdr_save.lua @@ -0,0 +1,105 @@ +-- Gemeinschaft 5 module: cdr event handler class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + + +function handler_class() + return CdrSave +end + + +function camelize_type(account_type) + ACCOUNT_TYPES = { + sipaccount = 'SipAccount', + conference = 'Conference', + faxaccount = 'FaxAccount', + callthrough = 'Callthrough', + huntgroup = 'HuntGroup', + automaticcalldistributor = 'AutomaticCallDistributor', + } + + return ACCOUNT_TYPES[account_type] or account_type; +end + + +CdrSave = {} + + +function CdrSave.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.class = 'cdrsave' + self.database = arg.database; + self.domain = arg.domain; + + return object; +end + + +function CdrSave.event_handlers(self) + return { CHANNEL_DESTROY = { [true] = self.channel_destroy } } +end + + +function CdrSave.channel_destroy(self, event) + local uuid = event:getHeader('Unique-ID'); + local direction = event:getHeader('variable_direction'); + + require 'common.str' + local save_cdr = common.str.to_b(event:getHeader('variable_gs_save_cdr')); + + if not save_cdr then + self.log:debug('[', uuid,'] CDR_SAVE - event: CHANNEL_DESTROY, direction: ', direction, ', save_cdr: ', save_cdr); + return false; + end + + require 'common.str' + local cdr = {} + + cdr.uuid = common.str.to_sql(uuid); + cdr.bleg_uuid = common.str.to_sql(event:getHeader('variable_bridge_uuid')); + cdr.dialed_number = common.str.to_sql(event:getHeader('Caller-Destination-Number')); + cdr.destination_number = common.str.to_sql(event:getHeader('variable_gs_destination_number')); + cdr.caller_id_number = common.str.to_sql(event:getHeader('variable_effective_caller_id_number')); + cdr.caller_id_name = common.str.to_sql(event:getHeader('variable_effective_caller_id_name')); + cdr.callee_id_number = common.str.to_sql(event:getHeader('variable_effective_callee_id_number')); + cdr.callee_id_name = common.str.to_sql(event:getHeader('variable_effective_callee_id_name')); + cdr.start_stamp = 'FROM_UNIXTIME(' .. math.floor(common.str.to_i(event:getHeader('Caller-Channel-Created-Time')) / 1000000) .. ')'; + cdr.answer_stamp = 'FROM_UNIXTIME(' .. math.floor(common.str.to_i(event:getHeader('Caller-Channel-Answered-Time')) / 1000000) .. ')'; + cdr.end_stamp = 'FROM_UNIXTIME(' .. math.floor(common.str.to_i(event:getHeader('Caller-Channel-Hangup-Time')) / 1000000) .. ')'; + cdr.bridge_stamp = common.str.to_sql(event:getHeader('variable_bridge_stamp')); + cdr.duration = common.str.to_sql(event:getHeader('variable_duration')); + cdr.billsec = common.str.to_sql(event:getHeader('variable_billsec')); + cdr.hangup_cause = common.str.to_sql(event:getHeader('variable_hangup_cause')); + cdr.dialstatus = common.str.to_sql(event:getHeader('variable_DIALSTATUS')); + cdr.forwarding_number = common.str.to_sql(event:getHeader('variable_gs_forwarding_number')); + cdr.forwarding_service = common.str.to_sql(event:getHeader('variable_gs_forwarding_service')); + cdr.forwarding_account_id = common.str.to_sql(event:getHeader('variable_gs_auth_account_id')); + cdr.forwarding_account_type = common.str.to_sql(camelize_type(event:getHeader('variable_gs_auth_account_type'))); + cdr.account_id = common.str.to_sql(event:getHeader('variable_gs_account_id')); + cdr.account_type = common.str.to_sql(camelize_type(event:getHeader('variable_gs_account_type'))); + cdr.bleg_account_id = common.str.to_sql(event:getHeader('variable_gs_destination_id')); + cdr.bleg_account_type = common.str.to_sql(camelize_type(event:getHeader('variable_gs_destination_type'))); + + local keys = {} + local values = {} + + for key, value in pairs(cdr) do + table.insert(keys, key); + table.insert(values, value); + end + + self.log:info('[', uuid,'] CDR_SAVE - account: ', cdr.account_type, '=', cdr.account_id, + ', caller: ', cdr.caller_id_number, ' ', cdr.caller_id_name, + ', callee: ', cdr.callee_id_number, ' ', cdr.callee_id_name, + ', cause: ', cdr.hangup_cause + ); + + local sql_query = 'INSERT INTO `cdrs` (`' .. table.concat(keys, "`, `") .. '`) VALUES (' .. table.concat(values, ", ") .. ')'; + return self.database:query(sql_query); +end diff --git a/misc/freeswitch/scripts/event/event.lua b/misc/freeswitch/scripts/event/event.lua new file mode 100644 index 0000000..8e67bc9 --- /dev/null +++ b/misc/freeswitch/scripts/event/event.lua @@ -0,0 +1,109 @@ +-- Gemeinschaft 5 module: event manager class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +EventManager = {} + +-- create event manager object +function EventManager.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.class = 'eventmanager' + self.database = arg.database; + self.domain = arg.domain; + + return object; +end + + +function EventManager.register(self) + self.consumer = freeswitch.EventConsumer('all'); + return (self.consumer ~= nil); +end + + +function EventManager.load_event_modules(self) + local CONFIG_FILE_NAME = '/opt/freeswitch/scripts/ini/events.ini'; + + require 'common.configuration_file' + self.config = common.configuration_file.get(CONFIG_FILE_NAME); + + return self.config.modules; +end + + +function EventManager.load_event_handlers(self, event_modules) + event_handlers = {} + + for index, event_module_name in ipairs(event_modules) do + event_module = require('event.' .. event_module_name); + if event_module then + self.log:info('[event] EVENT_MANAGER - loading handler module: ', event_module_name); + handler_class = event_module.handler_class(); + + if handler_class then + module_event_handlers = handler_class:new{ log = self.log, database = self.database, domain = self.domain }:event_handlers(); + if module_event_handlers then + for event_name, event_subclasses in pairs(module_event_handlers) do + if not event_handlers[event_name] then + event_handlers[event_name] = {}; + end + + for event_subclass, module_event_handler in pairs(event_subclasses) do + if not event_handlers[event_name][event_subclass] then + event_handlers[event_name][event_subclass] = {}; + end + + table.insert(event_handlers[event_name][event_subclass], { class = handler_class, method = module_event_handler } ); + self.log:info('[event] EVENT_MANAGER - module: ', event_module_name, ', handling events: ', event_name, ', subclass:', event_subclass); + end + end + end + end + end + end + + return event_handlers; +end + + +function EventManager.run(self) + + local event_modules = self:load_event_modules(); + local event_handlers = self:load_event_handlers(event_modules); + + if not event_handlers then + self.log:error('[event] EVENT_MANAGER - no handlers specified'); + return nil; + end + + if not self:register() then + return nil; + end + + freeswitch.setGlobalVariable('gs_event_manager', 'true'); + while freeswitch.getGlobalVariable('gs_event_manager') == 'true' do + local event = self.consumer:pop(1, 100); + if event then + local event_type = event:getType(); + local event_subclass = event:getHeader('Event-Subclass'); + if event_handlers[event_type] then + if event_handlers[event_type][event_subclass] and #event_handlers[event_type][event_subclass] > 0 then + for index, event_handler in ipairs(event_handlers[event_type][event_subclass]) do + event_handler.method(event_handler.class, event); + end + end + if event_handlers[event_type][true] and #event_handlers[event_type][true] > 0 then + for index, event_handler in ipairs(event_handlers[event_type][true]) do + event_handler.method(event_handler.class, event); + end + end + end + end + end +end diff --git a/misc/freeswitch/scripts/event/perimeter.lua b/misc/freeswitch/scripts/event/perimeter.lua new file mode 100644 index 0000000..3babba6 --- /dev/null +++ b/misc/freeswitch/scripts/event/perimeter.lua @@ -0,0 +1,106 @@ +-- Gemeinschaft 5 module: cdr event handler class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + + +function handler_class() + return Perimeter +end + + + +Perimeter = {} + +MALICIOUS_CONTACT_COUNT = 20; +MALICIOUS_CONTACT_TIME_SPAN = 2; +BAN_FUTILE = 2; + +function Perimeter.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.class = 'cdrsave' + self.database = arg.database; + self.domain = arg.domain; + + self.ip_address_table = {} + self:init(); + + return object; +end + + +function Perimeter.event_handlers(self) + return { CUSTOM = { ['sofia::pre_register'] = self.sofia_pre_register } } +end + + +function Perimeter.init(self) + local config = common.configuration_file.get('/opt/freeswitch/scripts/ini/perimeter.ini'); + if config and config.general then + self.malicious_contact_count = tonumber(config.general.malicious_contact_count) or MALICIOUS_CONTACT_COUNT; + self.malicious_contact_time_span = tonumber(config.general.malicious_contact_time_span) or MALICIOUS_CONTACT_TIME_SPAN; + self.ban_futile = tonumber(config.general.ban_futile) or BAN_FUTILE; + self.execute = config.general.execute; + end + + self.log:info('[perimeter] PERIMETER - setup perimeter defense - config: ', self.malicious_contact_count, '/', self.malicious_contact_time_span, ', execute: ', self.execute); +end + + +function Perimeter.sofia_pre_register(self, event) + local ip_address = event:getHeader('network-ip'); + self:check_ip(ip_address); +end + + +function Perimeter.check_ip(self, ip_address) + local event_time = os.time(); + + if not self.ip_address_table[ip_address] then + self.ip_address_table[ip_address] = { last_contact = event_time, contact_count = 0, start_stamp = event_time, banned = 0 } + end + + local ip_record = self.ip_address_table[ip_address]; + ip_record.last_contact = event_time; + ip_record.contact_count = ip_record.contact_count + 1; + + if ip_record.contact_count > MALICIOUS_CONTACT_COUNT then + if (event_time - ip_record.start_stamp) <= MALICIOUS_CONTACT_TIME_SPAN then + self.log:warning('[', ip_address, '] PERIMETER - too many registration attempts'); + ip_record.start_stamp = event_time; + ip_record.contact_count = 0; + if ip_record.banned < BAN_FUTILE then + ip_record.banned = ip_record.banned + 1; + self:ban_ip(ip_address); + else + self.log:error('[', ip_address, '] PERIMETER - ban futile'); + end + end + end +end + + +function Perimeter.ban_ip(self, ip_address) + self.ip_address = ip_address; + + if self.execute then + local command = self:expand_variables(self.execute); + self.log:debug('[', ip_address, '] PERIMETER - execute: ', command); + local result = os.execute(command); + if tostring(result) == '0' then + self.log:warning('[', ip_address, '] PERIMETER - IP banned'); + end + end +end + + +function Perimeter.expand_variables(self, line) + return (line:gsub('{([%a%d_-]+)}', function(captured) + return self[captured]; + end)) +end diff --git a/misc/freeswitch/scripts/event/presence_update.lua b/misc/freeswitch/scripts/event/presence_update.lua new file mode 100644 index 0000000..01ec17b --- /dev/null +++ b/misc/freeswitch/scripts/event/presence_update.lua @@ -0,0 +1,199 @@ + +module(...,package.seeall) + +function handler_class() + return PresenceUpdate +end + +ACCOUNT_RECORD_TIMEOUT = 120; + +PresenceUpdate = {} + +function PresenceUpdate.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.class = 'presenceupdate' + self.database = arg.database; + self.domain = arg.domain; + self.presence_accounts = {} + self.account_record = {} + + return object; +end + + +function PresenceUpdate.event_handlers(self) + return { + PRESENCE_PROBE = { [true] = self.presence_probe }, + CUSTOM = { ['sofia::register'] = self.sofia_register, ['sofia::unregister'] = self.sofia_ungerister }, + PRESENCE_IN = { [true] = self.presence_in }, + } +end + + +function PresenceUpdate.presence_probe(self, event) + local DIALPLAN_FUNCTION_PATTERN = '^f[_%-].*'; + + require 'common.str' + local event_to = event:getHeader('to'); + local event_from = event:getHeader('from'); + local probe_type = event:getHeader('probe-type'); + local account, domain = common.str.partition(event_from, '@'); + local subscription, domain = common.str.partition(event_to, '@'); + + self.log:debug('[', account, '] PRESENCE_UPDATE - subscription: ', subscription,', type: ', probe_type); + if (not self.presence_accounts[account] or not self.presence_accounts[account][subscription]) and subscription:find(DIALPLAN_FUNCTION_PATTERN) then + if not self.presence_accounts[account] then + self.presence_accounts[account] = {}; + end + if not self.presence_accounts[account][subscription] then + self.presence_accounts[account][subscription] = {}; + end + self:update_function_presence(account, domain, subscription); + end +end + + +function PresenceUpdate.sofia_register(self, event) + local account = event:getHeader('from-user'); + self.log:debug('[', account, '] PRESENCE_UPDATE - flushing account cache on register'); + self.presence_accounts[account] = nil; +end + + +function PresenceUpdate.sofia_ungerister(self, event) + local account = event:getHeader('from-user'); + self.log:debug('[', account, '] PRESENCE_UPDATE - flushing account cache on unregister'); + self.presence_accounts[account] = nil; +end + + +function PresenceUpdate.presence_in(self, event) + if not event:getHeader('status') then + return + end + + local account, domain = common.str.partition(event:getHeader('from'), '@'); + local direction = tostring(event:getHeader('presence-call-direction')) + local state = event:getHeader('presence-call-info-state'); + local uuid = event:getHeader('Unique-ID'); + local caller_id = event:getHeader('Caller-Caller-ID-Number'); + + if direction == 'inbound' then + self.log:info('[', uuid,'] PRESENCE_INBOUND: account: ', account, ', state: ', state); + self:sip_account(true, account, domain, state, uuid); + elseif direction == 'outbound' then + self.log:info('[', uuid,'] PRESENCE_OUTBOUND: account: ', account, ', state: ', state, ', caller: ', caller_id); + self:sip_account(false, account, domain, state, uuid, caller_id); + end +end + + +function PresenceUpdate.update_function_presence(self, account, domain, subscription) + local parameters = common.str.to_a(subscription, '_%-'); + local fid = parameters[2]; + local function_parameter = parameters[3]; + + if not fid then + self.log:error('[', account, '] PRESENCE_UPDATE - no function specified'); + return; + end + + if fid == 'cftg' and tonumber(function_parameter) then + self:call_forwarding(account, domain, function_parameter); + elseif fid == 'hgmtg' then + self:hunt_group_membership(account, domain, function_parameter); + elseif fid == 'acdmtg' then + self:acd_membership(account, domain, function_parameter); + end + +end + + +function PresenceUpdate.call_forwarding(self, account, domain, call_forwarding_id) + require 'common.call_forwarding' + local call_forwarding = common.call_forwarding.CallForwarding:new{ log=self.log, database=self.database, domain=domain }:find_by_id(call_forwarding_id); + + require 'common.str' + if call_forwarding and common.str.to_b(call_forwarding.record.active) then + local destination_type = tostring(call_forwarding.record.call_forwardable_type):lower() + + self.log:debug('[', account, '] PRESENCE_UPDATE - updating call forwarding presence - id: ', call_forwarding_id, ', destination: ', destination_type); + + if destination_type == 'voicemail' then + call_forwarding:presence_set('early'); + else + call_forwarding:presence_set('confirmed'); + end + end +end + + +function PresenceUpdate.hunt_group_membership(self, account, domain, member_id) + local sql_query = 'SELECT `active` FROM `hunt_group_members` WHERE `active` IS TRUE AND `id`=' .. tonumber(member_id) .. ' LIMIT 1'; + local status = self.database:query_return_value(sql_query); + + if status then + self.log:debug('[', account, '] PRESENCE_UPDATE - updating hunt group membership presence - id: ', member_id); + require 'dialplan.presence' + local presence_class = dialplan.presence.Presence:new{ + log = self.log, + database = self.database, + domain = domain, + accounts = {'f-hgmtg-' .. member_id}, + uuid = 'hunt_group_member_' .. member_id + }:set('confirmed'); + end +end + + +function PresenceUpdate.acd_membership(self, account, domain, member_id) + local sql_query = 'SELECT `status` FROM `acd_agents` WHERE `status` = "active" AND `id`=' .. tonumber(member_id) .. ' LIMIT 1'; + local status = self.database:query_return_value(sql_query); + + if status then + self.log:debug('[', account, '] PRESENCE_UPDATE - updating ACD membership presence - id: ', member_id); + require 'dialplan.presence' + local presence_class = dialplan.presence.Presence:new{ + log = self.log, + database = self.database, + domain = domain, + accounts = {'f-acdmtg-' .. member_id}, + uuid = 'acd_agent_' .. member_id + }:set(status); + end +end + + +function PresenceUpdate.sip_account(self, inbound, account, domain, status, uuid, caller_id) + local status_map = { progressing = 'early', alerting = 'confirmed', active = 'confirmed' } + + if not self.account_record[account] or ((os.time() - self.account_record[account].created_at) > ACCOUNT_RECORD_TIMEOUT) then + self.log:debug('[', uuid,'] PRESENCE - retrieve account data - account: ', account); + + require 'common.sip_account' + local sip_account = common.sip_account.SipAccount:new{ log = self.log, database = self.database }:find_by_auth_name(account); + + if not sip_account then + return + end + + require 'common.phone_number' + local phone_numbers = common.phone_number.PhoneNumber:new{ log = self.log, database = self.database }:list_by_owner(sip_account.id, sip_account.class); + + self.account_record[account] = { id = sip_account.id, class = sip_account.class, phone_numbers = phone_numbers, created_at = os.time() } + end + + require 'dialplan.presence' + local result = dialplan.presence.Presence:new{ + log = self.log, + database = self.database, + inbound = inbound, + domain = domain, + accounts = self.account_record[account].phone_numbers, + uuid = uuid + }:set(status_map[status] or 'terminated', caller_id); +end diff --git a/misc/freeswitch/scripts/event_manager.lua b/misc/freeswitch/scripts/event_manager.lua new file mode 100644 index 0000000..0e3c0e0 --- /dev/null +++ b/misc/freeswitch/scripts/event_manager.lua @@ -0,0 +1,39 @@ +-- Gemeinschaft 5.0 event handler +-- (c) AMOOMA GmbH 2012 +-- + +-- Set logger +require "common.log" +local log = common.log.Log:new() +log.prefix = "#E# " + +log:info('[event] EVENT_MANAGER start'); + +require 'common.database' +local database = common.database.Database:new{ log = log }:connect(); +if not database:connected() then + log:error('[event] EVENT_MANAGER - cannot connect to Gemeinschaft database'); + return; +end + +require "configuration.sip" +local sip = configuration.sip.Sip:new{ log = log, database = database } + +local domain = '127.0.0.1'; +local domains = sip:domains(); +if domains[1] then + domain = domains[1]['host']; +else + log:error('[event] EVENT_MANAGER - No SIP domains found!'); +end + +require 'event.event' +local event_manager = event.event.EventManager:new{ log = log, database = database, domain = domain } +event_manager:run(); + +-- ensure database handle is released on exit +if database then + database:release(); +end + +log:info('[event] EVENT_MANAGER exit'); diff --git a/misc/freeswitch/scripts/fax_daemon.lua b/misc/freeswitch/scripts/fax_daemon.lua new file mode 100644 index 0000000..cfe7c4e --- /dev/null +++ b/misc/freeswitch/scripts/fax_daemon.lua @@ -0,0 +1,42 @@ +-- Gemeinschaft 5.0 fax daemon +-- (c) AMOOMA GmbH 2012 +-- + +local MAIN_LOOP_SLEEP_TIME = 30; + +-- Set logger +require "common.log" +local log = common.log.Log:new() +log.prefix = "### [faxdaemon] " + +log:debug('Starting fax daemon'); + +local database = nil; +local api = freeswitch.API(); + +freeswitch.setGlobalVariable('gs_fax_daemon', 'true'); +while freeswitch.getGlobalVariable("gs_fax_daemon") == 'true' do + require 'common.database' + local database = common.database.Database:new{ log = log }:connect(); + + if not database:connected() then + log:error("connection to Gemeinschaft database lost - retry in " .. MAIN_LOOP_SLEEP_TIME .. " seconds") + else + require 'dialplan.fax' + local fax_documents = dialplan.fax.Fax:new{log=log, database=database}:queued_for_sending(); + + for key, fax_document in pairs(fax_documents) do + if table.getn(fax_document.destination_numbers) > 0 and tonumber(fax_document.retry_counter) > 0 then + log:debug('FAX_DAEMON_LOOP - fax_document=', fax_document.id, '/', fax_document.uuid, ', number: ' .. fax_document.destination_numbers[1]); + local result = api:executeString('luarun send_fax.lua ' .. fax_document.id); + end + end + end + database:release(); + + if freeswitch.getGlobalVariable("gs_fax_daemon") == 'true' then + freeswitch.msleep(MAIN_LOOP_SLEEP_TIME * 1000); + end +end + +log:debug('Exiting fax daemon'); diff --git a/misc/freeswitch/scripts/ini/conferences.ini b/misc/freeswitch/scripts/ini/conferences.ini new file mode 100644 index 0000000..d8d0817 --- /dev/null +++ b/misc/freeswitch/scripts/ini/conferences.ini @@ -0,0 +1,27 @@ +; Gemeinschaft 5 conferences configuration file +; (c) AMOOMA GmbH 2012 +; + +[parameters] +caller-controls = speaker +moderator-controls = moderator +max-members = 100 +rate = 16000 +interval = 20 +energy-level = 300 +sound-prefix = /opt/freeswitch/sounds/en/us/callie +muted-sound = conference/conf-muted.wav +unmuted-sound = conference/conf-unmuted.wav +alone-sound = conference/conf-alone.wav +moh-sound = local_stream://moh +enter-sound = tone_stream://%(200,0,500,600,700) +exit-sound = tone_stream://%(500,0,300,200,100,50,25) +kicked-sound = conference/conf-kicked.wav +locked-sound = conference/conf-locked.wav +is-locked-sound = conference/conf-is-locked.wav +is-unlocked-sound = conference/conf-is-unlocked.wav +pin-sound = conference/conf-pin.wav +bad-pin-sound = conference/conf-bad-pin.wav +caller-id-name = Conference +caller-id-number = +comfort-noise = true diff --git a/misc/freeswitch/scripts/ini/database.ini b/misc/freeswitch/scripts/ini/database.ini new file mode 100644 index 0000000..1652118 --- /dev/null +++ b/misc/freeswitch/scripts/ini/database.ini @@ -0,0 +1,11 @@ +; Gemeinschaft 5 database configuration +; (c) AMOOMA GmbH 2012 +; + +driver = mysql + +[mysql] +host = localhost +database = gemeinschaft +user = gemeinschaft +password = gemeinschaft diff --git a/misc/freeswitch/scripts/ini/dialplan.ini b/misc/freeswitch/scripts/ini/dialplan.ini new file mode 100644 index 0000000..f4a6b66 --- /dev/null +++ b/misc/freeswitch/scripts/ini/dialplan.ini @@ -0,0 +1,11 @@ +; Gemeinschaft 5 dialplan configuration file +; (c) AMOOMA GmbH 2012 +; + +[parameters] +node_id = 1 +phone_book_entry_image_url = http://192.168.0.150/uploads/phone_book_entry/image +user_image_url = http://192.168.0.150/uploads/user/image +ringtone_url = http://192.168.0.150 +ringback = %(2000,4000,440.0,480.0) +tone_busy = %(500,500,480,620);loops=4 diff --git a/misc/freeswitch/scripts/ini/events.ini b/misc/freeswitch/scripts/ini/events.ini new file mode 100644 index 0000000..e63eb73 --- /dev/null +++ b/misc/freeswitch/scripts/ini/events.ini @@ -0,0 +1,8 @@ +; Gemeinschaft 5 routing configuration file +; (c) AMOOMA GmbH 2012 +; + +[modules] +cdr_save +call_history_save +presence_update diff --git a/misc/freeswitch/scripts/ini/gateways.ini.example b/misc/freeswitch/scripts/ini/gateways.ini.example new file mode 100644 index 0000000..b6ae018 --- /dev/null +++ b/misc/freeswitch/scripts/ini/gateways.ini.example @@ -0,0 +1,23 @@ +; Gemeinschaft 5 gateways configuration file +; (c) AMOOMA GmbH 2012 +; + +[gateway1] +profile = gemeinschaft +name = gateway1 +username = gateway1 +realm = gemeinschaft +password = freeswitch +extension = default +proxy = 192.168.0.1 +expire-seconds = 600 +register = true + +[gateway2] +profile = gemeinschaft +name = sipgate +username = 1234567e0 +password = ABCdeF +proxy = sipgate.com +register = true +extension = {sip_to_user} diff --git a/misc/freeswitch/scripts/ini/perimeter.ini b/misc/freeswitch/scripts/ini/perimeter.ini new file mode 100644 index 0000000..ecbb032 --- /dev/null +++ b/misc/freeswitch/scripts/ini/perimeter.ini @@ -0,0 +1,9 @@ +; Gemeinschaft 5 perimeter defense configuration file +; (c) AMOOMA GmbH 2012 +; + +[general] +malicious_contact_count = 20 +malicious_contact_time_span = 2 +ban_futile = 5 +execute = sudo /usr/local/bin/ban_ip.sh {ip_address} diff --git a/misc/freeswitch/scripts/ini/routes.ini b/misc/freeswitch/scripts/ini/routes.ini new file mode 100644 index 0000000..1334e7b --- /dev/null +++ b/misc/freeswitch/scripts/ini/routes.ini @@ -0,0 +1,77 @@ +; Gemeinschaft 5 routing configuration file +; (c) AMOOMA GmbH 2012 +; + +[general] + + +[prerouting] +^%*0%*$ , f-li +^%*0%*(%d+)#*$ , f-li-%1 +^%*0%*(%d+)%*(%d+)#*$ , f-li-%1-%2 +^#0#$ , f-lo +^%*30#$ , f-clipon +^#30#$ , f-clipoff +^%*31#(%d+)$ , f-dclirof, f-%1 +^#31#(%d+)$ , f-dcliron-%1 +^%*43#$ , f-cwaon +^#43#$ , f-cwaoff +^#002#$ , f-cfoff +^##002#$ , f-cfdel +^%*21#$ , f-cfu +^%*21%*(%d+)#$ , f-cfu-%1 +^%*%*21%*(%d+)#$ , f-cfu-%1 +^#21#$ , f-cfuoff +^##21#$ , f-cfudel +^%*61#$ , f-cfn +^%*61%*(%d+)#$ , f-cfn-%1 +^%*%*61%*(%d+)#$ , f-cfn-%1 +^%*61%*(%d+)%*(%d+)#$ , f-cfn-%1-%2 +^%*%*61%*(%d+)%*(%d+)#$ , f-cfn-%1-%2 +^#61#$ , f-cfnoff +^##61#$ , f-cfndel +^%*62#$ , f-cfo +^%*62%*(%d+)#$ , f-cfo-%1 +^%*%*62%*(%d+)#$ , f-cfo-%1 +^#62#$ , f-cfooff +^##62#$ , f-cfodel +^%*67#$ , f-cfb +^%*67%*(%d+)#$ , f-cfb-%1 +^%*%*67%*(%d+)#$ , f-cfb-%1 +^#67#$ , f-cfboff +^##67#$ , f-cfbdel +^%*98$ , f-vmcheck +^%*98#$ , f-vmcheck +^%*98%*(%d+)#$ , f-vmcheck-%1 +^%*1337%*1%*1#$ , f-loaon +^%*1337%*1%*0#$ , f-loaoff + +^00(%d+)$ , +%1 +^0(%d+)$ , +49%1 + + +[outbound] +^%+(%d+)$ , class=gateway, endpoint=gateway1, group=users, %1 +^([1-9]%d+)$ , class=gateway, endpoint=gateway1, group=users, %1 + + +[failover] +UNALLOCATED_NUMBER = true +NORMAL_TEMPORARY_FAILURE = true + + +[outbound_cid_number] + + +[outbound_cid_name] + + +[inbound] +^00(%d+)$ , +%1 +^0(%d+)$ , +49%1 + +[inbound_cid_number] +^00(%d+)$ , +%1 +^0(%d+)$ , +49%1 + +[inbound_cid_name] diff --git a/misc/freeswitch/scripts/ini/sip_accounts.ini b/misc/freeswitch/scripts/ini/sip_accounts.ini new file mode 100644 index 0000000..73a5fae --- /dev/null +++ b/misc/freeswitch/scripts/ini/sip_accounts.ini @@ -0,0 +1,10 @@ +; Gemeinschaft 5 sip accounts default parameters +; (c) AMOOMA GmbH 2012 +; + +[parameters] +vm-enabled = true +vm-email-all-messages = false +vm-attach-file = false +vm-mailto = + diff --git a/misc/freeswitch/scripts/ini/sofia.ini b/misc/freeswitch/scripts/ini/sofia.ini new file mode 100644 index 0000000..9c73990 --- /dev/null +++ b/misc/freeswitch/scripts/ini/sofia.ini @@ -0,0 +1,55 @@ +; Gemeinschaft 5 sofia configuration file +; (c) AMOOMA GmbH 2012 +; + +[profiles] +gemeinschaft + +[parameters] +log-level = 3 +debug-presence = 0 + +[profile:gemeinschaft] +user-agent-string = Gemeinschaft5 +debug = 0 +sip-trace = no +log-auth-failures = false +context = default +rfc2833-pt = 101 +pass-rfc2833 = true +sip-port = 5060 +dialplan = XML +dtmf-duration = 2000 +rtp-timer-name = soft +inbound-codec-prefs = PCMA,G7221@32000h,G7221@16000h,G722,PCMU,GSM +outbound-codec-prefs = PCMA,G7221@32000h,G7221@16000h,G722,PCMU,GSM +inbound-codec-negotiation = greedy +ext-rtp-ip = auto-nat +ext-sip-ip = auto-nat +hold-music = local_stream://moh +manage-presence = true +tls = false +tls-sip-port = 5061 +tls-cert-dir = /opt/freeswitch/conf/ssl +accept-blind-reg = false +accept-blind-auth = false +nonce-ttl = 60 +disable-transcoding = false +manual-redirect = true +disable-transfer = false +disable-register = false +auth-calls = false +inbound-reg-force-matching-username = true +auth-all-packets = false +rtp-timeout-sec = 300 +rtp-hold-timeout-sec = 1800 +force-subscription-expires = 3600 +sip-force-expires = 3000 +sip-expires-max-deviation = 600; +challenge-realm = auto_from +rtp-rewrite-timestamps = true +inbound-use-callid-as-uuid = false +outbound-use-callid-as-uuid = false +context = default +record-template = /${record_file} +odbc-dsn = gemeinschaft:gemeinschaft:gemeinschaft diff --git a/misc/freeswitch/scripts/phones/phone.lua b/misc/freeswitch/scripts/phones/phone.lua new file mode 100644 index 0000000..5cd210b --- /dev/null +++ b/misc/freeswitch/scripts/phones/phone.lua @@ -0,0 +1,114 @@ +-- Gemeinschaft 5 module: phone class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +Phone = {} + +-- create phone object +function Phone.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.database = arg.database; + return object; +end + + + +-- Find a hot-deskable phone by sip-account +function Phone.find_all_hot_deskable_by_account(self, account_id) + require 'common.str' + + local sql_query = 'SELECT \ + `b`.`id`, `b`.`mac_address`, `b`.`ip_address`, `b`.`http_user`, `b`.`http_password`, `b`.`phoneable_type`, `b`.`phoneable_id`, \ + `d`.`ieee_name` \ + FROM `phone_sip_accounts` `a` \ + JOIN `phones` `b` ON `a`.`phone_id` = `b`.`id` \ + JOIN `phone_models` `c` ON `b`.`phone_model_id` = `c`.`id` \ + JOIN `manufacturers` `d` ON `c`.`manufacturer_id` = `d`.`id` \ + WHERE `b`.`hot_deskable` IS TRUE \ + AND `c`.`state` = "active" \ + AND `d`.`state` = "active" \ + AND `a`.`sip_account_id` = ' .. tonumber(account_id); + + local account_phones = {}; + + self.database:query(sql_query, function(account_entry) + local phone = Phone:new(self, {object = parent_class}); + phone.record = account_entry; + phone.record.ieee_name = common.str.downcase(account_entry.ieee_name); + + if phone.record.ieee_name == 'snom technology ag' then + require 'phones.snom' + phone.model = phones.snom.Snom:new(); + elseif account_entry.ieee_name == 'siemens enterprise communicationsgmbh & co. kg' then + require 'phones.siemens' + phone.model = phones.siemens.Siemens:new(); + end + table.insert(account_phones, phone); + end) + + return account_phones; +end + + +function Phone.find_hot_deskable_by_account(self, account_id) + return self:find_all_hot_deskable_by_account(account_id)[1]; +end + + +function Phone.tenant_id_get(self) + local sql_query = 'SELECT `c`.`sip_accountable_id` \ + FROM `phones` `a` LEFT JOIN `phone_sip_accounts` `b` ON `a`.`id` = `b`.`phone_id` \ + JOIN `sip_accounts` `c` ON `b`.`sip_account_id` = `c`.`id` AND `sip_accountable_type` = "Tenant" \ + WHERE `a`.`id` = ' .. tonumber(self.record.id) .. ' LIMIT 1'; + + local tenant_id = nil; + self.database:query(sql_query, function(tenant_entry) + tenant_id = tenant_entry.sip_accountable_id; + end) + + return tenant_id; +end + +function Phone.phoneable_set(self, phoneable_id, phoneable_type) + sql_query = 'UPDATE `phones` SET `phoneable_type` = "' .. phoneable_type ..'", `phoneable_id` = ' .. phoneable_id .. ' \ + WHERE `id` = ' .. tonumber(self.record.id); + self.database:query(sql_query); +end + +function Phone.logout(self, account_id) + local tenant_id = self:tenant_id_get(); + + if not tenant_id then + self.log:info('PHONE_LOGOUT - tenant not found'); + return false; + end + + self:phoneable_set(tenant_id, 'Tenant'); + + sql_query = 'DELETE FROM `phone_sip_accounts` WHERE `sip_account_id` = ' .. tonumber(account_id); + return self.database:query(sql_query); +end + +function Phone.login(self, account_id, owner_id, owner_type) + self:phoneable_set(owner_id, owner_type); + sql_query = 'INSERT INTO `phone_sip_accounts` (`phone_id`, `sip_account_id`, `position`, `created_at`, `updated_at`) \ + VALUES ('.. tonumber(self.record.id) .. ', '.. tonumber(account_id) .. ', 1, NOW(), NOW())'; + + return self.database:query(sql_query); +end + +function Phone.resync(self, arg) + if not self.model then + self.log:notice('PHONE_RESYNC - unsupported phone model'); + return false; + end + + arg.ip_address = arg.ip_address or self.record.ip_address; + return self.model:resync(arg); +end \ No newline at end of file diff --git a/misc/freeswitch/scripts/phones/siemens.lua b/misc/freeswitch/scripts/phones/siemens.lua new file mode 100644 index 0000000..71bb40a --- /dev/null +++ b/misc/freeswitch/scripts/phones/siemens.lua @@ -0,0 +1,45 @@ +-- Gemeinschaft 5 module: general siemens model class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +Siemens = {} + +-- create siemens object +function Siemens.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.PHONE_HTTP_PORT = 8085; + return object; +end + +-- send reload message to phone +function Siemens.resync(self, arg) + if arg.ip_address then + return self:resync_http(arg.ip_address, arg.http_user, arg.http_password, arg.http_port); + end + + return false; +end + +-- send reload message to ip +function Siemens.resync_http(self, ip_address, http_user, http_password, http_port) + local port_str = ''; + if tonumber(http_port) then + port_str = ':' .. http_port; + end + + get_command = 'wget --no-proxy -q -O /dev/null -o /dev/null -b --tries=2 --timeout=10 --user="' .. (http_user or '') .. '" --password="' .. (http_password or '') .. '"' .. + ' wget http://' .. tostring(ip_address):gsub('[^0-9%.]', '') .. ':' .. (tonumber(http_port) or self.PHONE_HTTP_PORT) .. '/contact_dls.html/ContactDLS' .. + ' 1>>/dev/null 2>>/dev/null &'; + + result = os.execute(get_command); + + if result and tonumber(result) == 0 then + return true; + end +end diff --git a/misc/freeswitch/scripts/phones/snom.lua b/misc/freeswitch/scripts/phones/snom.lua new file mode 100644 index 0000000..80d1fce --- /dev/null +++ b/misc/freeswitch/scripts/phones/snom.lua @@ -0,0 +1,65 @@ +-- Gemeinschaft 5 module: general snom model class +-- (c) AMOOMA GmbH 2012 +-- + +module(...,package.seeall) + +Snom = {} + +-- Create Snom object +function Snom.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.reboot = arg.reboot or true; + return object; +end + +-- send reload message to phone +function Snom.resync(self, arg) + if arg.reboot == nil then + arg.reboot = self.reboot; + end + + local success = nil; + if arg.auth_name and arg.domain then + success = self:resync_sip(arg.auth_name, arg.domain, arg.reboot); + end + + if arg.ip_address and arg.reboot then + success = self:resync_http(arg.ip_address, arg.http_user, arg.http_password, arg.http_port); + end + + return success; +end + +-- send reload message to sip_account +function Snom.resync_sip(self, sip_account, domain, reboot) + local event = freeswitch.Event('NOTIFY'); + event:addHeader('profile', 'gemeinschaft'); + event:addHeader('event-string', 'check-sync;reboot=' .. tostring(reboot)); + event:addHeader('user', sip_account); + event:addHeader('host', domain); + event:addHeader('content-type', 'application/simple-message-summary'); + return event:fire(); +end + +-- send reload message to ip +function Snom.resync_http(self, ip_address, http_user, http_password, http_port) + local port_str = ''; + if tonumber(http_port) then + port_str = ':' .. http_port; + end + + get_command = 'wget --no-proxy -q -O /dev/null -o /dev/null -b --tries=2 --timeout=10 --user="' .. (http_user or '') .. '" --password="' .. (http_password or '') .. '"' .. + ' wget http://' .. tostring(ip_address):gsub('[^0-9%.]', '') .. port_str .. '/advanced.htm?reboot=Reboot' .. + ' 1>>/dev/null 2>>/dev/null &'; + + result = os.execute(get_command); + + if result and tonumber(result) == 0 then + return true; + end +end diff --git a/misc/freeswitch/scripts/phones/uacsta.lua b/misc/freeswitch/scripts/phones/uacsta.lua new file mode 100644 index 0000000..61cb788 --- /dev/null +++ b/misc/freeswitch/scripts/phones/uacsta.lua @@ -0,0 +1,100 @@ +-- CommonModule: Uacsta +-- +module(...,package.seeall) + +Uacsta = {} + +-- Create Uacsta object +function Uacsta.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self) + self.__index = self + self.log = arg.log; + + return object +end + +function Uacsta.send(self, sip_account, domain, body) + local event = freeswitch.Event("NOTIFY"); + event:addHeader("profile", "gemeinschaft"); + event:addHeader("event-string", "uaCSTA"); + event:addHeader("user", sip_account); + event:addHeader("host", domain); + event:addHeader("content-type", "application/csta+xml"); + event:addBody(body); + event:fire(); +end + +function Uacsta.make_call(self, sip_account, domain, number) + local body = +[[ + + ]] .. sip_account .. [[ + ]] .. number .. [[ + doNotPrompt +]] + + self:send(sip_account, domain, body); +end + +function Uacsta.answer_call(self, sip_account, domain) + local body = +[[ + + + ]] .. sip_account .. [[ + +]] + + self:send(sip_account, domain, body); +end + +function Uacsta.set_microphone_mute(self, sip_account, domain, value) + local body = +[[ + + ]] .. sip_account .. [[ + 1 + ]] .. tostring(value) .. [[ +]] + + self:send(sip_account, domain, body); +end + +function Uacsta.set_speaker_volume(self, sip_account, domain, value) + local body = +[[ + + ]] .. sip_account .. [[ + 1 + ]] .. tonumber(value) .. [[ +]] + + self:send(sip_account, domain, body); +end + +function Uacsta.set_do_not_disturb(self, sip_account, domain, value) + local body = +[[ + + ]] .. sip_account .. [[ + ]] .. tostring(value) .. [[ +]] + + self:send(sip_account, domain, body); +end + +function Uacsta.set_forwarding(self, sip_account, domain, forwarding_type, number, activate) + local forwarding_types = { "forwardImmediate", "forwardBusy", "forwardNoAns" } + local body = +[[ + + ]] .. sip_account .. [[ + ]] .. tostring(forwarding_types[tonumber(forwarding_type)]) .. [[ + ]] .. number .. [[ + ]] .. tostring(activate) .. [[ +]] + + self:send(sip_account, domain, body); +end diff --git a/misc/freeswitch/scripts/send_fax.lua b/misc/freeswitch/scripts/send_fax.lua new file mode 100644 index 0000000..321a5b1 --- /dev/null +++ b/misc/freeswitch/scripts/send_fax.lua @@ -0,0 +1,170 @@ +-- Gemeinschaft 5.0 +-- (c) AMOOMA GmbH 2012 +-- + +local FAX_FILE_PATH = "/opt/GS5/public/uploads/fax_document/tiff/"; +local FAX_ANSWERING_TIMEOUT = 20; + +-- Set logger +require "common.log" +local log = common.log.Log:new() +log.prefix = "### [sendfax] " + +local document_id = argv[1]; + +require 'common.database' +local database = common.database.Database:new{ log = log }:connect(); + +if not database:connected() then + log:error('cannot connect to Gemeinschaft database'); + return +end + +if not tonumber(document_id) then + log:error('document id not specified'); + return +end + +local defaults = {log=log, database=database} +require "dialplan.fax" +local fax_class = dialplan.fax.Fax:new(defaults); + +local fax_document = fax_class:find_document_by_id(document_id); + +if not fax_document then + log:error('document ' .. document_id .. ' not found'); + return +end + +if tonumber(fax_document.retry_counter) > 0 then + fax_class:document_update(document_id, {state = 'sending', retry_counter = fax_document.retry_counter - 1}); +else + fax_class:document_update(document_id, {state = 'sending'}); +end + +local fax_account = fax_class:find_by_id(fax_document.fax_account_id); + +if not fax_account then + log:error('fax account ' .. fax_document.fax_account_id .. ' not found'); + return +end + +local destination_number = fax_class:destination_number(document_id); + +if not destination_number or tostring(destination_number) == '' then + log:error('destination number not found'); + return +end + +require 'common.str' +destination_number = common.str.strip(destination_number); + +log:info('FAX_SEND - fax_document=' .. document_id .. ', destination number: ' .. destination_number .. ', retries: ' .. fax_document.retry_counter); + +require "common.phone_number" +local phone_number_class = common.phone_number.PhoneNumber:new(defaults); + +phone_number = phone_number_class:find_by_number(destination_number); + +local origination_variables = { + 'gs_account_id=' .. fax_account.record.id, + 'gs_account_uuid=' .. fax_account.record.uuid, + 'gs_account_type=' .. 'faxaccount', + 'gs_auth_account_id=' .. fax_account.record.id, + 'gs_auth_account_uuid=' .. fax_account.record.uuid, + 'gs_auth_account_type=' .. 'faxaccount', +} + +local session = nil + +if phone_number then + session = freeswitch.Session("[" .. table.concat(origination_variables, ",") .. "]loopback/" .. destination_number .. "/default"); +else + local owner_class = common.str.downcase(fax_account.record.fax_accountable_type); + + local caller = {} + caller.caller_phone_numbers = phone_number_class:list_by_owner(fax_account.record.id, 'FaxAccount'); + caller.account = fax_account; + caller.auth_account = fax_account; + caller.caller_id_name = fax_account.record.station_id; + + if owner_class == 'user' then + require 'dialplan.user' + caller.auth_account.owner = dialplan.user.User:new{ log = log, database = database }:find_by_id(fax_account.record.fax_accountable_id); + if caller.auth_account.owner then + caller.auth_account.owner.groups = caller.auth_account.owner:list_groups(); + end + elseif owner_class == 'tenant' then + require 'dialplan.tenant' + caller.auth_account.owner = dialplan.tenant.Tenant:new{ log = log, database = database }:find_by_id(fax_account.record.fax_accountable_id); + end + + require 'common.configuration_file' + local routing_table = common.configuration_file.get('/opt/freeswitch/scripts/ini/routes.ini'); + require 'dialplan.route' + local routes = dialplan.route.Route:new{ log = log, database = database, routing_table = routing_table }:outbound(caller, destination_number); + + for index, route in ipairs(routes) do + log:info('FAX_SEND - ', route.class, '=', route.endpoint, ', number: ', route.value); + if route.class == 'gateway' then + table.insert(origination_variables, "origination_caller_id_number='" .. (route.caller_id_number or caller.caller_phone_numbers[1]) .. "'"); + table.insert(origination_variables, "origination_caller_id_name='" .. (route.caller_id_name or fax_account.record.station_id) .. "'"); + session = freeswitch.Session('[' .. table.concat(origination_variables, ',') .. ']sofia/gateway/' .. route.endpoint .. '/' .. route.value); + break; + end + end +end + +local loop_count = FAX_ANSWERING_TIMEOUT; +local cause = "UNSPECIFIED" + +while session and session:ready() and not session:answered() and loop_count >= 0 do + log:debug('waiting for answer: ' .. loop_count) + loop_count = loop_count - 1; + freeswitch.msleep(1000); +end + +if session and session:answered() then + log:info('FAX_SEND - sending fax_document=' .. fax_document.id .. ' (' .. fax_document.tiff .. ')'); + + local file_name = FAX_FILE_PATH .. fax_document.id .. "/" .. fax_document.tiff; + + session:setVariable('fax_ident', fax_account.record.station_id) + session:setVariable('fax_header', fax_account.record.name) + session:setVariable('fax_verbose', 'false') + local start_time = os.time(); + session:execute('txfax', file_name); + + fax_state = { + state = nil, + transmission_time = os.time() - start_time, + document_total_pages = common.str.to_i(session:getVariable('fax_document_total_pages')), + document_transferred_pages = common.str.to_i(session:getVariable('fax_document_transferred_pages')), + ecm_requested = common.str.to_b(session:getVariable('fax_ecm_requested')), + ecm_used = common.str.to_b(session:getVariable('fax_ecm_used')), + image_resolution = common.str.to_s(session:getVariable('fax_image_resolution')), + image_size = common.str.to_i(session:getVariable('fax_image_size')), + local_station_id = common.str.to_s(session:getVariable('fax_local_station_id')), + result_code = common.str.to_i(session:getVariable('fax_result_code')), + remote_station_id = common.str.to_s(session:getVariable('fax_remote_station_id')), + success = common.str.to_b(session:getVariable('fax_success')), + transfer_rate = common.str.to_i(session:getVariable('fax_transfer_rate')), + } + + if fax_state.success then + fax_state.state = 'successful'; + else + fax_state.state = 'unsuccessful'; + end + + fax_account:document_update(fax_document.id, fax_state) + + cause = session:hangupCause(); + log:info('FAX_SEND - end - fax_document=', fax_document.id, ', success: ', fax_state.state, ', cause: ', cause, ', result: ', fax_state.result_code, ' ', session:getVariable('fax_result_text')); +else + if session then + cause = session:hangupCause(); + end + log:debug('Destination "', destination_number, '" could not be reached, cause: ', cause) + fax_account:document_update(fax_document.id, {state = 'unsuccessful', result_code = "129"}) +end diff --git a/misc/mon_ami/asterisk.py b/misc/mon_ami/asterisk.py new file mode 100644 index 0000000..ffcff06 --- /dev/null +++ b/misc/mon_ami/asterisk.py @@ -0,0 +1,299 @@ +# -*- coding: utf-8 -*- +# MonAMI Asterisk Manger Interface Server +# Asterisk AMI client connector +# (c) AMOOMA GmbH 2012 + +from threading import Thread, Lock +from log import ldebug, linfo, lwarn, lerror, lcritic +from time import sleep +from traceback import format_exc +from helper import to_hash +import socket + +class AsteriskAMIServer(Thread): + + def __init__(self, client_socket, address, message_queue): + Thread.__init__(self) + self.runthread = True + self.LINE_SEPARATOR = "\r\n" + self.GREETING_STRING = 'Asterisk Call Manager/1.1' + self.ASTERISK_VERSION_STRING = 'Asterisk 1.6.2.9-2' + self.ASTERISK_CHANNEL_STATES = ( + 'Down', + 'Reserved', + 'Offhook', + 'Dialing', + 'Ring', + 'Ringing', + 'Up', + 'Busy', + 'Dialing_Offhook', + 'Pprering', + 'Mute', + ) + self.ASTERISK_PRESENTATION_INDICATOR = ( + 'Presentation allowed', + 'Presentation restricted', + 'Number not available due to interworking', + 'Reserved', + ) + self.ASTERISK_SCREENING_INDICATOR = ( + 'not screened', + 'verified and passed', + 'verified and failed', + 'Network provided', + ) + + self.write_lock = Lock() + self.socket = client_socket + self.address = address + self.message_queue = message_queue + + + def stop(self): + ldebug('thread stop', self) + self.runthread = False + + + def run(self): + ldebug('starting AMI server thread', self) + + data = '' + while self.runthread and self.socket: + try: + recv_buffer = self.socket.recv(128) + except socket.timeout as exception: + # Socket timeout occured + continue + except: + lerror(format_exc(), self) + self.runthread = False + break + + if not recv_buffer: + ldebug('client connection lost', self) + break + + data += recv_buffer + messages = data.split(self.LINE_SEPARATOR * 2) + data = messages.pop() + + for message_str in messages: + if not message_str: + continue + + message = to_hash(message_str.split(self.LINE_SEPARATOR)) + self.message_queue.appendleft({'type': 'ami_client_message', 'body': message}) + + ldebug('exiting AMI server thread', self) + + + def send(self, send_buffer): + try: + self.write_lock.acquire() + self.socket.send(send_buffer) + self.write_lock.release() + return True + except: + return False + + + def send_message(self, *message): + if len(message) == 1 and type(message[0]) == list: + self.send(self.LINE_SEPARATOR.join(message[0]) + (self.LINE_SEPARATOR * 2)) + else: + self.send(self.LINE_SEPARATOR.join(message) + (self.LINE_SEPARATOR * 2)) + + def send_greeting(self): + self.send_message(self.GREETING_STRING) + + def send_message_unknown(self, command): + self.send_message('Response: Error', 'Message: Invalid/unknown command: %s.' % command) + + def send_login_ack(self): + self.send_message('Response: Success', 'Message: Authentication accepted') + + def send_login_nack(self): + self.send_message('Response: Error', 'Message: Authentication failed') + + def send_logout_ack(self): + self.send_message('Response: Goodbye', 'Message: Thank you for flying MonAMI') + + def send_pong(self, action_id): + self.send_message('Response: Pong', "ActionID: %s" % str(action_id), 'Server: localhost') + + def send_asterisk_version(self, action_id): + self.send_message( + 'Response: Follows', + 'Privilege: Command', + "ActionID: %s" % str(action_id), + self.ASTERISK_VERSION_STRING, + '--END COMMAND--' + ) + + def send_hangup_ack(self): + self.send_message('Response: Success', 'Message: Channel Hungup') + + + def send_originate_ack(self, action_id): + self.send_message('Response: Success', "ActionID: %s" % str(action_id), 'Message: Originate successfully queued') + + + def send_status_ack(self, action_id): + self.send_message( + 'Response: Success', + "ActionID: %s" % str(action_id), + 'Message: Channel status will follow' + ) + self.send_message( + 'Event: StatusComplete', + "ActionID: %s" % action_id, + 'Items: 0' + ) + + def send_extension_state(self, action_id, extension, context = 'default', status = -1, hint = ''): + self.send_message( + 'Response: Success', + "ActionID: %s" % str(action_id), + 'Message: Extension Status', + 'Exten: %s' % extension, + 'Context: %s' % context, + 'Hint: %s' % hint, + 'Status: %d' % status, + ) + + + def send_event_newchannel(self, uuid, channel_name, channel_state, caller_id_number = '', caller_id_name = '', destination_number = ''): + self.send_message( + 'Event: Newchannel', + 'Privilege: call,all', + 'Channel: %s' % str(channel_name), + 'ChannelState: %d' % channel_state, + 'ChannelStateDesc: %s' % self.ASTERISK_CHANNEL_STATES[channel_state], + 'CallerIDNum: %s' % str(caller_id_number), + 'CallerIDName: %s' % str(caller_id_name), + 'AccountCode:', + 'Exten: %s' % str(destination_number), + 'Context: default', + 'Uniqueid: %s' % str(uuid), + ) + + + def send_event_newstate(self, uuid, channel_name, channel_state, caller_id_number = '', caller_id_name = ''): + self.send_message( + 'Event: Newstate', + 'Privilege: call,all', + 'Channel: %s' % str(channel_name), + 'ChannelState: %d' % channel_state, + 'ChannelStateDesc: %s' % self.ASTERISK_CHANNEL_STATES[channel_state], + 'CallerIDNum: %s' % str(caller_id_number), + 'CallerIDName: %s' % str(caller_id_name), + 'Uniqueid: %s' % str(uuid), + ) + + + def send_event_newcallerid(self, uuid, channel_name, caller_id_number = '', caller_id_name = '', calling_pres = 0): + + presentation = self.ASTERISK_PRESENTATION_INDICATOR[calling_pres >> 6] + screening = self.ASTERISK_SCREENING_INDICATOR[calling_pres & 3] + + self.send_message( + 'Event: NewCallerid', + 'Privilege: call,all', + 'Channel: %s' % str(channel_name), + 'CallerIDNum: %s' % str(caller_id_number), + 'CallerIDName: %s' % str(caller_id_name), + 'Uniqueid: %s' % str(uuid), + 'CID-CallingPres: %d (%s, %s)' % (calling_pres, presentation, screening), + ) + + + def send_event_hangup(self, uuid, channel_name, caller_id_number = '', caller_id_name = '', cause = 0): + self.send_message( + 'Event: Hangup', + 'Privilege: call,all', + 'Channel: %s' % str(channel_name), + 'CallerIDNum: %s' % str(caller_id_number), + 'CallerIDName: %s' % str(caller_id_name), + 'Cause: %d' % cause, + 'Cause-txt: Unknown', + 'Uniqueid: %s' % str(uuid) + ) + + + def send_event_dial_begin(self, uuid, channel_name, caller_id_number, caller_id_name, destination_channel, destination_uuid, destination_number): + self.send_message( + 'Event: Dial', + 'Privilege: call,all', + 'SubEvent: Begin', + "Channel: %s" % str(channel_name), + "Destination: %s" % str(destination_channel), + 'CallerIDNum: %s' % str(caller_id_number), + 'CallerIDName: %s' % str(caller_id_name), + 'Uniqueid: %s' % str(uuid), + 'DestUniqueid: %s' % str(destination_uuid), + 'Dialstring: %s@default' % str(destination_number) + ) + + + def send_event_dial_end(self, uuid, channel_name, dial_status = 'UNKNOWN'): + self.send_message( + 'Event: Dial', + 'Privilege: call,all', + 'SubEvent: End', + "Channel: %s" % str(channel_name), + 'Uniqueid: %s' % str(uuid), + "DialStatus: %s" % str(dial_status), + ) + + + def send_event_originate_response(self, uuid, channel_name, caller_id_number, caller_id_name, destination_number, action_id, reason): + #reasons: + #0: no such extension or number + #1: no answer + #4: answered + #8: congested or not available + + if reason == 4: + response = 'Success' + else: + response = 'Failure' + + self.send_message( + 'Event: OriginateResponse', + 'Privilege: call,all', + 'ActionID: %s' % str(action_id), + 'Response: %s' % response, + 'Channel: %s' % str(channel_name), + 'Context: default', + 'Exten: %s' % str(destination_number), + 'Reason: %d' % reason, + 'CallerIDNum: %s' % str(caller_id_number), + 'CallerIDName: %s' % str(caller_id_name), + 'Uniqueid: %s' % str(uuid), + ) + + + def send_event_bridge(self, uuid, channel_name, caller_id, o_uuid, o_channel_name, o_caller_id): + self.send_message( + 'Event: Bridge', + 'Privilege: call,all', + 'Bridgestate: Link', + 'Bridgetype: core', + 'Channel1: %s' % str(channel_name), + 'Channel2: %s' % str(o_channel_name), + 'Uniqueid1: %s' % str(uuid), + 'Uniqueid2: %s' % str(o_uuid), + 'CallerID1: %s' % str(caller_id), + 'CallerID2: %s' % str(o_caller_id), + ) + + def send_event_newaccountcode(self, uuid, channel_name): + self.send_message( + 'Event: NewAccountCode', + 'Privilege: call,all', + "Channel: %s" % str(channel_name), + 'Uniqueid: %s' % str(uuid), + 'AccountCode:', + 'OldAccountCode:', + ) diff --git a/misc/mon_ami/freeswitch.py b/misc/mon_ami/freeswitch.py new file mode 100644 index 0000000..eab9bb6 --- /dev/null +++ b/misc/mon_ami/freeswitch.py @@ -0,0 +1,194 @@ +# -*- coding: utf-8 -*- +# MonAMI Asterisk Manger Interface server +# FreeSWITCH event socket interface +# (c) AMOOMA GmbH 2012 + +from threading import Thread, Lock +from log import ldebug, linfo, lwarn, lerror, lcritic +from collections import deque +from time import sleep, time +from random import random +from helper import to_hash +from traceback import format_exc +import socket +import sys +import hashlib + + +class FreeswitchEventSocket(Thread): + + def __init__(self, host, port, password): + Thread.__init__(self) + self.LINE_SEPARATOR = "\n" + self.SOCKET_TIMEOUT = 1 + self.MESSAGE_PIPE_MAX_LENGTH = 128 + self.write_lock = Lock() + self.host = host + self.port = port + self.password = password + self.runthread = True + self.fs = None + self.client_queues = {} + + + def stop(self): + ldebug('thread stop', self) + self.runthread = False + + + def run(self): + ldebug('starting FreeSWITCH event_socket thread', self) + + while self.runthread: + if not self.connect(): + ldebug('could not connect to FreeSWITCH - retry', self) + sleep(self.SOCKET_TIMEOUT) + continue + ldebug('opening event_socket connection', self) + + data = '' + while self.runthread and self.fs: + + try: + recv_buffer = self.fs.recv(128) + except socket.timeout as exception: + # Socket timeout occured + continue + except: + lerror(format_exc(), self) + self.runthread = False + break + + if not recv_buffer: + ldebug('event_socket connection lost', self) + break + + data += recv_buffer + messages = data.split(self.LINE_SEPARATOR * 2) + data = messages.pop() + + for message_str in messages: + if not message_str: + continue + message_body = None + + message = to_hash(message_str.split(self.LINE_SEPARATOR)) + + if not 'Content-Type' in message: + ldebug('message without Content-Type', self) + continue + + if 'Content-Length' in message and int(message['Content-Length']) > 0: + content_length = int(message['Content-Length']) + while len(data) < int(message['Content-Length']): + try: + data += self.fs.recv(content_length - len(data)) + except socket.timeout as exception: + ldebug('Socket timeout in message body', self) + continue + except: + lerror(format_exc(), self) + break + message_body = data.strip() + data = '' + else: + content_length = 0 + + self.process_message(message['Content-Type'], message, content_length, message_body) + + + ldebug('closing event_socket connection', self) + if self.fs: + self.fs.close() + + + def connect(self): + fs = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + fs.connect((self.host, self.port)) + except: + lerror(format_exc(), self) + return False + + fs.settimeout(self.SOCKET_TIMEOUT) + self.fs = fs + return True + + + def authenticate(self): + ldebug('send authentication to FreeSWITCH', self) + self.send_message("auth %s" % self.password) + + + def send(self, send_buffer): + try: + self.write_lock.acquire() + self.fs.send(send_buffer) + self.write_lock.release() + return True + except: + return False + + + def send_message(self, *message): + if len(message) == 1 and type(message[0]) == list: + self.send(self.LINE_SEPARATOR.join(message[0]) + (self.LINE_SEPARATOR * 2)) + else: + self.send(self.LINE_SEPARATOR.join(message) + (self.LINE_SEPARATOR * 2)) + + + def process_message(self, content_type, message_head, content_length, message_body): + + if content_type == 'auth/request': + self.authenticate() + if content_type == 'command/reply': + if 'Reply-Text' in message_head: + ldebug('FreeSWITCH command reply: %s' % message_head['Reply-Text'], self) + elif content_type == 'text/event-plain': + event = to_hash(message_body.split(self.LINE_SEPARATOR)) + + if 'Event-Name' in event and event['Event-Name'] in self.client_queues: + event_type = event['Event-Name'] + for entry_id, message_pipe in self.client_queues[event_type].items(): + if type(message_pipe) == deque: + if len(message_pipe) < self.MESSAGE_PIPE_MAX_LENGTH: + message_pipe.appendleft({'type': 'freeswitch_event', 'body': event}) + else: + lwarn("event queue %d full" % entry_id) + else: + ldebug("force-deregister event queue %d for event type %s" % (entry_id, event_type), self) + del self.client_queues[event_type][entry_id] + + def register_client_queue(self, queue, event_type): + if not event_type in self.client_queues: + self.client_queues[event_type] = {} + self.send_message("event plain all %s" % event_type) + ldebug("we are listening now to events of type: %s" % event_type, self) + self.client_queues[event_type][id(queue)] = queue + ldebug("event queue %d registered for event type: %s" % (id(queue), event_type), self) + + + def deregister_client_queue(self, queue, event_type): + ldebug("deregister event queue %d for event type %s" % (id(queue), event_type), self) + del self.client_queues[event_type][id(queue)] + + def deregister_client_queue_all(self, queue): + for event_type, event_queues in self.client_queues.items(): + if id(queue) in event_queues: + ldebug("deregister event queue %d for all registered event types - event type %s" % (id(queue), event_type), self) + del self.client_queues[event_type][id(queue)] + + + def hangup(self, uuid, hangup_cause = 'NORMAL_CLEARING'): + ldebug('hangup channel: %s' % uuid, self) + self.send_message('SendMsg %s' % uuid, 'call-command: hangup', 'hangup-cause: %s' % hangup_cause) + + return True + + + def originate(self, sip_account, extension, action_id = ''): + uuid = hashlib.md5('%s%f' % (sip_account, random() * 65534)).hexdigest() + ldebug('originate call - from: %s, to: %s, uuid: %s' % (sip_account, extension, uuid), self) + self.send_message('bgapi originate {origination_uuid=%s,origination_action=%s,origination_caller_id_number=%s}user/%s %s' % (uuid, action_id, sip_account, sip_account, extension)) + + return uuid diff --git a/misc/mon_ami/helper.py b/misc/mon_ami/helper.py new file mode 100644 index 0000000..bf286de --- /dev/null +++ b/misc/mon_ami/helper.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# MonAMI Asterisk Manger Interface server +# helper functions +# (c) AMOOMA GmbH 2012 + + +def to_hash(message): + message_hash = {} + for line in message: + keyword, delimeter, value = line.partition(": ") + if (keyword): + message_hash[keyword] = value.strip() + + return message_hash + + +def sval(array, key): + try: + return array[key] + except: + return None diff --git a/misc/mon_ami/log.py b/misc/mon_ami/log.py new file mode 100644 index 0000000..92709ad --- /dev/null +++ b/misc/mon_ami/log.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +# Log library +# (c) AMOOMA GmbH 2012 + +import logging + +def ldebug(entry, initiator = None): + global logger + logger.debug('%s(%d) %s' % (type(initiator).__name__, id(initiator), entry)) + +def lwarn(entry, initiator = None): + global logger + logger.warning('%s(%d) %s' % (type(initiator).__name__, id(initiator), entry)) + +def lerror(entry, initiator = None): + global logger + logger.error('%s(%d) %s' % (type(initiator).__name__, id(initiator), entry)) + +def linfo(entry, initiator = None): + global logger + logger.info('%s(%d) %s' % (type(initiator).__name__, id(initiator), entry)) + +def lcritic(entry, initiator = None): + global logger + logger.critical('%s(%d) %s' % (type(initiator).__name__, id(initiator), entry)) + +def setup_log(file_name = None, loglevel = 5, logformat = None): + from sys import stdout + global logger + + if file_name: + try: + logfile = logging.FileHandler(file_name) + except: + logfile = logging.StreamHandler(stdout) + else: logfile = logging.StreamHandler(stdout) + + loglevel = int(loglevel) + + if (loglevel == 0): + logfile.setLevel(logging.NOTSET) + logger.setLevel(logging.NOTSET) + elif (loglevel == 1): + logfile.setLevel(logging.CRITICAL) + logger.setLevel(logging.CRITICAL) + elif (loglevel == 2): + logfile.setLevel(logging.ERROR) + logger.setLevel(logging.ERROR) + elif (loglevel == 3): + logfile.setLevel(logging.WARNING) + logger.setLevel(logging.WARNING) + elif (loglevel == 4): + logfile.setLevel(logging.INFO) + logger.setLevel(logging.INFO) + elif (loglevel >= 5): + logfile.setLevel(logging.DEBUG) + logger.setLevel(logging.DEBUG) + + if not logformat: + logformat = '%(asctime)s-%(name)s-%(levelname)s-%(message)s' + + try: + format = logging.Formatter(logformat) + logfile.setFormatter(format) + except: + format = logging.Formatter('%(asctime)s-%(name)s-%(levelname)s-%(message)s') + logfile.setFormatter(format) + + logger.addHandler(logfile) + +logger = logging.getLogger('#') diff --git a/misc/mon_ami/mon-ami b/misc/mon_ami/mon-ami new file mode 100755 index 0000000..a630140 --- /dev/null +++ b/misc/mon_ami/mon-ami @@ -0,0 +1,58 @@ +#!/bin/sh + +##################################################################### +# MonAMI Asterisk Manger Interface Emulator +# Start Script +# (c) AMOOMA GmbH 2012 +##################################################################### + +### BEGIN INIT INFO +# Provides: mon_ami +# Required-Start: freeswitch +# Required-Stop: freeswitch +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: MonAMI Asterisk Manger Interface Emulator +# Description: +# +### END INIT INFO + +DAEMON=/opt/GS5/misc/mon_ami/mon_ami +EXECUTABLE=`basename 'mon_ami'` +DESC="MonAMI Asterisk Manger Interface Emulator" +ARGS="--log-file=/var/log/mon_ami.log" + +if ! [ -x $DAEMON ] ; then + echo "ERROR: $DAEMON not found" + exit 1 +fi + +case "$1" in + start) + echo -n "Starting $DESC: " + start-stop-daemon --start --pidfile /var/run/$EXECUTABLE.pid \ + --make-pidfile --background --startas $DAEMON -- $ARGS + echo "$EXECUTABLE." + ;; + + stop) + echo -n "Stopping $DESC: " + start-stop-daemon --stop --quiet --oknodo --retry=TERM/30/KILL/5 \ + --pidfile /var/run/$EXECUTABLE.pid + rm -f /var/run/$NAME.pid + echo "$EXECUTABLE." + ;; + + reload|restart|force-reload) + $0 stop + sleep 2 + $0 start + ;; + + *) + echo "Usage: $0 {start|stop|restart|reload|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/misc/mon_ami/mon_ami b/misc/mon_ami/mon_ami new file mode 100755 index 0000000..a212cfe --- /dev/null +++ b/misc/mon_ami/mon_ami @@ -0,0 +1,10 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +# MonAMI Asterisk Manger Interface Server +# (c) AMOOMA GmbH 2012 +from mon_ami_main import main +from sys import exit + +if (__name__ == "__main__"): + result = main() + exit(result) diff --git a/misc/mon_ami/mon_ami_handler.py b/misc/mon_ami/mon_ami_handler.py new file mode 100644 index 0000000..59e9225 --- /dev/null +++ b/misc/mon_ami/mon_ami_handler.py @@ -0,0 +1,434 @@ +# -*- coding: utf-8 -*- +# MonAMI Asterisk Manger Interface Server +# Asterisk AMI Emulator Handler Process +# (c) AMOOMA GmbH 2012 + +from threading import Thread +from log import ldebug, linfo, lwarn, lerror, lcritic +from time import sleep +from traceback import format_exc +from collections import deque +from urllib import unquote +from asterisk import AsteriskAMIServer +from socket import SHUT_RDWR +from helper import sval + + +class MonAMIHandler(Thread): + + def __init__(self, socket, address, event_socket=None): + Thread.__init__(self) + self.runthread = True + self.socket = socket + self.address = address + self.event_socket = event_socket + self.ami = None + self.deregister_at_server = None + self.message_pipe = deque() + self.channels = {} + self.user_password_authentication = None + self.account_name = '' + + + def stop(self): + ldebug('thread stop', self) + self.ami.stop() + self.runthread = False + + + def shutdown(self): + self.deregister_at_server(self) + ldebug('closing connection to %s:%d' % self.address) + try: + self.socket.shutdown(SHUT_RDWR) + self.socket.close() + ldebug('connection closed ', self) + except: + ldebug('connection closed by foreign host', self) + + def run(self): + ldebug('starting MonAMI handler thread', self) + + # starting asterisk AMI thread + self.ami = AsteriskAMIServer(self.socket, self.address, self.message_pipe) + self.ami.start() + self.ami.send_greeting() + + # register for events + self.event_socket.register_client_queue(self.message_pipe, 'CHANNEL_CREATE') + self.event_socket.register_client_queue(self.message_pipe, 'CHANNEL_DESTROY') + self.event_socket.register_client_queue(self.message_pipe, 'CHANNEL_STATE') + self.event_socket.register_client_queue(self.message_pipe, 'CHANNEL_ANSWER') + self.event_socket.register_client_queue(self.message_pipe, 'CHANNEL_BRIDGE') + + while self.runthread and self.ami.isAlive(): + if self.message_pipe: + message = self.message_pipe.pop() + message_type = sval(message, 'type') + if message_type == 'freeswitch_event': + self.handle_fs_event(message['body']) + elif message_type == 'ami_client_message': + self.handle_ami_client_message(message['body']) + else: + sleep(0.1) + + self.event_socket.deregister_client_queue_all(self.message_pipe) + + ldebug('exiting MonAMI handler thread', self) + self.shutdown() + + + def handle_ami_client_message(self, message): + + if 'Action' in message: + action = message['Action'].lower() + + if action == 'login': + if 'UserName' in message: + self.account_name = message['UserName'] + if 'Secret' in message and self.user_password_authentication and self.user_password_authentication(self.account_name, message['Secret']): + self.ami.send_login_ack() + ldebug('AMI connection authenticated - account: %s' % self.account_name, self) + else: + self.ami.send_login_nack() + linfo('AMI authentication failed - account: %s' % sval(message, 'UserName'), self) + self.ami.stop() + self.stop() + elif action == 'logoff': + self.ami.send_logout_ack() + ldebug('AMI logout', self) + self.ami.stop() + self.stop() + elif action == 'ping': + self.ami.send_pong(sval(message, 'ActionID')) + elif action == 'status': + self.ami.send_status_ack(sval(message, 'ActionID')) + elif action == 'command' and sval(message, 'Command') == 'core show version': + self.ami.send_asterisk_version(sval(message, 'ActionID')) + elif action == 'hangup': + account_name, separator, uuid = str(sval(message, 'Channel')).rpartition('-uuid-') + if account_name != '': + self.event_socket.hangup(uuid) + self.ami.send_hangup_ack() + elif action == 'originate': + self.message_originate(message) + elif action == 'extensionstate': + self.ami.send_extension_state(sval(message, 'ActionID'), sval(message, 'Exten'), sval(message, 'Context')) + else: + ldebug('unknown asterisk message received: %s' % message, self) + self.ami.send_message_unknown(message['Action']) + + + def to_unique_channel_name(self, uuid, channel_name): + + # strip anything left of sip_account_name + path, separator, contact_part = channel_name.rpartition('/sip:') + if path == '': + path, separator, contact_part = channel_name.rpartition('/') + + # if failed return name unchanged + if path == '': + return channel_name + + + # strip domain part + account_name = contact_part.partition('@')[0] + + # if failed return name unchanged + if account_name == '': + return channel_name + + # create unique channel name + return 'SIP/%s-uuid-%s' % (account_name, uuid) + + def message_originate(self, message): + destination_number = str(sval(message, 'Exten')) + action_id = sval(message, 'ActionID') + self.ami.send_originate_ack(action_id) + uuid = self.event_socket.originate(self.account_name, destination_number, action_id) + + + def handle_fs_event(self, event): + event_type = event['Event-Name'] + #ldebug('event type received: %s' % event_type, self) + + event_types = { + 'CHANNEL_CREATE': self.event_channel_create, + 'CHANNEL_DESTROY': self.event_channel_destroy, + 'CHANNEL_STATE': self.event_channel_state, + 'CHANNEL_ANSWER': self.event_channel_answer, + 'CHANNEL_BRIDGE': self.event_channel_bridge, + } + + uuid = event_types[event_type](event) + + if not uuid: + return False + + channel = sval(self.channels, uuid); + + if not channel: + return False + + o_uuid = channel['o_uuid'] + o_channel = sval(self.channels, o_uuid); + + if sval(channel, 'origination_action') or sval(o_channel, 'origination_action'): + if not sval(channel, 'ami_start') and not sval(o_channel, 'ami_start'): + if sval(channel, 'owned') and sval(channel, 'origination_action'): + ldebug('sending AMI events for origitate call start (on this channel): %s' % uuid, self) + self.ami_send_originate_start(channel) + self.channels[uuid]['ami_start'] = True + elif sval(o_channel, 'owned') and sval(o_channel, 'origination_action'): + ldebug('sending AMI events for origitate call start (on other channel): %s' % uuid, self) + self.ami_send_originate_start(o_channel) + self.channels[o_uuid]['ami_start'] = True + elif o_channel: + if sval(channel, 'owned') and sval(channel, 'origination_action'): + ldebug('sending AMI events for origitate call progress (on this channel): %s' % uuid, self) + self.ami_send_originate_outbound(channel) + self.channels[uuid]['origination_action'] = False + elif sval(o_channel, 'owned') and sval(o_channel, 'origination_action'): + ldebug('sending AMI events for origitate call progress (on other channel): %s' % uuid, self) + self.ami_send_originate_outbound(o_channel) + self.channels[o_uuid]['origination_action'] = False + elif o_channel: + if not sval(channel, 'ami_start') and not sval(o_channel, 'ami_start'): + if sval(channel, 'owned') and sval(channel, 'direction') == 'inbound': + ldebug('sending AMI events for outbound call start (on this channel): %s' % uuid, self) + self.ami_send_outbound_start(channel) + self.channels[uuid]['ami_start'] = True + elif sval(o_channel, 'owned') and sval(channel, 'direction') == 'outbound': + ldebug('sending AMI events for outbound call start (on other channel): %s' % uuid, self) + self.ami_send_outbound_start(o_channel) + self.channels[o_uuid]['ami_start'] = True + + if not sval(channel, 'ami_start')and not sval(o_channel, 'ami_start'): + if sval(channel, 'owned') and sval(channel, 'direction') == 'outbound': + ldebug('sending AMI events for inbound call start (on this channel): %s' % uuid, self) + self.ami_send_inbound_start(channel) + self.channels[uuid]['ami_start'] = True + elif sval(o_channel, 'owned') and sval(channel, 'direction') == 'inbound': + ldebug('sending AMI events for inbound call start (on other channel): %s' % uuid, self) + self.ami_send_inbound_start(o_channel) + self.channels[o_uuid]['ami_start'] = True + + + def event_channel_create(self, event): + uuid = sval(event, 'Unique-ID') + o_uuid = sval(event, 'Other-Leg-Unique-ID') + + if uuid in self.channels: + ldebug('channel already listed: %s' % uuid, self) + return false + + channel_name = self.to_unique_channel_name(uuid, unquote(str(sval(event, 'Channel-Name')))) + o_channel_name = self.to_unique_channel_name(o_uuid, unquote(str(sval(event, 'Other-Leg-Channel-Name')))) + + if self.account_name in channel_name: + channel_owned = True + else: + channel_owned = False + + if self.account_name in o_channel_name: + channel_related = True + else: + channel_related = False + + if not channel_owned and not channel_related: + ldebug('channel neither owned nor reladed to account: %s' % uuid, self) + return False + + channel = { + 'uuid': uuid, + 'name': channel_name, + 'direction': sval(event, 'Call-Direction'), + 'channel_state': sval(event, 'Channel-State'), + 'call_state': sval(event, 'Channel-Call-State'), + 'answer_state': sval(event, 'Answer-State'), + 'owned': channel_owned, + 'related': channel_related, + 'caller_id_name': unquote(str(sval(event, 'Caller-Caller-ID-Name'))), + 'caller_id_number': unquote(str(sval(event, 'Caller-Caller-ID-Number'))), + 'callee_id_name': unquote(str(sval(event, 'Caller-Callee-ID-Name'))), + 'callee_id_number': unquote(str(sval(event, 'Caller-Callee-ID-Number'))), + 'destination_number': str(sval(event, 'Caller-Destination-Number')), + 'origination_action': sval(event, 'variable_origination_action'), + 'o_uuid': o_uuid, + 'o_name': o_channel_name, + } + + if channel['answer_state'] == 'ringing': + if channel['direction'] == 'inbound': + asterisk_channel_state = 4 + else: + asterisk_channel_state = 5 + else: + asterisk_channel_state = 0 + + if not o_uuid: + ldebug('one legged call, channel: %s' % uuid, self) + elif o_uuid not in self.channels: + o_channel = { + 'uuid': o_uuid, + 'name': o_channel_name, + 'direction': sval(event, 'Other-Leg-Direction'), + 'channel_state': sval(event, 'Channel-State'), + 'call_state': sval(event, 'Channel-Call-State'), + 'answer_state': sval(event, 'Answer-State'), + 'owned': channel_related, + 'related': channel_owned, + 'caller_id_name': unquote(str(sval(event, 'Caller-Caller-ID-Name'))), + 'caller_id_number': unquote(str(sval(event, 'Caller-Caller-ID-Number'))), + 'callee_id_name': unquote(str(sval(event, 'Caller-Callee-ID-Name'))), + 'callee_id_number': unquote(str(sval(event, 'Caller-Callee-ID-Number'))), + 'destination_number': str(sval(event, 'Other-Leg-Destination-Number')), + 'o_uuid': uuid, + 'o_name': channel_name, + } + + if o_channel['answer_state'] == 'ringing': + if o_channel['direction'] == 'inbound': + asterisk_o_channel_state = 4 + else: + asterisk_o_channel_state = 5 + else: + asterisk_o_channel_state = 0 + + ldebug('create channel list entry for related channel: %s, name: %s' % (o_uuid, o_channel_name), self) + self.channels[o_uuid] = o_channel + else: + ldebug('updating channel: %s, name: %s, o_uuid: %s, o_name %s' % (o_uuid, o_channel_name, uuid, channel_name), self) + self.channels[o_uuid]['o_uuid'] = uuid + self.channels[o_uuid]['o_name'] = channel_name + o_channel = self.channels[o_uuid] + + if channel_owned: + ldebug('create channel list entry for own channel: %s, name: %s' % (uuid, channel_name), self) + elif channel_related: + ldebug('create channel list entry for related channel: %s, name: %s' % (uuid, channel_name), self) + + self.channels[uuid] = channel + + return uuid + + + def event_channel_destroy(self, event): + uuid = sval(event, 'Unique-ID') + hangup_cause_code = int(sval(event, 'variable_hangup_cause_q850')) + channel = sval(self.channels, uuid) + + if channel: + channel['hangup_cause_code'] = hangup_cause_code + if sval(channel, 'ami_start'): + self.ami_send_outbound_end(channel) + del self.channels[uuid] + ldebug('channel removed from list: %s, cause %d' % (uuid, hangup_cause_code), self) + + return uuid + + + def event_channel_state(self, event): + uuid = sval(event, 'Unique-ID') + channel_state = sval(event, 'Channel-State') + call_state = sval(event, 'Channel-Call-State') + answer_state = sval(event, 'Answer-State') + + if sval(self.channels, uuid) and False: + ldebug('updating channel state - channel: %s, channel_state: %s, call_state %s, answer_state: %s' % (uuid, channel_state, call_state, answer_state), self) + self.channels[uuid]['channel_state'] = channel_state + self.channels[uuid]['call_state'] = call_state + self.channels[uuid]['answer_state'] = answer_state + + return uuid + + + def event_channel_answer(self, event): + uuid = sval(event, 'Unique-ID') + o_uuid = sval(event, 'Other-Leg-Unique-ID') + channel = sval(self.channels, uuid) + if not o_uuid: + o_uuid = sval(channel, 'o_uuid') + o_channel = sval(self.channels, o_uuid) + origination_action = sval(channel, 'origination_action') + + if channel: + channel_state = sval(event, 'Channel-State') + call_state = sval(event, 'Channel-Call-State') + answer_state = sval(event, 'Answer-State') + ldebug('channel answered - channel: %s, owned: %s, channel_state: %s, call_state %s, answer_state: %s, other leg: %s' % (uuid, sval(channel, 'owned'), channel_state, call_state, answer_state, o_uuid), self) + self.ami.send_event_newstate(uuid, sval(channel, 'name'), 6, sval(channel, 'caller_id_number'), sval(channel, 'caller_id_name')) + + self.channels[uuid]['channel_state'] = channel_state + self.channels[uuid]['call_state'] = call_state + self.channels[uuid]['answer_state'] = answer_state + + if sval(channel, 'origination_action'): + if sval(channel, 'owned'): + ldebug('sending AMI originate response - success: %s' % uuid, self) + self.ami.send_event_originate_response(sval(channel, 'uuid'), sval(channel, 'name'), sval(channel, 'caller_id_number'), sval(channel, 'caller_id_name'), '101', sval(channel, 'origination_action'), 4) + elif not o_uuid: + ldebug('sending AMI events for outbound call start on one legged call (this channel): %s' % uuid, self) + self.ami_send_outbound_start(channel) + self.ami.send_event_bridge(uuid, sval(channel, 'name'), sval(channel, 'caller_id_number'), o_uuid, sval(o_channel, 'name'), sval(o_channel, 'caller_id_number')) + + self.channels[uuid]['ami_start'] = True + + return uuid + + return False + + + def event_channel_bridge(self, event): + uuid = sval(event, 'Unique-ID') + o_uuid = sval(event, 'Other-Leg-Unique-ID') + + ldebug('bridge channel: %s to %s' % (uuid, o_uuid), self) + channel = sval(self.channels, uuid) + o_channel = sval(self.channels, o_uuid) + + if sval(channel, 'owned') or sval(o_channel, 'owned'): + ldebug('sending AMI bridge response: %s -> %s' % (uuid, o_uuid), self) + self.ami.send_event_bridge(uuid, sval(channel, 'name'), sval(channel, 'caller_id_number'), o_uuid, sval(o_channel, 'name'), sval(o_channel, 'caller_id_number')) + + + def ami_send_outbound_start(self, channel): + self.ami.send_event_newchannel(sval(channel, 'uuid'), sval(channel, 'name'), 0, sval(channel, 'caller_id_number'), sval(channel, 'caller_id_name'), sval(channel, 'destination_number')) + self.ami.send_event_newstate(sval(channel, 'uuid'), sval(channel, 'name'), 4, sval(channel, 'caller_id_number'), sval(channel, 'caller_id_name')) + self.ami.send_event_newchannel(sval(channel, 'o_uuid'), sval(channel, 'o_name'), 0, '', '', '') + self.ami.send_event_dial_begin(sval(channel, 'uuid'), sval(channel, 'name'), sval(channel, 'caller_id_number'), sval(channel, 'caller_id_name'), sval(channel, 'o_name'), sval(channel, 'o_uuid'), sval(channel, 'destination_number')) + self.ami.send_event_newcallerid(sval(channel, 'o_uuid'), sval(channel, 'o_name'), sval(channel, 'destination_number'), '', 0) + self.ami.send_event_newstate(sval(channel, 'o_uuid'), sval(channel, 'o_name'), 5, sval(channel, 'destination_number'), '') + + + def ami_send_outbound_end(self, channel): + self.ami.send_event_hangup(sval(channel, 'o_uuid'), sval(channel, 'o_name'), sval(channel, 'destination_number'), '', sval(channel, 'hangup_cause_code')) + self.ami.send_event_dial_end(sval(channel, 'uuid'), sval(channel, 'name')) + self.ami.send_event_hangup(sval(channel, 'uuid'), sval(channel, 'name'), sval(channel, 'caller_id_number'), sval(channel, 'caller_id_name'), sval(channel, 'hangup_cause_code')) + + if sval(channel, 'origination_action'): + self.ami.send_event_originate_response(sval(channel, 'uuid'), sval(channel, 'name'), sval(channel, 'caller_id_number'), sval(channel, 'caller_id_name'), sval(channel, 'destination_number'), sval(channel, 'origination_action'), 1) + + + def ami_send_inbound_start(self, channel): + self.ami.send_event_newchannel(sval(channel, 'o_uuid'), sval(channel, 'o_name'), 0, sval(channel, 'caller_id_number'), sval(channel, 'caller_id_name'), sval(channel, 'callee_id_number')) + self.ami.send_event_newstate(sval(channel, 'o_uuid'), sval(channel, 'o_name'), 4, sval(channel, 'caller_id_number'), sval(channel, 'caller_id_name')) + self.ami.send_event_newchannel(sval(channel, 'uuid'), sval(channel, 'name'), 0, '', '', '') + self.ami.send_event_dial_begin(sval(channel, 'o_uuid'), sval(channel, 'o_name'), sval(channel, 'caller_id_number'), sval(channel, 'caller_id_name'), sval(channel, 'name'), sval(channel, 'uuid'), sval(channel, 'destination_number')) + self.ami.send_event_newstate(sval(channel, 'uuid'), sval(channel, 'name'), 5, sval(channel, 'caller_id_number'), sval(channel, 'caller_id_name')) + self.ami.send_event_newcallerid(sval(channel, 'uuid'), sval(channel, 'name'), sval(channel, 'destination_number'), '', 0) + + + def ami_send_originate_start(self, channel): + self.ami.send_event_newchannel(sval(channel, 'uuid'), sval(channel, 'name'), 0, '', '', '') + self.ami.send_event_newcallerid(sval(channel, 'uuid'), sval(channel, 'name'), sval(channel, 'caller_id_number'), sval(channel, 'caller_id_name'), 0) + self.ami.send_event_newaccountcode(sval(channel, 'uuid'), sval(channel, 'name')) + self.ami.send_event_newcallerid(sval(channel, 'uuid'), sval(channel, 'name'), sval(channel, 'caller_id_number'), sval(channel, 'caller_id_name'), 0) + self.ami.send_event_newstate(sval(channel, 'uuid'), sval(channel, 'name'), 5, sval(channel, 'caller_id_number'), sval(channel, 'caller_id_name')) + + + def ami_send_originate_outbound(self, channel): + self.ami.send_event_newchannel(sval(channel, 'o_uuid'), sval(channel, 'o_name'), 0, '', '', '') + self.ami.send_event_dial_begin(sval(channel, 'uuid'), sval(channel, 'name'), sval(channel, 'caller_id_number'), sval(channel, 'caller_id_name'), sval(channel, 'o_name'), sval(channel, 'o_uuid'), sval(channel, 'destination_number')) + self.ami.send_event_newcallerid(sval(channel, 'o_uuid'), sval(channel, 'o_name'), sval(channel, 'destination_number'), '', 0) + self.ami.send_event_newstate(sval(channel, 'o_uuid'), sval(channel, 'o_name'), 5, sval(channel, 'destination_number'), '') diff --git a/misc/mon_ami/mon_ami_main.py b/misc/mon_ami/mon_ami_main.py new file mode 100644 index 0000000..13dd4bb --- /dev/null +++ b/misc/mon_ami/mon_ami_main.py @@ -0,0 +1,117 @@ +# -*- coding: utf-8 -*- +# MonAMI Asterisk Manger Interface Server +# Main Programm +# (c) AMOOMA GmbH 2012 + +from log import ldebug, linfo, lwarn, lerror, lcritic, setup_log +from time import sleep +from signal import signal, SIGHUP, SIGTERM, SIGINT +from optparse import OptionParser +from freeswitch import FreeswitchEventSocket +from mon_ami_server import MonAMIServer +from sqliter import SQLiteR + +def signal_handler(signal_number, frame): + global event_socket + global mon_ami_server + + ldebug('signal %d received ' % signal_number, frame) + + if (signal_number == SIGTERM): + ldebug('shutdown signal (%d) received ' % signal_number, frame) + event_socket.stop() + mon_ami_server.stop() + elif (signal_number == SIGINT): + ldebug('interrupt signal (%d) received ' % signal_number, frame) + event_socket.stop() + mon_ami_server.stop() + elif (signal_number == SIGHUP): + ldebug('hangup signal (%d) received - ignore' % signal_number, frame) + +def user_password_authentication(user_name, password): + global configuration_options + + if configuration_options.user_ignore_name and configuration_options.user_ignore_password: + ldebug('user-password authentication credentials provided but ignored - user: %s, password: %s' % (user_name, '*' * len(str(password)))) + return True + + if configuration_options.user_override_name != None and configuration_options.user_override_password != None: + if user_name == configuration_options.user_override_name and password == configuration_options.user_override_password: + return True + return False + + db = SQLiteR(configuration_options.user_db_name) + if not db.connect(): + lerror('cound not connect to user database "%s"' % configuration_options.user_db_name) + return False + + user = db.find(configuration_options.user_db_table, {configuration_options.user_db_name_row: user_name, configuration_options.user_db_password_row: password}) + db.disconnect() + + if user: + ldebug('user-password authentication accepted - user: %s, password: %s' % (user_name, '*' * len(str(password)))) + return True + + linfo('user-password authentication failed - user: %s, password: %s' % (user_name, '*' * len(str(password)))) + return False + +def main(): + global event_socket + global mon_ami_server + global configuration_options + + option_parser = OptionParser() + + # Log options + option_parser.add_option("--log-file", action="store", type="string", dest="log_file", default=None) + option_parser.add_option("--log-level", action="store", type="int", dest="log_level", default=5) + + # FreeSWITCH event_socket + option_parser.add_option("--freeswitch-address", action="store", type="string", dest="freeswitch_address", default='127.0.0.1') + option_parser.add_option("--freeswitch-port", action="store", type="int", dest="freeswitch_port", default=8021) + option_parser.add_option("--freeswitch-password", action="store", type="string", dest="freeswitch_password", default='ClueCon') + + # Asterisk Manager Interface + option_parser.add_option("-a", "--address", "--ami-address", action="store", type="string", dest="ami_address", default='0.0.0.0') + option_parser.add_option("-p", "--port", "--ami-port", action="store", type="int", dest="ami_port", default=5038) + + # User database + option_parser.add_option("--user-db-name", action="store", type="string", dest="user_db_name", default='/opt/GS5/db/development.sqlite3') + option_parser.add_option("--user-db-table", action="store", type="string", dest="user_db_table", default='sip_accounts') + option_parser.add_option("--user-db-name-row", action="store", type="string", dest="user_db_name_row", default='auth_name') + option_parser.add_option("--user-db-password-row", action="store", type="string", dest="user_db_password_row", default='password') + + # Define common User/Password options + option_parser.add_option("--user-override-name", action="store", type="string", dest="user_override_name", default=None) + option_parser.add_option("--user-override-password", action="store", type="string", dest="user_override_password", default=None) + option_parser.add_option("--user-ignore-name", action="store_true", dest="user_ignore_name", default=False) + option_parser.add_option("--user-ignore-password", action="store_true", dest="user_ignore_password", default=False) + + (configuration_options, args) = option_parser.parse_args() + + setup_log(configuration_options.log_file, configuration_options.log_level) + ldebug('starting MonAMI main process') + + # Catch signals + signal(SIGHUP, signal_handler) + signal(SIGTERM, signal_handler) + signal(SIGINT, signal_handler) + + # Starting FreeSWITCH event_socket thread + event_socket = FreeswitchEventSocket(configuration_options.freeswitch_address, configuration_options.freeswitch_port, configuration_options.freeswitch_password) + event_socket.start() + + if event_socket.isAlive(): + # Starting Asterisk manager thread + mon_ami_server = MonAMIServer(configuration_options.ami_address, configuration_options.ami_port, event_socket) + mon_ami_server.user_password_authentication = user_password_authentication + mon_ami_server.start() + + while mon_ami_server.isAlive(): + sleep(1) + + if event_socket.isAlive(): + ldebug('killing event_socket thread') + event_socket.stop() + + ldebug('exiting MonAMI main process') diff --git a/misc/mon_ami/mon_ami_server.py b/misc/mon_ami/mon_ami_server.py new file mode 100644 index 0000000..68e72c8 --- /dev/null +++ b/misc/mon_ami/mon_ami_server.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +# MonAMI Asterisk Manger Interface Server +# Asterisk AMI Emulator server thread +# (c) AMOOMA GmbH 2012 + +from threading import Thread +from log import ldebug, linfo, lwarn, lerror, lcritic +from time import sleep +from traceback import format_exc +from tcp_server import TCPServer +from mon_ami_handler import MonAMIHandler +import socket + +class MonAMIServer(Thread): + + def __init__(self, address=None, port=None, event_socket=None): + Thread.__init__(self) + self.runthread = True + self.port = port + self.address = address + self.event_socket = event_socket + self.handler_threads = {} + self.user_password_authentication = None + + def stop(self): + ldebug('thread stop', self) + ldebug('client connections: %s' % len(self.handler_threads), self) + for thread_id, handler_thread in self.handler_threads.items(): + if handler_thread.isAlive(): + handler_thread.stop() + self.runthread = False + + def register_handler_thread(self, handler_thread): + if handler_thread.isAlive(): + ldebug('registering handler thread %d ' % id(handler_thread), self) + self.handler_threads[id(handler_thread)] = handler_thread + else: + lwarn('handler thread passed away: %d' % id(handler_thread), self) + + + def deregister_handler_thread(self, handler_thread): + if id(handler_thread) in self.handler_threads: + ldebug('deregistering handler thread %d ' % id(handler_thread), self) + del self.handler_threads[id(handler_thread)] + else: + lwarn('handler thread %d not registered' % id(handler_thread), self) + + + def run(self): + ldebug('starting MonAMI server thread', self) + serversocket = TCPServer(self.address, self.port).listen() + #serversocket.setblocking(0) + + if not serversocket: + ldebug('server socket could not be bound', self) + return 1 + + while self.runthread: + try: + client_socket, client_address = serversocket.accept() + except socket.timeout as exception: + # Socket timeout occured + continue + except socket.error as exception: + lerror('socket error (%s): %s - ' % (exception, format_exc()), self) + sleep(1) + continue + except: + lerror('general error: %s - ' % format_exc(), self) + sleep(1) + continue + + ldebug('connected to %s:%d' % client_address, self) + + client_thread = MonAMIHandler(client_socket, client_address, self.event_socket) + client_thread.deregister_at_server = self.deregister_handler_thread + client_thread.user_password_authentication = self.user_password_authentication + client_thread.start() + if client_thread.isAlive(): + self.register_handler_thread(client_thread) + + ldebug('registered handler threads: %d' % len(self.handler_threads), self) + + ldebug('exiting MonAMI server thread', self) + diff --git a/misc/mon_ami/sqliter.py b/misc/mon_ami/sqliter.py new file mode 100644 index 0000000..5b03729 --- /dev/null +++ b/misc/mon_ami/sqliter.py @@ -0,0 +1,132 @@ +# -*- coding: utf-8 -*- +# SQLite library + +import sqlite3 + +class SQLiteR(): + + def __init__(self, database = None): + self.db_name = database + if (self.db_name == None): + self.db_name = ':memory:' + self.db_conn = None + self.db_cursor = None + + def record_factory(self, cursor, row): + record = dict() + for index, column in enumerate(cursor.description): + record[column[0]] = row[index] + return record + + def connect(self, isolation_level = None): + try: + self.db_conn = sqlite3.connect(self.db_name) + self.db_conn.row_factory = self.record_factory + self.db_cursor = self.db_conn.cursor() + except: + return False + + self.db_conn.isolation_level = isolation_level + return True + + def disconnect(self): + try: + self.db_nonn.close() + except: + return False + return True + + def execute(self, query, parameters = []): + try: + return self.db_cursor.execute(query, parameters) + except: + return False + + def fetch_row(self): + return self.db_cursor.fetchone() + + def fetch_rows(self): + return self.db_cursor.fetchall() + + def execute_get_rows(self, query, parameters = []): + if (self.execute(query, parameters)): + return self.fetch_rows() + else: + return False + + def execute_get_row(self, query, parameters = []): + query = "%s LIMIT 1" % query + if (self.execute(query, parameters)): + return self.fetch_row() + else: + return False + + def execute_get_value(self, query, parameters = []): + row = self.execute_get_row(query, parameters) + if (row): + return row[0] + else: + return row + + def create_table(self, table, structure, primary_key = None): + columns = list() + for row in structure: + key, value = row.items()[0] + sql_type = "VARCHAR(255)" + sql_key = '' + if (key == primary_key): + sql_key = 'PRIMARY KEY' + type_r = value.split(':', 1) + type_n = type_r[0] + if (type_n == 'integer'): + sql_type = 'INTEGER' + elif (type_n == 'string'): + try: + sql_type = "VARCHAR(%s)" % type_r[1] + except IndexError, e: + sql_type = "VARCHAR(255)" + + columns.append('"%s" %s %s' % (key, sql_type, sql_key)) + + query = 'CREATE TABLE "%s" (%s)' % (table, ', '.join(columns)) + return self.execute(query) + + def save(self, table, row): + keys = row.keys() + query = 'INSERT OR REPLACE INTO "%s" (%s) VALUES (:%s)' % (table, ', '.join(keys), ', :'.join(keys)) + + return self.execute(query, row) + + def find_sql(self, table, rows = None): + values = list() + if (rows): + if (type(rows) == type(list())): + rows_list = rows + else: + rows_list = list() + rows_list.append(rows) + + query_parts = list() + + for row in rows_list: + statements = list() + for key, value in row.items(): + if (value == None): + statements.append("\"%s\" IS ?" % (key)) + else: + statements.append("\"%s\" = ?" % (key)) + values.append(value) + query_parts.append('(%s)' % ' AND '.join(statements)) + + query = 'SELECT * FROM "%s" WHERE %s' % (table, ' OR '.join(query_parts)) + else: + query = 'SELECT * FROM "%s"' % table + return query, values + + def find(self, table, row = None): + query, value = self.find_sql(table, row) + return self.execute_get_row(query, value) + + def findall(self, table, row = None): + query, values = self.find_sql(table, row) + return self.execute_get_rows(query, values) diff --git a/misc/mon_ami/tcp_server.py b/misc/mon_ami/tcp_server.py new file mode 100644 index 0000000..5536282 --- /dev/null +++ b/misc/mon_ami/tcp_server.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# MonAMI Asterisk Manger Interface Server +# TCP Server +# (c) AMOOMA GmbH 2012 + +import socket +from traceback import format_exc +from log import ldebug, linfo, lwarn, lerror, lcritic + +class TCPServer(): + + def __init__(self, address=None, port=None, timeout=1): + self.SOCKET_BACKLOG = 5 + self.port = port + self.address = address + self.socket_timeout = timeout + + def listen(self): + tcpsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + tcpsocket.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 ) + + ldebug('binding server to %s:%d, timeout: %d' % (self.address, self.port, self.socket_timeout), self) + + try: + tcpsocket.bind((self.address, self.port)) + except ValueError as exception: + lerror('server socket address error: %s - %s' % (exception, format_exc()), self) + return False + except socket.error as exception: + lerror('server socket error (%d): %s - %s' % (exception[0], exception[1], format_exc()), self) + return False + except: + lerror('general server socket error: %s' % format_exc(), self) + return False + + tcpsocket.listen(self.SOCKET_BACKLOG) + tcpsocket.settimeout(self.socket_timeout) + + return tcpsocket diff --git a/misc/nginx/nginx.conf b/misc/nginx/nginx.conf new file mode 100644 index 0000000..c1c1a39 --- /dev/null +++ b/misc/nginx/nginx.conf @@ -0,0 +1,81 @@ + +user www-data; +worker_processes 1; + +#error_log logs/error.log; +#error_log logs/error.log notice; +#error_log logs/error.log info; + +#pid logs/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + passenger_root /usr/local/rvm/gems/ruby-1.9.2-p290/gems/passenger-3.0.11; + passenger_ruby /usr/local/rvm/wrappers/ruby-1.9.2-p290/ruby; + + include mime.types; + default_type application/octet-stream; + + #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + # '$status $body_bytes_sent "$http_referer" ' + # '"$http_user_agent" "$http_x_forwarded_for"'; + + #access_log logs/access.log main; + + sendfile on; + #tcp_nopush on; + + #keepalive_timeout 0; + keepalive_timeout 65; + + #gzip on; + + server { + listen 80; + server_name localhost; + root /opt/GS5/public; + passenger_enabled on; + } + + # another virtual host using mix of IP-, name-, and port-based configuration + # + #server { + # listen 8000; + # listen somename:8080; + # server_name somename alias another.alias; + + # location / { + # root html; + # index index.html index.htm; + # } + #} + + + # HTTPS server + # + #server { + # listen 443; + # server_name localhost; + + # ssl on; + # ssl_certificate cert.pem; + # ssl_certificate_key cert.key; + + # ssl_session_timeout 5m; + + # ssl_protocols SSLv2 SSLv3 TLSv1; + # ssl_ciphers HIGH:!aNULL:!MD5; + # ssl_prefer_server_ciphers on; + + # location / { + # root html; + # index index.html index.htm; + # } + #} + +} diff --git a/private_pub.ru b/private_pub.ru new file mode 100644 index 0000000..2db4acf --- /dev/null +++ b/private_pub.ru @@ -0,0 +1,8 @@ +# Run with: rackup private_pub.ru -s thin -E production +require "bundler/setup" +require "yaml" +require "faye" +require "private_pub" + +PrivatePub.load_config(File.expand_path("../config/private_pub.yml", __FILE__), ENV["RAILS_ENV"] || "development") +run PrivatePub.faye_app diff --git a/public/404.html b/public/404.html new file mode 100644 index 0000000..9a48320 --- /dev/null +++ b/public/404.html @@ -0,0 +1,26 @@ + + + + The page you were looking for doesn't exist (404) + + + + + +
    +

    The page you were looking for doesn't exist.

    +

    You may have mistyped the address or the page may have moved.

    +
    + + diff --git a/public/422.html b/public/422.html new file mode 100644 index 0000000..83660ab --- /dev/null +++ b/public/422.html @@ -0,0 +1,26 @@ + + + + The change you wanted was rejected (422) + + + + + +
    +

    The change you wanted was rejected.

    +

    Maybe you tried to change something you didn't have access to.

    +
    + + diff --git a/public/500.html b/public/500.html new file mode 100644 index 0000000..da74faf --- /dev/null +++ b/public/500.html @@ -0,0 +1,26 @@ + + + + We're sorry, but something went wrong (500) + + + + + +
    +

    We're sorry, but something went wrong.

    +

    Please take a minute and report an issue at https://github.com/amooma/GS5/issues or contact your admin.

    +
    + + diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..e69de29 diff --git a/public/images/fallback/mini_default.jpg b/public/images/fallback/mini_default.jpg new file mode 100644 index 0000000..42c9f2d Binary files /dev/null and b/public/images/fallback/mini_default.jpg differ diff --git a/public/images/fallback/mini_default_female.png b/public/images/fallback/mini_default_female.png new file mode 100644 index 0000000..bc54d26 Binary files /dev/null and b/public/images/fallback/mini_default_female.png differ diff --git a/public/images/fallback/mini_default_male.png b/public/images/fallback/mini_default_male.png new file mode 100644 index 0000000..b75e36c Binary files /dev/null and b/public/images/fallback/mini_default_male.png differ diff --git a/public/images/fallback/profile_default.jpg b/public/images/fallback/profile_default.jpg new file mode 100644 index 0000000..d807028 Binary files /dev/null and b/public/images/fallback/profile_default.jpg differ diff --git a/public/images/fallback/profile_default.psd b/public/images/fallback/profile_default.psd new file mode 100644 index 0000000..89b5b55 Binary files /dev/null and b/public/images/fallback/profile_default.psd differ diff --git a/public/images/fallback/profile_default_female.png b/public/images/fallback/profile_default_female.png new file mode 100644 index 0000000..614c4bc Binary files /dev/null and b/public/images/fallback/profile_default_female.png differ diff --git a/public/images/fallback/profile_default_male.png b/public/images/fallback/profile_default_male.png new file mode 100644 index 0000000..f7b44ff Binary files /dev/null and b/public/images/fallback/profile_default_male.png differ diff --git a/public/images/fallback/small_default.jpg b/public/images/fallback/small_default.jpg new file mode 100644 index 0000000..5a8cbf2 Binary files /dev/null and b/public/images/fallback/small_default.jpg differ diff --git a/public/images/fallback/small_default_female.png b/public/images/fallback/small_default_female.png new file mode 100644 index 0000000..b9de992 Binary files /dev/null and b/public/images/fallback/small_default_female.png differ diff --git a/public/images/fallback/small_default_male.png b/public/images/fallback/small_default_male.png new file mode 100644 index 0000000..e5d3434 Binary files /dev/null and b/public/images/fallback/small_default_male.png differ diff --git a/public/images/fallback/snom_caller_picture_default.jpg b/public/images/fallback/snom_caller_picture_default.jpg new file mode 100644 index 0000000..6bbcc83 Binary files /dev/null and b/public/images/fallback/snom_caller_picture_default.jpg differ diff --git a/public/images/fallback/snom_caller_picture_default_female.png b/public/images/fallback/snom_caller_picture_default_female.png new file mode 100644 index 0000000..da6a904 Binary files /dev/null and b/public/images/fallback/snom_caller_picture_default_female.png differ diff --git a/public/images/fallback/snom_caller_picture_default_male.png b/public/images/fallback/snom_caller_picture_default_male.png new file mode 100644 index 0000000..a783f8b Binary files /dev/null and b/public/images/fallback/snom_caller_picture_default_male.png differ diff --git a/public/images/snom/snom_300.jpg b/public/images/snom/snom_300.jpg new file mode 100644 index 0000000..f115b4b Binary files /dev/null and b/public/images/snom/snom_300.jpg differ diff --git a/public/images/snom/snom_320.jpg b/public/images/snom/snom_320.jpg new file mode 100644 index 0000000..8d83dd5 Binary files /dev/null and b/public/images/snom/snom_320.jpg differ diff --git a/public/images/snom/snom_360.jpg b/public/images/snom/snom_360.jpg new file mode 100644 index 0000000..d633d67 Binary files /dev/null and b/public/images/snom/snom_360.jpg differ diff --git a/public/images/snom/snom_370.jpg b/public/images/snom/snom_370.jpg new file mode 100644 index 0000000..2698586 Binary files /dev/null and b/public/images/snom/snom_370.jpg differ diff --git a/public/images/snom/snom_820.jpg b/public/images/snom/snom_820.jpg new file mode 100644 index 0000000..8306ea7 Binary files /dev/null and b/public/images/snom/snom_820.jpg differ diff --git a/public/images/snom/snom_821.jpg b/public/images/snom/snom_821.jpg new file mode 100644 index 0000000..8306ea7 Binary files /dev/null and b/public/images/snom/snom_821.jpg differ diff --git a/public/images/snom/snom_870.jpg b/public/images/snom/snom_870.jpg new file mode 100644 index 0000000..c0fa148 Binary files /dev/null and b/public/images/snom/snom_870.jpg differ diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..b9fe2d7 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,6 @@ +# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file +# +# Because it is a PBX we disallow any search engine by default. +# +User-Agent: * +Disallow: / diff --git a/script/agi_server b/script/agi_server new file mode 100755 index 0000000..0a0fd76 --- /dev/null +++ b/script/agi_server @@ -0,0 +1,35 @@ +#! /usr/bin/env ruby + +APP_PATH = File.expand_path('../../config/application', __FILE__) +require File.expand_path('../../config/boot', __FILE__) +require APP_PATH + +begin + Rails.application.require_environment! +rescue ActiveRecord::AdapterNotSpecified => e + $stderr.puts "No such Rails environment: \"#{Rails.env}\"." + exit 1 +end + +begin + require 'agi_server' + server_instance = AGIServer::server() + +rescue SignalException => e + case e.signo + when 1 + $stderr.puts "Signal 1 caught, exiting" + when 2 + $stderr.puts "Interrupt signal caught, exiting" + when 15 + $stderr.puts "Exit signal caught, exiting" + else + $stderr.print "#{e.class.to_s}" + $stderr.print " (Signal #{e.signo.to_s})" if e.respond_to?(:signo) && e.signo + end + $stderr.puts "" + exit (e.signo + 128) +end + +exit 0 + diff --git a/script/delayed_job b/script/delayed_job new file mode 100755 index 0000000..edf1959 --- /dev/null +++ b/script/delayed_job @@ -0,0 +1,5 @@ +#!/usr/bin/env ruby + +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment')) +require 'delayed/command' +Delayed::Command.new(ARGV).daemonize diff --git a/script/erd b/script/erd new file mode 100755 index 0000000..5ba938c --- /dev/null +++ b/script/erd @@ -0,0 +1,38 @@ +#! /bin/sh + +echo "" +echo "### Generating Dot file ..." +bundle exec \ + rake erd filetype=dot \ + attributes=content,foreign_keys \ + indirect=true \ + orientation=horizontal \ + notation=simple + +if which dot; then + echo "" + echo "### Generating PDF file (via dot) ..." + dot -Tpdf:quartz:quartz -o ERD.pdf ERD.dot +else + if which graphviz; then + echo "" + echo "### Generating PDF file (via graphviz) ..." + bundle exec \ + rake erd filetype=pdf \ + attributes=content,foreign_keys \ + indirect=true \ + orientation=horizontal \ + notation=simple + else + echo "No dot no PDF." + fi +fi + +if which dot; then + echo "" + echo "### Generating PNG file (via dot) ..." + dot -Tpng:quartz:quartz -o ERD.png ERD.dot +else + echo "No dot no PNG." +fi + diff --git a/script/fax_new b/script/fax_new new file mode 100755 index 0000000..8015da8 --- /dev/null +++ b/script/fax_new @@ -0,0 +1,111 @@ +#! /usr/bin/env ruby + +begin + +if !ARGV[0] or ARGV[0] == '' or !ARGV[10] or ARGV[10] == '' + $stderr.puts "usage: fax_new \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +" + exit 1 +end + +fax_arguments = { + :fax_account_id => ARGV[0], + :result_code => ARGV[1], + :document_total_pages => ARGV[2], + :document_transferred_pages => ARGV[3], + :ecm_requested => ARGV[4], + :ecm_used => ARGV[5], + :image_resolution => ARGV[6], + :remote_station_id => ARGV[7], + :transfer_rate => ARGV[8], + :transmission_time => ARGV[9], + :document => ARGV[10], + :caller_id_number => ARGV[11], + :caller_id_name => ARGV[12], +} + +APP_PATH = File.expand_path('../../config/application', __FILE__) +require File.expand_path('../../config/boot', __FILE__) +require APP_PATH + +begin + Rails.application.require_environment! +rescue ActiveRecord::AdapterNotSpecified => e + error "No such Rails environment: \"#{Rails.env}\"." + exit 1 +end + +TIFF_FUFFIX = ".tiff" +PDF_SUFFIX = ".pdf" + +tiff_file = fax_arguments[:document] + +if !tiff_file or !File.exists?( tiff_file ) + $stderr.puts "File \"#{tiff_file}\" does not exist" + exit 1 +end + +paper_size = "letter" +pdf_file = "#{File.dirname(tiff_file)}/#{File.basename(tiff_file, TIFF_FUFFIX)}#{PDF_SUFFIX}" + +system "tiff2pdf \\ + -o \"#{pdf_file}\" \\ + -p #{paper_size} \\ + -a \"#{fax_arguments[:remote_station_id]}\" \\ + -c \"AMOOMA Gemeinschaft version #{GEMEINSCHAFT_VERSION}\" \\ + -t \"#{fax_arguments[:remote_station_id]}\" \"#{tiff_file}\"" + +if !File.exists?( pdf_file ) + $stderr.puts "File \"#{pdf_file}\" does not exist" + exit 1 +end + +fax_account = FaxAccount.find(fax_arguments[:fax_account_id]) +if !fax_account + $stderr.puts "Fax account \"#{fax_arguments[:fax_account_id]}\" does not exist" + exit 1 +end + +fax_arguments[:document] = nil +fax_arguments[:success] = true +fax_arguments[:inbound] = true +fax_arguments[:sent_at] = Time.now +fax_arguments[:local_station_id] = fax_account.station_id +fax_arguments[:retry_counter] = 0 +fax_arguments[:fax_resolution_id] = FaxResolution.first.id +fax_arguments[:image_size] = File.size(tiff_file) +fax_arguments[:ecm_used] = fax_arguments[:ecm_used] == "on" ? true : false +fax_document = fax_account.fax_documents.build(fax_arguments) +fax_document.document = File.open(pdf_file) + +if ! fax_document.save + $stderr.puts "Error(s) creating fax document:" + $stderr.puts fax_document.errors.inspect + exit 1 +end + +fax_document.mark_as_inbound! + +Notifications.new_fax(fax_document).deliver + +exit 0 + +rescue SignalException => e + $stderr.print "#{e.class.to_s}" + $stderr.print " (Signal #{e.signo.to_s})" if e.respond_to?(:signo) && e.signo + $stderr.puts "" + exit 130 +end + +exit 0 diff --git a/script/fax_new.sh b/script/fax_new.sh new file mode 100755 index 0000000..3c98d41 --- /dev/null +++ b/script/fax_new.sh @@ -0,0 +1,4 @@ +#! /bin/bash +cd /opt/GS5/script/ +source /usr/local/rvm/scripts/rvm +/opt/GS5/script/fax_new "$@" diff --git a/script/logout_phones b/script/logout_phones new file mode 100755 index 0000000..2a1f266 --- /dev/null +++ b/script/logout_phones @@ -0,0 +1,29 @@ +#! /usr/bin/env ruby + +begin + +APP_PATH = File.expand_path('../../config/application', __FILE__) +require File.expand_path('../../config/boot', __FILE__) +require APP_PATH + +begin + Rails.application.require_environment! +rescue ActiveRecord::AdapterNotSpecified => e + error "No such Rails environment: \"#{Rails.env}\"." + exit 1 +end + +phones = Phone.where(:nightly_reboot => true).each do |phone| + if ! phone.user_logout + $stderr.puts "#{phone.id} #{phone.mac_address} - #{phone.errors.messages.inspect}" + end +end + +rescue SignalException => e + $stderr.print "#{e.class.to_s}" + $stderr.print " (Signal #{e.signo.to_s})" if e.respond_to?(:signo) && e.signo + $stderr.puts "" + exit 130 +end + +exit 0 diff --git a/script/logout_phones.sh b/script/logout_phones.sh new file mode 100755 index 0000000..2a1a54e --- /dev/null +++ b/script/logout_phones.sh @@ -0,0 +1,4 @@ +#! /bin/bash +cd /opt/GS5/script/ +source /usr/local/rvm/scripts/rvm +/opt/GS5/script/logout_phones $@ diff --git a/script/notes b/script/notes new file mode 100755 index 0000000..1285884 --- /dev/null +++ b/script/notes @@ -0,0 +1,25 @@ +#! /bin/sh + +# `rake notes` doesn't find everything and is too slow. + +#find . -type f \ +# | grep -vEe '/(\.git|\.DS_Store|\.idea/|\.project|doc/app/|script/notes|log/|debian/visual-inspection/|public/javascripts/controls\.js)' \ +# | xargs grep --color -IEe '# *(FIXME|TODO|OPTIMIZE)' +#exit 0 + +find . -not \( \ + -name '.svn' -prune -o \ + -name '.git' -prune -o \ + -name '.DS_Store' -prune -o \ + -name '.idea' -prune -o \ + -name '.project' -prune -o \ + -path '*/script/notes' -prune -o \ + -path '*/doc/app/*' -prune -o \ + -path '*/doc/html-onefile/*.html' -prune -o \ + -path '*/doc/docbook-xsl-*' -prune -o \ + -path '*/public/javascripts/controls.js' -prune -o \ + -path '*/log/*.log' -prune -o \ + -false \ + \) -type f -print0 \ + | xargs -0 grep --color -IEe '#[^#]*(FIXME|TODO|OPTIMIZE)\b.*' + diff --git a/script/rails b/script/rails new file mode 100755 index 0000000..5f16f40 --- /dev/null +++ b/script/rails @@ -0,0 +1,68 @@ +#!/usr/bin/env ruby +# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. + +APP_PATH = File.expand_path('../../config/application', __FILE__) +require File.expand_path('../../config/boot', __FILE__) + + +# # ---[ Custom stuff ]--------------------------------------{ +# # Start web server with SSL enabled. +# # http://www.nearinfinity.com/blogs/chris_rohr/configuring_webrick_to_use_ssl.html +# +# require 'rubygems' +# require 'rails/commands/server' +# require 'rack' +# +# # like WEBrick::Utils::getservername() +# def getservername() +# return 'abc' +# require 'socket' +# host = Socket::gethostname +# begin +# return Socket::gethostbyname(host)[0] +# rescue +# return host +# end +# end +# +# require 'webrick' +# require 'webrick/https' +# +# module Rails +# class Server < ::Rack::Server +# # http://api.rubyonrails.org/classes/Rails/Server.html#method-i-default_options +# def default_options +# super.merge({ +# :Port => 3001, +# # https://github.com/raesene/dradisframework/commit/705d067eb9eef9ac98de29439757a0b1102c15cc +# :DoNotReverseLookup => true, +# :environment => (ENV['RAILS_ENV'] || 'development').dup, +# :daemonize => false, +# :debugger => false, +# :pid => File.expand_path( 'tmp/pids/server.pid' ), +# :config => File.expand_path( 'config.ru' ), +# :SSLEnable => true, +# :SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE, +# :SSLPrivateKey => OpenSSL::PKey::RSA.new( +# File.open( 'misc/etc/ssl/amooma/server_key.pem' ).read), +# :SSLCertificate => OpenSSL::X509::Certificate.new( +# File.open( 'misc/etc/ssl/amooma/server_cert.pem' ).read), +# :SSLCertName => [[ 'CN', getservername() ]], +# }) +# end +# end +# end +# +# # require 'rack/handler' +# # Rack::Handler.class_eval do +# # def self.default( options = {} ) +# # Rack::Handler::Thin +# # end +# # end +# +# # ---------------------------------------------------------} +# + + +require 'rails/commands' + diff --git a/script/voicemail_new b/script/voicemail_new new file mode 100755 index 0000000..bfdf39f --- /dev/null +++ b/script/voicemail_new @@ -0,0 +1,61 @@ +#! /usr/bin/env ruby + +begin + +if !ARGV[0] or ARGV[0] == '' or !ARGV[1] or ARGV[1] == '' + $stderr.puts "usage: voicemail_new " + exit 1 +end + + +APP_PATH = File.expand_path('../../config/application', __FILE__) +require File.expand_path('../../config/boot', __FILE__) +require APP_PATH + +begin + Rails.application.require_environment! +rescue ActiveRecord::AdapterNotSpecified => e + error "No such Rails environment: \"#{Rails.env}\"." + exit 1 +end + +voicemail_account_name = ARGV[0] +uuid = ARGV[1] + +message = FreeswitchVoicemailMsg.where(:username => voicemail_account_name, :uuid => uuid).first + +if ! message + $stderr.puts "Message \"#{uuid}\" does not exist" + exit 1 +end + +if !File.exists?( message.file_path ) + $stderr.puts "File \"#{message.file_path}\" does not exist" + exit 1 +end + +owner_account = SipAccount.where(:auth_name => voicemail_account_name).first +if ! owner_account + $stderr.puts "SipAccount \"#{voicemail_account_name}\" does not exist" + exit 1 +end + +sip_account = SipAccount.find_by_auth_name(message.username) +if sip_account && sip_account.sip_accountable.class == User + user = sip_account.sip_accountable + + if user.send_voicemail_as_email_attachment == true + if Notifications.new_voicemail(message).deliver + message.delete + end + end +end + +rescue SignalException => e + $stderr.print "#{e.class.to_s}" + $stderr.print " (Signal #{e.signo.to_s})" if e.respond_to?(:signo) && e.signo + $stderr.puts "" + exit 130 +end + +exit 0 diff --git a/script/voicemail_new.sh b/script/voicemail_new.sh new file mode 100755 index 0000000..dcb29f5 --- /dev/null +++ b/script/voicemail_new.sh @@ -0,0 +1,4 @@ +#! /bin/bash + +source /usr/local/rvm/scripts/rvm +/opt/GS5/script/voicemail_new $@ diff --git a/test/factories/api_rows.rb b/test/factories/api_rows.rb new file mode 100644 index 0000000..42428ae --- /dev/null +++ b/test/factories/api_rows.rb @@ -0,0 +1,17 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +FactoryGirl.define do + factory :row do + user_name "MyString" + last_name "MyString" + middle_name "MyString" + first_name "MyString" + office_phone_number "MyString" + internal_extension "MyString" + mobile_phone_number "MyString" + fax_phone_number "MyString" + email "MyString" + pin "MyString" + photo_file_name "MyString" + end +end diff --git a/test/factories/area_codes.rb b/test/factories/area_codes.rb new file mode 100644 index 0000000..87b2271 --- /dev/null +++ b/test/factories/area_codes.rb @@ -0,0 +1,7 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :area_code do |f| + f.sequence(:name) { |n| "AreaCode #{n}" } + f.sequence(:area_code) { |n| "#{n}" } + f.association :country +end \ No newline at end of file diff --git a/test/factories/call_forwards.rb b/test/factories/call_forwards.rb new file mode 100644 index 0000000..d275e9d --- /dev/null +++ b/test/factories/call_forwards.rb @@ -0,0 +1,16 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :call_forward do |f| + f.association :phone_number + #OPTIMIZE Make sure that the phone_number's phone_numberable + # isn't a phone_book_entry but a sip_account. + #f.sequence( :call_forward_case_id ) { |n| CallForwardCase.where(:value => "always").first.id } + #f.association :call_forward_case + f.sequence( :call_forward_case_id ) { |n| 1 } + f.sequence( :destination ) { |n| "20#{n}" } + f.sequence( :to_voicemail ) { |n| false } + f.sequence( :timeout ) { |n| nil } + f.sequence( :source ) { |n| nil } + f.sequence( :depth ) { |n| 5 } + f.sequence( :active ) { |n| false } +end diff --git a/test/factories/conference_invitees.rb b/test/factories/conference_invitees.rb new file mode 100644 index 0000000..4e1eb68 --- /dev/null +++ b/test/factories/conference_invitees.rb @@ -0,0 +1,8 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :conference_invitee do |f| + f.phone_number { Factory.build(:phone_number) } + f.association :conference + f.speaker true + f.moderator false +end \ No newline at end of file diff --git a/test/factories/conferences.rb b/test/factories/conferences.rb new file mode 100644 index 0000000..3c49a7a --- /dev/null +++ b/test/factories/conferences.rb @@ -0,0 +1,8 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :conference do |f| + f.sequence(:name) { |n| "Conference room #{n}" } + f.open_for_anybody true + f.association :conferenceable, :factory => :tenant + f.max_members 10 +end \ No newline at end of file diff --git a/test/factories/countries.rb b/test/factories/countries.rb new file mode 100644 index 0000000..cc3fc88 --- /dev/null +++ b/test/factories/countries.rb @@ -0,0 +1,8 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :country do |f| + f.sequence(:name) { |n| "Country #{n}" } + f.sequence(:country_code) { |n| "#{n}" } + f.sequence(:international_call_prefix) { |n| "#{n}" } + f.sequence(:trunk_prefix) { |n| "#{n}" } +end \ No newline at end of file diff --git a/test/factories/gemeinschaft_setups.rb b/test/factories/gemeinschaft_setups.rb new file mode 100644 index 0000000..ed69bc3 --- /dev/null +++ b/test/factories/gemeinschaft_setups.rb @@ -0,0 +1,8 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :gemeinschaft_setup do |f| + f.association :user + f.association :sip_domain + f.association :country + f.association :language +end \ No newline at end of file diff --git a/test/factories/gui_function_memberships.rb b/test/factories/gui_function_memberships.rb new file mode 100644 index 0000000..c6f6d4a --- /dev/null +++ b/test/factories/gui_function_memberships.rb @@ -0,0 +1,10 @@ +# Read about factories at https://github.com/thoughtbot/factory_girl + +FactoryGirl.define do + factory :gui_function_membership do + gui_function_id 1 + user_group_id 1 + activated false + output "MyString" + end +end diff --git a/test/factories/languages.rb b/test/factories/languages.rb new file mode 100644 index 0000000..29d2ece --- /dev/null +++ b/test/factories/languages.rb @@ -0,0 +1,6 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :language do |f| + f.name 'Deutsch' + f.code 'de' +end \ No newline at end of file diff --git a/test/factories/manufacturers.rb b/test/factories/manufacturers.rb new file mode 100644 index 0000000..f091dd2 --- /dev/null +++ b/test/factories/manufacturers.rb @@ -0,0 +1,6 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :manufacturer do |f| + f.sequence(:name) { |n| "#{n}. manufacturer" } + f.sequence(:ieee_name) { |n| "#{n}. ieee" } +end \ No newline at end of file diff --git a/test/factories/ouis.rb b/test/factories/ouis.rb new file mode 100644 index 0000000..3a90fd4 --- /dev/null +++ b/test/factories/ouis.rb @@ -0,0 +1,6 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :oui do |f| + f.association :manufacturer + f.sequence(:value) { |n| (n + 11184810).to_s(16).upcase } +end \ No newline at end of file diff --git a/test/factories/phone_book_entries.rb b/test/factories/phone_book_entries.rb new file mode 100644 index 0000000..7427886 --- /dev/null +++ b/test/factories/phone_book_entries.rb @@ -0,0 +1,7 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :phone_book_entry do |f| + f.sequence(:last_name) { |n| "Lastname #{n}" } + f.sequence(:is_male) { |n| true } + f.association :phone_book +end diff --git a/test/factories/phone_books.rb b/test/factories/phone_books.rb new file mode 100644 index 0000000..4aa8d07 --- /dev/null +++ b/test/factories/phone_books.rb @@ -0,0 +1,6 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :phone_book do |f| + f.sequence(:name) { |n| "Phone book #{n}" } + f.association :phone_bookable, :factory => :user +end diff --git a/test/factories/phone_models.rb b/test/factories/phone_models.rb new file mode 100644 index 0000000..8e6a50f --- /dev/null +++ b/test/factories/phone_models.rb @@ -0,0 +1,6 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :phone_model do |f| + f.sequence(:name) { |n| "Phone Model #{n}" } + f.association :manufacturer +end diff --git a/test/factories/phone_number_ranges.rb b/test/factories/phone_number_ranges.rb new file mode 100644 index 0000000..cb2f7ee --- /dev/null +++ b/test/factories/phone_number_ranges.rb @@ -0,0 +1,6 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :phone_number_range do |f| + f.name INTERNAL_EXTENSIONS + f.association :phone_number_rangeable, :factory => :tenant +end diff --git a/test/factories/phone_numbers.rb b/test/factories/phone_numbers.rb new file mode 100644 index 0000000..74b43cc --- /dev/null +++ b/test/factories/phone_numbers.rb @@ -0,0 +1,7 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :phone_number do |f| + f.sequence(:name) { |n| "Name #{n}" } + f.sequence(:number) { |n| "(0)30 227 #{n}" } + f.association :phone_numberable, :factory => :phone_book_entry +end \ No newline at end of file diff --git a/test/factories/phones.rb b/test/factories/phones.rb new file mode 100644 index 0000000..646d548 --- /dev/null +++ b/test/factories/phones.rb @@ -0,0 +1,15 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :phone do |f| + f.sequence(:mac_address) { |n| ('%06d' % n).to_s + ('%06d' % n).to_s } + f.association :phone_model + f.association :phoneable, :factory => :tenant + + # We have to make sure that the OUI is created as well. + f.after_build do |instance| + Factory.create(:oui, + :manufacturer => instance.phone_model.manufacturer, + :value => instance.mac_address.slice(0, 6) + ) + end +end \ No newline at end of file diff --git a/test/factories/sip_accounts.rb b/test/factories/sip_accounts.rb new file mode 100644 index 0000000..2f91717 --- /dev/null +++ b/test/factories/sip_accounts.rb @@ -0,0 +1,17 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :sip_account do |f| + f.association :sip_accountable, :factory => :user + f.sequence(:auth_name) {|n| "auth_name#{n}" } + f.sequence(:caller_name) {|n| "Foo Account #{n}" } + f.sequence(:password) {|n| "12345678" } + + f.after_build do |sip_account| + if sip_account.tenant_id.blank? + tenant = sip_account.create_tenant(FactoryGirl.build(:tenant).attributes) + sip_domain = tenant.create_sip_domain(FactoryGirl.build(:sip_domain).attributes) + sip_account.tenant.tenant_memberships.create(:user_id => sip_account.sip_accountable.id) + sip_account.tenant_id = tenant.id + end + end +end diff --git a/test/factories/sip_domains.rb b/test/factories/sip_domains.rb new file mode 100644 index 0000000..347b6a6 --- /dev/null +++ b/test/factories/sip_domains.rb @@ -0,0 +1,6 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :sip_domain do |f| + f.sequence(:host ) {|n| "host#{n}.localdomain" } + f.sequence(:realm ) {|n| "host#{n}.localdomain" } +end diff --git a/test/factories/softkey_functions.rb b/test/factories/softkey_functions.rb new file mode 100644 index 0000000..6af7cac --- /dev/null +++ b/test/factories/softkey_functions.rb @@ -0,0 +1,7 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +FactoryGirl.define do + factory :softkey_function do + name "MyString" + end +end diff --git a/test/factories/tenant_memberships.rb b/test/factories/tenant_memberships.rb new file mode 100644 index 0000000..ee52367 --- /dev/null +++ b/test/factories/tenant_memberships.rb @@ -0,0 +1,6 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :tenant_membership do |f| + f.association :user + f.association :tenant +end \ No newline at end of file diff --git a/test/factories/tenants.rb b/test/factories/tenants.rb new file mode 100644 index 0000000..9a62e93 --- /dev/null +++ b/test/factories/tenants.rb @@ -0,0 +1,8 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :tenant do |f| + f.sequence(:name) { |n| "Tenant #{n}" } + f.association :country + f.association :language +# f.association :sip_domain +end diff --git a/test/factories/user_group_memberships.rb b/test/factories/user_group_memberships.rb new file mode 100644 index 0000000..7904f2f --- /dev/null +++ b/test/factories/user_group_memberships.rb @@ -0,0 +1,14 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :user_group_membership do |f| + f.association :user_group + f.association :user + + # Make sure that the User is a member of the Tenant. + f.after_build do |instance| + Factory.create(:tenant_membership, + :tenant_id => instance.user_group.tenant.id, + :user_id => instance.user.id + ) + end +end \ No newline at end of file diff --git a/test/factories/user_groups.rb b/test/factories/user_groups.rb new file mode 100644 index 0000000..9a448ec --- /dev/null +++ b/test/factories/user_groups.rb @@ -0,0 +1,6 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :user_group do |f| + f.sequence(:name) { |n| "UserGroup #{n}" } + f.association :tenant +end \ No newline at end of file diff --git a/test/factories/users.rb b/test/factories/users.rb new file mode 100644 index 0000000..3d53141 --- /dev/null +++ b/test/factories/users.rb @@ -0,0 +1,11 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +Factory.define :user do |f| + f.sequence(:user_name) { |n| "User #{n}" } + f.sequence(:first_name) { |n| "John #{n}" } + f.sequence(:last_name) { |n| "Smith #{n}" } + f.sequence(:email) { |n| "john.smith#{n}@company.com" } + f.sequence(:password) { |n| "Testpassword#{n}" } + f.sequence(:password_confirmation) { |n| "Testpassword#{n}" } + f.association :language +end \ No newline at end of file diff --git a/test/fixtures/.gitkeep b/test/fixtures/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/test/functional/.gitkeep b/test/functional/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/test/functional/access_authorizations_controller_test.rb b/test/functional/access_authorizations_controller_test.rb new file mode 100644 index 0000000..98761fd --- /dev/null +++ b/test/functional/access_authorizations_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class AccessAuthorizationsControllerTest < ActionController::TestCase + setup do + @access_authorization = access_authorizations(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:access_authorizations) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create access_authorization" do + assert_difference('AccessAuthorization.count') do + post :create, access_authorization: @access_authorization.attributes + end + + assert_redirected_to access_authorization_path(assigns(:access_authorization)) + end + + test "should show access_authorization" do + get :show, id: @access_authorization.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @access_authorization.to_param + assert_response :success + end + + test "should update access_authorization" do + put :update, id: @access_authorization.to_param, access_authorization: @access_authorization.attributes + assert_redirected_to access_authorization_path(assigns(:access_authorization)) + end + + test "should destroy access_authorization" do + assert_difference('AccessAuthorization.count', -1) do + delete :destroy, id: @access_authorization.to_param + end + + assert_redirected_to access_authorizations_path + end +end diff --git a/test/functional/acd_agents_controller_test.rb b/test/functional/acd_agents_controller_test.rb new file mode 100644 index 0000000..11355eb --- /dev/null +++ b/test/functional/acd_agents_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class AcdAgentsControllerTest < ActionController::TestCase + setup do + @acd_agent = acd_agents(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:acd_agents) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create acd_agent" do + assert_difference('AcdAgent.count') do + post :create, acd_agent: @acd_agent.attributes + end + + assert_redirected_to acd_agent_path(assigns(:acd_agent)) + end + + test "should show acd_agent" do + get :show, id: @acd_agent.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @acd_agent.to_param + assert_response :success + end + + test "should update acd_agent" do + put :update, id: @acd_agent.to_param, acd_agent: @acd_agent.attributes + assert_redirected_to acd_agent_path(assigns(:acd_agent)) + end + + test "should destroy acd_agent" do + assert_difference('AcdAgent.count', -1) do + delete :destroy, id: @acd_agent.to_param + end + + assert_redirected_to acd_agents_path + end +end diff --git a/test/functional/acd_callers_controller_test.rb b/test/functional/acd_callers_controller_test.rb new file mode 100644 index 0000000..960de7d --- /dev/null +++ b/test/functional/acd_callers_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class AcdCallersControllerTest < ActionController::TestCase + setup do + @acd_caller = acd_callers(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:acd_callers) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create acd_caller" do + assert_difference('AcdCaller.count') do + post :create, acd_caller: @acd_caller.attributes + end + + assert_redirected_to acd_caller_path(assigns(:acd_caller)) + end + + test "should show acd_caller" do + get :show, id: @acd_caller.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @acd_caller.to_param + assert_response :success + end + + test "should update acd_caller" do + put :update, id: @acd_caller.to_param, acd_caller: @acd_caller.attributes + assert_redirected_to acd_caller_path(assigns(:acd_caller)) + end + + test "should destroy acd_caller" do + assert_difference('AcdCaller.count', -1) do + delete :destroy, id: @acd_caller.to_param + end + + assert_redirected_to acd_callers_path + end +end diff --git a/test/functional/addresses_controller_test.rb b/test/functional/addresses_controller_test.rb new file mode 100644 index 0000000..b1f5c83 --- /dev/null +++ b/test/functional/addresses_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class AddressesControllerTest < ActionController::TestCase +# setup do +# @address = addresses(:one) +# end +# +# test "should get index" do +# get :index +# assert_response :success +# assert_not_nil assigns(:addresses) +# end +# +# test "should get new" do +# get :new +# assert_response :success +# end +# +# test "should create address" do +# assert_difference('Address.count') do +# post :create, address: @address.attributes +# end +# +# assert_redirected_to address_path(assigns(:address)) +# end +# +# test "should show address" do +# get :show, id: @address.to_param +# assert_response :success +# end +# +# test "should get edit" do +# get :edit, id: @address.to_param +# assert_response :success +# end +# +# test "should update address" do +# put :update, id: @address.to_param, address: @address.attributes +# assert_redirected_to address_path(assigns(:address)) +# end +# +# test "should destroy address" do +# assert_difference('Address.count', -1) do +# delete :destroy, id: @address.to_param +# end +# +# assert_redirected_to addresses_path +# end +end diff --git a/test/functional/api/rows_controller_test.rb b/test/functional/api/rows_controller_test.rb new file mode 100644 index 0000000..ca1926c --- /dev/null +++ b/test/functional/api/rows_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class Api::RowsControllerTest < ActionController::TestCase + setup do + @api_row = api_rows(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:api_rows) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create api_row" do + assert_difference('Api::Row.count') do + post :create, api_row: @api_row.attributes + end + + assert_redirected_to api_row_path(assigns(:api_row)) + end + + test "should show api_row" do + get :show, id: @api_row + assert_response :success + end + + test "should get edit" do + get :edit, id: @api_row + assert_response :success + end + + test "should update api_row" do + put :update, id: @api_row, api_row: @api_row.attributes + assert_redirected_to api_row_path(assigns(:api_row)) + end + + test "should destroy api_row" do + assert_difference('Api::Row.count', -1) do + delete :destroy, id: @api_row + end + + assert_redirected_to api_rows_path + end +end diff --git a/test/functional/automatic_call_distributors_controller_test.rb b/test/functional/automatic_call_distributors_controller_test.rb new file mode 100644 index 0000000..e8914fd --- /dev/null +++ b/test/functional/automatic_call_distributors_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class AutomaticCallDistributorsControllerTest < ActionController::TestCase + setup do + @automatic_call_distributor = automatic_call_distributors(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:automatic_call_distributors) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create automatic_call_distributor" do + assert_difference('AutomaticCallDistributor.count') do + post :create, automatic_call_distributor: @automatic_call_distributor.attributes + end + + assert_redirected_to automatic_call_distributor_path(assigns(:automatic_call_distributor)) + end + + test "should show automatic_call_distributor" do + get :show, id: @automatic_call_distributor.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @automatic_call_distributor.to_param + assert_response :success + end + + test "should update automatic_call_distributor" do + put :update, id: @automatic_call_distributor.to_param, automatic_call_distributor: @automatic_call_distributor.attributes + assert_redirected_to automatic_call_distributor_path(assigns(:automatic_call_distributor)) + end + + test "should destroy automatic_call_distributor" do + assert_difference('AutomaticCallDistributor.count', -1) do + delete :destroy, id: @automatic_call_distributor.to_param + end + + assert_redirected_to automatic_call_distributors_path + end +end diff --git a/test/functional/call_forwards_controller_test.rb b/test/functional/call_forwards_controller_test.rb new file mode 100644 index 0000000..0993623 --- /dev/null +++ b/test/functional/call_forwards_controller_test.rb @@ -0,0 +1,91 @@ +require 'test_helper' + +class CallForwardsControllerTest < ActionController::TestCase + + setup do + @user = Factory.create(:user) + + #@tenant = Factory.create(:tenant) + #@tenant.tenant_memberships.create(:user_id => @user.id) + #@user.update_attributes!(:current_tenant_id => @tenant.id) + + @sip_account = Factory.create( + :sip_account, + :sip_accountable => @user, + ) + @user.sip_accounts << @sip_account + @sip_account = @user.sip_accounts.last + + @phone_number = Factory.create( + :phone_number, + :phone_numberable => @sip_account, + ) + @sip_account.phone_numbers << @phone_number + @phone_number = @sip_account.phone_numbers.last + + @call_forward = Factory.create( + :call_forward, + :phone_number => @phone_number, + ) + @phone_number.call_forwards << @call_forward + @call_forward = @phone_number.call_forwards.last + end + + test "should get index" do + session[:user_id] = @user.id + get :index, + :phone_number_id => @phone_number.to_param + assert_response :success + assert_not_nil assigns(:call_forwards) + end + + test "should get new" do + get :new, + :phone_number_id => @phone_number.to_param + assert_response :success + end + + #TODO +# test "should create call_forward" do +# assert_difference('CallForward.count') do +# post :create, +# :phone_number_id => @phone_number.to_param, +# :call_forward => Factory.attributes_for( +# :call_forward +# ) +# end +# assert_redirected_to( phone_number_call_forward_path( @phone_number, @call_forward ) ) +# end + + test "should show call_forward" do + session[:user_id] = @user.id + get :show, + :phone_number_id => @phone_number.to_param, + :id => @call_forward.to_param + assert_response :success + end + + test "should get edit" do + get :edit, + :phone_number_id => @phone_number.to_param, + :id => @call_forward.to_param + assert_response :success + end + + test "should update call_forward" do + put :update, + :phone_number_id => @phone_number.to_param, + :id => @call_forward.to_param, call_forward: @call_forward.attributes + assert_redirected_to( phone_number_call_forward_path( @phone_number, @call_forward ) ) + end + + test "should destroy call_forward" do + assert_difference('CallForward.count', -1) do + delete :destroy, + :phone_number_id => @phone_number.to_param, + :id => @call_forward.to_param + end + assert_redirected_to( phone_number_call_forwards_path( @phone_number ) ) + end + +end diff --git a/test/functional/callthroughs_controller_test.rb b/test/functional/callthroughs_controller_test.rb new file mode 100644 index 0000000..330629c --- /dev/null +++ b/test/functional/callthroughs_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class CallthroughsControllerTest < ActionController::TestCase + setup do + @callthrough = callthroughs(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:callthroughs) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create callthrough" do + assert_difference('Callthrough.count') do + post :create, callthrough: @callthrough.attributes + end + + assert_redirected_to callthrough_path(assigns(:callthrough)) + end + + test "should show callthrough" do + get :show, id: @callthrough.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @callthrough.to_param + assert_response :success + end + + test "should update callthrough" do + put :update, id: @callthrough.to_param, callthrough: @callthrough.attributes + assert_redirected_to callthrough_path(assigns(:callthrough)) + end + + test "should destroy callthrough" do + assert_difference('Callthrough.count', -1) do + delete :destroy, id: @callthrough.to_param + end + + assert_redirected_to callthroughs_path + end +end diff --git a/test/functional/conference_invitees_controller_test.rb b/test/functional/conference_invitees_controller_test.rb new file mode 100644 index 0000000..72d2e2c --- /dev/null +++ b/test/functional/conference_invitees_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class ConferenceInviteesControllerTest < ActionController::TestCase + + setup do + @conference_invitee = Factory.create(:conference_invitee) + end + +# test "should get index" do +# get :index +# assert_response :success +# assert_not_nil assigns(:conference_invitees) +# end +# +# test "should get new" do +# get :new +# assert_response :success +# end +# +# test "should create conference_invitee" do +# assert_difference('ConferenceInvitee.count') do +# post :create, conference_invitee: @conference_invitee.attributes +# end +# assert_redirected_to conference_invitee_path(assigns(:conference_invitee)) +# end +# +# test "should show conference_invitee" do +# get :show, id: @conference_invitee.to_param +# assert_response :success +# end +# +# test "should get edit" do +# get :edit, id: @conference_invitee.to_param +# assert_response :success +# end +# +# test "should update conference_invitee" do +# put :update, id: @conference_invitee.to_param, conference_invitee: @conference_invitee.attributes +# assert_redirected_to conference_invitee_path(assigns(:conference_invitee)) +# end +# +# test "should destroy conference_invitee" do +# assert_difference('ConferenceInvitee.count', -1) do +# delete :destroy, id: @conference_invitee.to_param +# end +# assert_redirected_to conference_invitees_path +# end + +end diff --git a/test/functional/conferences_controller_test.rb b/test/functional/conferences_controller_test.rb new file mode 100644 index 0000000..954838b --- /dev/null +++ b/test/functional/conferences_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class ConferencesControllerTest < ActionController::TestCase + + setup do + @conference = Factory.create(:conference) + end + +# test "should get index" do +# get :index +# assert_response :success +# assert_not_nil assigns(:conferences) +# end +# +# test "should get new" do +# get :new +# assert_response :success +# end +# +# test "should create conference" do +# assert_difference('Conference.count') do +# post :create, conference: @conference.attributes +# end +# assert_redirected_to conference_path(assigns(:conference)) +# end +# +# test "should show conference" do +# get :show, id: @conference.to_param +# assert_response :success +# end +# +# test "should get edit" do +# get :edit, id: @conference.to_param +# assert_response :success +# end +# +# test "should update conference" do +# put :update, id: @conference.to_param, conference: @conference.attributes +# assert_redirected_to conference_path(assigns(:conference)) +# end +# +# test "should destroy conference" do +# assert_difference('Conference.count', -1) do +# delete :destroy, id: @conference.to_param +# end +# assert_redirected_to conferences_path +# end + +end diff --git a/test/functional/config_siemens_controller_test.rb b/test/functional/config_siemens_controller_test.rb new file mode 100644 index 0000000..949f776 --- /dev/null +++ b/test/functional/config_siemens_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class ConfigSiemensControllerTest < ActionController::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/functional/fax_accounts_controller_test.rb b/test/functional/fax_accounts_controller_test.rb new file mode 100644 index 0000000..64b781d --- /dev/null +++ b/test/functional/fax_accounts_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class FaxAccountsControllerTest < ActionController::TestCase + setup do + @fax_account = fax_accounts(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:fax_accounts) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create fax_account" do + assert_difference('FaxAccount.count') do + post :create, fax_account: @fax_account.attributes + end + + assert_redirected_to fax_account_path(assigns(:fax_account)) + end + + test "should show fax_account" do + get :show, id: @fax_account.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @fax_account.to_param + assert_response :success + end + + test "should update fax_account" do + put :update, id: @fax_account.to_param, fax_account: @fax_account.attributes + assert_redirected_to fax_account_path(assigns(:fax_account)) + end + + test "should destroy fax_account" do + assert_difference('FaxAccount.count', -1) do + delete :destroy, id: @fax_account.to_param + end + + assert_redirected_to fax_accounts_path + end +end diff --git a/test/functional/fax_documents_controller_test.rb b/test/functional/fax_documents_controller_test.rb new file mode 100644 index 0000000..0322c61 --- /dev/null +++ b/test/functional/fax_documents_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class FaxDocumentsControllerTest < ActionController::TestCase + setup do + @fax_document = fax_documents(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:fax_documents) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create fax_document" do + assert_difference('FaxDocument.count') do + post :create, fax_document: @fax_document.attributes + end + + assert_redirected_to fax_document_path(assigns(:fax_document)) + end + + test "should show fax_document" do + get :show, id: @fax_document.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @fax_document.to_param + assert_response :success + end + + test "should update fax_document" do + put :update, id: @fax_document.to_param, fax_document: @fax_document.attributes + assert_redirected_to fax_document_path(assigns(:fax_document)) + end + + test "should destroy fax_document" do + assert_difference('FaxDocument.count', -1) do + delete :destroy, id: @fax_document.to_param + end + + assert_redirected_to fax_documents_path + end +end diff --git a/test/functional/gemeinschaft_setups_controller_test.rb b/test/functional/gemeinschaft_setups_controller_test.rb new file mode 100644 index 0000000..b23a878 --- /dev/null +++ b/test/functional/gemeinschaft_setups_controller_test.rb @@ -0,0 +1,50 @@ +require 'test_helper' + +class GemeinschaftSetupsControllerTest < ActionController::TestCase + + setup do + @gemeinschaft_setup = Factory.build(:gemeinschaft_setup) + end + +# test "should get index" do +# get :index +# assert_response :success +# assert_not_nil assigns(:gemeinschaft_setups) +# end + + test "should get new" do + get :new + assert_response :success + end + +# test "should create gemeinschaft_setup" do +# assert_difference('GemeinschaftSetup.count') do +# post :create, +# gemeinschaft_setup: Factory.attributes_for(:gemeinschaft_setup) +# end +# assert_redirected_to gemeinschaft_setup_path(assigns(:gemeinschaft_setup)) +# end + +# test "should show gemeinschaft_setup" do +# get :show, id: @gemeinschaft_setup.to_param +# assert_response :success +# end + +# test "should get edit" do +# get :edit, id: @gemeinschaft_setup.to_param +# assert_response :success +# end + +# test "should update gemeinschaft_setup" do +# put :update, id: @gemeinschaft_setup.to_param, gemeinschaft_setup: @gemeinschaft_setup.attributes +# assert_redirected_to gemeinschaft_setup_path(assigns(:gemeinschaft_setup)) +# end + +# test "should destroy gemeinschaft_setup" do +# assert_difference('GemeinschaftSetup.count', -1) do +# delete :destroy, id: @gemeinschaft_setup.to_param +# end +# assert_redirected_to gemeinschaft_setups_path +# end + +end diff --git a/test/functional/gs_cluster_sync_log_entries_controller_test.rb b/test/functional/gs_cluster_sync_log_entries_controller_test.rb new file mode 100644 index 0000000..f8fa336 --- /dev/null +++ b/test/functional/gs_cluster_sync_log_entries_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class GsClusterSyncLogEntriesControllerTest < ActionController::TestCase + setup do + @gs_cluster_sync_log_entry = gs_cluster_sync_log_entries(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:gs_cluster_sync_log_entries) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create gs_cluster_sync_log_entry" do + assert_difference('GsClusterSyncLogEntry.count') do + post :create, gs_cluster_sync_log_entry: @gs_cluster_sync_log_entry.attributes + end + + assert_redirected_to gs_cluster_sync_log_entry_path(assigns(:gs_cluster_sync_log_entry)) + end + + test "should show gs_cluster_sync_log_entry" do + get :show, id: @gs_cluster_sync_log_entry.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @gs_cluster_sync_log_entry.to_param + assert_response :success + end + + test "should update gs_cluster_sync_log_entry" do + put :update, id: @gs_cluster_sync_log_entry.to_param, gs_cluster_sync_log_entry: @gs_cluster_sync_log_entry.attributes + assert_redirected_to gs_cluster_sync_log_entry_path(assigns(:gs_cluster_sync_log_entry)) + end + + test "should destroy gs_cluster_sync_log_entry" do + assert_difference('GsClusterSyncLogEntry.count', -1) do + delete :destroy, id: @gs_cluster_sync_log_entry.to_param + end + + assert_redirected_to gs_cluster_sync_log_entries_path + end +end diff --git a/test/functional/gs_nodes_controller_test.rb b/test/functional/gs_nodes_controller_test.rb new file mode 100644 index 0000000..f5349ed --- /dev/null +++ b/test/functional/gs_nodes_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class GsNodesControllerTest < ActionController::TestCase + setup do + @gs_node = gs_nodes(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:gs_nodes) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create gs_node" do + assert_difference('GsNode.count') do + post :create, gs_node: @gs_node.attributes + end + + assert_redirected_to gs_node_path(assigns(:gs_node)) + end + + test "should show gs_node" do + get :show, id: @gs_node.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @gs_node.to_param + assert_response :success + end + + test "should update gs_node" do + put :update, id: @gs_node.to_param, gs_node: @gs_node.attributes + assert_redirected_to gs_node_path(assigns(:gs_node)) + end + + test "should destroy gs_node" do + assert_difference('GsNode.count', -1) do + delete :destroy, id: @gs_node.to_param + end + + assert_redirected_to gs_nodes_path + end +end diff --git a/test/functional/gui_functions_controller_test.rb b/test/functional/gui_functions_controller_test.rb new file mode 100644 index 0000000..9a6326f --- /dev/null +++ b/test/functional/gui_functions_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class GuiFunctionsControllerTest < ActionController::TestCase + setup do + @gui_function = gui_functions(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:gui_functions) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create gui_function" do + assert_difference('GuiFunction.count') do + post :create, gui_function: @gui_function.attributes + end + + assert_redirected_to gui_function_path(assigns(:gui_function)) + end + + test "should show gui_function" do + get :show, id: @gui_function.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @gui_function.to_param + assert_response :success + end + + test "should update gui_function" do + put :update, id: @gui_function.to_param, gui_function: @gui_function.attributes + assert_redirected_to gui_function_path(assigns(:gui_function)) + end + + test "should destroy gui_function" do + assert_difference('GuiFunction.count', -1) do + delete :destroy, id: @gui_function.to_param + end + + assert_redirected_to gui_functions_path + end +end diff --git a/test/functional/hunt_group_members_controller_test.rb b/test/functional/hunt_group_members_controller_test.rb new file mode 100644 index 0000000..9830c99 --- /dev/null +++ b/test/functional/hunt_group_members_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class HuntGroupMembersControllerTest < ActionController::TestCase + setup do + @hunt_group_member = hunt_group_members(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:hunt_group_members) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create hunt_group_member" do + assert_difference('HuntGroupMember.count') do + post :create, hunt_group_member: @hunt_group_member.attributes + end + + assert_redirected_to hunt_group_member_path(assigns(:hunt_group_member)) + end + + test "should show hunt_group_member" do + get :show, id: @hunt_group_member.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @hunt_group_member.to_param + assert_response :success + end + + test "should update hunt_group_member" do + put :update, id: @hunt_group_member.to_param, hunt_group_member: @hunt_group_member.attributes + assert_redirected_to hunt_group_member_path(assigns(:hunt_group_member)) + end + + test "should destroy hunt_group_member" do + assert_difference('HuntGroupMember.count', -1) do + delete :destroy, id: @hunt_group_member.to_param + end + + assert_redirected_to hunt_group_members_path + end +end diff --git a/test/functional/hunt_groups_controller_test.rb b/test/functional/hunt_groups_controller_test.rb new file mode 100644 index 0000000..0234e12 --- /dev/null +++ b/test/functional/hunt_groups_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class HuntGroupsControllerTest < ActionController::TestCase + setup do + @hunt_group = hunt_groups(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:hunt_groups) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create hunt_group" do + assert_difference('HuntGroup.count') do + post :create, hunt_group: @hunt_group.attributes + end + + assert_redirected_to hunt_group_path(assigns(:hunt_group)) + end + + test "should show hunt_group" do + get :show, id: @hunt_group.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @hunt_group.to_param + assert_response :success + end + + test "should update hunt_group" do + put :update, id: @hunt_group.to_param, hunt_group: @hunt_group.attributes + assert_redirected_to hunt_group_path(assigns(:hunt_group)) + end + + test "should destroy hunt_group" do + assert_difference('HuntGroup.count', -1) do + delete :destroy, id: @hunt_group.to_param + end + + assert_redirected_to hunt_groups_path + end +end diff --git a/test/functional/manufacturers_controller_test.rb b/test/functional/manufacturers_controller_test.rb new file mode 100644 index 0000000..dad38e5 --- /dev/null +++ b/test/functional/manufacturers_controller_test.rb @@ -0,0 +1,77 @@ +require 'test_helper' + +class ManufacturersControllerTest < ActionController::TestCase + setup do + @tenant = Factory.create(:tenant) + @user = Factory.create(:user) + + @tenant.tenant_memberships.create(:user_id => @user.id) + + @user.update_attributes!(:current_tenant_id => @tenant.id) + + @manufacturer = Factory.create(:manufacturer) + + @expected_status_if_not_authorized = :redirect + end + + test "should not do anything for a normal user" do + session[:user_id] = @user.id + get :index + assert_response :redirect + + get :new + assert_response :redirect + + get :show, id: @manufacturer.to_param + assert_response :redirect + + get :edit, id: @manufacturer.to_param + assert_response :redirect + end + + # Maybe some sort of SuperUser Group should have access. + # Needs some more thinking. + # + # test "should get index" do + # session[:user_id] = @user.id + # get :index + # assert_response :success + # assert_not_nil assigns(:manufacturers) + # end + # + # test "should get new" do + # get :new + # assert_response :success + # end + # + # test "should create manufacturer" do + # assert_difference('Manufacturer.count') do + # post :create, manufacturer: Factory.build(:manufacturer).attributes + # end + # + # assert_redirected_to manufacturer_path(assigns(:manufacturer)) + # end + # + # test "should show manufacturer" do + # get :show, id: @manufacturer.to_param + # assert_response :success + # end + # + # test "should get edit" do + # get :edit, id: @manufacturer.to_param + # assert_response :success + # end + # + # test "should update manufacturer" do + # put :update, id: @manufacturer.to_param, manufacturer: @manufacturer.attributes + # assert_redirected_to manufacturer_path(assigns(:manufacturer)) + # end + # + # test "should destroy manufacturer" do + # assert_difference('Manufacturer.count', -1) do + # delete :destroy, id: @manufacturer.to_param + # end + # + # assert_redirected_to manufacturers_path + # end +end diff --git a/test/functional/notifications_test.rb b/test/functional/notifications_test.rb new file mode 100644 index 0000000..d84bda2 --- /dev/null +++ b/test/functional/notifications_test.rb @@ -0,0 +1,12 @@ +require 'test_helper' + +class NotificationsTest < ActionMailer::TestCase + test "new_pin" do + mail = Notifications.new_pin + assert_equal "New pin", mail.subject + assert_equal ["to@example.org"], mail.to + assert_equal ["from@example.com"], mail.from + assert_match "Hi", mail.body.encoded + end + +end diff --git a/test/functional/page_controller_test.rb b/test/functional/page_controller_test.rb new file mode 100644 index 0000000..a5ae5ad --- /dev/null +++ b/test/functional/page_controller_test.rb @@ -0,0 +1,35 @@ +require 'test_helper' + +class PageControllerTest < ActionController::TestCase + + #test "on a fresh system you should not get index but be redirected to the setup wizard" do + test "should be redirected to setup wizard on a fresh system" do + session[:user_id] = nil + get :index + assert_redirected_to wizards_new_initial_setup_path + end + + + test "a logged in user should get index" do + @tenant = Factory.create(:tenant) + @user = Factory.create(:user) + + @tenant.users << @user + + session[:user_id] = @user.id + get :index + assert_response :success + end + + test "a logged out user should be redirected to the login" do + @tenant = Factory.create(:tenant) + @user = Factory.create(:user) + + @tenant.users << @user + + session[:user_id] = nil + get :index + assert_redirected_to log_in_path + end + +end diff --git a/test/functional/phone_book_entries_controller_test.rb b/test/functional/phone_book_entries_controller_test.rb new file mode 100644 index 0000000..81c5b61 --- /dev/null +++ b/test/functional/phone_book_entries_controller_test.rb @@ -0,0 +1,103 @@ +require 'test_helper' + +class PhoneBookEntriesControllerTest < ActionController::TestCase + + setup do + @user1 = Factory.create(:user) + pb = @user1.phone_books.first + @user1_phone_book_entry = Factory.create( + :phone_book_entry, + :phone_book_id => pb.id + ) + + @expected_status_if_not_authorized = :redirect + end + + test "should not get index (not logged in)" do + get :index + assert_response @expected_status_if_not_authorized + end + + test "should get index" do + session[:user_id] = @user1.id + get :index + assert_response :success + assert_not_nil assigns(:phone_book_entries) + end + + +# test "should get new" do +# get :new +# assert_response :success +# end + + test "should not have a route for new" do + assert_raises(ActionController::RoutingError) { + get :new + } + end + +# +# test "should create phone_book_entry" do +# assert_difference('PhoneBookEntry.count') do +# post :create, phone_book_entry: @user1_phone_book_entry.attributes +# end +# +# assert_redirected_to phone_book_entry_path(assigns(:phone_book_entry)) +# end +# + test "should not show phone_book_entry (not logged in)" do + get :show, id: @user1_phone_book_entry.to_param + assert_response @expected_status_if_not_authorized + end + + test "should show phone_book_entry without nesting" do + session[:user_id] = @user1.id + get :show, id: @user1_phone_book_entry.to_param + assert_response :success + end + + test "should show phone_book_entry nested in phone_book" do + session[:user_id] = @user1.id + get :show, phone_book_id: @user1_phone_book_entry.phone_book.id, id: @user1_phone_book_entry.to_param + assert_response :success + end +# +# test "should get edit" do +# get :edit, id: @user1_phone_book_entry.to_param +# assert_response :success +# end + + test "should not have a route for edit" do + assert_raises(ActionController::RoutingError) { + get :edit, id: @user1_phone_book_entry.to_param + } + end + +# +# test "should update phone_book_entry" do +# put :update, id: @user1_phone_book_entry.to_param, phone_book_entry: @user1_phone_book_entry.attributes +# assert_redirected_to phone_book_entry_path(assigns(:phone_book_entry)) +# end + + test "should not have a route for update" do + assert_raises(ActionController::RoutingError) { + put :update, id: @user1_phone_book_entry.to_param, phone_book_entry: @user1_phone_book_entry.attributes + } + end + +# +# test "should destroy phone_book_entry" do +# assert_difference('PhoneBookEntry.count', -1) do +# delete :destroy, id: @user1_phone_book_entry.to_param +# end +# assert_redirected_to phone_book_entries_path +# end + + test "should not have a route for destroy" do + assert_raises(ActionController::RoutingError) { + delete :destroy, id: @user1_phone_book_entry.to_param + } + end + +end diff --git a/test/functional/phone_books_controller_test.rb b/test/functional/phone_books_controller_test.rb new file mode 100644 index 0000000..a00f597 --- /dev/null +++ b/test/functional/phone_books_controller_test.rb @@ -0,0 +1,71 @@ +require 'test_helper' + +class PhoneBooksControllerTest < ActionController::TestCase + setup do + @tenant = Factory.create(:tenant) + @admins = @tenant.user_groups.find_or_create_by_name('Admins') + @users = @tenant.user_groups.find_or_create_by_name('Users') + @user = Factory.create(:user) + + @tenant.users << @user + @users.users << @user + + @personal_phone_book = Factory.create(:phone_book, + :phone_bookable_type => @user.class.to_s, + :phone_bookable_id => @user.id + ) + phone_book_entry = Factory.create(:phone_book_entry) + @personal_phone_book.phone_book_entries << phone_book_entry + + @expected_status_if_not_authorized = :redirect + + session[:user_id] = @user.id + end + + test "should get index" do + get :index, user_id: @user.id + assert_response :success + assert_not_nil assigns(:phone_books) + end + + test "should get new" do + get :new, user_id: @user.id + assert_response :success + end + + test "should create phone_book" do + phone_book2 = Factory.build(:phone_book, + :phone_bookable_type => @user.class.to_s, + :phone_bookable_id => @user.id + ) + assert_difference('PhoneBook.count') do + post :create, phone_book: phone_book2.attributes, user_id: @user.id + end + assert_redirected_to( user_phone_book_path( @user, assigns(:phone_book))) + end + + test "should show phone_book" do + get :show, id: @personal_phone_book.to_param, user_id: @user.id + assert_response :success + end + + test "should get edit" do + get :edit, id: @personal_phone_book.to_param, user_id: @user.id + assert_response :success + end + + test "should update phone_book" do + put :update, id: @personal_phone_book.to_param, phone_book: @personal_phone_book.attributes, user_id: @user.id + assert_redirected_to( user_phone_book_path(@user, assigns(:phone_book))) + end + + # TODO: Fix this test + # + # test "should destroy phone_book" do + # assert_difference('PhoneBook.count', -1) do + # delete :destroy, id: @personal_phone_book.to_param, user_id: @user.id + # end + # assert_redirected_to( user_phone_books_path( @user )) + # end + +end diff --git a/test/functional/phone_models_controller_test.rb b/test/functional/phone_models_controller_test.rb new file mode 100644 index 0000000..2d1a87a --- /dev/null +++ b/test/functional/phone_models_controller_test.rb @@ -0,0 +1,143 @@ +require 'test_helper' + +class PhoneModelsControllerTest < ActionController::TestCase + + setup do + # Create a tenant: + @tenant = Factory.create(:tenant) + + # Create a User who is member of the Tenant but has no special rights: + @user = Factory.create(:user) + @tenant.tenant_memberships.create(:user_id => @user.id) + @user.update_attributes!(:current_tenant_id => @tenant.id) + + # Create a User who is member of the Tenant and has super admin rights: + @super_admin = Factory.create(:user) + @tenant.tenant_memberships.create(:user_id => @super_admin.id) + @super_admin.update_attributes!(:current_tenant_id => @tenant.id) + + # Create a PhoneModel + # + @phone_model = Factory.create(:phone_model) + end + + [ '@user.id', '' ].each do |user_id_code| + # Note: Do *not* actually create the user outside of tests. + + explanation = user_id_code.blank? ? + "if not logged in" : + "if logged in as an ordinary user" + + test "should not get index #{explanation}" do + session[:user_id] = eval( user_id_code ) + get :index, manufacturer_id: @phone_model.manufacturer_id + assert_response :redirect + end + + test "should not get new #{explanation}" do + session[:user_id] = eval( user_id_code ) + get :new, manufacturer_id: @phone_model.manufacturer_id + assert_response :redirect + end + + test "should not create phone_model #{explanation}" do + session[:user_id] = eval( user_id_code ) + + assert_no_difference('PhoneModel.count') do + post :create, manufacturer_id: @phone_model.manufacturer_id, phone_model: Factory.build(:phone_model, + :manufacturer_id => @phone_model.manufacturer_id).attributes + end + end + + test "should not show phone_model #{explanation}" do + session[:user_id] = eval( user_id_code ) + get :show, manufacturer_id: @phone_model.manufacturer_id, id: @phone_model.to_param + assert_response :redirect + end + + test "should not get edit #{explanation}" do + session[:user_id] = eval( user_id_code ) + get :edit, manufacturer_id: @phone_model.manufacturer_id, id: @phone_model.to_param + assert_response :redirect + end + + test "should not update phone_model #{explanation}" do + session[:user_id] = eval( user_id_code ) + + # save the old name: + old_name = PhoneModel.find(@phone_model.id).name + # try to make an update: + put :update, manufacturer_id: @phone_model.manufacturer_id, id: @phone_model.to_param, phone_model: @phone_model.attributes.merge({ + 'name' => @phone_model.name.reverse + }) + # check that the update didn't work: + assert_equal old_name, PhoneModel.find(@phone_model.id).name + + assert_response :redirect + end + + test "should not destroy phone_model #{explanation}" do + session[:user_id] = eval( user_id_code ) + + assert_no_difference('PhoneModel.count') do + delete :destroy, manufacturer_id: @phone_model.manufacturer_id, id: @phone_model.to_param + end + assert_response :redirect + end + + end + + + test "should get index as super admin" do + session[:user_id] = @super_admin.id + get :index, manufacturer_id: @phone_model.manufacturer_id + assert_response :success + assert_not_nil assigns(:phone_models) + end + + test "should get new as super admin" do + session[:user_id] = @super_admin.id + get :new, manufacturer_id: @phone_model.manufacturer_id + assert_response :success + end + + + # # We don't have access to manufacturer_id. We'll need to + # # add routes first. + # test "should create phone_model as super admin" do + # assert_difference('PhoneModel.count') do + # post :create, phone_model: Factory.build(:phone_model, + # :manufacturer_id => @phone_model.manufacturer_id).attributes + # end + # + # assert_redirected_to manufacturer_phone_model_path( @phone_model.manufacturer_id, assigns(:phone_model)) + # end + + test "should show phone_model as super admin" do + session[:user_id] = @super_admin.id + get :show, manufacturer_id: @phone_model.manufacturer_id, id: @phone_model.to_param + assert_response :success + end + + test "should get edit as super admin" do + session[:user_id] = @super_admin.id + get :edit, manufacturer_id: @phone_model.manufacturer_id, id: @phone_model.to_param + assert_response :success + end + + test "should update phone_model as super admin" do + session[:user_id] = @super_admin.id + put :update, manufacturer_id: @phone_model.manufacturer_id, id: @phone_model.to_param, phone_model: @phone_model.attributes + assert_redirected_to manufacturer_phone_model_path( @phone_model.manufacturer_id, assigns(:phone_model)) + end + + test "should destroy phone_model as super admin" do + session[:user_id] = @super_admin.id + assert_difference('PhoneModel.count', -1) do + delete :destroy, manufacturer_id: @phone_model.manufacturer_id, id: @phone_model.to_param + end + + assert_redirected_to manufacturer_phone_models_path( @phone_model.manufacturer_id ) + end + +end diff --git a/test/functional/phone_number_ranges_controller_test.rb b/test/functional/phone_number_ranges_controller_test.rb new file mode 100644 index 0000000..39f28c4 --- /dev/null +++ b/test/functional/phone_number_ranges_controller_test.rb @@ -0,0 +1,78 @@ +require 'test_helper' + +class PhoneNumberRangesControllerTest < ActionController::TestCase + + #TODO Uncomment tests once the views are implemented. + + setup do + @phone_number_range = Factory.create(:phone_number_range) + end + + test "should get index" do + get :index, + :"#{@phone_number_range.phone_number_rangeable_type.underscore}_id" => @phone_number_range.phone_number_rangeable.try(:to_param) + assert_response :success + assert_not_nil assigns(:phone_number_ranges) + end + +# test "should get new" do +# get :new, +# :"#{@phone_number_range.phone_number_rangeable_type.underscore}_id" => @phone_number_range.phone_number_rangeable.try(:to_param) +# assert_response :success +# end + +# test "should create phone_number_range" do +# assert_difference('PhoneNumberRange.count') do +# post :create, +# :"#{@phone_number_range.phone_number_rangeable_type.underscore}_id" => @phone_number_range.phone_number_rangeable.try(:to_param), +# :phone_number_range => @phone_number_range.attributes +# end +# assert_redirected_to( +# method( :"#{@phone_number_range.phone_number_rangeable_type.underscore}_phone_number_range_path" ).( +# @phone_number_range.phone_number_rangeable, +# @phone_number_range +# ) +# ) +# end + +# test "should show phone_number_range" do +# get :show, +# :"#{@phone_number_range.phone_number_rangeable_type.underscore}_id" => @phone_number_range.phone_number_rangeable.try(:to_param), +# :id => @phone_number_range.to_param +# assert_response :success +# end + +# test "should get edit" do +# get :edit, +# :"#{@phone_number_range.phone_number_rangeable_type.underscore}_id" => @phone_number_range.phone_number_rangeable.try(:to_param), +# :id => @phone_number_range.to_param +# assert_response :success +# end + + test "should update phone_number_range" do + put :update, + :"#{@phone_number_range.phone_number_rangeable_type.underscore}_id" => @phone_number_range.phone_number_rangeable.try(:to_param), + :id => @phone_number_range.to_param, + :phone_number_range => @phone_number_range.attributes +# assert_redirected_to( +# method( :"#{@phone_number_range.phone_number_rangeable_type.underscore}_phone_number_range_path" ).( +# @phone_number_range.phone_number_rangeable, +# @phone_number_range +# ) +# ) + end + +# test "should destroy phone_number_range" do +# assert_difference('PhoneNumberRange.count', -1) do +# delete :destroy, +# :"#{@phone_number_range.phone_number_rangeable_type.underscore}_id" => @phone_number_range.phone_number_rangeable.try(:to_param), +# :id => @phone_number_range.to_param +# end +# assert_redirected_to( +# method( :"#{@phone_number_range.phone_number_rangeable_type.underscore}_phone_number_ranges_path" ).( +# @phone_number_range.phone_number_rangeable +# ) +# ) +# end + +end diff --git a/test/functional/phone_numbers_controller_test.rb b/test/functional/phone_numbers_controller_test.rb new file mode 100644 index 0000000..ab0a4b2 --- /dev/null +++ b/test/functional/phone_numbers_controller_test.rb @@ -0,0 +1,115 @@ +require 'test_helper' + +class PhoneNumbersControllerTest < ActionController::TestCase + + setup do + @tenant = Factory.create(:tenant) + @user = Factory.create(:user) + + @tenant.tenant_memberships.create(:user_id => @user.id) + + @user.update_attributes!(:current_tenant_id => @tenant.id) + + @private_phone_book = @user.phone_books.first + + @private_phone_book_entry = Factory.create( + :phone_book_entry, + :phone_book => @private_phone_book + ) + @phone_number = Factory.create( + :phone_number, + :phone_numberable => @private_phone_book_entry + ) + + @expected_status_if_not_authorized = :redirect + end + + + test "should get index" do + session[:user_id] = @user.id + get :index, phone_book_entry_id: @private_phone_book_entry.id + assert_response :success + assert_not_nil assigns(:phone_numbers) + end + + test "should not get index (not logged in)" do + get :index, phone_book_entry_id: @private_phone_book_entry.id + assert_response @expected_status_if_not_authorized + end + + test "should get new" do + session[:user_id] = @user.id + get :new, phone_book_entry_id: @private_phone_book_entry.id + assert_response :success + end + + # test "should not get new (not logged in)" do + # get :new, phone_book_entry_id: @private_phone_book_entry.id + # assert_response @expected_status_if_not_authorized + # end + + # test "should create phone_number" do + # session[:user_id] = @user.id + # assert_difference('PhoneNumber.count') do + # post :create, phone_book_entry_id: @private_phone_book_entry.id, phone_number: @phone_number.attributes + # end + # assert_redirected_to( phone_book_entry_phone_number_path( assigns(:phone_number))) + # end + # + # test "should not create phone_number (not logged in)" do + # assert_no_difference('PhoneNumber.count') do + # post :create, phone_book_entry_id: @private_phone_book_entry.id, phone_number: @phone_number.attributes + # end + # assert_response @expected_status_if_not_authorized + # end + + test "should show phone_number" do + session[:user_id] = @user.id + get :show, phone_book_entry_id: @private_phone_book_entry.id, id: @phone_number.to_param + assert_response :success + end + + test "should not show phone_number (not logged in)" do + get :show, phone_book_entry_id: @private_phone_book_entry.id, id: @phone_number.to_param + assert_response @expected_status_if_not_authorized + end + + + test "should get edit" do + session[:user_id] = @user.id + get :edit, phone_book_entry_id: @private_phone_book_entry.id, id: @phone_number.to_param + assert_response :success + end + + test "should not get edit (not logged in)" do + get :edit, phone_book_entry_id: @private_phone_book_entry.id, id: @phone_number.to_param + assert_response @expected_status_if_not_authorized + end + + test "should update phone_number" do + session[:user_id] = @user.id + put :update, phone_book_entry_id: @private_phone_book_entry.id, id: @phone_number.to_param, phone_number: @phone_number.attributes + assert_redirected_to( phone_book_entry_phone_number_path( assigns(:phone_number))) + end + + test "should not update phone_number (not logged in)" do + put :update, phone_book_entry_id: @private_phone_book_entry.id, id: @phone_number.to_param, phone_number: @phone_number.attributes + assert_response @expected_status_if_not_authorized + end + + test "should destroy phone_number" do + session[:user_id] = @user.id + assert_difference('PhoneNumber.count', -1) do + delete :destroy, phone_book_entry_id: @private_phone_book_entry.id, id: @phone_number.to_param + end + assert_redirected_to( phone_book_entry_phone_numbers_path() ) + end + + test "should not destroy phone_number (not logged in)" do + assert_no_difference('PhoneNumber.count') do + delete :destroy, phone_book_entry_id: @private_phone_book_entry.id, id: @phone_number.to_param + end + assert_response @expected_status_if_not_authorized + end + +end diff --git a/test/functional/phone_sip_accounts_controller_test.rb b/test/functional/phone_sip_accounts_controller_test.rb new file mode 100644 index 0000000..37a3219 --- /dev/null +++ b/test/functional/phone_sip_accounts_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class PhoneSipAccountsControllerTest < ActionController::TestCase + setup do + @phone_sip_account = phone_sip_accounts(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:phone_sip_accounts) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create phone_sip_account" do + assert_difference('PhoneSipAccount.count') do + post :create, phone_sip_account: @phone_sip_account.attributes + end + + assert_redirected_to phone_sip_account_path(assigns(:phone_sip_account)) + end + + test "should show phone_sip_account" do + get :show, id: @phone_sip_account.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @phone_sip_account.to_param + assert_response :success + end + + test "should update phone_sip_account" do + put :update, id: @phone_sip_account.to_param, phone_sip_account: @phone_sip_account.attributes + assert_redirected_to phone_sip_account_path(assigns(:phone_sip_account)) + end + + test "should destroy phone_sip_account" do + assert_difference('PhoneSipAccount.count', -1) do + delete :destroy, id: @phone_sip_account.to_param + end + + assert_redirected_to phone_sip_accounts_path + end +end diff --git a/test/functional/phones_controller_test.rb b/test/functional/phones_controller_test.rb new file mode 100644 index 0000000..1b0aa55 --- /dev/null +++ b/test/functional/phones_controller_test.rb @@ -0,0 +1,55 @@ +require 'test_helper' + +class PhonesControllerTest < ActionController::TestCase + # TODO nil und normaler User duerfen nichts. + + #TODO Uncomment tests once the route has been implemented. + +# setup do +# @phone = Factory.create(:phone) +# end +# +# test "should get index" do +# get :index +# assert_response :success +# assert_not_nil assigns(:phones) +# end +# +# test "should get new" do +# get :new +# assert_response :success +# end +# +# # Would have to be a nested route to work. +# # +# # test "should create phone" do +# # assert_difference('Phone.count') do +# # post :create, phone: Factory.build(:phone, :phone_model_id => @phone.phone_model_id).attributes +# # end +# # +# # assert_redirected_to phone_path(assigns(:phone)) +# # end +# +# test "should show phone" do +# get :show, id: @phone.to_param +# assert_response :success +# end +# +# test "should get edit" do +# get :edit, id: @phone.to_param +# assert_response :success +# end +# +# test "should update phone" do +# put :update, id: @phone.to_param, phone: @phone.attributes +# assert_redirected_to phone_path(assigns(:phone)) +# end +# +# test "should destroy phone" do +# assert_difference('Phone.count', -1) do +# delete :destroy, id: @phone.to_param +# end +# +# assert_redirected_to phones_path +# end +end diff --git a/test/functional/phones_sip_accounts_controller_test.rb b/test/functional/phones_sip_accounts_controller_test.rb new file mode 100644 index 0000000..967b8fe --- /dev/null +++ b/test/functional/phones_sip_accounts_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class PhonesSipAccountsControllerTest < ActionController::TestCase + + setup do + @phones_sip_account = Factory.create(:phones_sip_account) + end + +# test "should get index" do +# get :index +# assert_response :success +# assert_not_nil assigns(:phones_sip_accounts) +# end +# +# test "should get new" do +# get :new +# assert_response :success +# end +# +# test "should create phones_sip_account" do +# assert_difference('PhonesSipAccount.count') do +# post :create, phones_sip_account: @phones_sip_account.attributes +# end +# assert_redirected_to phones_sip_account_path(assigns(:phones_sip_account)) +# end +# +# test "should show phones_sip_account" do +# get :show, id: @phones_sip_account.to_param +# assert_response :success +# end +# +# test "should get edit" do +# get :edit, id: @phones_sip_account.to_param +# assert_response :success +# end +# +# test "should update phones_sip_account" do +# put :update, id: @phones_sip_account.to_param, phones_sip_account: @phones_sip_account.attributes +# assert_redirected_to phones_sip_account_path(assigns(:phones_sip_account)) +# end +# +# test "should destroy phones_sip_account" do +# assert_difference('PhonesSipAccount.count', -1) do +# delete :destroy, id: @phones_sip_account.to_param +# end +# assert_redirected_to phones_sip_accounts_path +# end + +end diff --git a/test/functional/ringtones_controller_test.rb b/test/functional/ringtones_controller_test.rb new file mode 100644 index 0000000..f0f04f6 --- /dev/null +++ b/test/functional/ringtones_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class RingtonesControllerTest < ActionController::TestCase + setup do + @ringtone = ringtones(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:ringtones) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create ringtone" do + assert_difference('Ringtone.count') do + post :create, ringtone: @ringtone.attributes + end + + assert_redirected_to ringtone_path(assigns(:ringtone)) + end + + test "should show ringtone" do + get :show, id: @ringtone.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @ringtone.to_param + assert_response :success + end + + test "should update ringtone" do + put :update, id: @ringtone.to_param, ringtone: @ringtone.attributes + assert_redirected_to ringtone_path(assigns(:ringtone)) + end + + test "should destroy ringtone" do + assert_difference('Ringtone.count', -1) do + delete :destroy, id: @ringtone.to_param + end + + assert_redirected_to ringtones_path + end +end diff --git a/test/functional/sessions_controller_test.rb b/test/functional/sessions_controller_test.rb new file mode 100644 index 0000000..d30ebc3 --- /dev/null +++ b/test/functional/sessions_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class SessionsControllerTest < ActionController::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/functional/sip_accounts_controller_test.rb b/test/functional/sip_accounts_controller_test.rb new file mode 100644 index 0000000..5c97dd2 --- /dev/null +++ b/test/functional/sip_accounts_controller_test.rb @@ -0,0 +1,76 @@ +require 'test_helper' + +class SipAccountsControllerTest < ActionController::TestCase + + setup do + @tenant = Factory.create(:tenant) + @user = Factory.create(:user) + @tenant.tenant_memberships.create(:user_id => @user.id) + @sip_account = @user.sip_accounts.create( Factory.build(:sip_account).attributes ) + + @parent_param = @sip_account.sip_accountable_type.foreign_key.to_sym + @parent_id = @sip_account.sip_accountable.id + end + + test "should get index" do + session[:user_id] = @user.id + get :index, + @parent_param => @parent_id + assert_response :success + assert_not_nil assigns(:sip_accounts) + end + + test "should get new" do + session[:user_id] = @user.id + get :new, + @parent_param => @parent_id + assert_response :success + end + + test "should create sip_account" do + session[:user_id] = @user.id + assert_difference('SipAccount.count') do + post :create, + @parent_param => @parent_id, + sip_account: Factory.attributes_for(:sip_account) + end + end + + test "should show sip_account" do + session[:user_id] = @user.id + get :show, + @parent_param => @parent_id, + id: @sip_account.to_param + assert_response :success + end + + test "should get edit" do + session[:user_id] = @user.id + get :edit, + @parent_param => @parent_id, + id: @sip_account.to_param + assert_response :success + end + + test "should update sip_account" do + session[:user_id] = @user.id + put :update, + @parent_param => @parent_id, + id: @sip_account.to_param, + sip_account: @sip_account.attributes + # TODO Find the right redirect/answer. + #assert_redirected_to method( :"#{@sip_account.sip_accountable_type.underscore}_sip_account_path" ).( @sip_account.sip_accountable, @sip_account ) + end + + test "should destroy sip_account" do + session[:user_id] = @user.id + assert_difference('SipAccount.count', -1) do + delete :destroy, + @parent_param => @parent_id, + id: @sip_account.to_param + end + # TODO Find the right redirect/answer. + #assert_redirected_to method( :"#{@sip_account.sip_accountable_type.underscore}_sip_accounts_path" ).( @sip_account.sip_accountable ) + end + +end diff --git a/test/functional/sip_domains_controller_test.rb b/test/functional/sip_domains_controller_test.rb new file mode 100644 index 0000000..f26ea02 --- /dev/null +++ b/test/functional/sip_domains_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class SipDomainsControllerTest < ActionController::TestCase + setup do + @sip_domain = Factory.create(:sip_domain) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:sip_domains) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create sip_domain" do + assert_difference('SipDomain.count') do + post :create, sip_domain: Factory.build(:sip_domain).attributes + end + + assert_redirected_to sip_domain_path(assigns(:sip_domain)) + end + + test "should show sip_domain" do + get :show, id: @sip_domain.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @sip_domain.to_param + assert_response :success + end + + test "should update sip_domain" do + put :update, id: @sip_domain.to_param, sip_domain: @sip_domain.attributes + assert_redirected_to sip_domain_path(assigns(:sip_domain)) + end + + test "should destroy sip_domain" do + assert_difference('SipDomain.count', -1) do + delete :destroy, id: @sip_domain.to_param + end + + assert_redirected_to sip_domains_path + end +end diff --git a/test/functional/softkeys_controller_test.rb b/test/functional/softkeys_controller_test.rb new file mode 100644 index 0000000..6eed165 --- /dev/null +++ b/test/functional/softkeys_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class SoftkeysControllerTest < ActionController::TestCase + setup do + @softkey = softkeys(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:softkeys) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create softkey" do + assert_difference('Softkey.count') do + post :create, softkey: @softkey.attributes + end + + assert_redirected_to softkey_path(assigns(:softkey)) + end + + test "should show softkey" do + get :show, id: @softkey.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @softkey.to_param + assert_response :success + end + + test "should update softkey" do + put :update, id: @softkey.to_param, softkey: @softkey.attributes + assert_redirected_to softkey_path(assigns(:softkey)) + end + + test "should destroy softkey" do + assert_difference('Softkey.count', -1) do + delete :destroy, id: @softkey.to_param + end + + assert_redirected_to softkeys_path + end +end diff --git a/test/functional/system_messages_controller_test.rb b/test/functional/system_messages_controller_test.rb new file mode 100644 index 0000000..2894cd3 --- /dev/null +++ b/test/functional/system_messages_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class SystemMessagesControllerTest < ActionController::TestCase + setup do + @system_message = system_messages(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:system_messages) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create system_message" do + assert_difference('SystemMessage.count') do + post :create, system_message: @system_message.attributes + end + + assert_redirected_to system_message_path(assigns(:system_message)) + end + + test "should show system_message" do + get :show, id: @system_message.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @system_message.to_param + assert_response :success + end + + test "should update system_message" do + put :update, id: @system_message.to_param, system_message: @system_message.attributes + assert_redirected_to system_message_path(assigns(:system_message)) + end + + test "should destroy system_message" do + assert_difference('SystemMessage.count', -1) do + delete :destroy, id: @system_message.to_param + end + + assert_redirected_to system_messages_path + end +end diff --git a/test/functional/tenants_controller_test.rb b/test/functional/tenants_controller_test.rb new file mode 100644 index 0000000..b4e2df4 --- /dev/null +++ b/test/functional/tenants_controller_test.rb @@ -0,0 +1,51 @@ +require 'test_helper' + +class TenantsControllerTest < ActionController::TestCase + # TODO Create tests which test that a login user has specific rights. + + # setup do + # @tenant = Factory.create(:tenant) + # end + # + # test "should get index" do + # get :index + # assert_response :success + # assert_not_nil assigns(:tenants) + # end + # + # test "should get new" do + # get :new + # assert_response :success + # end + # + # test "should create tenant" do + # assert_difference('Tenant.count') do + # post :create, tenant: Factory.build(:tenant).attributes + # end + # + # assert_redirected_to tenant_path(assigns(:tenant)) + # end + # + # test "should show tenant" do + # get :show, id: @tenant.to_param + # assert_response :success + # end + # + # test "should get edit" do + # get :edit, id: @tenant.to_param + # assert_response :success + # end + # + # test "should update tenant" do + # put :update, id: @tenant.to_param, tenant: @tenant.attributes + # assert_redirected_to tenant_path(assigns(:tenant)) + # end + # + # test "should destroy tenant" do + # assert_difference('Tenant.count', -1) do + # delete :destroy, id: @tenant.to_param + # end + # + # assert_redirected_to tenants_path + # end +end diff --git a/test/functional/user_groups_controller_test.rb b/test/functional/user_groups_controller_test.rb new file mode 100644 index 0000000..0e39048 --- /dev/null +++ b/test/functional/user_groups_controller_test.rb @@ -0,0 +1,51 @@ +require 'test_helper' + +class UserGroupsControllerTest < ActionController::TestCase + # TODO Create tests which test that a login user has specific rights. + + # setup do + # @user_group = Factory.create(:user_group) + # end + # + # test "should get index" do + # get :index + # assert_response :success + # assert_not_nil assigns(:user_groups) + # end + # + # test "should get new" do + # get :new + # assert_response :success + # end + # + # test "should create user_group" do + # assert_difference('UserGroup.count') do + # post :create, user_group: Factory.build(:user_group).attributes + # end + # + # assert_redirected_to user_group_path(assigns(:user_group)) + # end + # + # test "should show user_group" do + # get :show, id: @user_group.to_param + # assert_response :success + # end + # + # test "should get edit" do + # get :edit, id: @user_group.to_param + # assert_response :success + # end + # + # test "should update user_group" do + # put :update, id: @user_group.to_param, user_group: @user_group.attributes + # assert_redirected_to user_group_path(assigns(:user_group)) + # end + # + # test "should destroy user_group" do + # assert_difference('UserGroup.count', -1) do + # delete :destroy, id: @user_group.to_param + # end + # + # assert_redirected_to user_groups_path + # end +end diff --git a/test/functional/users_controller_test.rb b/test/functional/users_controller_test.rb new file mode 100644 index 0000000..d1898f7 --- /dev/null +++ b/test/functional/users_controller_test.rb @@ -0,0 +1,65 @@ +require 'test_helper' + +class UsersControllerTest < ActionController::TestCase + setup do + @tenant = Factory.create(:tenant) + @user = Factory.create(:user) + + @tenant.tenant_memberships.create(:user_id => @user.id) + + @user.update_attributes!(:current_tenant_id => @tenant.id) + + @expected_status_if_not_authorized = :redirect + end + + test "should get index" do + session[:user_id] = @user.id + get :index + assert_response :success + assert_not_nil assigns(:users) + end + + test "should get new" do + session[:user_id] = nil + get :new + assert_response :success + end + + # TODO Fix Test + # + # test "should create user" do + # session[:user_id] = nil + # assert_difference('User.count') do + # post :create, user: Factory.build(:user).attributes + # end + # + # # assert_redirected_to user_path(assigns(:user)) + # end + + test "should show user" do + session[:user_id] = @user.id + get :show, id: @user.to_param + assert_response :success + end + + + test "should get edit" do + session[:user_id] = @user.id + get :edit, id: @user.to_param + assert_response :success + end + + test "should update user" do + session[:user_id] = @user.id + put :update, id: @user.to_param, user: @user.attributes + assert_redirected_to user_path(assigns(:user)) + end + + test "should not destroy itself" do + assert_no_difference('User.count') do + delete :destroy, id: @user.to_param + end + +# assert_redirected_to users_path + end +end diff --git a/test/functional/whitelists_controller_test.rb b/test/functional/whitelists_controller_test.rb new file mode 100644 index 0000000..842069f --- /dev/null +++ b/test/functional/whitelists_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class WhitelistsControllerTest < ActionController::TestCase + setup do + @whitelist = whitelists(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:whitelists) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create whitelist" do + assert_difference('Whitelist.count') do + post :create, whitelist: @whitelist.attributes + end + + assert_redirected_to whitelist_path(assigns(:whitelist)) + end + + test "should show whitelist" do + get :show, id: @whitelist.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @whitelist.to_param + assert_response :success + end + + test "should update whitelist" do + put :update, id: @whitelist.to_param, whitelist: @whitelist.attributes + assert_redirected_to whitelist_path(assigns(:whitelist)) + end + + test "should destroy whitelist" do + assert_difference('Whitelist.count', -1) do + delete :destroy, id: @whitelist.to_param + end + + assert_redirected_to whitelists_path + end +end diff --git a/test/integration/.gitkeep b/test/integration/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/test/performance/browsing_test.rb b/test/performance/browsing_test.rb new file mode 100644 index 0000000..3fea27b --- /dev/null +++ b/test/performance/browsing_test.rb @@ -0,0 +1,12 @@ +require 'test_helper' +require 'rails/performance_test_help' + +class BrowsingTest < ActionDispatch::PerformanceTest + # Refer to the documentation for all available options + # self.profile_options = { :runs => 5, :metrics => [:wall_time, :memory] + # :output => 'tmp/performance', :formats => [:flat] } + + def test_homepage + get '/' + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..b6836c0 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,13 @@ +ENV["RAILS_ENV"] = "test" +require File.expand_path('../../config/environment', __FILE__) +require 'rails/test_help' + +class ActiveSupport::TestCase + # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order. + # + # Note: You'll currently still have to declare fixtures explicitly in integration tests + # -- they do not yet inherit this setting + # fixtures :all + + # Add more helper methods to be used by all tests here... +end diff --git a/test/unit/.gitkeep b/test/unit/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/access_authorization_test.rb b/test/unit/access_authorization_test.rb new file mode 100644 index 0000000..ebd9f0b --- /dev/null +++ b/test/unit/access_authorization_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class AccessAuthorizationTest < ActiveSupport::TestCase + # def test_should_be_valid + # assert AccessAuthorization.new.valid? + # end +end diff --git a/test/unit/acd_agent_test.rb b/test/unit/acd_agent_test.rb new file mode 100644 index 0000000..9e1a116 --- /dev/null +++ b/test/unit/acd_agent_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class AcdAgentTest < ActiveSupport::TestCase + def test_should_be_valid + assert AcdAgent.new.valid? + end +end diff --git a/test/unit/acd_caller_test.rb b/test/unit/acd_caller_test.rb new file mode 100644 index 0000000..68d5801 --- /dev/null +++ b/test/unit/acd_caller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class AcdCallerTest < ActiveSupport::TestCase + def test_should_be_valid + assert AcdCaller.new.valid? + end +end diff --git a/test/unit/address_test.rb b/test/unit/address_test.rb new file mode 100644 index 0000000..6d676ba --- /dev/null +++ b/test/unit/address_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class AddressTest < ActiveSupport::TestCase + def test_should_be_valid + assert Address.new.valid? + end +end diff --git a/test/unit/api/row_test.rb b/test/unit/api/row_test.rb new file mode 100644 index 0000000..dc21050 --- /dev/null +++ b/test/unit/api/row_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class Api::RowTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/unit/area_code_test.rb b/test/unit/area_code_test.rb new file mode 100644 index 0000000..10c7c08 --- /dev/null +++ b/test/unit/area_code_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class AreaCodeTest < ActiveSupport::TestCase + def test_should_have_a_valid_factory + assert Factory.build(:area_code).valid? + end +end diff --git a/test/unit/automatic_call_distributor_test.rb b/test/unit/automatic_call_distributor_test.rb new file mode 100644 index 0000000..b025df8 --- /dev/null +++ b/test/unit/automatic_call_distributor_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class AutomaticCallDistributorTest < ActiveSupport::TestCase + def test_should_be_valid + assert AutomaticCallDistributor.new.valid? + end +end diff --git a/test/unit/call_forward_case_test.rb b/test/unit/call_forward_case_test.rb new file mode 100644 index 0000000..0d1d238 --- /dev/null +++ b/test/unit/call_forward_case_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class CallForwardCaseTest < ActiveSupport::TestCase + + # Cannot be factory'd. CallForwardCases are seeded. + +end diff --git a/test/unit/call_forward_test.rb b/test/unit/call_forward_test.rb new file mode 100644 index 0000000..95716c5 --- /dev/null +++ b/test/unit/call_forward_test.rb @@ -0,0 +1,9 @@ +require 'test_helper' + +class CallForwardTest < ActiveSupport::TestCase + + test "should have a valid factory" do + assert Factory.build(:call_forward).valid? + end + +end diff --git a/test/unit/callthrough_test.rb b/test/unit/callthrough_test.rb new file mode 100644 index 0000000..c1c6ab3 --- /dev/null +++ b/test/unit/callthrough_test.rb @@ -0,0 +1,134 @@ +require 'test_helper' + +class CallthroughTest < ActiveSupport::TestCase + def setup + # Basic setup of a new system + # + germany = Country.create(:name => "Germany", :country_code => "49", :international_call_prefix => "00", :trunk_prefix => "0" ) + Language.create(:name => 'Deutsch', :code => 'de') + AreaCode.create(:country => germany, :name => "Bendorf", :area_code => "2622") + + @gemeinschaft_setup = GemeinschaftSetup.new + @gemeinschaft_setup.country = Country.first + @gemeinschaft_setup.language = Language.first + + @current_user = @gemeinschaft_setup.build_user( + :user_name => I18n.t('gemeinschaft_setups.initial_setup.admin_name'), + :male => true, + :email => 'admin@localhost', + :first_name => 'Max', + :last_name => 'Mustermann', + :password => 'xxxxxxxxxx', + :password_confirmation => 'xxxxxxxxxx', + :language_id => Language.first.id, + ) + @sip_domain = @gemeinschaft_setup.build_sip_domain( + :host => '10.0.0.1', + :realm => '10.0.0.1', + ) + + @gemeinschaft_setup.save + + super_tenant = Tenant.create( + :name => SUPER_TENANT_NAME, + :country_id => @gemeinschaft_setup.country.id, + :language_id => @gemeinschaft_setup.language_id, + :description => I18n.t('gemeinschaft_setups.initial_setup.super_tenant_description'), + ) + + # Admin + super_tenant.tenant_memberships.create(:user_id => @gemeinschaft_setup.user.id) + + # Create the Super-Tenant's group: + super_tenant_super_admin_group = super_tenant.user_groups.create(:name => I18n.t('gemeinschaft_setups.initial_setup.super_admin_group_name')) + super_tenant_super_admin_group.user_group_memberships.create(:user_id => @gemeinschaft_setup.user.id) + + # Create the tenant. + # + @tenant = @sip_domain.tenants.build(:name => 'AMOOMA GmbH') + @tenant.country = Country.first + @tenant.language = Language.first + @tenant.internal_extension_ranges = '10-20' + @tenant.did_list = '02622-70648-x, 02622-706480' + @tenant.save + + @tenant.tenant_memberships.create(:user_id => @current_user.id) + @current_user.update_attributes!(:current_tenant_id => @tenant.id) + + # The first user becomes a member of the 'admin' UserGroup + # + admin_group = @tenant.user_groups.create(:name => I18n.t('gemeinschaft_setups.initial_setup.admin_group_name')) + admin_group.users << @current_user + + # User group + # + user_group = @tenant.user_groups.create(:name => I18n.t('gemeinschaft_setups.initial_setup.user_group_name')) + user_group.users << @current_user + + # Generate the internal_extensions + # + @tenant.generate_internal_extensions + + # Generate the external numbers (DIDs) + # + @tenant.generate_dids + end + + test 'the setup should create a valid system' do + # Basics + # + assert_equal 1, Country.count + assert_equal 1, Language.count + + # Testing the installation + # + assert @gemeinschaft_setup.valid? + assert @sip_domain.valid? + assert @current_user.valid? + + assert @tenant.valid? + + assert_equal 0, SipAccount.count + assert_equal 2, Tenant.count + assert_equal 1, User.count + + # Check the amount of phone_numbers + # + assert_equal 11, @tenant.phone_number_ranges.find_by_name(INTERNAL_EXTENSIONS).phone_numbers.count + assert_equal 12, @tenant.phone_number_ranges.find_by_name(DIRECT_INWARD_DIALING_NUMBERS).phone_numbers.count + end + + test 'that a callthrough can only be created with at least one DID' do + assert_equal 0, Callthrough.count + + did = @tenant.phone_number_ranges.find_by_name(DIRECT_INWARD_DIALING_NUMBERS).phone_numbers.first + + callthrough = @tenant.callthroughs.build + + assert !callthrough.valid? + + callthrough.phone_numbers.build(:number => did.number) + + assert callthrough.save + assert_equal 1, Callthrough.count + end + + # TODO Activate this after fixing unique phone_number + # + # test 'that one DID can not be used by two different callthroughs' do + # assert_equal 0, Callthrough.count + + # did = @tenant.phone_number_ranges.find_by_name(DIRECT_INWARD_DIALING_NUMBERS).phone_numbers.first + + # callthroughs = Array.new + # (1..2).each do |i| + # callthroughs[i] = @tenant.callthroughs.build + # callthroughs[i].phone_numbers.build(:number => did.number) + # callthroughs[i].save + # end + + # assert callthroughs[1].valid?, '1st Callthrough is not valid' + # assert !callthroughs[2].valid?, '2nd Callthrough is not valid' + # end + +end diff --git a/test/unit/conference_invitee_test.rb b/test/unit/conference_invitee_test.rb new file mode 100644 index 0000000..bcc4c9b --- /dev/null +++ b/test/unit/conference_invitee_test.rb @@ -0,0 +1,17 @@ +require 'test_helper' + +class ConferenceInviteeTest < ActiveSupport::TestCase + + def test_should_have_a_valid_factory + assert Factory.build(:conference_invitee).valid? + end + + test "parent conference should not have a phone number twice" do + invitee = Factory.create(:conference_invitee) + conference = invitee.conference + phone_number = PhoneNumber.new(:number => invitee.phone_number.number) + invitee_bad = conference.conference_invitees.build(:phone_number => phone_number) + assert !invitee_bad.valid? + end + +end diff --git a/test/unit/conference_test.rb b/test/unit/conference_test.rb new file mode 100644 index 0000000..b7cce28 --- /dev/null +++ b/test/unit/conference_test.rb @@ -0,0 +1,48 @@ +require 'test_helper' + +class ConferenceTest < ActiveSupport::TestCase + + def test_should_have_a_valid_factory + assert Factory.build(:conference).valid? + end + + def test_dates_must_make_sense + # We can't create a conference in the past. + assert !Factory.build(:conference, :start => Time.now - 1.day, :end => Time.now + 1.day).valid? + + # But we can create a conference which started 2 minutes ago. + assert Factory.build(:conference, :start => Time.now - 2.minutes, :end => Time.now + 1.hour).valid? + + # The end must be before the start. + assert !Factory.build(:conference, :start => Time.now + 2.day, :end => Time.now + 1.day).valid? + + # No date at all is fine. + assert Factory.build(:conference, :start => nil, :end => nil).valid? + + # Just start or just end is not ok. + assert !Factory.build(:conference, :start => nil, :end => Time.now + 1.day).valid? + assert !Factory.build(:conference, :start => Time.now + 1.day, :end => nil).valid? + end + + def test_pin_must_be_nil_or_more_than_6_digits + conference = Factory.build(:conference, :pin => nil) + + assert conference.valid? + + (MINIMUM_PIN_LENGTH - 1).times do |i| + pin = "#{10**i}" + conference.pin = pin + assert !conference.valid? + end + + conference.pin = "#{10**(MINIMUM_PIN_LENGTH - 1)}" + assert conference.valid? + + conference.pin = "-#{10**(MINIMUM_PIN_LENGTH - 1)}" + assert !conference.valid? + + conference.pin = 'Teststring' + assert !conference.valid? + end + +end diff --git a/test/unit/country_test.rb b/test/unit/country_test.rb new file mode 100644 index 0000000..4933843 --- /dev/null +++ b/test/unit/country_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class CountryTest < ActiveSupport::TestCase + def test_should_have_a_valid_factory + assert Factory.build(:country).valid? + end +end diff --git a/test/unit/dial_in_number_store_test.rb b/test/unit/dial_in_number_store_test.rb new file mode 100644 index 0000000..d1341f9 --- /dev/null +++ b/test/unit/dial_in_number_store_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class DialInNumberStoreTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/unit/fax_account_test.rb b/test/unit/fax_account_test.rb new file mode 100644 index 0000000..f4048cb --- /dev/null +++ b/test/unit/fax_account_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class FaxAccountTest < ActiveSupport::TestCase + # def test_should_be_valid + # assert FaxAccount.new.valid? + # end +end diff --git a/test/unit/fax_document_test.rb b/test/unit/fax_document_test.rb new file mode 100644 index 0000000..190a953 --- /dev/null +++ b/test/unit/fax_document_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class FaxDocumentTest < ActiveSupport::TestCase + # def test_should_be_valid + # assert FaxDocument.new.valid? + # end +end diff --git a/test/unit/fax_page_test.rb b/test/unit/fax_page_test.rb new file mode 100644 index 0000000..522ffd5 --- /dev/null +++ b/test/unit/fax_page_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class FaxPageTest < ActiveSupport::TestCase + # def test_should_be_valid + # assert FaxPage.new.valid? + # end +end diff --git a/test/unit/fax_resolution_test.rb b/test/unit/fax_resolution_test.rb new file mode 100644 index 0000000..93676af --- /dev/null +++ b/test/unit/fax_resolution_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class FaxResolutionTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/unit/fax_thumbnail_test.rb b/test/unit/fax_thumbnail_test.rb new file mode 100644 index 0000000..4fc5bc8 --- /dev/null +++ b/test/unit/fax_thumbnail_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class FaxThumbnailTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/unit/gemeinschaft_setup_test.rb b/test/unit/gemeinschaft_setup_test.rb new file mode 100644 index 0000000..5ea6523 --- /dev/null +++ b/test/unit/gemeinschaft_setup_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class GemeinschaftSetupTest < ActiveSupport::TestCase + def test_should_have_a_valid_factory + assert Factory.build(:gemeinschaft_setup).valid? + end +end diff --git a/test/unit/gs_cluster_sync_log_entry_test.rb b/test/unit/gs_cluster_sync_log_entry_test.rb new file mode 100644 index 0000000..bff49e9 --- /dev/null +++ b/test/unit/gs_cluster_sync_log_entry_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class GsClusterSyncLogEntryTest < ActiveSupport::TestCase + def test_should_be_valid + assert GsClusterSyncLogEntry.new.valid? + end +end diff --git a/test/unit/gs_node_test.rb b/test/unit/gs_node_test.rb new file mode 100644 index 0000000..1155cab --- /dev/null +++ b/test/unit/gs_node_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class GsNodeTest < ActiveSupport::TestCase + def test_should_be_valid + assert GsNode.new.valid? + end +end diff --git a/test/unit/gui_function_membership_test.rb b/test/unit/gui_function_membership_test.rb new file mode 100644 index 0000000..c85ec68 --- /dev/null +++ b/test/unit/gui_function_membership_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class GuiFunctionMembershipTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/unit/gui_function_test.rb b/test/unit/gui_function_test.rb new file mode 100644 index 0000000..60bce1d --- /dev/null +++ b/test/unit/gui_function_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class GuiFunctionTest < ActiveSupport::TestCase + def test_should_be_valid + assert GuiFunction.new.valid? + end +end diff --git a/test/unit/helpers/api/rows_helper_test.rb b/test/unit/helpers/api/rows_helper_test.rb new file mode 100644 index 0000000..16c8fe7 --- /dev/null +++ b/test/unit/helpers/api/rows_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class Api::RowsHelperTest < ActionView::TestCase +end diff --git a/test/unit/helpers/config_siemens_helper_test.rb b/test/unit/helpers/config_siemens_helper_test.rb new file mode 100644 index 0000000..1afae0d --- /dev/null +++ b/test/unit/helpers/config_siemens_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class ConfigSiemensHelperTest < ActionView::TestCase +end diff --git a/test/unit/helpers/page_helper_test.rb b/test/unit/helpers/page_helper_test.rb new file mode 100644 index 0000000..6009662 --- /dev/null +++ b/test/unit/helpers/page_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class PageHelperTest < ActionView::TestCase +end diff --git a/test/unit/helpers/sessions_helper_test.rb b/test/unit/helpers/sessions_helper_test.rb new file mode 100644 index 0000000..7d44e09 --- /dev/null +++ b/test/unit/helpers/sessions_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class SessionsHelperTest < ActionView::TestCase +end diff --git a/test/unit/hunt_group_member_test.rb b/test/unit/hunt_group_member_test.rb new file mode 100644 index 0000000..4472cc2 --- /dev/null +++ b/test/unit/hunt_group_member_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class HuntGroupMemberTest < ActiveSupport::TestCase + # def test_should_be_valid + # assert HuntGroupMember.new.valid? + # end +end diff --git a/test/unit/hunt_group_test.rb b/test/unit/hunt_group_test.rb new file mode 100644 index 0000000..5ef843b --- /dev/null +++ b/test/unit/hunt_group_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class HuntGroupTest < ActiveSupport::TestCase + # def test_should_be_valid + # assert HuntGroup.new.valid? + # end +end diff --git a/test/unit/language_test.rb b/test/unit/language_test.rb new file mode 100644 index 0000000..3308735 --- /dev/null +++ b/test/unit/language_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class LanguageTest < ActiveSupport::TestCase + test "has a valid factory" do + assert Factory.build(:language).valid? + end +end diff --git a/test/unit/manufacturer_test.rb b/test/unit/manufacturer_test.rb new file mode 100644 index 0000000..635a977 --- /dev/null +++ b/test/unit/manufacturer_test.rb @@ -0,0 +1,27 @@ +require 'test_helper' + +class ManufacturerTest < ActiveSupport::TestCase + def test_should_have_a_valid_factory + assert Factory.build(:manufacturer).valid? + end + + # StateMachine Tests: + def test_that_the_initial_state_should_be_active + @manufacturer = Factory.create(:manufacturer) + assert_equal 'active', @manufacturer.state + assert @manufacturer.active? + end + + def test_not_active_state_will_not_be_displayed + @manufacturer = Factory.create(:manufacturer) + assert_equal 1, Manufacturer.count + + @manufacturer.deactivate! + assert_equal 0, Manufacturer.count + assert_equal 1, Manufacturer.unscoped.count + + @manufacturer.activate! + assert_equal 1, Manufacturer.count + assert_equal Manufacturer.count, Manufacturer.unscoped.count + end +end diff --git a/test/unit/oui_test.rb b/test/unit/oui_test.rb new file mode 100644 index 0000000..de48a97 --- /dev/null +++ b/test/unit/oui_test.rb @@ -0,0 +1,14 @@ +require 'test_helper' + +class OuiTest < ActiveSupport::TestCase + def test_should_have_a_valid_factory + assert Factory.build(:oui).valid? + end + + def test_that_the_initial_state_should_be_active + @oui = Factory.create(:oui) + assert_equal 'active', @oui.state + assert @oui.active? + end + +end diff --git a/test/unit/phone_book_entry_test.rb b/test/unit/phone_book_entry_test.rb new file mode 100644 index 0000000..c8d639b --- /dev/null +++ b/test/unit/phone_book_entry_test.rb @@ -0,0 +1,51 @@ +require 'test_helper' + +class PhoneBookEntryTest < ActiveSupport::TestCase + def test_should_be_valid + assert Factory.build(:phone_book_entry).valid? + end + + # TODO Fix this test. + + # test "only user can read entries in private phone books" do + # user = Factory.create(:user) + # phone_book = Factory.create(:phone_book, :phone_bookable_type => 'User', :phone_bookable_id => user.id) + # phone_book_entry = Factory.create(:phone_book_entry, :phone_book_id => phone_book.id) + + # evil_user = Factory.create(:user) + + # user_ability = Ability.new( user ) + # evil_user_ability = Ability.new( evil_user ) + + # [ :show, :index ].each { |action| + # assert user_ability.can? action, phone_book_entry + # assert evil_user_ability.cannot? action, phone_book_entry + # } + # end + + def test_that_the_initial_state_should_be_active + @phone_book_entry = Factory.create(:phone_book_entry) + assert_equal 'active', @phone_book_entry.state + assert @phone_book_entry.active? + end + + test "a destroyed phone_book will destroy all phone_book_entries" do + phone_book = Factory.create(:phone_book) + 10.times { Factory.create(:phone_book_entry, :phone_book_id => phone_book.id) } + + phone_book2 = Factory.create(:phone_book) + 5.times { Factory.create(:phone_book_entry, :phone_book_id => phone_book2.id) } + + assert_equal 15, PhoneBookEntry.all.count + + phone_book.destroy + + assert_equal 5, PhoneBookEntry.all.count + end + + test "that the value_of_to_s field is filled" do + phone_book_entry = Factory.create(:phone_book_entry) + assert_equal phone_book_entry.value_of_to_s, phone_book_entry.to_s + end + +end diff --git a/test/unit/phone_book_test.rb b/test/unit/phone_book_test.rb new file mode 100644 index 0000000..7db48f8 --- /dev/null +++ b/test/unit/phone_book_test.rb @@ -0,0 +1,119 @@ +require 'test_helper' + +class PhoneBookTest < ActiveSupport::TestCase + def test_should_have_a_valid_factory + assert Factory.build(:phone_book).valid? + end + + def test_should_have_unique_name_depending_on_type + user1 = Factory.create(:user) + user2 = Factory.create(:user) + tenant = Factory.create(:tenant) + + phonebook = Factory.create(:phone_book, :phone_bookable => user1) + assert !user1.phone_books.build(:name => phonebook.name).valid? + assert user2.phone_books.build(:name => phonebook.name).valid? + assert tenant.phone_books.build(:name => phonebook.name).valid? + end + + # TODO Create a real system for the phone_book tests and than test again. + + + # test "User gets a private phone book with rw rights" do + # user = Factory.create(:user) + # assert_equal 1, user.phone_books.count + + # phone_book = user.phone_books.first + + # user_ability = Ability.new( user ) + + # [ :show, :destroy, :edit ].each { |action| + # assert user_ability.can?( action, phone_book ), "should be able to #{action}" + # } + + # # Lets test some stuff about the phone_book_entries + # assert_equal 0, phone_book.phone_book_entries.count + + # entry1 = Factory.create(:phone_book_entry, :phone_book_id => phone_book.id) + # entry2 = Factory.create(:phone_book_entry, :phone_book_id => phone_book.id) + # entry3 = Factory.create(:phone_book_entry, :phone_book_id => phone_book.id) + # assert_equal 3, phone_book.phone_book_entries.count + + # assert_equal 1, PhoneBookEntry.where(:id => entry1.id).count + # assert_equal 1, PhoneBookEntry.where(:id => entry2.id).count + # assert_equal 1, PhoneBookEntry.where(:id => entry3.id).count + # user.phone_books.first.destroy + # assert_equal 0, user.phone_books.count + # assert_equal 0, PhoneBookEntry.where(:id => entry1.id).count + # assert_equal 0, PhoneBookEntry.where(:id => entry2.id).count + # assert_equal 0, PhoneBookEntry.where(:id => entry3.id).count + # end + + test "Tenant gets automatically one phone book and can destroy it" do + tenant = Factory.create(:tenant) + assert_equal 1, tenant.phone_books.count + tenant.phone_books.first.destroy + assert_equal 0, tenant.phone_books.count + end + + # test "only tenant members can read a tenant phone book" do + # tenant = Factory.create(:tenant) + # user = Factory.create(:user) + # tenant.users << user + # tenant.save + # user.current_tenant = tenant + # user.save + # phone_book = Factory.create(:phone_book, :phone_bookable_type => 'Tenant', :phone_bookable_id => tenant.id) + + # evil_user = Factory.create(:user) + + # user_ability = Ability.new( user ) + # evil_user_ability = Ability.new( evil_user ) + + # [ :show ].each { |action| + # assert user_ability.can?( action, phone_book ), "should be able to #{action}" + # assert evil_user_ability.cannot?( action, phone_book ), "should not be able to #{action}" + # } + # end + + + + # test "tenant's phone book can not be edited by tenant members" do + # tenant = Factory.create(:tenant) + # user = Factory.create(:user) + # tenant.users << user + # phone_book = Factory.create(:phone_book, :phone_bookable_type => 'Tenant', :phone_bookable_id => tenant.id) + + # evil_user = Factory.create(:user) + + # user_ability = Ability.new( user ) + # evil_user_ability = Ability.new( evil_user ) + + # [ :edit, :destroy ].each { |action| + # assert user_ability.cannot?( action, phone_book ), "should not be able to #{action}" + # assert evil_user_ability.cannot?( action, phone_book ), "should not be able to #{action}" + # } + # end + + # test "only user can manage his private phone book after creating it" do + # user = Factory.create(:user) + # phone_book = Factory.create(:phone_book, :phone_bookable_type => 'User', :phone_bookable_id => user.id) + + # evil_user = Factory.create(:user) + + # user_ability = Ability.new( user ) + # evil_user_ability = Ability.new( evil_user ) + + # [ :show, :destroy, :edit ].each { |action| + # assert user_ability.can?( action, phone_book ), "should be able to #{action}" + # assert evil_user_ability.cannot?( action, phone_book ), "should not be able to #{action}" + # } + # end + + def test_that_the_initial_state_should_be_active + @phone_book = Factory.create(:phone_book) + assert_equal 'active', @phone_book.state + assert @phone_book.active? + end + +end diff --git a/test/unit/phone_model_test.rb b/test/unit/phone_model_test.rb new file mode 100644 index 0000000..e358cf9 --- /dev/null +++ b/test/unit/phone_model_test.rb @@ -0,0 +1,9 @@ +require 'test_helper' + +class PhoneModelTest < ActiveSupport::TestCase + + def test_should_have_a_valid_factory + assert Factory.build(:phone_model).valid? + end + +end diff --git a/test/unit/phone_number_range_test.rb b/test/unit/phone_number_range_test.rb new file mode 100644 index 0000000..1770299 --- /dev/null +++ b/test/unit/phone_number_range_test.rb @@ -0,0 +1,9 @@ +require 'test_helper' + +class PhoneNumberRangeTest < ActiveSupport::TestCase + + def test_should_have_a_valid_factory + assert Factory.build(:phone_number_range).valid? + end + +end diff --git a/test/unit/phone_number_test.rb b/test/unit/phone_number_test.rb new file mode 100644 index 0000000..e10b20c --- /dev/null +++ b/test/unit/phone_number_test.rb @@ -0,0 +1,260 @@ +# ruby coding: utf-8 + +require 'test_helper' + +class PhoneNumberTest < ActiveSupport::TestCase + + test "should have valid factory" do + assert Factory.build(:phone_number).valid? + end + + def test_that_the_initial_state_should_be_active + @phone_number = Factory.create(:phone_number) + assert_equal 'active', @phone_number.state + assert @phone_number.active? + end + + test "that the value_of_to_s field is filled" do + phone_number = Factory.create(:phone_number) + assert_equal phone_number.value_of_to_s, phone_number.to_s + end + + { + '+492612000' => { + :country_code => "49", + :area_code => "261", + :central_office_code => nil, + :subscriber_number => "2000", + :extension => nil, + }, + '+49 261 2000' => { + :country_code => "49", + :area_code => "261", + :central_office_code => nil, + :subscriber_number => "2000", + :extension => nil, + }, + '+49-261-2000' => { + :country_code => "49", + :area_code => "261", + :central_office_code => nil, + :subscriber_number => "2000", + :extension => nil, + }, + '492612000' => { + :country_code => "49", + :area_code => "261", + :central_office_code => nil, + :subscriber_number => "2000", + :extension => nil, + }, + '49888888882000' => nil, # unknown area code + '552612000' => nil, # unknown country code + '15551234567' => { + :country_code => "1", + :area_code => "555", + :central_office_code => "123", + :subscriber_number => "4567", + :extension => nil, + }, + '2612000' => nil, # not an international number + '02612000' => nil, # not an international number + '00492612000' => nil, # invalid format + '2000' => nil, + '' => nil, + nil => nil, + '++++' => nil, + '###' => nil, + 'äöü' => nil, + false => nil, + true => nil, # true.to_s == "true" # invalid number + }.each_pair do |number, expected| + test "should parse number #{number.inspect} correctly" do + # load some country codes: + usa = Country.create(:name => "United States of America", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + germany = Country.create(:name => "Germany", :country_code => "49", :international_call_prefix => "00", :trunk_prefix => "0" ) + cuba = Country.create(:name => "Cuba", :country_code => "53", :international_call_prefix => "119", :trunk_prefix => "" ) + # load some area codes: + AreaCode.create(:country => germany, :name => "Koblenz am Rhein", :area_code => "261") + AreaCode.create(:country => germany, :name => "Neuwied", :area_code => "2631") + AreaCode.create(:country => germany, :name => "Berlin", :area_code => "30") + AreaCode.create(:country => germany, :name => "Hamburg", :area_code => "40") + AreaCode.create(:country => germany, :name => "Hohenmocker", :area_code => "39993") + + assert_equal expected, PhoneNumber.parse_international_number( number ) + end + end + + { + '+492612000' => { + :country_code => "49", + :area_code => "261", + :central_office_code => nil, + :subscriber_number => "2000", + :extension => nil, + }, + '+49 261 2000' => { + :country_code => "49", + :area_code => "261", + :central_office_code => nil, + :subscriber_number => "2000", + :extension => nil, + }, + '+49-261-2000' => { + :country_code => "49", + :area_code => "261", + :central_office_code => nil, + :subscriber_number => "2000", + :extension => nil, + }, + '110' => { + :country_code => nil, + :area_code => nil, + :central_office_code => nil, + :subscriber_number => "110", + :extension => nil, + }, + '11833' => { + :country_code => nil, + :area_code => nil, + :central_office_code => nil, + :subscriber_number => "11833", + :extension => nil, + }, + '15551234567' => { + :country_code => nil, + :area_code => nil, + :central_office_code => nil, + :subscriber_number => "15551234567", + :extension => nil, + }, + '0015551234567' => { + :country_code => "1", + :area_code => "555", + :central_office_code => "123", + :subscriber_number => "4567", + :extension => nil, + }, + '+15551234567' => { + :country_code => "1", + :area_code => "555", + :central_office_code => "123", + :subscriber_number => "4567", + :extension => nil, + }, + '02612000' => { + :country_code => "49", + :area_code => "261", + :central_office_code => nil, + :subscriber_number => "2000", + :extension => nil, + }, + '00492612000' => { + :country_code => "49", + :area_code => "261", + :central_office_code => nil, + :subscriber_number => "2000", + :extension => nil, + }, + '2000' => { + :country_code => nil, + :area_code => nil, + :central_office_code => nil, + :subscriber_number => nil, + :extension => "2000", + }, + '99' => { + :country_code => nil, + :area_code => nil, + :central_office_code => nil, + :subscriber_number => nil, + :extension => "99", + }, + '5' => { + :country_code => nil, + :area_code => nil, + :central_office_code => nil, + :subscriber_number => nil, + :extension => "5", + }, + '' => nil, + nil => nil, + '++++' => nil, + '###' => nil, + 'äöü' => nil, + false => nil, + true => nil, # true.to_s == "true" # invalid number + }.each_pair do |number, expected| + test "should parse number #{number.inspect} correctly for a specific tenant" do + # load some country codes: + usa = Country.create(:name => "United States of America", :country_code => "1", :international_call_prefix => "011", :trunk_prefix => "1" ) + germany = Country.create(:name => "Germany", :country_code => "49", :international_call_prefix => "00", :trunk_prefix => "0" ) + cuba = Country.create(:name => "Cuba", :country_code => "53", :international_call_prefix => "119", :trunk_prefix => "" ) + # load some area codes: + AreaCode.create(:country => germany, :name => "Koblenz am Rhein", :area_code => "261") + AreaCode.create(:country => germany, :name => "Neuwied", :area_code => "2631") + AreaCode.create(:country => germany, :name => "Berlin", :area_code => "30") + AreaCode.create(:country => germany, :name => "Hamburg", :area_code => "40") + AreaCode.create(:country => germany, :name => "Hohenmocker", :area_code => "39993") + + # create a tenant + tenant = Factory.create(:tenant, :country_id => germany.id) + # create some extensions + internal_extension_range = tenant.phone_number_ranges.create(:name => INTERNAL_EXTENSIONS) + ['2000', '2001', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010', '5', '99'].each do |extension| + internal_extension_range.phone_numbers.create(:name => "Extension #{extension}", :number => extension) + end + + assert_equal expected, PhoneNumber.parse( number, tenant ) + end + end + + # TODO: Test uniqueness of a phone_number when creating it. + + # test "has to be unique per sip_account" do + # germany = Country.create(:name => "Germany", :country_code => "49", :international_call_prefix => "00", :trunk_prefix => "0" ) + # Language.create(:name => 'Deutsch', :code => 'de') + # AreaCode.create(:country => germany, :name => "Bendorf", :area_code => "2622") + + # @sip_domain = Factory.create(:sip_domain) + + # @tenant = @sip_domain.tenants.build(:name => 'AMOOMA GmbH') + # @tenant.country = Country.first + # @tenant.language = Language.first + # @tenant.internal_extension_ranges = '10-20' + # @tenant.save + + # @tenant.generate_internal_extensions + + # sip_account = @tenant.sip_accounts.build(Factory.create(:sip_account).attributes) + # phone_number = sip_account.phone_numbers.create(Factory.build(:phone_number, :number => '10').attributes) + # phone_number_evil = sip_account.phone_numbers.build(phone_number.attributes) + + # assert phone_number.valid? + # assert !phone_number_evil.valid? + # end + + # test "has to be unique per SIP domain even for different tenants" do + # provider_sip_domain = Factory.create(:sip_domain) + # tenants = [] + # sip_accounts = [] + # 2.times { |i| + # tenants[i] = provider_sip_domain.tenants.create(Factory.build(:tenant, :internal_extension_ranges => '10-20').attributes) + # tenants[i].generate_internal_extensions + + # sip_accounts[i] = tenants[i].sip_accounts.build(Factory.build(:sip_account, :tenant_id => tenants[i].id).attributes) + # sip_accounts[i].phone_numbers.build(:number => '10') + # } + # sip_accounts[0].save + + # assert sip_accounts[0].valid?, 'Should be valid.' + # assert ! sip_accounts[1].valid?, + # "Shouldn't be possible to use the same phone number more than once per SIP domain." + + # # Lets change the second phone_number for a positiv test: + # # + # sip_accounts[1].phone_numbers.first.number = '11' + # assert sip_accounts[1].valid? + # end + +end diff --git a/test/unit/phone_sip_account_test.rb b/test/unit/phone_sip_account_test.rb new file mode 100644 index 0000000..735799e --- /dev/null +++ b/test/unit/phone_sip_account_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class PhoneSipAccountTest < ActiveSupport::TestCase + # def test_should_be_valid + # assert PhoneSipAccount.new.valid? + # end +end diff --git a/test/unit/phone_test.rb b/test/unit/phone_test.rb new file mode 100644 index 0000000..4ad21df --- /dev/null +++ b/test/unit/phone_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class PhoneTest < ActiveSupport::TestCase + + def test_should_have_a_valid_factory + assert Factory.build(:phone).valid? + end + + # test "should destroy_all phones_sip_accounts if the phoneable changed" do + # sip_domain = Factory.create(:sip_domain) + # tenant = sip_domain.tenants.create(Factory.build(:tenant).attributes) + # + # user1 = Factory.create(:user) + # user2 = Factory.create(:user) + # tenant.tenant_memberships.create(:user_id => user1.id) + # tenant.tenant_memberships.create(:user_id => user2.id) + # + # phone = Factory.create(:phone, :phoneable => tenant) + # + # # Nothing there + # # + # assert_equal 0, phone.sip_accounts.count + # + # # move the phone to user1 + # # + # phone.phoneable = user1 + # phone.save + # + # # create some sip_accounts associated to phone + # # + # 3.times { Factory.create(:sip_account, :sip_accountable => user1, :tenant_id => tenant.id) } + # SipAccount.all.each do |sip_account| + # phone.phones_sip_accounts.create(:sip_account_id => sip_account.id) + # end + # + # # Should have 3 sip_accounts + # # + # assert_equal 3, phone.sip_accounts.count + # + # # Move to user2 + # phone.phoneable = user2 + # phone.save + # + # # Should have 0 sip_accounts + # # + # assert_equal 0, phone.sip_accounts.count + # end + +end diff --git a/test/unit/ringtone_test.rb b/test/unit/ringtone_test.rb new file mode 100644 index 0000000..dee6002 --- /dev/null +++ b/test/unit/ringtone_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class RingtoneTest < ActiveSupport::TestCase + # def test_should_be_valid + # assert Ringtone.new.valid? + # end +end diff --git a/test/unit/sip_account_test.rb b/test/unit/sip_account_test.rb new file mode 100644 index 0000000..6595ccc --- /dev/null +++ b/test/unit/sip_account_test.rb @@ -0,0 +1,34 @@ +require 'test_helper' + +class SipAccountTest < ActiveSupport::TestCase + + def test_should_have_a_valid_factory + assert Factory.build(:sip_account).valid? + end + + test "that the value_of_to_s field is filled" do + sip_account = Factory.create(:sip_account) + assert_equal sip_account.value_of_to_s, sip_account.to_s + end + + test "should have a unique auth_name per sip_domain" do + provider_sip_domain = Factory.create(:sip_domain) + tenants = [] + sip_accounts = [] + 2.times { |i| + tenants[i] = provider_sip_domain.tenants.create(Factory.build(:tenant).attributes) + sip_accounts[i] = Factory.build( + :sip_account, + :sip_accountable => tenants[i], + :auth_name => "somerandomauthname", + :tenant_id => tenants[i].id + ) + } + sip_accounts[0].save! + + assert sip_accounts[0].valid? + assert ! sip_accounts[1].valid?, + "Shouldn't be possible to use the same phone number more than once per SIP realm." + end + +end diff --git a/test/unit/sip_domain_test.rb b/test/unit/sip_domain_test.rb new file mode 100644 index 0000000..5d31f69 --- /dev/null +++ b/test/unit/sip_domain_test.rb @@ -0,0 +1,9 @@ +require 'test_helper' + +class SipDomainTest < ActiveSupport::TestCase + + def test_should_have_a_valid_factory + assert Factory.build(:sip_domain).valid? + end + +end diff --git a/test/unit/softkey_function_test.rb b/test/unit/softkey_function_test.rb new file mode 100644 index 0000000..ed63836 --- /dev/null +++ b/test/unit/softkey_function_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class SoftkeyFunctionTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/unit/softkey_test.rb b/test/unit/softkey_test.rb new file mode 100644 index 0000000..ca173f9 --- /dev/null +++ b/test/unit/softkey_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class SoftkeyTest < ActiveSupport::TestCase + # def test_should_be_valid + # assert Softkey.new.valid? + # end +end diff --git a/test/unit/system_message_test.rb b/test/unit/system_message_test.rb new file mode 100644 index 0000000..0476ac8 --- /dev/null +++ b/test/unit/system_message_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class SystemMessageTest < ActiveSupport::TestCase + # def test_should_be_valid + # assert SystemMessage.new.valid? + # end +end diff --git a/test/unit/tenant_membership_test.rb b/test/unit/tenant_membership_test.rb new file mode 100644 index 0000000..8e7a191 --- /dev/null +++ b/test/unit/tenant_membership_test.rb @@ -0,0 +1,14 @@ +require 'test_helper' + +class TenantMembershipTest < ActiveSupport::TestCase + def test_should_have_a_valid_factory + assert Factory.build(:tenant_membership).valid? + end + + def test_that_the_initial_state_should_be_active + @tenant_membership = Factory.create(:tenant_membership) + assert_equal 'active', @tenant_membership.state + assert @tenant_membership.active? + end + +end diff --git a/test/unit/tenant_test.rb b/test/unit/tenant_test.rb new file mode 100644 index 0000000..4d4abce --- /dev/null +++ b/test/unit/tenant_test.rb @@ -0,0 +1,33 @@ +require 'test_helper' + +class TenantTest < ActiveSupport::TestCase + def test_should_have_a_valid_factory + assert Factory.build(:tenant).valid? + end + + def test_should_have_unique_name + tenant = Factory.create(:tenant) + assert !Factory.build(:tenant, :name => tenant.name).valid? + assert Factory.build(:tenant, :name => "different_#{tenant.name}").valid? + end + + def test_that_the_initial_state_should_be_active + @tenant = Factory.create(:tenant) + assert_equal 'active', @tenant.state + assert @tenant.active? + end + + def test_not_active_state_will_not_be_displayed + @tenant = Factory.create(:tenant) + assert_equal 1, Tenant.count + + @tenant.deactivate! + assert_equal 0, Tenant.count + assert_equal 1, Tenant.unscoped.count + + @tenant.activate! + assert_equal 1, Tenant.count + assert_equal Tenant.count, Tenant.unscoped.count + end + +end diff --git a/test/unit/user_group_membership_test.rb b/test/unit/user_group_membership_test.rb new file mode 100644 index 0000000..251229f --- /dev/null +++ b/test/unit/user_group_membership_test.rb @@ -0,0 +1,39 @@ +require 'test_helper' + +class UserGroupMembershipTest < ActiveSupport::TestCase + def test_should_have_a_valid_factory + assert Factory.build(:user_group_membership).valid? + end + def test_should_have_unique_members_in_each_group + group1 = Factory.create(:user_group) + group2 = Factory.create(:user_group) + user1 = Factory.create(:user) + user2 = Factory.create(:user) + member = Factory.create( + :user_group_membership, + :user_id => user1.id, + :user_group_id => group1.id + ) + assert !Factory.build( + :user_group_membership, + :user_id => user1.id, + :user_group_id => group1.id + ).valid? + assert Factory.build( + :user_group_membership, + :user_id => user1.id, + :user_group_id => group2.id + ).valid? + assert Factory.build( + :user_group_membership, + :user_id => user2.id, + :user_group_id => group1.id + ).valid? + end + + def test_that_the_initial_state_should_be_active + @user_group_membership = Factory.create(:user_group_membership) + assert_equal 'active', @user_group_membership.state + assert @user_group_membership.active? + end +end diff --git a/test/unit/user_group_test.rb b/test/unit/user_group_test.rb new file mode 100644 index 0000000..5e815a8 --- /dev/null +++ b/test/unit/user_group_test.rb @@ -0,0 +1,38 @@ +require 'test_helper' + +class UserGroupTest < ActiveSupport::TestCase + def test_should_have_a_valid_factory + assert Factory.build(:user_group).valid? + end + + def test_should_have_unique_name_on_same_tenant + tenant1 = Factory.create(:tenant) + tenant2 = Factory.create(:tenant) + group = Factory.create(:user_group, :tenant_id => tenant1.id) + assert !Factory.build(:user_group, :name => group.name, :tenant_id => tenant1.id).valid? + assert Factory.build(:user_group, :name => group.name, :tenant_id => tenant2.id).valid? + assert Factory.build(:user_group, :name => "different_#{group.name}", :tenant_id => tenant1.id).valid? + end + + test "user_group_membership only available for tenant_memberships" do + good_tenant = Factory.create(:tenant) + evil_tenant = Factory.create(:tenant) + + user = Factory.create(:user) + good_tenant.tenant_memberships.create(:user_id => user.id) + + good_user_group = good_tenant.user_groups.create(:name => 'Example') + evil_user_group = evil_tenant.user_groups.create(:name => 'Example') + + # Check the basics + assert_equal 1, good_tenant.user_groups.count + assert_equal 1, evil_tenant.user_groups.count + assert_equal 1, good_tenant.users.count + assert_equal 0, evil_tenant.users.count + + # Check if the user can become a member + assert good_user_group.user_group_memberships.build(:user_id => user.id).valid? + assert !evil_user_group.user_group_memberships.build(:user_id => user.id).valid? + end + +end diff --git a/test/unit/user_test.rb b/test/unit/user_test.rb new file mode 100644 index 0000000..bb89e77 --- /dev/null +++ b/test/unit/user_test.rb @@ -0,0 +1,82 @@ +require 'test_helper' + +class UserTest < ActiveSupport::TestCase + + def test_should_have_a_valid_factory + assert Factory.build(:user).valid? + end + + def test_should_have_a_unique_email_address + user = Factory.create(:user) + assert !Factory.build(:user, :email => user.email).valid? + assert Factory.build(:user, :email => "different_#{user.email}").valid? + end + + def test_can_not_move_to_a_current_tenant_without_a_membership_relation + super_tenant = Factory.create(:tenant) + good_tenant = Factory.create(:tenant) + evil_tenant = Factory.create(:tenant) + + user = Factory.create(:user) + super_tenant.tenant_memberships.create(:user_id => user.id) + good_tenant.tenant_memberships.create(:user_id => user.id) + + assert user.update_attributes(:current_tenant_id => super_tenant.id) + assert !user.update_attributes(:current_tenant_id => evil_tenant.id) + assert user.update_attributes(:current_tenant_id => good_tenant.id) + end + + test "should be possible to modify the user without changing the PIN" do + user = Factory.create(:user) + pin_salt = user.pin_salt + pin_hash = user.pin_hash + user.middle_name = "#{user.middle_name} Foo" + assert user.save, "Should be possible to save the user." + user = User.where(:id => user.id).first + assert user + assert_equal pin_salt, user.pin_salt, "PIN salt should not change." + assert_equal pin_hash, user.pin_hash, "PIN hash should not change." + end + + test "should be possible to change the PIN" do + user = Factory.create(:user) + pin_salt = user.pin_salt + pin_hash = user.pin_hash + new_pin = '453267' + user.new_pin = new_pin + user.new_pin_confirmation = new_pin + assert user.save, "Should be possible to save the user." + user = User.where(:id => user.id).first + assert_not_equal "#{pin_salt}#{pin_hash}", "#{user.pin_salt}#{user.pin_hash}", + "PIN salt/hash should have changed." + end + + test "should not be possible to change the PIN if the confirmation does not match" do + user = Factory.create(:user) + pin_salt = user.pin_salt + pin_hash = user.pin_hash + user.new_pin = '123001' + user.new_pin_confirmation = '123002' + assert ! user.save, "Should not be possible to save the user." + assert ! user.valid?, "Should not be valid." + assert user.errors && user.errors.messages + assert ( + (user.errors.messages[:new_pin] && user.errors.messages[:new_pin].length > 0) || + (user.errors.messages[:new_pin_confirmation] && user.errors.messages[:new_pin_confirmation].length > 0) + ), "There should be an error message because new_pin != new_pin_confirmation." + end + + test "PIN must be numeric" do + user = Factory.create(:user) + new_pin = 'xxxx' + user.new_pin = new_pin + user.new_pin_confirmation = new_pin + assert ! user.save, "Should not be possible to save the user." + assert ! user.valid?, "Should not be valid." + assert ( + (user.errors.messages[:new_pin] && user.errors.messages[:new_pin].length > 0) || + (user.errors.messages[:new_pin_confirmation] && user.errors.messages[:new_pin_confirmation].length > 0) + ), "There should be an error message because PIN isn't numeric." + end + +end diff --git a/test/unit/whitelist_test.rb b/test/unit/whitelist_test.rb new file mode 100644 index 0000000..5678bbb --- /dev/null +++ b/test/unit/whitelist_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class WhitelistTest < ActiveSupport::TestCase + def test_should_be_valid + assert Whitelist.new.valid? + end +end diff --git a/vendor/assets/stylesheets/.gitkeep b/vendor/assets/stylesheets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/vendor/plugins/.gitkeep b/vendor/plugins/.gitkeep new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3