github.com/gigforks/mattermost-server@v4.9.1-0.20180619094218-800d97fa55d0+incompatible/model/manifest.go (about) 1 // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package model 5 6 import ( 7 "encoding/json" 8 "io" 9 "io/ioutil" 10 "os" 11 "path/filepath" 12 13 "gopkg.in/yaml.v2" 14 ) 15 16 type PluginOption struct { 17 // The display name for the option. 18 DisplayName string `json:"display_name" yaml:"display_name"` 19 20 // The string value for the option. 21 Value string `json:"value" yaml:"value"` 22 } 23 24 type PluginSetting struct { 25 // The key that the setting will be assigned to in the configuration file. 26 Key string `json:"key" yaml:"key"` 27 28 // The display name for the setting. 29 DisplayName string `json:"display_name" yaml:"display_name"` 30 31 // The type of the setting. 32 // 33 // "bool" will result in a boolean true or false setting. 34 // 35 // "dropdown" will result in a string setting that allows the user to select from a list of 36 // pre-defined options. 37 // 38 // "generated" will result in a string setting that is set to a random, cryptographically secure 39 // string. 40 // 41 // "radio" will result in a string setting that allows the user to select from a short selection 42 // of pre-defined options. 43 // 44 // "text" will result in a string setting that can be typed in manually. 45 // 46 // "username" will result in a text setting that will autocomplete to a username. 47 Type string `json:"type" yaml:"type"` 48 49 // The help text to display to the user. 50 HelpText string `json:"help_text" yaml:"help_text"` 51 52 // The help text to display alongside the "Regenerate" button for settings of the "generated" type. 53 RegenerateHelpText string `json:"regenerate_help_text,omitempty" yaml:"regenerate_help_text,omitempty"` 54 55 // The placeholder to display for "text", "generated" and "username" types when blank. 56 Placeholder string `json:"placeholder" yaml:"placeholder"` 57 58 // The default value of the setting. 59 Default interface{} `json:"default" yaml:"default"` 60 61 // For "radio" or "dropdown" settings, this is the list of pre-defined options that the user can choose 62 // from. 63 Options []*PluginOption `json:"options,omitempty" yaml:"options,omitempty"` 64 } 65 66 type PluginSettingsSchema struct { 67 // Optional text to display above the settings. 68 Header string `json:"header" yaml:"header"` 69 70 // Optional text to display below the settings. 71 Footer string `json:"footer" yaml:"footer"` 72 73 // A list of setting definitions. 74 Settings []*PluginSetting `json:"settings" yaml:"settings"` 75 } 76 77 // The plugin manifest defines the metadata required to load and present your plugin. The manifest 78 // file should be named plugin.json or plugin.yaml and placed in the top of your 79 // plugin bundle. 80 // 81 // Example plugin.yaml: 82 // 83 // id: com.mycompany.myplugin 84 // name: My Plugin 85 // description: This is my plugin. It does stuff. 86 // backend: 87 // executable: myplugin 88 // settings_schema: 89 // settings: 90 // - key: enable_extra_thing 91 // type: bool 92 // display_name: Enable Extra Thing 93 // help_text: When true, an extra thing will be enabled! 94 // default: false 95 type Manifest struct { 96 // The id is a globally unique identifier that represents your plugin. Ids must be at least 97 // 3 characters, at most 190 characters and must match ^[a-zA-Z0-9-_\.]+$. 98 // Reverse-DNS notation using a name you control is a good option, e.g. "com.mycompany.myplugin". 99 Id string `json:"id" yaml:"id"` 100 101 // The name to be displayed for the plugin. 102 Name string `json:"name,omitempty" yaml:"name,omitempty"` 103 104 // A description of what your plugin is and does. 105 Description string `json:"description,omitempty" yaml:"description,omitempty"` 106 107 // A version number for your plugin. Semantic versioning is recommended: http://semver.org 108 Version string `json:"version" yaml:"version"` 109 110 // If your plugin extends the server, you'll need define backend. 111 Backend *ManifestBackend `json:"backend,omitempty" yaml:"backend,omitempty"` 112 113 // If your plugin extends the web app, you'll need to define webapp. 114 Webapp *ManifestWebapp `json:"webapp,omitempty" yaml:"webapp,omitempty"` 115 116 // To allow administrators to configure your plugin via the Mattermost system console, you can 117 // provide your settings schema. 118 SettingsSchema *PluginSettingsSchema `json:"settings_schema,omitempty" yaml:"settings_schema,omitempty"` 119 } 120 121 type ManifestBackend struct { 122 // The path to your executable binary. This should be relative to the root of your bundle and the 123 // location of the manifest file. 124 // 125 // On Windows, this file must have a ".exe" extension. 126 Executable string `json:"executable" yaml:"executable"` 127 } 128 129 type ManifestWebapp struct { 130 // The path to your webapp bundle. This should be relative to the root of your bundle and the 131 // location of the manifest file. 132 BundlePath string `json:"bundle_path" yaml:"bundle_path"` 133 } 134 135 func (m *Manifest) ToJson() string { 136 b, _ := json.Marshal(m) 137 return string(b) 138 } 139 140 func ManifestListToJson(m []*Manifest) string { 141 b, _ := json.Marshal(m) 142 return string(b) 143 } 144 145 func ManifestFromJson(data io.Reader) *Manifest { 146 var m *Manifest 147 json.NewDecoder(data).Decode(&m) 148 return m 149 } 150 151 func ManifestListFromJson(data io.Reader) []*Manifest { 152 var manifests []*Manifest 153 json.NewDecoder(data).Decode(&manifests) 154 return manifests 155 } 156 157 func (m *Manifest) HasClient() bool { 158 return m.Webapp != nil 159 } 160 161 func (m *Manifest) ClientManifest() *Manifest { 162 cm := new(Manifest) 163 *cm = *m 164 cm.Name = "" 165 cm.Description = "" 166 cm.Backend = nil 167 if cm.Webapp != nil { 168 cm.Webapp = new(ManifestWebapp) 169 *cm.Webapp = *m.Webapp 170 cm.Webapp.BundlePath = "/static/" + m.Id + "_bundle.js" 171 } 172 return cm 173 } 174 175 // FindManifest will find and parse the manifest in a given directory. 176 // 177 // In all cases other than a does-not-exist error, path is set to the path of the manifest file that was 178 // found. 179 // 180 // Manifests are JSON or YAML files named plugin.json, plugin.yaml, or plugin.yml. 181 func FindManifest(dir string) (manifest *Manifest, path string, err error) { 182 for _, name := range []string{"plugin.yml", "plugin.yaml"} { 183 path = filepath.Join(dir, name) 184 f, ferr := os.Open(path) 185 if ferr != nil { 186 if !os.IsNotExist(ferr) { 187 err = ferr 188 return 189 } 190 continue 191 } 192 b, ioerr := ioutil.ReadAll(f) 193 f.Close() 194 if ioerr != nil { 195 err = ioerr 196 return 197 } 198 var parsed Manifest 199 err = yaml.Unmarshal(b, &parsed) 200 if err != nil { 201 return 202 } 203 manifest = &parsed 204 return 205 } 206 207 path = filepath.Join(dir, "plugin.json") 208 f, ferr := os.Open(path) 209 if ferr != nil { 210 if os.IsNotExist(ferr) { 211 path = "" 212 } 213 err = ferr 214 return 215 } 216 defer f.Close() 217 var parsed Manifest 218 err = json.NewDecoder(f).Decode(&parsed) 219 if err != nil { 220 return 221 } 222 manifest = &parsed 223 return 224 }