Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce a plugin/extension/module system #7717

Open
1 task done
spaceottercode opened this issue Jun 3, 2018 · 11 comments
Open
1 task done

Introduce a plugin/extension/module system #7717

spaceottercode opened this issue Jun 3, 2018 · 11 comments
Labels
suggestion Feature suggestion

Comments

@spaceottercode
Copy link

spaceottercode commented Jun 3, 2018

Introduce a mechanism that allows admins the ability to load and execute custom code/scripts. I'm impartial whether this is accomplished via the introduction of an API, hookscripts, or some other mechanism, whether they can load at runtime, whether they encompass the backend and frontend only or both.

I believe this could prove beneficial to admins wanting to alter Mastodon sometimes in minor ways.
admins correct me if I'm wrong.

The new system need not cover all such alterations of course. Any subset would be welcome. One advantage is keeping custom code and alterations neatly separate and ideally independent. Potentially making updates easier.

please note, this does not have to be an all or nothing. That is to say, dismissing the inclusion of the system because all of its component or goals cannot be met. Any useful subset is welcomed.

I can only offer perhaps not the best example so take these as a flake on the tip of the iceberg (hopefully admins can offer better examples). (examples are frontend ones). Say I want my instance to support markdown (let's put aside whether this is a bad idea or not) I could fork the code, write a whole new front end, or write a user script or web extension. Instead I could load a module. A slightly more ambitious module is one whose installation script modifies the db (always make a backup) to add support for, say, (non federated?) polls. these are probably not the best examples, but I'm sure you can imagine more potent ones.

A bazaar of plugins could arise (and the same could probably be said of instances but there might be some convergence). the trust worthiness of modules as with all applications is one that lies outside this scope. fragmentation concerns should be no different from those of forking. I understand this is likely a big undertaking.


  • I searched or browsed the repo’s other issues to ensure this is not a duplicate.
@spaceottercode
Copy link
Author

spaceottercode commented Jun 3, 2018

other petty (probably poor) examples (once again frontend-ish; not that backend ones could not exist). module that rainbow-izes certain tags on June, migrate core code responsible for disallowing specific tags into its own module, a module that adds support for emojitags. I admit, not good ones but I thought laying out more examples no matter how petty could help expand the above.

@selfagency
Copy link

as an instance admin, this is something i've been thinking about a lot as well. it would be wonderful if there were a way for admins to extend their mastodon instances through a plugin architecture instead of having to mess with the core.

@gdpelican
Copy link
Contributor

I'm very interested in this, perhaps as a project once I can get my feet wet a little bit. There's a couple of other great examples of plugin systems on Ruby in Loomio and Discourse, which have examples of plugging in components on the frontend in Angular and Ember, respectively, but I know React has some decent transclusion-style libraries that could be used for this as well.

@Gargron Gargron added the suggestion Feature suggestion label Oct 20, 2018
@Angular-Angel
Copy link

Mmm, I think a plug in system could be really useful. It'd mean that many existing features could be moved to plug-ins, for people who don't appreciate them, and thereby cut down on the forking necessary. Searching toots by text, for example. :/

@gdpelican
Copy link
Contributor

I'm working on an initial implementation of this at the moment, which is going pretty well. Here's the initial stab at an API, which I've tried to keep as minimal as possible to start:

module Mastodon
  module Plugins
    class Example < Mastodon::Plugin
      def setup!
       # putting a js or scss file in (plugin)/assets will cause it to be added to webpacker, for example I have a file (plugin)/assets/example-component.js that looks like this:
       # import React from 'react';
       # class Example extends React.PureComponent {
       #   render () {
       #     return <div className='example'>Hello world!</div>;
       #   }
       # }

       # putting an rb file in (plugin)/app will cause it to be run on app boot, for example I have a file (plugin)/app/controllers/examples_controller that looks like this:
       # class ExamplesController < ApplicationController
       #   def show
       #      render json: { message: "Hello world!" }
       #   end
       # end

       # putting yml files in (plugin)/locales will allow them to add new or override existing translations in the app

        # add an api route /api/v1/example_plugin which calls the ExamplesController#show method
        use_route(:get, "example_plugin", "examples#show")

        # find a component like this: <Outlet name='below-header' />
        # and render a component like this into it: <Example name=name />
        use_outlet("below-header", "Example", name: 'name')

        # override the functionality of an existing class using class_eval
        extend_class("Status") do
          def self.say_hello!
            "hello from Status!"
          end
        end

       # Add a database table called 'examples', which can accept anything you could pass to a create_table in a migration
       # I'm currently pretty vehemently against adding the ability to modify existing tables.
        use_database_table(:examples) do |t|
          t.string :title
          t.timestamps
        end
      end
    end
  end
end

Some major use cases this covers:

  • Adding components to the interface (anywhere we'd be willing to put an element)
  • Overriding existing or adding new translations and styles
  • Adding new endpoints to the API
  • Overriding or modifying existing backend logic
  • Storing proprietary data in the database

Some use cases this might not cover yet

  • Adding or overriding existing view code
  • Overriding or modifying existing frontend logic (Ember has reopen functionality, which React can maybe replicate but I'm not sure yet)
  • Changing email templates (but you can override translations so that's a good start)

I'll update as I get a bit closer to having something to show, and would be open to feedback now on the API; what else should it be able to do? :)

@jfrederickson
Copy link

I don't have a whole lot to add to this, but I feel like a plugin system could help ease some of the tension between groups that disagree with some decisions made in core Mastodon. The barrier to maintaining a Mastodon fork is potentially pretty high, while the barrier to maintaining a plugin would likely be much lower. (And instance admins can only really choose one fork to run.)

Which is to say: when solidifying the API, it might be worthwhile to look at where there's been disagreement in the community and ensure the plugin API is capable of covering those use cases.

@stale
Copy link

stale bot commented Oct 26, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the status/wontfix This will not be worked on label Oct 26, 2019
@jpgochile
Copy link

I'm working on an initial implementation of this at the moment, which is going pretty well. Here's the initial stab at an API, which I've tried to keep as minimal as possible to start:

module Mastodon
  module Plugins
    class Example < Mastodon::Plugin
      def setup!
       # putting a js or scss file in (plugin)/assets will cause it to be added to webpacker, for example I have a file (plugin)/assets/example-component.js that looks like this:
       # import React from 'react';
       # class Example extends React.PureComponent {
       #   render () {
       #     return <div className='example'>Hello world!</div>;
       #   }
       # }

       # putting an rb file in (plugin)/app will cause it to be run on app boot, for example I have a file (plugin)/app/controllers/examples_controller that looks like this:
       # class ExamplesController < ApplicationController
       #   def show
       #      render json: { message: "Hello world!" }
       #   end
       # end

       # putting yml files in (plugin)/locales will allow them to add new or override existing translations in the app

        # add an api route /api/v1/example_plugin which calls the ExamplesController#show method
        use_route(:get, "example_plugin", "examples#show")

        # find a component like this: <Outlet name='below-header' />
        # and render a component like this into it: <Example name=name />
        use_outlet("below-header", "Example", name: 'name')

        # override the functionality of an existing class using class_eval
        extend_class("Status") do
          def self.say_hello!
            "hello from Status!"
          end
        end

       # Add a database table called 'examples', which can accept anything you could pass to a create_table in a migration
       # I'm currently pretty vehemently against adding the ability to modify existing tables.
        use_database_table(:examples) do |t|
          t.string :title
          t.timestamps
        end
      end
    end
  end
end

Some major use cases this covers:

* Adding components to the interface (anywhere we'd be willing to put an  element)

* Overriding existing or adding new translations and styles

* Adding new endpoints to the API

* Overriding or modifying existing backend logic

* Storing proprietary data in the database

Some use cases this might not cover yet

* Adding or overriding existing view code

* Overriding or modifying existing frontend logic (Ember has `reopen` functionality, which React can maybe replicate but I'm not sure yet)

* Changing email templates (but you _can_ override translations so that's a good start)

I'll update as I get a bit closer to having something to show, and would be open to feedback now on the API; what else should it be able to do? :)

Hi, any status please...I want to add an independent frame to main GUI for certain information and your project sound like great.

thanks...
Juan

@stale stale bot removed the status/wontfix This will not be worked on label Dec 18, 2019
@ryliejamesthomas
Copy link

I'd especially love this to be implemented in a way we can install plug-ins from the admin panel, so admins using places like Masto Host could install stuff too.

@artifex404
Copy link

The ability to extend Mastodon via plugins would add huge potential for the project. I think we can mimic a lot from WordPress, no need to invent the wheel again. The plugin should be able to extend the front-end React but also the back-end.

@jpgochile, Did you get anywhere with your implementation?

@davidwolfpaw
Copy link

I want to keep this issue fresh. A plugin/extension/module system would be highly useful. I can think of a dozen little things that I'd like to do but don't want to maintain a separate codebase for.

A lot of complaints around Mastodon features are lack of options for instance admins. I think that the only way for the platform to really grow is to allow more customization. By growth I don't just mean user count or instance count, but in directions that the platform can go. Making a system where instance admins don't have to edit core to make customizations to their instances will open us up to new ways to do things, and ideas that can't all be created top-down.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
suggestion Feature suggestion
Projects
None yet
Development

No branches or pull requests

10 participants