Skip to main content

Blog

In today’s article we are going to provide a reference of all configuration options that can be set in migration definition files. Additional configuration options available for migrations defined as configuration will also be listed. Finally, we present the configuration options for migrations groups.

List of configuration options in YAML definition files

General configuration keys

The following keys can be set for any Drupal migration.

id key

A required string value. It serves as the identifier for the migration. The value should be a machine name. That is, lowercase letters with underscores instead of spaces. The value is for creating mapping and messages tables. For example, if the id is ud_migrations, the Migrate API will create the following migrations migrate_map_ud_migrations and migrate_message_ud_migrations.

label key

A string value. The human-readable label for the migration. The value is used in different interfaces to refer to the migration.

audit key

A boolean value. Defaults to FALSE. It indicates whether the migration is auditable. When set to TRUE, a warning is displayed if entities might be overridden when the migration is executed. For example, when doing an upgrade from a previous version of Drupal, nodes created in the new site before running the automatic upgrade process would be overridden and a warning is logged. The Migrate API checks if the highest destination ID is greater than the highest source ID.

migration_tags key

An array value. It can be set to an optional list of strings representing the tags associated with the migration. They are used by the plugin manager for filtering. For example, you can import or rollback all migrations with the Content tag using the following Drush commands provided by the Migrate Tools module:

$ drush migrate:import --tag='Content'
$ drush migrate:rollback --tag='Content'

source key

A nested array value. This represents the configuration of the source plugin. At a minimum, it contains an id key which indicates which source plugin to use for the migration. Possible values include embedded_data for hardcoded data; csv for CSV files; url for JSON feeds, XML files, and Google Sheets; spreadsheet for Microsoft Excel and LibreOffice Calc files; and many more. Each plugin is configured differently. Refer to our list of configuration options for source plugins to find out what is available for each of them. Additionally, in this section you can define source contents that can be later used in the process pipeline.

process key

A nested array value. This represents the configuration of how source data will be processed and transformed to match the expected destination structure. This section contains a list of entity properties (e.g. nid for a node) and fields (e.g. field_image in the default article content type). Refer to our list of properties for content entities including Commerce related entities to find out which properties can be set depending on your destination (e.g. nodes, users, taxonomy terms, files and images, paragraphs, etc.). For field mappings, you use the machine name of the field as configured in the entity bundle. Some fields have complex structures so you migrate data into specific subfields. Refer to our list of subfields per field type to determine which options are available. When migrating multivalue fields, you might need to set deltas as well. Additionally, you can have pseudofields to store temporary values within the process pipeline.

For each entity property, field, or pseudofield, you can use one or more process plugins to manipulate the data. Many of them are provided by Drupal core while others become available when contributed modules are installed on the site like Migrate Plus and Migrate Process Extra. Throughout the 31 days of migrations series, we provided examples of how many process plugins are used. Most of the work for migrations will be devoted to configuring the right mappings in the process section. Make sure to check our debugging tips in case some values are not migrated properly.

destination key

A nested array value. This represents the configuration of the destination plugin. At a minimum, it contains an id key which indicates which destination plugin to use for the migration. Possible values include entity:node for nodes, entity:user for users, entity:taxonomy_term for taxonomy terms, entity:file for files and images, entity_reference_revisions:paragraph for paragraphs, and many more. Each plugin is configured differently. Refer to our list of configuration options for destination plugins to find out what is available for each of them.

This is an example migration from the ud_migrations_csv_source module used in the article on CSV sources.

id: udm_csv_source_paragraph
label: 'UD dependee paragraph migration for CSV source example'
migration_tags:
  - UD CSV Source
  - UD Example
source:
  plugin: csv
  path: modules/custom/ud_migrations/ud_migrations_csv_source/sources/udm_book_paragraph.csv
  ids: [book_id]
  header_offset: null
  fields:
    - name: book_id
    - name: book_title
    - name: 'Book author'
process:
  field_ud_book_paragraph_title: book_title
  field_ud_book_paragraph_author: 'Book author'
destination:
  plugin: 'entity_reference_revisions:paragraph'
  default_bundle: ud_book_paragraph

migration_dependencies key

A nested array value. The value is used by the Migrate API to make sure the listed migrations are executed in advance of the current one. For example, a node migration might require users to be imported first so you can specify who is the author of the node. Also, it is possible to list optional migrations so that they are only executed in case they are present. The following example from the d7_node.yml migration shows how key can be configured:

migration_dependencies:
  required:
    - d7_user
    - d7_node_type
  optional:
    - d7_field_instance
    - d7_comment_field_instance

To configure the migration dependencies you specify required and optional subkeys whose values are an array of migration IDs. If no dependencies are needed, you can omit this key. Alternatively, you can set either required or optional dependencies without having to specify both keys. As of Drupal 8.8 an InvalidPluginDefinitionException will be thrown if the migration_dependencies key is incorrectly formatted.

class key

A string value. If set, it should point to the class used as the migration plugin. The MigrationPluginManager sets this key to \Drupal\migrate\Plugin\Migration by default. Whatever class specified here should implement the MigrationInterface. This configuration key rarely needs to be set as the default value can be used most of the time. In Drupal core there are few cases where a different class is used as the migration plugin:

deriver key

A string value. If set, it should point to the class used as a plugin deriver for this migration. This is an advanced topic that will be covered in a future entry. In short, it is a mechanism in which new migration plugins can be created dynamically from a base template. For example, the d7_node.yml migration uses the D7NodeDeriver to create one node migration per content type during a Drupal upgrade operation. In this case, the configuration key is set to Drupal\node\Plugin\migrate\D7NodeDeriver. There are many other derivers used by the Migrate API including D7NodeDeriver, D7TaxonomyTermDeriver, EntityReferenceTranslationDeriver, D6NodeDeriver, and D6TermNodeDeriver.

field_plugin_method key

A string value. This key must be set only in migrations that use Drupal\migrate_drupal\Plugin\migrate\FieldMigration as the plugin class. They take care of importing fields from previous versions of Drupal. The following is a list of possible values:

  • alterFieldMigration as set by d7_field.yml.
  • alterFieldFormatterMigration as set by d7_field_formatter_settings.yml.
  • alterFieldInstanceMigration as set by d7_field_instance.yml.
  • alterFieldWidgetMigration as set by d7_field_instance_widget_settings.yml

There are Drupal 6 counterparts for these migrations. Note that the field_plugin_method key is a replacement for the deprecated cck_plugin_method key.

provider key

An array value. If set, it should contain a list of module machine names that must be enabled for this migration to work. Refer to the d7_entity_reference_translation.yml and d6_entity_reference_translation.yml migrations for examples of possible values. This key rarely needs to be set. Usually the same module providing the migration definition file is the only one needed for the migration to work.

Deriver specific configuration keys

It is possible that some derivers require extra configuration keys to be set. For example, the EntityReferenceTranslationDeriver the target_types to be set. Refer to the d7_entity_reference_translation.yml and d6_entity_reference_translation.yml migrations for examples of possible values. These migrations are also interesting because the source, process, and destination keys are not configured in the YAML definition files. They are actually set dynamically by the deriver.

Migration configuration entity keys

The following keys should be used only if the migration is created as a configuration entity using the Migrate Plus module. Only the migration_group key is specific to migrations as configuration entities. All other keys apply for any configuration entity in Drupal. Refer to the ConfigEntityBase abstract class for more details on how they are used.

migration_group key

A string value. If set, it should correspond to the id key of a migration group configuration entity. This allows inheriting configuration values from the group. For example, the database connection for the source configuration. Refer to this article for more information on sharing configuration using migration groups. They can be used to import or rollback all migrations within a group using the following Drush commands provided by the Migrate Tools module:

$ drush migrate:import --group='udm_config_group_json_source'
$ drush migrate:rollback --group='udm_config_group_json_source'

uuid key

A string value. The value should be a UUID v4. If not set, the configuration management system will create a UUID on the fly and assign it to the migration entity. Refer to this article for more details on setting UUIDs for migrations defined as configuration entities.

langcode key

A string value. The language code of the entity's default language. English is assumed by default. For example: en.

status key

A boolean value. The enabled/disabled status of the configuration entity. For example: true.

dependencies key

A nested array value. Configuration entities can declare dependencies on modules, themes, content entities, and other configuration entities. These dependencies can be recalculated on save operations or enforced. Refer to the ConfigDependencyManager class’ documentation for details on how to configure this key. One practical use of this key is to automatically remove the migration (configuration entity) when the module that defined it is uninstalled. To accomplish this, you need to set an enforced module dependency on the same module that provides the migration. This is explained in the article on defining Drupal migrations as configuration entities. For reference, below is a code snippet from that article showing how to configure this key:

uuid: b744190e-3a48-45c7-97a4-093099ba0547
id: udm_config_json_source_node_local
label: 'UD migrations configuration example'
dependencies:
  enforced:
    module:
      - ud_migrations_config_json_source

Migration group configuration entity keys

Migration groups are also configuration entities. That means that they can have uuid, langcode, status, and dependencies keys as explained before. Additionally, the following keys can be set. These other keys can be set for migration groups:

id key

A required string value. It serves as the identifier for the migration group. The value should be a machine name.

label key

A string value. The human-readable label for the migration group.

description key

A string value. More information about the group.

source_type key

A string value. Short description of the type of source. For example: "Drupal 7" or "JSON source".

module key

A string value. The machine name of a dependent module. This key rarely needs to be set. A configuration entity is always dependent on its provider, the module defining the migration group.

shared_configuration key

A nested array value. Any configuration key for a migration can be set under this key. Those values will be inherited by any migration associated with the current group. Refer to this article for more information on sharing configuration using migration groups. The following is an example from the ud_migrations_config_group_json_source module from the article on executing migrations from the Drupal interface.

uuid: 78925705-a799-4749-99c9-a1725fb54def
id: udm_config_group_json_source
label: 'UD Config Group (JSON source)'
description: 'A container for migrations about individuals and their favorite books. Learn more at https://understanddrupal.com/migrations.'
source_type: 'JSON resource'
shared_configuration:
  dependencies:
    enforced:
      module:
        - ud_migrations_config_group_json_source
  migration_tags:
    - UD Config Group (JSON Source)
    - UD Example
  source:
    plugin: url
    data_fetcher_plugin: file
    data_parser_plugin: json
    urls:
      - modules/custom/ud_migrations/ud_migrations_config_group_json_source/sources/udm_data.json

What did you learn in today’s article? Did you know there were so many configuration options for migration definition files? Were you aware that some keys apply only when migrations are defined as configuration entities? Have you used migrations groups to share configuration across migrations? Share your answers in the comments. Also, I would be grateful if you shared this blog post with friends and colleagues.

We have already covered two of many ways to migrate images into Drupal. One example allows you to set the image subfields manually. The other example uses a process plugin that accomplishes the same result using plugin configuration options. Although valid ways to migrate images, these approaches have an important limitation. The files and images are not removed from the system upon rollback. In the previous blog post, we talked further about this topic. Today, we are going to perform an image migration that will clear after itself when it is rolled back. Note that in Drupal images are a special case of files. Even though the example will migrate images, the same approach can be used to import any type of file. This migration will also serve as the basis for explaining migration dependencies in the next blog post.

Code snippet for file entity migration.

File entity migrate destination

All the examples so far have been about creating nodes. The migrate API is a full ETL framework able to write to different destinations. In the case of Drupal, the target can be other content entities like files, users, taxonomy terms, comments, etc. Writing to content entities is straightforward. For example, to migrate into files, the process section is configured like this:

destination:
  plugin: 'entity:file'

You use a plugin whose name is entity: followed by the machine name of your target entity. In this case file. Other possible values are user, taxonomy_term, and comment. Remember that each migration definition file can only write to one destination.

Source section definition

The source of a migration is independent of its destination. The following code snippet shows the source definition for the image migration example:

source:
  constants:
    SOURCE_DOMAIN: 'https://agaric.coop'
    DRUPAL_FILE_DIRECTORY: 'public://portrait/'
  plugin: embedded_data
  data_rows:
    - photo_id: 'P01'
      photo_url: 'sites/default/files/2018-12/micky-cropped.jpg'
    - photo_id: 'P02'
      photo_url: ''
    - photo_id: 'P03'
      photo_url: 'sites/default/files/pictures/picture-94-1480090110.jpg'
    - photo_id: 'P04'
      photo_url: 'sites/default/files/2019-01/clayton-profile-medium.jpeg'
  ids:
    photo_id:
      type: string

Note that the source contains relative paths to the images. Eventually, we will need an absolute path to them. Therefore, the SOURCE_DOMAIN constant is created to assemble the absolute path in the process pipeline. Also, note that one of the rows contains an empty photo_url. No file can be created without a proper URL. In the process section we will accommodate for this. An alternative could be to filter out invalid data in a source clean up operation before executing the migration.

Another important thing to note is that the row identifier photo_id is of type string. You need to explicitly tell the system the name and type of the identifiers you want to use. The configuration for this varies slightly from one source plugin to another. For the embedded_data plugin, you do it using the ids configuration key. It is possible to have more than one source column as identifier. For example, if the combination of two columns (e.g. name and date of birth) are required to uniquely identify each element (e.g. person) in the source.

You can get the full code example at https://github.com/dinarcon/ud_migrations The module to enable is UD migration dependencies introduction whose machine name is ud_migrations_dependencies_intro. The migration to run is udm_dependencies_intro_image. Refer to this article to learn where the module should be placed.

Process section definition

The fields to map in the process section will depend on the target. For files and images, only one entity property is required: uri. Its value should be set to the file path within Drupal using stream wrappers. In this example, the public stream (public://) is used to store the images in a location that is publicly accessible by any visitor to the site. If the file was already in the system and we knew the path the whole process section for this migration could be reduced to two lines:

process:
  uri: source_column_file_uri

That is rarely the case though. Fortunately, there are many process plugins that allow you to transform the available data. When combined with constants and pseudofields, you can come up with creative solutions to produce the format expected by your destination.

Skipping invalid records

The source for this migration contains one record that lacks the URL to the photo. No image can be imported without a valid path. Let’s accommodate for this. In the same step, a pseudofield will be created to extract the name of the file out of its path.

psf_destination_filename:
  - plugin: callback
    callable: basename
    source: photo_url
  - plugin: skip_on_empty
    method: row
    message: 'Cannot import empty image filename.'

The psf_destination_filename pseudofield uses the callback plugin to derive the filename from the relative path to the image. This is accomplished using the basename PHP function. Also, taking advantage of plugin chaining, the system is instructed to skip process the row if no filename could be obtained. For example, because an empty source value was provided. This is done by the skip_on_empty which is also configured log a message to indicate what happened. In this case, the message is hardcoded. You can make it dynamic to include the ID of the row that was skipped using other process plugins. This is left as an exercise to the curious reader. Feel free to share your answer in the comments below.

Tip: To read the messages log during any migration, execute the following Drush command: drush migrate:messages [migration-id].

Creating the destination URI

The next step is to create the location where the file is going to be saved in the system. For this, the psf_destination_full_path pseudofield is used to concatenate the value of a constant defined in the source and the file named obtained in the previous step. As explained before, order is important when using pseudofields as part of the migrate process pipeline. The following snippet shows how to do it:

psf_destination_full_path:
  - plugin: concat
    source:
      - constants/DRUPAL_FILE_DIRECTORY
      - '@psf_destination_filename'
  - plugin: urlencode

The end result of this operation would be something like public://portrait/micky-cropped.jpg. The URI specifies that the image should be stored inside a portrait subdirectory inside Drupal’s public file system. Copying files to specific subdirectories is not required, but it helps with file organizations. Also, some hosting providers might impose limitations on the number of files per directory. Specifying subdirectories for your file migrations is a recommended practice.

Also note that after the URI is created, it gets encoded using the urlencode plugin. This will replace special characters to an equivalent string literal. For example, é and ç will be converted to %C3%A9 and %C3%A7 respectively. Space characters will be changed to %20. The end result is an equivalent URI that can be used inside Drupal, as part of an email, or via another medium. Always encode any URI when working with Drupal migrations.

Creating the source URI

The next step is to create assemble an absolute path for the source image. For this, you concatenate the domain stored in a source constant and the image relative path stored in a source column. The following snippet shows how to do it:

psf_source_image_path:
  - plugin: concat
    delimiter: '/'
    source:
      - constants/SOURCE_DOMAIN
      - photo_url
  - plugin: urlencode

The end result of this operation will be something like https://agaric.coop/sites/default/files/2018-12/micky-cropped.jpg. Note that the concat and urlencode plugins are used just like in the previous step. A subtle difference is that a delimiter is specifying in the concatenation step. This is because, contrary to the DRUPAL_FILE_DIRECTORY constant, the SOURCE_DOMAIN constant does not end with a slash (/). This was done intentionally to highlight two things. First, it is important to understand your source data. Second, you can transform it as needed by using various process plugins.

Copying the image file to Drupal

Only two tasks remain to complete this image migration: download the image and assign the uri property of the file entity. Luckily, both steps can be accomplished at the same time using the file_copy plugin. The following snippet shows how to do it:

uri:
  plugin: file_copy
  source:
    - '@psf_source_image_path'
    - '@psf_destination_full_path'
  file_exists: 'rename'
  move: FALSE

The source configuration of file_copy plugin expects an array of two values: the URI to copy the file from and the URI to copy the file to. Optionally, you can specify what happens if a file with the same name exists in the destination directory. In this case, we are instructing the system to rename the file to prevent name clashes. The way this is done is appending the string _X to the filename and before the file extension. The X is a number starting with zero (0) that keeps incrementing until the filename is unique. The move flag is also optional. If set to TRUE it tells the system that the file should be moved instead of copied. As you can guess, Drupal does not have access to the file system in the remote server. The configuration option is shown for completeness, but does not have any effect in this example.

In addition to downloading the image and place it inside Drupal’s file system, the file_copy also returns the destination URI. That is why this plugin can be used to assign the uri destination property. And that’s it, you have successfully imported images into Drupal! Clever use of the process pipeline, isn’t it? ;-)

One important thing to note is an image’s alternative text, title, width, and height are not associated with the file entity. That information is actually stored in a field of type image. This will be illustrated in the next article. To reiterate, the same approach to migrate images can be used to migrate any file type.

Technical note: The file entity contains other properties you can write to. For a list of available options check the baseFieldDefinitions() method of the File class defining the entity. Note that more properties can be available up in the class hierarchy. Also, this entity does not have multiple bundles like the node entity does.

What did you learn in today’s blog post? Had you created file migrations before? If so, had you followed a different approach? Did you know that you can do complex data transformations using process plugins? Did you know you can skip the processing of a row if the required data is not available? Please share your answers in the comments. Also, I would be grateful if you shared this blog post with your colleagues.

Next: Introduction to migration dependencies in Drupal

This blog post series, cross-posted at UnderstandDrupal.com as well as here on Agaric.coop, is made possible thanks to these generous sponsors. Contact Understand Drupal if your organization would like to support this documentation project, whether it is the migration series or other topics.

 

The contextual filter selection screen.

As Drupal awareness grows and more people adopt it as a platform, the community becomes more interesting. There are some real characters that have grown to be major contributors to every facet of the beast. How did they evolve and find their place?

You cannot just apply the stereotypical nerd face to the Drupal community; it will not stick. This is the most welcoming community I have been a part of in my 17 years as a contributor in the Web Development arena, and in 8 years with Drupal, I have seen many new members welcomed enthusiastically.

For newcomers to the community, and to plenty of us who have been here for years, sometimes the question can be: where is my place in the Drupal community? The answer is: You can have many places or roles in the Drupal community. You are not limited to wearing one hat. Believe it or not, there is even a place for someone that has never seen Drupal. What better UI test candidate is there? From Guinea Pig to Drupal Glory, the path can start right there at zero.

Here is a recent month in my life with Drupal: January, 2014.

I managed to go to several meetups, be part of a Drupal Nights panel at BioRAFT in Cambridge, MA and I have three new Drupal client Websites in progress. I am a Project Manager on two sites and an Architect on the other. I introduced four new people to the Drupal community, two PHP developers, one artist, and one musician. All four of my friends have come to a meetup and they have each installed their first Drupal site! I think it is important to introduce new people to the Drupal community and to try and see it through by hooking them up with specific projects that may interest them, or by introducing them to people already part of the Drupal community that may have similar projects or goals.

A few weeks ago I finally convinced a colleague and friend that lives in Western Massachusetts to attend a Drupal meetup. We met years ago when we worked together at an over-funded company that developed an over-priced proprietary software app similar to Google Hangouts (we broadcast concerts and live events to anyone that downloaded the proprietary player). The company blew up in the dot com bubble burst at the turn of the century (just wanted to be able to say that phrase—'turn of the century'—it sounds kind of epic).

My friend had been trying to get his online store to be automated and he had been through the mill trying different solutions, some proprietary, Wordpress, even doing some strange super complex import process using Microsoft Access. I drove from Boston 100 miles West to pick up my friend and find the meetup in a small town called Hadley, MA. On the meetup page it counted only three people that had RSVP'd to attend. I hoped they were the right three people for my friend to meet. I also brought another friend with me from Boston, a local artist that needs a portfolio site and a way to sustain himself financially while helping other artists/musicians. He had just installed his first Drupal 7 site and had no prior experience with creating a website.

We arrived at the meetup just in time for some delicious pizza (yes, Drupal does feed your body as well as your mind sometimes) and lo and behold, there were about 20 people that showed up. The highlight of my night was when my friend asked if anyone thought he could create his site using the Commerce Kickstart distribution. He had already installed it and had started watching tutorials on how to set it up; the resounding answer was—of course—yes… but the better part is that a couple of people took great interest in his project (they were probably musicians) and right then and there, they walked him through a few solutions to some of the biggest challenges of his project, suggesting configurations and additional modules he could use.

The best part: Now my friend will be able to share his knowledge and help other people set up Drupal with Commerce Kickstart. In the near future I am sure he will also be helpful working on projects that require advanced configurations for Commerce Kickstart because I have known him to be creative, caring, and brilliant at learning new things— and now he has been bitten by the Drupal bug!

So, for that night, my place was to introduce new people to the community. The next day I helped someone install Drupal, so my hat changed. Another day my partners Ben Melançon and Stefan Freudenburg helped me set up my development environment on my new Linux box (which I promptly destroyed beyond repair). That day I was in the "help me I am falling" cheap seats place, but it did not feel irreversible. I was soon back in my site-builder role (making a site for my local Linux users group). A place we can all occupy sometimes, a role we can all play, is introducing new Drupal community members into the fold.

I would love to hear your stories of non-scary (or scary) introductions to Drupal, and hats you tried on to see if they would fit!


Join us at an upcoming event in Boston/Cambridge MA - Boston/Cambridge Worker Cooperative Meetup

Social Simple buttons

This covers 90% of use cases, but what if we need to add a button for a new network?

Creating a Custom Social Simple Button

The Social Simple module already supports custom buttons, we just need to let the module know that we want to add one.

What we need to do is:

  • Create a class that implements SocialNetworkInterface.
  • Register this class in our services file.
  • Add the tag social_simple_network to our service.

For our example we are going to create a basic Mail button. We start by creating a custom module. Inside our module let's create a Mail php file inside of the src/SocialNetwork folder:

 

mkdir -p src/SocialNetwork cd src/SocialNetwork touch Mail.php

 

The next step is to create a class and implement the SocialNetworkInterface which interface has the following methods:

  • getShareLink: This is the most important method. It must return a rendered array which later Drupal will use to create the button.
  • getLabel: Here we will need to provide the name of our button. In our case Mail.
  • getId: The ID of the button. We can choose any ID here, we just need to make sure that it is unique. Let's use mail for our example.
  • getLinkAttributes: These attributes are going to be passed to the link. We can add custom parameters to the link in this part.

Our class looks like this:


namespace Drupal\social_simple\SocialNetwork; use Drupal\Core\Entity\EntityInterface; 

use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url; 

/** * The Mail button. */
class Mail implements SocialNetworkInterface { 

use StringTranslationTrait; 

/** * The social network base share link. */
const MAIL = 'mailto:'; 

/** * {@inheritdoc} */
public function getId() {
  return 'mail';
} 

/** * {@inheritdoc} */
public function getLabel() {
  return $this->t('Mail');
} 

/** * {@inheritdoc} */
public function getShareLink($share_url, $title = '', EntityInterface $entity = NULL, array $additional_options = []) {
  $options = [
    'query' => [
      'body' => $share_url,
      'subject' => $title,
    ],
    'absolute' => TRUE,
    'external' => TRUE,
  ]; 

  if ($additional_options) {
    foreach ($additional_options as $id => $value) {
      $options['query'][$id] = $value;
    }
  }
  $url = Url::fromUri(self::MAIL, $options);
  $link = [
    'url' => $url,
    'title' => ['#markup' => '' . $this->getLabel() . ''],
    'attributes' => $this->getLinkAttributes($this->getLabel()),
  ]; return $link;
} 

/** * {@inheritdoc} */
public function getLinkAttributes($network_name) {
  $attributes = [ 'title' => $network_name, ];
  return $attributes;
  }
}

The next step is to let the social network know about our new button and we do this by adding this class as a service in our module.services.yml. If you are not familiar with this file, you can read the structure of a service file documentation..

Basically we need to add something like this:


services: 
  social_simple.mail: 
    class: Drupal\custom_module\SocialNetwork\Mail 
    tags: - { name: social_simple_network, priority: 0 }

Next, rebuild the cache. Now when we visit the social simple configuration we will see our new button there, ready to be used.

Social Simple Configuration page

The only thing that we need to pay extra attention to is that the Social Simple module will just search the services with the tag social_simple_network otherwise our class will not be found.

If you want to see how the whole thing is working, you can check this patch that I made as a part of a project: https://www.drupal.org/project/social_simple/issues/2899517. As a bonus, I made an initial integration with the Forward module.

A plain two-edged razor blade (for a pun on double-edged razor).

Double-edged Raiser

Past time to ditch Blackbaud

Sometimes we need a Drupal installation for a quick test of a module, theme, or feature that we are working on. You can have a LAMP stack installed locally or, as we do at Agaric, use virtual machines. In both cases, it can take a considerable amount of time to make the required configuration to install Drupal. It is possible to avoid all that by leveraging Drupal’s support for SQLite and using PHP’s built in web server. Let me show you how to easily create a disposable installation with a few drush commands.

During BADCamp 2015 sprints, some developers and myself joined Jesús Manuel Olivas to work on Drupal Console. It is an amazing project that allows you to speed up your Drupal 8 development by generating scaffolding code. Some Console commands require a Drupal installation to work. I wanted to contribute to the project so I used drush to download and install Drupal in seconds. For instructions on installing drush, check this great article by Karen Stevenson.

1. Download Drupal

drush pm-download --drupal-project-rename=drupal drupal-8.0.x

This will download the latest development version of Drupal 8.0 and place it in the directory specified by the --drupal-project-rename parameter. In our case, the directory name will be called drupal. If you omit this parameter, the files will be downloaded to a directory with the Drupal version number in it.

2. Change directory and install Drupal

cd drupal
drush site-install standard --db-url=sqlite:///tmp/test.db

Once we have downloaded the code, we change directories to the Drupal root and issue the installation command. standard is the installation profile to be used. The --db-url parameter allows us to specify the database to connect to. Usually this would include the credentials for MySQL or your favorite database server. In our case, we are going to use SQLite which is a self-contained database engine. To use it, we only need to precede with sqlite:// a file path on our system where the database will be created. In this example, that path is /tmp/test.db

3. Start PHP’s built in server

drush runserver

Starting in version 5.4.0, PHP includes a lightweight web server. The previous command will start the server listening by default on 127.0.0.1:8888. Paste that in your browser’s address and enjoy a fully working Drupal installation in front of you. If you got a different IP address or port number use that instead. The server will keep listening and even output logs as you interact with the site. When you are done testing, press Ctrl + C to stop the web server.

4. Clean up

rm /tmp/test.db
cd ..
rm -rf drupal

Finally, do some clean up. Delete the database file. If you set up the database in /tmp you might not need to manually delete it. You should also remove the Drupal directory. Everything will be gone in a snap.

The complete recipe is:

# Download Drupal
drush pm-download --drupal-project-rename=drupal drupal-8.0.x

# Change directory and install Drupal
cd drupal
drush site-install standard --db-url=sqlite:///tmp/test.db

# Start PHP’s built in server. Press Ctrl + C to stop the web server.
drush runserver

# Clean up.
rm /tmp/test.db
cd ..
rm -rf drupal

A shortcut

drush core-quick-drupal --core=drupal-8.0.x --profile=standard drupal

The previous drush command will download Drupal, install it using SQLite, start PHP's built in server, and even open a browser windows with user 1 already logged in. The command exposes lots of parameter to configure the Drupal installation. In our example, we are downloading version 8.0.x, place it in a directory called drupal, and use the standard installation profile. All the other parameters would use the defaults. For a list of available parameters and arguments issue the following command in the terminal drush help core-quick-drupal.

My motivation for following this approach was that I needed to write and test code when sprinting on Drupal Console. If you do not need to modify code, Patrick Drotleff has built an amazing website that allows you to create temporary Drupal installations with support for modules, themes, distributions, patches, and more. To use it, visit https://simplytest.me

Drupal Console not only generates scaffolding code. It also lets you interact with your Drupal installation in similar ways to Drush. For example, it lets you download and install Drupal using a MySQL database. Notwithstanding, it is not possible at the moment to install Drupal using SQLite or start the PHP’s built in server. Jesús Manuel Olivas, one of the project maintainers, said that these options would be available in future versions of Drupal Console.

What do you think about this method for creating disposable Drupal installations? Do you follow a different approach? Let me know in the comments.

With Drupal 7's third and final release candidate unleashed on us all this morning, it is long past time to help the #D7CX movement with a seasonal offering of our own.

The most fitting gift would be porting a Drupal 6 module, but it wouldn't be a modern winter holiday without an environmentally irresponsible brand new toy: Introducing the Xray module, designed to help site builders and module developers investigate a Drupal 7 site.

X ray photo showing skeleton drilling into a wall The feature i'd like to point out in relation to porting modules and developing for Drupal 7 is Xray's report showing permission machine names (screenshot below). Permissions in Drupal 7 have human-friendly translatable titles, which is awesome, but the machine names – which module developers must use – have disappeared entirely from the user interface.

A moderately complex Drupal site can have a Permissions page like a Las Vegas building-side of lightbulbs... but with checkboxes – so i don't like to create new permissions unless i know of a clear use case. In developing modules, therefore, i prefer to reuse existing permissions when applicable. For instance, the Xray module, instead of defining a special permission for its reports, reuses the "View site reports" permission.

To refer to a permission in code, we need its machine name, not the title we can see on the Permissions page (admin/people/permissions). My chapter on module development in the coming Definitive Guide to Drupal 7 covers (in the course of building the Xray module) how to find permission machine names in the database or in the code, but it wouldn't be Drupal if we couldn't say there's a module for that, so a permission machine name report is incorporated into Xray itself.

Note: Anything incorrect in this chapter may misinform tens of thousands, so please, code review Xray module mercilessly, and all comments and suggestions requested and welcome!

Further note: Please vote for the When There's Not a Module for That, the intermediate module building session at Drupalcon Chicago which will include parts of the making of Xray module, and for sessions involving other DGD7 authors, and then for every session that interests you because there's less than 24 hours left to vote!

By the way, the machine name for "View site reports" is access site reports. Drupal will always keep us on our toes.

Xray, in another feature interesting for module developers and sometimes for site builders, displays what function and arguments produce each page you visit.

The most up-to-date code for Xray can be downloaded directly (tar.gz) from Gitorious.

A table of permission titles and permission machine names.

The grocery store was open for a brief time, but it was never a cooperative. I know, because I joined as a member the day it first opened in 2017, on August 11. (I first e-mailed to ask about becoming a member ten months earlier, but that required meeting in person and this was the first time it was feasible.)

On 2018, June 12, after Wirth Cooperative Grocery had been closed for two months, I received my only formal communication as a member owner: an e-mail acknowledging that the store was closed, noting that the current grocery market is extremely competitive, and saying they had plans to re-open by the end of the month.

The e-mail did not ask for decisions. It did not ask for volunteers or help of any kind. While addressed to us as member owners, it did not afford us any opportunity to affect the future of the store. It did not provide any information on which we might try to act. Instead it told us to wait to be notified when an opening date was set. An opening date was never set.

Although I'm certain some staff and volunteers worked hard behind the scenes, from my perspective as a member owner the grocery store went down without a fight.

That's why it's so important for cooperatives to be true cooperatives. The seven cooperative principles aren't a "pick any three" sort of deal.

The first principle specifies that membership in a cooperative be open to all people willing to accept the responsibilities, but a person cannot accept responsibilities which aren't offered.

The second principle is democratic member control, but people cannot exercise direct control or hold representatives accountable without information and without a means to communicate with one another.

Likewise for the next three cooperative principles: the third, that members democratically control capital; the fourth, that external agreements preserve democratic control; and the fifth, that a cooperative educate, train, and inform members so they can contribute to it effectively. An organization with no mechanisms for discussion nor for democracy violates these principles, too.

Principles six and seven, cooperation among cooperatives and concern for community, are likely to be hollow without functioning internal democracy— and certainly cannot be realized if the business fails.

A cooperative can't exist only on good intentions.

When I hear this sentiment expressed by experienced cooperators—founders and developers of cooperatives—it usually means that there needs to be a solid business model for a cooperative, because a cooperative that isn't economically viable can't fulfill any of its goals.

A more fundamental meaning is that a business can't be a cooperative if it merely intends to be; it must act like a cooperative. Otherwise, it's just another business with some co-op lip service gloss— and given the greater success of cooperatives compared to other businesses it's less likely to be around as a business at all, if it does not live up to its cooperative principles.

I'm not trying to use technicalities to dodge counting the failed Wirth grocery store as a failure for "team cooperative". On the contrary, this is a wakeup call for everybody who supports cooperatives, one that must rouse us, because fully-functioning cooperatives are bigger than the cooperative movement. Cooperatives can prefigure true democracy. We need to show that economic democracy works in our voluntary organizations; we need to give people in a world which is already ruled unjustly, and threatening to spiral out of control, a promise and a practice for how whole communities can take collective control.

In my experience as a member owner, Wirth Cooperative Grocery was not a co-op beyond its name and some vague intentions. Now I know that my experience matched everyone else's, thanks to Cirien Saadeh's reporting, both last year and in the most recent issue of North News (an invaluable local non-profit enterprise).

What worries me, then, is that no one quoted in these articles called out this failure to meet the basic requirements of being a cooperative. Minneapolis and Minnesota have perhaps the highest rate of cooperative membership in the United States, with about half of all residents estimated to belong to at least one cooperative of one kind or another. If we, here, don't have the awareness and interest to note when a cooperative doesn't act like a cooperative, who will?

More important than calling out failures is providing pathways to success. There are many programs and organizations supporting cooperatives in Minnesota and beyond, but none put ensuring member control first.

The bias of my profession and my passion is to lead with an online tool: ensure member owners can communicate with one another. Although a technological fix can't solve political problems, people who are affected need a way to talk among themselves to come up with a solution.

Efforts like a local cooperative grocery are small enough that a Loomio group or any mailing list would mostly work for member owner discussion. A better software application would work for collaborative groups of any size: members would filter messages for quality without ceding control to any outside group. This self-moderation for groups of equals, including cooperatives, is a goal of Visions Unite.

Are you in a position to provide resources to cooperatives and other groups seeking to grow and be democratic? Are you starting or do you want to start a cooperative or group? Do you have other ideas on how to help new and established cooperatives live by the foundational cooperative principles? I would like to hear from you!

Ben Melançon asiste a un taller de Ujima.

Benjamin Melançon y Clayton Dewey se ofrecen como voluntarios en el equipo de liderazgo de Drutopia, una iniciativa para llevar sitios web impulsados por Drupal a organizaciones de base.

Plans for a new way of connecting students with their community

Problem: Schools and students are traditionally disconnected from their community and seldom do they work on interrelated projects that will benefit both the school and the people of the community.

Solution: Mentoring students to develop free software, such as the Drupal content management system, will introduce students to the myriad of careers and skills necessary to build a successful web presence - cooperatively. A web presence is more than just a website and also includes items like video, audio, and content that is compelling. No longer are we limited to a brochure online type of approach. Engaging people is the name of the game now. Beyond a web presence, students will also be mentored in ways to engage their community in building platform tools owned by the community.

How to: The Boston Collaboratory School will use the free software Drupal as the framework for a curriculum to mentor students in relevant technical and non-technical skills which can be applied at local and global scales. Mentors will connect students' interests and community needs, with Drupal serving as a gateway to introduce students to the many different career paths they might take. The focus of the Boston Collaboratory School on projects which benefit communities will also give these students practical experience creating ethical businesses in the form of platform cooperatives and participating in the free software movement via the Drupal framework. Read more

¿Qué es el Software Libre?

Un programa es software libre si los usuarios del programa tienen las cuatro libertades esenciales:

0. La libertad de ejecutar el programa y utilizarlo para cualquier propósito (libertad 0).

1. La libertad para acceder y estudiar cómo funciona un programa y cambiarlo, adaptándolo a suspropias necesidades (libertad 1).

2. La libertad de redistribuir copias para que pueda ayudar a otros usuarios (libertad 2).

3. La libertad de hacer cambios y distribuir las versiones modificadas a otros (libertad 3).

El acceso al código fuente es una condición previa para lograr esto. Para determinar si el código fuente es libre, revise qué licencia tiene y luego verifique la lista del proyecto GNU

Free software examples

Tenemos algunas tareas para las cuales no contamos con software de código abierto. En ocasiones, nos vemos obligados a usar un software no libre si el cliente insiste en incluirlo en su sitio web. Cuando esto sucede, se sacrifica parte de nuestra libertad.  Algunos activistas se negarían rotundamente a esto. 

A nosotros no nos gusta comprometer nuestra autonomía, por lo que preferimos ayudar a desarrollar reemplazos para estos programas y siempre que este en nuestras posibilidades elegiremos un software que refleje nuestra ética y filosofía. 

Sistemas Operativos

GNU/Linux

Gnu logo and Linux logo

Hemos optado por utilizar GNU / Linux como nuestro sistema predeterminado para nuestro desarrollo local. Cuando tenemos un nuevo estudiante, instalamos una distribución GNU / Linux y siempre damos la opción de disponer de una diferente si el estudiante así lo desea. 

 

Estas son las distribuciones de GNU / Linux preferidas utilizadas por los miembros de nuestro equipo cooperativo* : 

Estas no son las mejores versiones de GNU / Linux en cuanto a ser completamente libres, pero existen mas opciones. Puede consultar la lista de distribuciones en el sitio web de la Free Software Foundation para elegir la que mejor se adapte a sus necesidades. 

* Actualmente, un miembro del equipo está utilizando el Mac OS X patentado pero basado en BSD, que cumple con el estándar Unix 03 / POSIX que también cumplen las distribuciones GNU / Linux.

Navegadores

Firefox

Firefox logo

Como desarrolladores, tenemos que probar sitios de clientes en diferentes navegadores, pero para trabajar y construir sitios web, utilizamos Mozilla Firefox. Y aunque el código fuente de Firefox es software libre, incluye algunos iconos, marcas registradas y logotipos en la descarga que lo hacen no completamente libre.

Estos se pueden eliminar fácilmente como se ha hecho con IceCat, la versión GNU del navegador Firefox, la cual tiene un gran rendimiento, herramientas de desarrollo y una gran comunidad. El lado positivo de tener una comunidad en torno al software que utilizamos, es el acceso a un gran grupo de personas con experiencia y disposición para orientar, a medida de que podamos aprender y seguir construyendo juntos. 

Tor Browser

Tor logo

Como ciudadanos libres, no nos gusta que nos rastreen, por lo que utilizamos un navegador web de anonimato que no permite seguimientos. Se llama Tor.

 

Micky usa y ama el navegador Brave en Android y su computadora portátil GNU / Linux. ¡ Con ellos puedes bloquear los anuncios desde el primer momento! https://brave.com/ 

 

Si no observamos profundamente a Qwant, luce bastante decente -

Nos encontramos con Qwant a través de https://iridiumbrowser.de/  una versión de cromo más segura, pero probablemente tiene algunas cosas que quizás no sepamos o no queramos tener...

Almacenamiento de archivos y calendario

NextCloud

Nextcloud logo.

NextCloud es una colección de utilidades adecuadas para el proceso de desgoogización. Este software nos proporciona la mayoría de las herramientas populares en Google Drive y está centrado específicamente en brindar seguridad, privacidad y control total de todos sus datos a los usuarios de un  forma totalmente transparente.  Agaric utiliza una versión alojada de NextCloud en los servidores de MayFirst.org que incluyen:

  •     Almacenamiento de documentos y archivos
  •     Sincronizaciónde múltiples dispositivos
  •     Galerías de imágenes 
  •     Calendario
  •     Contactos

Vea una comparación de las características que ofrece NextCloud frente a las opciones propietarias que ofrece GoogleDocs / Drive.

Finanzas, contabilidad y teneduría de libros

GNUcash

Gnucash logo

GNUcash Es una herramienta de  software libre para la gestión financiera. De una forma sencilla permite controlar cuentas bancarias, gastos y  pagos tanto para uso personal como para pequeñas empresas y autónomos. Este es el software que utilizamos para llevar nuestra la contabilidad. 

 

Usted puede ver una revisión de GNUcash vs. Quickbooks para comparar y decidir cualle resulta adecuado.  Hemos encontrado algunas cooperativas contables que hacen su trabajan con GnuCash. 

Chat en tiempo real

Nosotros confiamos en diferentes herramientas para comunicarnos entre nosotros y con los clientes sobre las actividades diarias y los objetivos de proyectos a largo plazo. Nuestro  equipo esta distribuido en diferentes ubicaciones alrededor del mundo, por lo cual, es importante mantener contacto, especialmente cuando se realiza programación en pareja o durante una migración que requiere manos a la obra. Además, de la necesidad de compartir algunas notas de texto informativas y documentos que incluyen datos administrativos.

Freenode

Freenode logo

El Internet Relay Chat, mejor conocido como IRC o simplemente Chat,  es un servicio de comunicación en tiempo real a través de Internet entre dos o mas personas en formato textual. Sí, nosotros todavía utilizamos IRC y se nos puede encontrar en el servidor irc.freenode.net en el canal # devs-r-us

Nuestras preferencias aquí son tan variadas como los miembros de nuestro equipo: unos usan IRSSI a través de un servidor virtual remoto siempre activo, otros usan opciones de escritorio como HexChat o Konversation y algunos aún prefieren la solución basada en la web "The Lounge".

 

Email

MayFirst.org aloja el correo electrónico de Agaric.com

Email Cliente: Thunderbird

 

Thunderbird logo

Thunderbird es un cliente de correo electrónico de Mozilla, fabricado por Firefox y que también está disponible para su teléfono móvil. Cuenta también con un complemento de cifrado llamado EnigMail que funciona bien y no es difícil de configurar. 

Correo electrónico alojado: RiseUp

RiseUp es una organización colectiva administrada por voluntarios anónimos dedicada a proveer servicios de correo electrónico encriptado y alojamientos privados y seguros a personas y organizaciones comprometidas con la justicia social y política. Para obtener acceso debe ser invitado a ser miembro.

MayFirst ofrece tres soluciones de correo electrónico basadas en la web.

1. Roundcube, que tiene una interfaz web amigable y simple, lo que hace que sea fácil de usar.

2. ¡SquirrelMail es una opción que no tiene Javascript!

3. Horde por otro lado, ofrece más que solo un correo electrónico: usted puede compartir calendarios, tareas pendientes, entre otras opciones con otros miembros de su grupo.

Alojamiento de correo electrónico

Protonmailes: un servicio de correo electrónico seguro, fácil de usar, con cifrado de extremo a extremo. 

Listas de correo electrónico:

Utilizamos servidores de listas de correo electrónico para listas de correo basadas en grupos y diferentes temas. Permite el envío grupal a personas que se inscriben en una lista específica.

Servidor de correo electrónico MayFirst

Servidor de correo electrónico RiseUp

Medios para la comunicación social

Mastodonte: publica todo lo que quieras: enlaces, imágenes, texto y video. Todo dentro de una plataforma de propiedad comunitaria y sin publicidad.

Social.coop: una comunidad similar a Twitter, con la principal diferencia de que es propiedad de los miembros. Por tan solo un 1 dólar al mes, puede convertirse en propietario / miembro y participar en la configuración del futuro de la plataforma. 

Puede encontrar y seguir a Agaric en social.coop, un rincón cooperativo del Fediverse, una red con un enfoque cooperativo y transparente para operar una plataforma social. 

Transmisión en vivo:

Transmisión en vivo de MayFirst: la membresía incluye transmisión en vivo.

Llamadas de conferencia y reuniones en línea

Jitsi es un software de cliente multiplataforma, libre y de código abierto que opera con Mensajería Instantánea (IM), chat de voz y video en Internet. Jitsi Videobridge y Jitsi Meet, le permiten tener conferencias en Internet y le permite utilizar funciones como audio, acceso telefónico, grabación y transmisión simultánea.

Algunos miembros del equipo de Agaric lo están usando y reconocen que es un trabajo en progreso y que a veces puede haber fallas técnicas, como también las hemos encontrado al usar Hangouts de Google: tiempo de retraso, cortes, mala calidad de sonido y problemas con el uso compartido de la pantalla. 

En ocasiones, descubrimos que necesitamos usar una solución patentada que parece funcionar de manera confiable a medida que continuamos apoyando los esfuerzos de desarrollo y la corrección de errores con Jitsi. 

Usted puede alojar una instancia de Jitsi o elegir una versión previamente alojada usando https://meet.jit.si . También está disponible para uso público en https://meet.mayfirst.org

Le recomendamos que se convierta en miembro de MayFirst y tenga acceso a todas las herramientas de software libre que ellos ofrecen. 

¡El proyecto Jitsi necesita voluntarios para probar sus servicios y encontrar opciones para mejorar rápidamente!

Actualmente, Agaric está utilizando y pagando el servicio y software patentado de audio-conferencia y videoconferencia de Zoom. Nos encantaría recomendar a otra opción estable que sea el software libre.

Llamadas telefónicas y mensajes de texto

Agaric usa Signal para cifrar mensajes de texto SMS y llamadas telefónicas.

Signal

Una aplicación de software gratuita y abierta que emplea  criptografía end-to-end, lo que permite a los usuarios enviar mensajes de grupos, textos, imágenes y mensajes de vídeo con cifrado, esta altamente recomendada por Edward Snowden. Hay que tener en cuenta que la seguridad es una carrera armamentista y que esto podría volverse falso en cualquier momento. 

 

Toma de notas colaborativa

RiseUp:

RiseUp almohadillas es una sencilla aplicación web que permite editar el mismo documento (Pad) de manera simultánea por varias personas en tiempo real. Cuando organizamos una reunión en línea, generalmente abrimos un bloc de notas compartido para que todos puedan contribuir a que se registren los bits importantes. El texto de RiseUp se sincroniza para que todos los que estén en la página vean el mismo texto y puedan colaborar en documentos con equipos grandes o pequeños sin problemas.

Nosotros usamos la versión alojada, pero puede hospedarla usted mismo. Hemos probado algunos pads en línea y nos hemos decidido por Etherpad como el más confiable.

* NextCloud también tiene esta característica colaborativa.

Discusión colaborativa continua

Con algunos colaboradores, particularmente personas involucradas con la iniciativa Drutopia, utilizamos Mattermost en lugar de IRC. Mattermost es un conjunto de herramientas de colaboración que tiene como característica principal un servicio de mensajería instantánea útil para las discusiones en curso y de la cuál se puede acceder al resto de las funcionalidades. Es similar a Slack y ofrece una conversación entrelazada. La versión comunitaria es software libre.

Notas y listas de tareas

TomBoy una pequeña aplicación Open Source multiplataforma que permite tomar notas mientras crea convenientemente hipervínculos de títulos y permite la sincronización a través de SSH y más.

Gestión de contraseñas

KeePass un sistema de administración de contraseñas que elimina en su mayoría la preocupación de almacenar y recuperar la información de inicio de sesión para múltiples proyectos y sitios.

Edición de documentos de texto, hojas de cálculo y presentaciones

Es posible que haya oído hablar de OpenOffice; ahora se llama LibreOffice y es un conjunto de herramientas de oficina similares a Microsoft Office, incluye Documentos, Hojas de cálculo y Diapositivas. Utilizamos las herramientas de LibreOffice que vienen como software central en las distribuciones de GNU / Linux que tenemos instaladas. 

Estos son los que usamos con más frecuencia:

1. LibreOffice Calc: Tiene características y funciones similares a las de un software para crear hojas de cálculo como Microsoft Excel. 

2. LibreOffice Writer: un procesador de textos con una funcionalidad similar a la de Microsoft Word. 

3. LibreOffice Impress: utilizamos esta herramienta para crear diapositivas y presentaciones utilizando texto / gráficos y videos. Tiene las mismas ventajas que  Microsoft PowerPoint.

Gestión de proyectos y seguimiento de problemas

* GitLab: es una herramienta de código abierto para el control de versiones y desarrollo de software colaborativo, ademas de ser gestor de repositorio de Git basado en la web y auto hospedado en wikis, cuanta con la característica de seguimiento de errores. Utilizamos Gitlab para el desarrollo cooperativo en nuestros proyectos.

* Aunque GitLab no es un software totalmente libre, pero sí ofrece una versión auto hospedada. La versión alojada de Enterprise tiene características adicionales y se desarrolla bajo una licencia propietaria.

Redmine: es una aplicación web libre para la gestión de proyectos y seguimiento de problemas. Se puede ejecutar localmente o en su propio servidor. Antes de encontrar GitLab, utilizamos una instancia de Redmine auto hospedada que es software libre.

Toma de decisiones y votación

Loomio:  un servicio alojado disponible en http://loomio.org

Loomio es un software libre que ofrece un sistema distribuido de toma de decisiones y donde se puede formar grupos y realizar discusiones para tomar decisiones sin tener una reunión en persona. Para decidir sí o no, o si lo que necesitas es más información.

Ten en cuenta que Loomio también ha creado un gran recurso cooperativo en su otra URL: http://loomio.coop

Gestión de la relación con el cliente

CiviCRM:  Agaric está trabajando con los desarrolladores de MyDropWizard para echar un vistazo a CiviCRM con Drupal 8.
CviCRM es un software libre  gestor de relaciones y membresías con los clientes. Todavía no lo hemos implementado. 

Directorios de recursos y software libre  

Puede contribuir a grupos que trabajan para encontrar soluciones, hay muchos roles y no tiene que ser desarrollador. Por ejemplo, * IndieWeb y Jitsi son proyectos a los que dedicamos tiempo para apoyar con el desarrollo, las pruebas, la divulgación y la retro-alimentación.

* Con IndieWeb puede tomar el control de sus artículos y los mensajes de estado se pueden distribuir a todos los servicios, no solo a uno, lo que le permite interactuar con todos en su red o gráfico social. Incluso las respuestas y los “me gusta” de otros servicios pueden volver a su sitio para que estén todos en un solo lugar.

Framasoft: Es una gran colección de herramientas de software libre donde usamos el calendario y el software de encuestas con mayor frecuencia. Estamos experimentando con varias otras herramientas de FramaSoft y para poder adoptarlas en un futuro.

Si esta ha sido una lectura útil, compártela y cuéntanos en los comentarios cómo te ayudó. Una publicación de seguimiento enumerará las herramientas que utilizamos para fines de desarrollo. Asegúrese de mencionar cualquier software gratuito que haya encontrado y esté utilizando ahora.

Framasoft: A large collection of free software tools where we use the calendar and polling software most often. We are experimenting with several other FramaSoft tools and may adopt them in the future.

Los dejamos con una excelente charla TEDx donde Richard Stallman explica el Software Libre:

 

 

Abico aptent erat gilvus immitto lenis nisl os pala virtus. Augue caecus neo nostrud pagus secundum valetudo vero. Dolore jumentum melior quae ullamcorper. Abbas exputo iusto modo quae ullamcorper uxor vulputate. Abbas aliquam aliquip inhibeo mos vel. Abbas aliquam brevitas commodo dolor macto populus premo sino. Abico aliquip causa consectetuer diam dolus imputo jugis obruo olim.

Accumsan caecus eros esca eu huic letalis metuo vereor zelus. Immitto macto os pneum praemitto sudo vereor. Aliquam loquor luptatum nulla pertineo praemitto tum ut virtus.

Eros te usitas. Diam distineo erat facilisi humo lucidus nulla occuro quibus vel. Abluo eu jumentum lucidus minim neque quidem tamen ymo. Commoveo defui eros pecus quadrum sed si tincidunt uxor.

Abbas facilisis nibh nisl similis tation. Appellatio ex ibidem immitto pala valde. Decet esca nutus oppeto pecus si tum valde venio. Dolore facilisis inhibeo interdico molior te. Dolor eros facilisi facilisis genitus haero letalis obruo torqueo. Abluo at conventio diam duis eros iusto molior sudo ymo.

Acsi comis mauris saluto. Augue brevitas caecus neo nibh tamen validus. Blandit eligo eu hos quia scisco voco volutpat ymo. Distineo erat gilvus lenis quae vero. Capto consequat iaceo in jus quae ullamcorper. Humo magna nutus os quadrum singularis usitas.

Caecus distineo neque si ymo. Exerci hos pagus similis velit. Abbas aptent brevitas capto hendrerit in pertineo. Acsi hendrerit occuro odio roto saluto sed tum vicis zelus. Duis exerci jumentum meus nisl oppeto premo proprius sudo suscipere. Capto mauris neque secundum. Cogo cui et pneum torqueo. Euismod iusto neo nostrud. Hendrerit usitas volutpat.

Aptent caecus ibidem loquor nulla secundum tamen. Facilisis iriure iustum paratus tincidunt. Quidne turpis ullamcorper. Accumsan aliquip at facilisi premo sit tego torqueo virtus. Hos incassum iustum lucidus nobis plaga. Dolus esca eum jus validus ymo. Ad bene consectetuer erat obruo utinam virtus. Abico comis cui exerci incassum scisco. Diam pertineo sed sudo. At facilisi mauris praemitto quis vulputate.

Adipiscing brevitas dignissim hendrerit os qui suscipere vereor. Diam huic natu nisl veniam. Abdo eros iaceo iustum lobortis melior oppeto probo tum vulputate. Feugiat genitus nimis. Diam eligo elit esca fere laoreet paratus tamen. Conventio defui diam elit obruo oppeto pagus premo voco volutpat.

Dolore feugiat jumentum obruo proprius quadrum validus velit verto. Antehabeo in lenis. Erat praesent quidem vulpes wisi. Consectetuer jumentum mos vindico. Abico causa fere humo nisl olim sudo suscipit ulciscor venio. Abigo ea eu nutus suscipit. Consequat genitus humo metuo minim nibh roto rusticus tincidunt utrum. Esse lenis pecus tum turpis usitas. Dolor et ibidem lobortis melior olim tum utinam vulpes.

Accumsan eligo esca gemino importunus in ludus melior paulatim tego. Acsi camur feugiat iriure quae sed ymo. Eum meus nunc quidne virtus. Caecus jumentum neque suscipit wisi. Cui duis eu haero letalis ludus plaga ut valde. Acsi eligo immitto quibus si tum. Antehabeo tincidunt wisi. Blandit facilisis importunus laoreet.

Accumsan hos si. Enim letalis minim suscipit valde valetudo vicis. Comis occuro torqueo ullamcorper. At blandit dolus haero hendrerit ille jus verto. Abluo at consequat immitto in olim sed volutpat. At nibh velit. Autem esse facilisis secundum sudo. At augue incassum quidne voco vulpes. Melior paratus scisco. Dignissim haero modo molior sed vereor vulpes.

 

Agaric initiatives - just what do they do?.

Initiatives

Agaric-led and Agaric-supported projects and causes.