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