Moved the plugin manager to the routes package.
Added many, many tests for the plugin system. Refactored some of the plugin system queries. Fixed a bug where prepared statements would build up and crash Gosora. Removed the inline CSS from the plugin rows.
This commit is contained in:
parent
d74a221467
commit
50d5be6f32
|
@ -8,14 +8,18 @@ package common
|
|||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"../query_gen/lib"
|
||||
)
|
||||
|
||||
var ErrPluginNotInstallable = errors.New("This plugin is not installable")
|
||||
|
||||
type PluginList map[string]*Plugin
|
||||
|
||||
// TODO: Have a proper store rather than a map?
|
||||
var Plugins PluginList = make(map[string]*Plugin)
|
||||
|
||||
// Hooks with a single argument. Is this redundant? Might be useful for inlining, as variadics aren't inlined? Are closures even inlined to begin with?
|
||||
|
@ -152,7 +156,7 @@ type Plugin struct {
|
|||
|
||||
Init func() error
|
||||
Activate func() error
|
||||
Deactivate func()
|
||||
Deactivate func() // TODO: We might want to let this return an error?
|
||||
Install func() error
|
||||
Uninstall func() error
|
||||
|
||||
|
@ -160,8 +164,60 @@ type Plugin struct {
|
|||
Data interface{} // Usually used for hosting the VMs / reusable elements of non-native plugins
|
||||
}
|
||||
|
||||
func (plugin *Plugin) BypassActive() (active bool, err error) {
|
||||
err = extendStmts.isActive.QueryRow(plugin.UName).Scan(&active)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return false, err
|
||||
}
|
||||
return active, nil
|
||||
}
|
||||
|
||||
func (plugin *Plugin) InDatabase() (exists bool, err error) {
|
||||
var sink bool
|
||||
err = extendStmts.isActive.QueryRow(plugin.UName).Scan(&sink)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return false, err
|
||||
}
|
||||
return err == nil, nil
|
||||
}
|
||||
|
||||
// TODO: Silently add to the database, if it doesn't exist there rather than forcing users to call AddToDatabase instead?
|
||||
func (plugin *Plugin) SetActive(active bool) (err error) {
|
||||
_, err = extendStmts.setActive.Exec(active, plugin.UName)
|
||||
if err == nil {
|
||||
plugin.Active = active
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: Silently add to the database, if it doesn't exist there rather than forcing users to call AddToDatabase instead?
|
||||
func (plugin *Plugin) SetInstalled(installed bool) (err error) {
|
||||
if !plugin.Installable {
|
||||
return ErrPluginNotInstallable
|
||||
}
|
||||
_, err = extendStmts.setInstalled.Exec(installed, plugin.UName)
|
||||
if err == nil {
|
||||
plugin.Installed = installed
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (plugin *Plugin) AddToDatabase(active bool, installed bool) (err error) {
|
||||
_, err = extendStmts.add.Exec(plugin.UName, active, installed)
|
||||
if err == nil {
|
||||
plugin.Active = active
|
||||
plugin.Installed = installed
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type ExtendStmts struct {
|
||||
getPlugins *sql.Stmt
|
||||
|
||||
isActive *sql.Stmt
|
||||
setActive *sql.Stmt
|
||||
setInstalled *sql.Stmt
|
||||
add *sql.Stmt
|
||||
}
|
||||
|
||||
var extendStmts ExtendStmts
|
||||
|
@ -170,6 +226,11 @@ func init() {
|
|||
DbInits.Add(func(acc *qgen.Accumulator) error {
|
||||
extendStmts = ExtendStmts{
|
||||
getPlugins: acc.Select("plugins").Columns("uname, active, installed").Prepare(),
|
||||
|
||||
isActive: acc.Select("plugins").Columns("active").Where("uname = ?").Prepare(),
|
||||
setActive: acc.Update("plugins").Set("active = ?").Where("uname = ?").Prepare(),
|
||||
setInstalled: acc.Update("plugins").Set("installed = ?").Where("uname = ?").Prepare(),
|
||||
add: acc.Insert("plugins").Columns("uname, active, installed").Fields("?,?,?").Prepare(),
|
||||
}
|
||||
return acc.FirstError()
|
||||
})
|
||||
|
|
36
gen_mssql.go
36
gen_mssql.go
|
@ -9,17 +9,13 @@ import "./common"
|
|||
|
||||
// nolint
|
||||
type Stmts struct {
|
||||
isPluginActive *sql.Stmt
|
||||
isThemeDefault *sql.Stmt
|
||||
forumEntryExists *sql.Stmt
|
||||
groupEntryExists *sql.Stmt
|
||||
getForumTopics *sql.Stmt
|
||||
addForumPermsToForum *sql.Stmt
|
||||
addPlugin *sql.Stmt
|
||||
addTheme *sql.Stmt
|
||||
createWordFilter *sql.Stmt
|
||||
updatePlugin *sql.Stmt
|
||||
updatePluginInstall *sql.Stmt
|
||||
updateTheme *sql.Stmt
|
||||
updateGroupPerms *sql.Stmt
|
||||
updateGroup *sql.Stmt
|
||||
|
@ -44,14 +40,6 @@ type Stmts struct {
|
|||
func _gen_mssql() (err error) {
|
||||
common.DebugLog("Building the generated statements")
|
||||
|
||||
common.DebugLog("Preparing isPluginActive statement.")
|
||||
stmts.isPluginActive, err = db.Prepare("SELECT [active] FROM [plugins] WHERE [uname] = ?1")
|
||||
if err != nil {
|
||||
log.Print("Error in isPluginActive statement.")
|
||||
log.Print("Bad Query: ","SELECT [active] FROM [plugins] WHERE [uname] = ?1")
|
||||
return err
|
||||
}
|
||||
|
||||
common.DebugLog("Preparing isThemeDefault statement.")
|
||||
stmts.isThemeDefault, err = db.Prepare("SELECT [default] FROM [themes] WHERE [uname] = ?1")
|
||||
if err != nil {
|
||||
|
@ -92,14 +80,6 @@ func _gen_mssql() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
common.DebugLog("Preparing addPlugin statement.")
|
||||
stmts.addPlugin, err = db.Prepare("INSERT INTO [plugins] ([uname],[active],[installed]) VALUES (?,?,?)")
|
||||
if err != nil {
|
||||
log.Print("Error in addPlugin statement.")
|
||||
log.Print("Bad Query: ","INSERT INTO [plugins] ([uname],[active],[installed]) VALUES (?,?,?)")
|
||||
return err
|
||||
}
|
||||
|
||||
common.DebugLog("Preparing addTheme statement.")
|
||||
stmts.addTheme, err = db.Prepare("INSERT INTO [themes] ([uname],[default]) VALUES (?,?)")
|
||||
if err != nil {
|
||||
|
@ -116,22 +96,6 @@ func _gen_mssql() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
common.DebugLog("Preparing updatePlugin statement.")
|
||||
stmts.updatePlugin, err = db.Prepare("UPDATE [plugins] SET [active] = ? WHERE [uname] = ?")
|
||||
if err != nil {
|
||||
log.Print("Error in updatePlugin statement.")
|
||||
log.Print("Bad Query: ","UPDATE [plugins] SET [active] = ? WHERE [uname] = ?")
|
||||
return err
|
||||
}
|
||||
|
||||
common.DebugLog("Preparing updatePluginInstall statement.")
|
||||
stmts.updatePluginInstall, err = db.Prepare("UPDATE [plugins] SET [installed] = ? WHERE [uname] = ?")
|
||||
if err != nil {
|
||||
log.Print("Error in updatePluginInstall statement.")
|
||||
log.Print("Bad Query: ","UPDATE [plugins] SET [installed] = ? WHERE [uname] = ?")
|
||||
return err
|
||||
}
|
||||
|
||||
common.DebugLog("Preparing updateTheme statement.")
|
||||
stmts.updateTheme, err = db.Prepare("UPDATE [themes] SET [default] = ? WHERE [uname] = ?")
|
||||
if err != nil {
|
||||
|
|
32
gen_mysql.go
32
gen_mysql.go
|
@ -11,17 +11,13 @@ import "./common"
|
|||
|
||||
// nolint
|
||||
type Stmts struct {
|
||||
isPluginActive *sql.Stmt
|
||||
isThemeDefault *sql.Stmt
|
||||
forumEntryExists *sql.Stmt
|
||||
groupEntryExists *sql.Stmt
|
||||
getForumTopics *sql.Stmt
|
||||
addForumPermsToForum *sql.Stmt
|
||||
addPlugin *sql.Stmt
|
||||
addTheme *sql.Stmt
|
||||
createWordFilter *sql.Stmt
|
||||
updatePlugin *sql.Stmt
|
||||
updatePluginInstall *sql.Stmt
|
||||
updateTheme *sql.Stmt
|
||||
updateGroupPerms *sql.Stmt
|
||||
updateGroup *sql.Stmt
|
||||
|
@ -46,13 +42,6 @@ type Stmts struct {
|
|||
func _gen_mysql() (err error) {
|
||||
common.DebugLog("Building the generated statements")
|
||||
|
||||
common.DebugLog("Preparing isPluginActive statement.")
|
||||
stmts.isPluginActive, err = db.Prepare("SELECT `active` FROM `plugins` WHERE `uname` = ?")
|
||||
if err != nil {
|
||||
log.Print("Error in isPluginActive statement.")
|
||||
return err
|
||||
}
|
||||
|
||||
common.DebugLog("Preparing isThemeDefault statement.")
|
||||
stmts.isThemeDefault, err = db.Prepare("SELECT `default` FROM `themes` WHERE `uname` = ?")
|
||||
if err != nil {
|
||||
|
@ -88,13 +77,6 @@ func _gen_mysql() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
common.DebugLog("Preparing addPlugin statement.")
|
||||
stmts.addPlugin, err = db.Prepare("INSERT INTO `plugins`(`uname`,`active`,`installed`) VALUES (?,?,?)")
|
||||
if err != nil {
|
||||
log.Print("Error in addPlugin statement.")
|
||||
return err
|
||||
}
|
||||
|
||||
common.DebugLog("Preparing addTheme statement.")
|
||||
stmts.addTheme, err = db.Prepare("INSERT INTO `themes`(`uname`,`default`) VALUES (?,?)")
|
||||
if err != nil {
|
||||
|
@ -109,20 +91,6 @@ func _gen_mysql() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
common.DebugLog("Preparing updatePlugin statement.")
|
||||
stmts.updatePlugin, err = db.Prepare("UPDATE `plugins` SET `active` = ? WHERE `uname` = ?")
|
||||
if err != nil {
|
||||
log.Print("Error in updatePlugin statement.")
|
||||
return err
|
||||
}
|
||||
|
||||
common.DebugLog("Preparing updatePluginInstall statement.")
|
||||
stmts.updatePluginInstall, err = db.Prepare("UPDATE `plugins` SET `installed` = ? WHERE `uname` = ?")
|
||||
if err != nil {
|
||||
log.Print("Error in updatePluginInstall statement.")
|
||||
return err
|
||||
}
|
||||
|
||||
common.DebugLog("Preparing updateTheme statement.")
|
||||
stmts.updateTheme, err = db.Prepare("UPDATE `themes` SET `default` = ? WHERE `uname` = ?")
|
||||
if err != nil {
|
||||
|
|
24
gen_pgsql.go
24
gen_pgsql.go
|
@ -10,11 +10,8 @@ import "./common"
|
|||
// nolint
|
||||
type Stmts struct {
|
||||
addForumPermsToForum *sql.Stmt
|
||||
addPlugin *sql.Stmt
|
||||
addTheme *sql.Stmt
|
||||
createWordFilter *sql.Stmt
|
||||
updatePlugin *sql.Stmt
|
||||
updatePluginInstall *sql.Stmt
|
||||
updateTheme *sql.Stmt
|
||||
updateGroupPerms *sql.Stmt
|
||||
updateGroup *sql.Stmt
|
||||
|
@ -44,13 +41,6 @@ func _gen_pgsql() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
common.DebugLog("Preparing addPlugin statement.")
|
||||
stmts.addPlugin, err = db.Prepare("INSERT INTO "plugins"("uname","active","installed") VALUES (?,?,?)")
|
||||
if err != nil {
|
||||
log.Print("Error in addPlugin statement.")
|
||||
return err
|
||||
}
|
||||
|
||||
common.DebugLog("Preparing addTheme statement.")
|
||||
stmts.addTheme, err = db.Prepare("INSERT INTO "themes"("uname","default") VALUES (?,?)")
|
||||
if err != nil {
|
||||
|
@ -65,20 +55,6 @@ func _gen_pgsql() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
common.DebugLog("Preparing updatePlugin statement.")
|
||||
stmts.updatePlugin, err = db.Prepare("UPDATE `plugins` SET `active` = ? WHERE `uname` = ?")
|
||||
if err != nil {
|
||||
log.Print("Error in updatePlugin statement.")
|
||||
return err
|
||||
}
|
||||
|
||||
common.DebugLog("Preparing updatePluginInstall statement.")
|
||||
stmts.updatePluginInstall, err = db.Prepare("UPDATE `plugins` SET `installed` = ? WHERE `uname` = ?")
|
||||
if err != nil {
|
||||
log.Print("Error in updatePluginInstall statement.")
|
||||
return err
|
||||
}
|
||||
|
||||
common.DebugLog("Preparing updateTheme statement.")
|
||||
stmts.updateTheme, err = db.Prepare("UPDATE `themes` SET `default` = ? WHERE `uname` = ?")
|
||||
if err != nil {
|
||||
|
|
|
@ -65,10 +65,10 @@ var RouteMap = map[string]interface{}{
|
|||
"routePanelThemesMenuItemCreateSubmit": routePanelThemesMenuItemCreateSubmit,
|
||||
"routePanelThemesMenuItemDeleteSubmit": routePanelThemesMenuItemDeleteSubmit,
|
||||
"routePanelThemesMenuItemOrderSubmit": routePanelThemesMenuItemOrderSubmit,
|
||||
"routePanelPlugins": routePanelPlugins,
|
||||
"routePanelPluginsActivate": routePanelPluginsActivate,
|
||||
"routePanelPluginsDeactivate": routePanelPluginsDeactivate,
|
||||
"routePanelPluginsInstall": routePanelPluginsInstall,
|
||||
"panel.Plugins": panel.Plugins,
|
||||
"panel.PluginsActivate": panel.PluginsActivate,
|
||||
"panel.PluginsDeactivate": panel.PluginsDeactivate,
|
||||
"panel.PluginsInstall": panel.PluginsInstall,
|
||||
"panel.Users": panel.Users,
|
||||
"panel.UsersEdit": panel.UsersEdit,
|
||||
"panel.UsersEditSubmit": panel.UsersEditSubmit,
|
||||
|
@ -194,10 +194,10 @@ var routeMapEnum = map[string]int{
|
|||
"routePanelThemesMenuItemCreateSubmit": 41,
|
||||
"routePanelThemesMenuItemDeleteSubmit": 42,
|
||||
"routePanelThemesMenuItemOrderSubmit": 43,
|
||||
"routePanelPlugins": 44,
|
||||
"routePanelPluginsActivate": 45,
|
||||
"routePanelPluginsDeactivate": 46,
|
||||
"routePanelPluginsInstall": 47,
|
||||
"panel.Plugins": 44,
|
||||
"panel.PluginsActivate": 45,
|
||||
"panel.PluginsDeactivate": 46,
|
||||
"panel.PluginsInstall": 47,
|
||||
"panel.Users": 48,
|
||||
"panel.UsersEdit": 49,
|
||||
"panel.UsersEditSubmit": 50,
|
||||
|
@ -321,10 +321,10 @@ var reverseRouteMapEnum = map[int]string{
|
|||
41: "routePanelThemesMenuItemCreateSubmit",
|
||||
42: "routePanelThemesMenuItemDeleteSubmit",
|
||||
43: "routePanelThemesMenuItemOrderSubmit",
|
||||
44: "routePanelPlugins",
|
||||
45: "routePanelPluginsActivate",
|
||||
46: "routePanelPluginsDeactivate",
|
||||
47: "routePanelPluginsInstall",
|
||||
44: "panel.Plugins",
|
||||
45: "panel.PluginsActivate",
|
||||
46: "panel.PluginsDeactivate",
|
||||
47: "panel.PluginsInstall",
|
||||
48: "panel.Users",
|
||||
49: "panel.UsersEdit",
|
||||
50: "panel.UsersEditSubmit",
|
||||
|
@ -1223,7 +1223,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
err = routePanelThemesMenuItemOrderSubmit(w,req,user,extraData)
|
||||
case "/panel/plugins/":
|
||||
counters.RouteViewCounter.Bump(44)
|
||||
err = routePanelPlugins(w,req,user)
|
||||
err = panel.Plugins(w,req,user)
|
||||
case "/panel/plugins/activate/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
if err != nil {
|
||||
|
@ -1232,7 +1232,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
}
|
||||
|
||||
counters.RouteViewCounter.Bump(45)
|
||||
err = routePanelPluginsActivate(w,req,user,extraData)
|
||||
err = panel.PluginsActivate(w,req,user,extraData)
|
||||
case "/panel/plugins/deactivate/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
if err != nil {
|
||||
|
@ -1241,7 +1241,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
}
|
||||
|
||||
counters.RouteViewCounter.Bump(46)
|
||||
err = routePanelPluginsDeactivate(w,req,user,extraData)
|
||||
err = panel.PluginsDeactivate(w,req,user,extraData)
|
||||
case "/panel/plugins/install/":
|
||||
err = common.NoSessionMismatch(w,req,user)
|
||||
if err != nil {
|
||||
|
@ -1250,7 +1250,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
}
|
||||
|
||||
counters.RouteViewCounter.Bump(47)
|
||||
err = routePanelPluginsInstall(w,req,user,extraData)
|
||||
err = panel.PluginsInstall(w,req,user,extraData)
|
||||
case "/panel/users/":
|
||||
counters.RouteViewCounter.Bump(48)
|
||||
err = panel.Users(w,req,user)
|
||||
|
|
108
misc_test.go
108
misc_test.go
|
@ -828,6 +828,114 @@ func TestProfileReplyStore(t *testing.T) {
|
|||
// TODO: Test profileReply.SetBody() and profileReply.Creator()
|
||||
}
|
||||
|
||||
func TestPluginManager(t *testing.T) {
|
||||
if !gloinited {
|
||||
gloinit()
|
||||
}
|
||||
if !common.PluginsInited {
|
||||
common.InitPlugins()
|
||||
}
|
||||
|
||||
_, ok := common.Plugins["fairy-dust"]
|
||||
expect(t, !ok, "Plugin fairy-dust shouldn't exist")
|
||||
plugin, ok := common.Plugins["bbcode"]
|
||||
expect(t, ok, "Plugin bbcode should exist")
|
||||
expect(t, !plugin.Installable, "Plugin bbcode shouldn't be installable")
|
||||
expect(t, !plugin.Installed, "Plugin bbcode shouldn't be 'installed'")
|
||||
expect(t, !plugin.Active, "Plugin bbcode shouldn't be active")
|
||||
active, err := plugin.BypassActive()
|
||||
expectNilErr(t, err)
|
||||
expect(t, !active, "Plugin bbcode shouldn't be active in the database either")
|
||||
hasPlugin, err := plugin.InDatabase()
|
||||
expectNilErr(t, err)
|
||||
expect(t, !hasPlugin, "Plugin bbcode shouldn't exist in the database")
|
||||
// TODO: Add some test cases for SetActive and SetInstalled before calling AddToDatabase
|
||||
|
||||
expectNilErr(t, plugin.AddToDatabase(true, false))
|
||||
expect(t, !plugin.Installable, "Plugin bbcode shouldn't be installable")
|
||||
expect(t, !plugin.Installed, "Plugin bbcode shouldn't be 'installed'")
|
||||
expect(t, plugin.Active, "Plugin bbcode should be active")
|
||||
active, err = plugin.BypassActive()
|
||||
expectNilErr(t, err)
|
||||
expect(t, active, "Plugin bbcode should be active in the database too")
|
||||
hasPlugin, err = plugin.InDatabase()
|
||||
expectNilErr(t, err)
|
||||
expect(t, hasPlugin, "Plugin bbcode should exist in the database")
|
||||
expect(t, plugin.Init != nil, "Plugin bbcode should have an init function")
|
||||
expectNilErr(t, plugin.Init())
|
||||
|
||||
expectNilErr(t, plugin.SetActive(true))
|
||||
expect(t, !plugin.Installable, "Plugin bbcode shouldn't be installable")
|
||||
expect(t, !plugin.Installed, "Plugin bbcode shouldn't be 'installed'")
|
||||
expect(t, plugin.Active, "Plugin bbcode should still be active")
|
||||
active, err = plugin.BypassActive()
|
||||
expectNilErr(t, err)
|
||||
expect(t, active, "Plugin bbcode should still be active in the database too")
|
||||
hasPlugin, err = plugin.InDatabase()
|
||||
expectNilErr(t, err)
|
||||
expect(t, hasPlugin, "Plugin bbcode should still exist in the database")
|
||||
|
||||
expectNilErr(t, plugin.SetActive(false))
|
||||
expect(t, !plugin.Installable, "Plugin bbcode shouldn't be installable")
|
||||
expect(t, !plugin.Installed, "Plugin bbcode shouldn't be 'installed'")
|
||||
expect(t, !plugin.Active, "Plugin bbcode shouldn't be active")
|
||||
active, err = plugin.BypassActive()
|
||||
expectNilErr(t, err)
|
||||
expect(t, !active, "Plugin bbcode shouldn't be active in the database")
|
||||
hasPlugin, err = plugin.InDatabase()
|
||||
expectNilErr(t, err)
|
||||
expect(t, hasPlugin, "Plugin bbcode should still exist in the database")
|
||||
expect(t, plugin.Deactivate != nil, "Plugin bbcode should have an init function")
|
||||
plugin.Deactivate() // Returns nothing
|
||||
|
||||
// Not installable, should not be mutated
|
||||
expect(t, plugin.SetInstalled(true) == common.ErrPluginNotInstallable, "Plugin was set as installed despite not being installable")
|
||||
expect(t, !plugin.Installable, "Plugin bbcode shouldn't be installable")
|
||||
expect(t, !plugin.Installed, "Plugin bbcode shouldn't be 'installed'")
|
||||
expect(t, !plugin.Active, "Plugin bbcode shouldn't be active")
|
||||
active, err = plugin.BypassActive()
|
||||
expectNilErr(t, err)
|
||||
expect(t, !active, "Plugin bbcode shouldn't be active in the database either")
|
||||
hasPlugin, err = plugin.InDatabase()
|
||||
expectNilErr(t, err)
|
||||
expect(t, hasPlugin, "Plugin bbcode should still exist in the database")
|
||||
|
||||
expect(t, plugin.SetInstalled(false) == common.ErrPluginNotInstallable, "Plugin was set as not installed despite not being installable")
|
||||
expect(t, !plugin.Installable, "Plugin bbcode shouldn't be installable")
|
||||
expect(t, !plugin.Installed, "Plugin bbcode shouldn't be 'installed'")
|
||||
expect(t, !plugin.Active, "Plugin bbcode shouldn't be active")
|
||||
active, err = plugin.BypassActive()
|
||||
expectNilErr(t, err)
|
||||
expect(t, !active, "Plugin bbcode shouldn't be active in the database either")
|
||||
hasPlugin, err = plugin.InDatabase()
|
||||
expectNilErr(t, err)
|
||||
expect(t, hasPlugin, "Plugin bbcode should still exist in the database")
|
||||
|
||||
// This isn't really installable, but we want to get a few tests done before getting plugins which are stateful
|
||||
plugin.Installable = true
|
||||
expectNilErr(t, plugin.SetInstalled(true))
|
||||
expect(t, plugin.Installable, "Plugin bbcode should be installable")
|
||||
expect(t, plugin.Installed, "Plugin bbcode should be 'installed'")
|
||||
expect(t, !plugin.Active, "Plugin bbcode shouldn't be active")
|
||||
active, err = plugin.BypassActive()
|
||||
expectNilErr(t, err)
|
||||
expect(t, !active, "Plugin bbcode shouldn't be active in the database either")
|
||||
hasPlugin, err = plugin.InDatabase()
|
||||
expectNilErr(t, err)
|
||||
expect(t, hasPlugin, "Plugin bbcode should still exist in the database")
|
||||
|
||||
expectNilErr(t, plugin.SetInstalled(false))
|
||||
expect(t, plugin.Installable, "Plugin bbcode should be installable")
|
||||
expect(t, !plugin.Installed, "Plugin bbcode shouldn't be 'installed'")
|
||||
expect(t, !plugin.Active, "Plugin bbcode shouldn't be active")
|
||||
active, err = plugin.BypassActive()
|
||||
expectNilErr(t, err)
|
||||
expect(t, !active, "Plugin bbcode shouldn't be active in the database either")
|
||||
hasPlugin, err = plugin.InDatabase()
|
||||
expectNilErr(t, err)
|
||||
expect(t, hasPlugin, "Plugin bbcode should still exist in the database")
|
||||
}
|
||||
|
||||
func TestSlugs(t *testing.T) {
|
||||
var res string
|
||||
var msgList []MEPair
|
||||
|
|
179
panel_routes.go
179
panel_routes.go
|
@ -300,185 +300,6 @@ func routePanelWordFiltersDeleteSubmit(w http.ResponseWriter, r *http.Request, u
|
|||
return nil
|
||||
}
|
||||
|
||||
func routePanelPlugins(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||
header, stats, ferr := common.PanelUserCheck(w, r, &user)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManagePlugins {
|
||||
return common.NoPermissions(w, r, user)
|
||||
}
|
||||
header.Title = common.GetTitlePhrase("panel_plugins")
|
||||
|
||||
var pluginList []interface{}
|
||||
for _, plugin := range common.Plugins {
|
||||
pluginList = append(pluginList, plugin)
|
||||
}
|
||||
|
||||
pi := common.PanelPage{&common.BasePanelPage{header, stats, "plugins", common.ReportForumID}, pluginList, nil}
|
||||
return panelRenderTemplate("panel_plugins", w, r, user, &pi)
|
||||
}
|
||||
|
||||
func routePanelPluginsActivate(w http.ResponseWriter, r *http.Request, user common.User, uname string) common.RouteError {
|
||||
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManagePlugins {
|
||||
return common.NoPermissions(w, r, user)
|
||||
}
|
||||
|
||||
plugin, ok := common.Plugins[uname]
|
||||
if !ok {
|
||||
return common.LocalError("The plugin isn't registered in the system", w, r, user)
|
||||
}
|
||||
if plugin.Installable && !plugin.Installed {
|
||||
return common.LocalError("You can't activate this plugin without installing it first", w, r, user)
|
||||
}
|
||||
|
||||
var active bool
|
||||
err := stmts.isPluginActive.QueryRow(uname).Scan(&active)
|
||||
if err != nil && err != ErrNoRows {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
var hasPlugin = (err == nil)
|
||||
|
||||
if common.Plugins[uname].Activate != nil {
|
||||
err = common.Plugins[uname].Activate()
|
||||
if err != nil {
|
||||
return common.LocalError(err.Error(), w, r, user)
|
||||
}
|
||||
}
|
||||
|
||||
if hasPlugin {
|
||||
if active {
|
||||
return common.LocalError("The plugin is already active", w, r, user)
|
||||
}
|
||||
_, err = stmts.updatePlugin.Exec(1, uname)
|
||||
} else {
|
||||
_, err = stmts.addPlugin.Exec(uname, 1, 0)
|
||||
}
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
log.Printf("Activating plugin '%s'", plugin.Name)
|
||||
plugin.Active = true
|
||||
common.Plugins[uname] = plugin
|
||||
err = common.Plugins[uname].Init()
|
||||
if err != nil {
|
||||
return common.LocalError(err.Error(), w, r, user)
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/panel/plugins/", http.StatusSeeOther)
|
||||
return nil
|
||||
}
|
||||
|
||||
func routePanelPluginsDeactivate(w http.ResponseWriter, r *http.Request, user common.User, uname string) common.RouteError {
|
||||
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManagePlugins {
|
||||
return common.NoPermissions(w, r, user)
|
||||
}
|
||||
|
||||
plugin, ok := common.Plugins[uname]
|
||||
if !ok {
|
||||
return common.LocalError("The plugin isn't registered in the system", w, r, user)
|
||||
}
|
||||
|
||||
var active bool
|
||||
err := stmts.isPluginActive.QueryRow(uname).Scan(&active)
|
||||
if err == ErrNoRows {
|
||||
return common.LocalError("The plugin you're trying to deactivate isn't active", w, r, user)
|
||||
} else if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
if !active {
|
||||
return common.LocalError("The plugin you're trying to deactivate isn't active", w, r, user)
|
||||
}
|
||||
_, err = stmts.updatePlugin.Exec(0, uname)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
plugin.Active = false
|
||||
common.Plugins[uname] = plugin
|
||||
common.Plugins[uname].Deactivate()
|
||||
|
||||
http.Redirect(w, r, "/panel/plugins/", http.StatusSeeOther)
|
||||
return nil
|
||||
}
|
||||
|
||||
func routePanelPluginsInstall(w http.ResponseWriter, r *http.Request, user common.User, uname string) common.RouteError {
|
||||
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManagePlugins {
|
||||
return common.NoPermissions(w, r, user)
|
||||
}
|
||||
|
||||
plugin, ok := common.Plugins[uname]
|
||||
if !ok {
|
||||
return common.LocalError("The plugin isn't registered in the system", w, r, user)
|
||||
}
|
||||
if !plugin.Installable {
|
||||
return common.LocalError("This plugin is not installable", w, r, user)
|
||||
}
|
||||
if plugin.Installed {
|
||||
return common.LocalError("This plugin has already been installed", w, r, user)
|
||||
}
|
||||
|
||||
var active bool
|
||||
err := stmts.isPluginActive.QueryRow(uname).Scan(&active)
|
||||
if err != nil && err != ErrNoRows {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
var hasPlugin = (err == nil)
|
||||
|
||||
if common.Plugins[uname].Install != nil {
|
||||
err = common.Plugins[uname].Install()
|
||||
if err != nil {
|
||||
return common.LocalError(err.Error(), w, r, user)
|
||||
}
|
||||
}
|
||||
|
||||
if common.Plugins[uname].Activate != nil {
|
||||
err = common.Plugins[uname].Activate()
|
||||
if err != nil {
|
||||
return common.LocalError(err.Error(), w, r, user)
|
||||
}
|
||||
}
|
||||
|
||||
if hasPlugin {
|
||||
_, err = stmts.updatePluginInstall.Exec(1, uname)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
_, err = stmts.updatePlugin.Exec(1, uname)
|
||||
} else {
|
||||
_, err = stmts.addPlugin.Exec(uname, 1, 1)
|
||||
}
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
log.Printf("Installing plugin '%s'", plugin.Name)
|
||||
plugin.Active = true
|
||||
plugin.Installed = true
|
||||
common.Plugins[uname] = plugin
|
||||
err = common.Plugins[uname].Init()
|
||||
if err != nil {
|
||||
return common.LocalError(err.Error(), w, r, user)
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/panel/plugins/", http.StatusSeeOther)
|
||||
return nil
|
||||
}
|
||||
|
||||
func routePanelGroups(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||
header, stats, ferr := common.PanelUserCheck(w, r, &user)
|
||||
if ferr != nil {
|
||||
|
|
|
@ -139,6 +139,15 @@ func (selectItem *AccSelectBuilder) Prepare() *sql.Stmt {
|
|||
return selectItem.build.SimpleSelect(selectItem.table, selectItem.columns, selectItem.where, selectItem.orderby, selectItem.limit)
|
||||
}
|
||||
|
||||
func (builder *AccSelectBuilder) query() (string, error) {
|
||||
// TODO: Phase out the procedural API and use the adapter's OO API? The OO API might need a bit more work before we do that and it needs to be rolled out to MSSQL.
|
||||
if builder.dateCutoff != nil || builder.inChain != nil {
|
||||
selectBuilder := builder.build.GetAdapter().Builder().Select().FromAcc(builder)
|
||||
return builder.build.GetAdapter().ComplexSelect(selectBuilder)
|
||||
}
|
||||
return builder.build.adapter.SimpleSelect("_builder", builder.table, builder.columns, builder.where, builder.orderby, builder.limit)
|
||||
}
|
||||
|
||||
func (selectItem *AccSelectBuilder) Query(args ...interface{}) (*sql.Rows, error) {
|
||||
stmt := selectItem.Prepare()
|
||||
if stmt != nil {
|
||||
|
@ -160,17 +169,21 @@ func (wrap *AccRowWrap) Scan(dest ...interface{}) error {
|
|||
}
|
||||
|
||||
// TODO: Test to make sure the errors are passed up properly
|
||||
func (selectItem *AccSelectBuilder) QueryRow(args ...interface{}) *AccRowWrap {
|
||||
stmt := selectItem.Prepare()
|
||||
func (builder *AccSelectBuilder) QueryRow(args ...interface{}) *AccRowWrap {
|
||||
stmt := builder.Prepare()
|
||||
if stmt != nil {
|
||||
return &AccRowWrap{stmt.QueryRow(args...), nil}
|
||||
}
|
||||
return &AccRowWrap{nil, selectItem.build.FirstError()}
|
||||
return &AccRowWrap{nil, builder.build.FirstError()}
|
||||
}
|
||||
|
||||
// Experimental, reduces lines
|
||||
func (selectItem *AccSelectBuilder) Each(handle func(*sql.Rows) error) error {
|
||||
rows, err := selectItem.Query()
|
||||
func (builder *AccSelectBuilder) Each(handle func(*sql.Rows) error) error {
|
||||
query, err := builder.query()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rows, err := builder.build.query(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -184,8 +197,12 @@ func (selectItem *AccSelectBuilder) Each(handle func(*sql.Rows) error) error {
|
|||
}
|
||||
return rows.Err()
|
||||
}
|
||||
func (selectItem *AccSelectBuilder) EachInt(handle func(int) error) error {
|
||||
rows, err := selectItem.Query()
|
||||
func (builder *AccSelectBuilder) EachInt(handle func(int) error) error {
|
||||
query, err := builder.query()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rows, err := builder.build.query(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -227,21 +244,20 @@ func (insert *accInsertBuilder) Prepare() *sql.Stmt {
|
|||
return insert.build.SimpleInsert(insert.table, insert.columns, insert.fields)
|
||||
}
|
||||
|
||||
func (insert *accInsertBuilder) Exec(args ...interface{}) (res sql.Result, err error) {
|
||||
stmt := insert.Prepare()
|
||||
if stmt != nil {
|
||||
return stmt.Exec(args...)
|
||||
func (builder *accInsertBuilder) Exec(args ...interface{}) (res sql.Result, err error) {
|
||||
query, err := builder.build.adapter.SimpleInsert("_builder", builder.table, builder.columns, builder.fields)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
return res, insert.build.FirstError()
|
||||
return builder.build.exec(query, args...)
|
||||
}
|
||||
|
||||
func (builder *accInsertBuilder) Run(args ...interface{}) (int, error) {
|
||||
stmt := builder.Prepare()
|
||||
if stmt == nil {
|
||||
return 0, builder.build.FirstError()
|
||||
query, err := builder.build.adapter.SimpleInsert("_builder", builder.table, builder.columns, builder.fields)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
res, err := stmt.Exec(args...)
|
||||
res, err := builder.build.exec(query, args...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
|
@ -58,6 +58,22 @@ func (build *Accumulator) prepare(res string, err error) *sql.Stmt {
|
|||
return stmt
|
||||
}
|
||||
|
||||
func (build *Accumulator) query(query string, args ...interface{}) (rows *sql.Rows, err error) {
|
||||
err = build.FirstError()
|
||||
if err != nil {
|
||||
return rows, err
|
||||
}
|
||||
return build.conn.Query(query, args...)
|
||||
}
|
||||
|
||||
func (build *Accumulator) exec(query string, args ...interface{}) (res sql.Result, err error) {
|
||||
err = build.FirstError()
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
return build.conn.Exec(query, args...)
|
||||
}
|
||||
|
||||
func (build *Accumulator) Tx(handler func(*TransactionBuilder) error) {
|
||||
tx, err := build.conn.Begin()
|
||||
if err != nil {
|
||||
|
|
|
@ -256,8 +256,6 @@ func writeSelects(adapter qgen.Adapter) error {
|
|||
|
||||
// Looking for getTopic? Your statement is in another castle
|
||||
|
||||
build.Select("isPluginActive").Table("plugins").Columns("active").Where("uname = ?").Parse()
|
||||
|
||||
//build.Select("isPluginInstalled").Table("plugins").Columns("installed").Where("uname = ?").Parse()
|
||||
|
||||
build.Select("isThemeDefault").Table("themes").Columns("default").Where("uname = ?").Parse()
|
||||
|
@ -284,8 +282,6 @@ func writeInserts(adapter qgen.Adapter) error {
|
|||
|
||||
build.Insert("addForumPermsToForum").Table("forums_permissions").Columns("gid,fid,preset,permissions").Fields("?,?,?,?").Parse()
|
||||
|
||||
build.Insert("addPlugin").Table("plugins").Columns("uname, active, installed").Fields("?,?,?").Parse()
|
||||
|
||||
build.Insert("addTheme").Table("themes").Columns("uname, default").Fields("?,?").Parse()
|
||||
|
||||
build.Insert("createWordFilter").Table("word_filters").Columns("find, replacement").Fields("?,?").Parse()
|
||||
|
@ -296,10 +292,6 @@ func writeInserts(adapter qgen.Adapter) error {
|
|||
func writeUpdates(adapter qgen.Adapter) error {
|
||||
build := adapter.Builder()
|
||||
|
||||
build.Update("updatePlugin").Table("plugins").Set("active = ?").Where("uname = ?").Parse()
|
||||
|
||||
build.Update("updatePluginInstall").Table("plugins").Set("installed = ?").Where("uname = ?").Parse()
|
||||
|
||||
build.Update("updateTheme").Table("themes").Set("default = ?").Where("uname = ?").Parse()
|
||||
|
||||
build.Update("updateGroupPerms").Table("users_groups").Set("permissions = ?").Where("gid = ?").Parse()
|
||||
|
|
|
@ -177,10 +177,10 @@ func buildPanelRoutes() {
|
|||
Action("routePanelThemesMenuItemDeleteSubmit", "/panel/themes/menus/item/delete/submit/", "extraData"),
|
||||
Action("routePanelThemesMenuItemOrderSubmit", "/panel/themes/menus/item/order/edit/submit/", "extraData"),
|
||||
|
||||
View("routePanelPlugins", "/panel/plugins/"),
|
||||
Action("routePanelPluginsActivate", "/panel/plugins/activate/", "extraData"),
|
||||
Action("routePanelPluginsDeactivate", "/panel/plugins/deactivate/", "extraData"),
|
||||
Action("routePanelPluginsInstall", "/panel/plugins/install/", "extraData"),
|
||||
View("panel.Plugins", "/panel/plugins/"),
|
||||
Action("panel.PluginsActivate", "/panel/plugins/activate/", "extraData"),
|
||||
Action("panel.PluginsDeactivate", "/panel/plugins/deactivate/", "extraData"),
|
||||
Action("panel.PluginsInstall", "/panel/plugins/install/", "extraData"),
|
||||
|
||||
View("panel.Users", "/panel/users/"),
|
||||
View("panel.UsersEdit", "/panel/users/edit/", "extraData"),
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
package panel
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"../../common"
|
||||
)
|
||||
|
||||
//routePanelPlugins
|
||||
func Plugins(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||
basePage, ferr := buildBasePage(w, r, &user, "plugins", "plugins")
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManagePlugins {
|
||||
return common.NoPermissions(w, r, user)
|
||||
}
|
||||
|
||||
var pluginList []interface{}
|
||||
for _, plugin := range common.Plugins {
|
||||
pluginList = append(pluginList, plugin)
|
||||
}
|
||||
|
||||
pi := common.PanelPage{basePage, pluginList, nil}
|
||||
return panelRenderTemplate("panel_plugins", w, r, user, &pi)
|
||||
}
|
||||
|
||||
//routePanelPluginsActivate
|
||||
// TODO: Abstract more of the plugin activation / installation / deactivation logic, so we can test all that more reliably and easily
|
||||
func PluginsActivate(w http.ResponseWriter, r *http.Request, user common.User, uname string) common.RouteError {
|
||||
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManagePlugins {
|
||||
return common.NoPermissions(w, r, user)
|
||||
}
|
||||
|
||||
plugin, ok := common.Plugins[uname]
|
||||
if !ok {
|
||||
return common.LocalError("The plugin isn't registered in the system", w, r, user)
|
||||
}
|
||||
if plugin.Installable && !plugin.Installed {
|
||||
return common.LocalError("You can't activate this plugin without installing it first", w, r, user)
|
||||
}
|
||||
|
||||
active, err := plugin.BypassActive()
|
||||
hasPlugin, err2 := plugin.InDatabase()
|
||||
if err != nil || err2 != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
if plugin.Activate != nil {
|
||||
err = plugin.Activate()
|
||||
if err != nil {
|
||||
return common.LocalError(err.Error(), w, r, user)
|
||||
}
|
||||
}
|
||||
|
||||
if hasPlugin {
|
||||
if active {
|
||||
return common.LocalError("The plugin is already active", w, r, user)
|
||||
}
|
||||
err = plugin.SetActive(true)
|
||||
} else {
|
||||
err = plugin.AddToDatabase(true, false)
|
||||
}
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
log.Printf("Activating plugin '%s'", plugin.Name)
|
||||
err = plugin.Init()
|
||||
if err != nil {
|
||||
return common.LocalError(err.Error(), w, r, user)
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/panel/plugins/", http.StatusSeeOther)
|
||||
return nil
|
||||
}
|
||||
|
||||
//routePanelPluginsDeactivate
|
||||
func PluginsDeactivate(w http.ResponseWriter, r *http.Request, user common.User, uname string) common.RouteError {
|
||||
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManagePlugins {
|
||||
return common.NoPermissions(w, r, user)
|
||||
}
|
||||
|
||||
plugin, ok := common.Plugins[uname]
|
||||
if !ok {
|
||||
return common.LocalError("The plugin isn't registered in the system", w, r, user)
|
||||
}
|
||||
|
||||
active, err := plugin.BypassActive()
|
||||
if !active {
|
||||
return common.LocalError("The plugin you're trying to deactivate isn't active", w, r, user)
|
||||
} else if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
err = plugin.SetActive(false)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
plugin.Deactivate()
|
||||
|
||||
http.Redirect(w, r, "/panel/plugins/", http.StatusSeeOther)
|
||||
return nil
|
||||
}
|
||||
|
||||
//routePanelPluginsInstall
|
||||
func PluginsInstall(w http.ResponseWriter, r *http.Request, user common.User, uname string) common.RouteError {
|
||||
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManagePlugins {
|
||||
return common.NoPermissions(w, r, user)
|
||||
}
|
||||
|
||||
plugin, ok := common.Plugins[uname]
|
||||
if !ok {
|
||||
return common.LocalError("The plugin isn't registered in the system", w, r, user)
|
||||
}
|
||||
if !plugin.Installable {
|
||||
return common.LocalError("This plugin is not installable", w, r, user)
|
||||
}
|
||||
if plugin.Installed {
|
||||
return common.LocalError("This plugin has already been installed", w, r, user)
|
||||
}
|
||||
|
||||
active, err := plugin.BypassActive()
|
||||
hasPlugin, err2 := plugin.InDatabase()
|
||||
if err != nil || err2 != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
if active {
|
||||
return common.InternalError(errors.New("An uninstalled plugin is still active"), w, r)
|
||||
}
|
||||
|
||||
if plugin.Install != nil {
|
||||
err = plugin.Install()
|
||||
if err != nil {
|
||||
return common.LocalError(err.Error(), w, r, user)
|
||||
}
|
||||
}
|
||||
|
||||
if plugin.Activate != nil {
|
||||
err = plugin.Activate()
|
||||
if err != nil {
|
||||
return common.LocalError(err.Error(), w, r, user)
|
||||
}
|
||||
}
|
||||
|
||||
if hasPlugin {
|
||||
err = plugin.SetInstalled(true)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
err = plugin.SetActive(true)
|
||||
} else {
|
||||
err = plugin.AddToDatabase(true, true)
|
||||
}
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
log.Printf("Installing plugin '%s'", plugin.Name)
|
||||
err = plugin.Init()
|
||||
if err != nil {
|
||||
return common.LocalError(err.Error(), w, r, user)
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/panel/plugins/", http.StatusSeeOther)
|
||||
return nil
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
<div class="rowitem editable_parent">
|
||||
<a {{if .URL}}href="{{.URL}}" {{end}}class="editable_block" class="panel_upshift">{{.Name}}</a><br />
|
||||
<small style="margin-left: 2px;">{{lang "panel_plugins_author_prefix"}}{{.Author}}</small>
|
||||
<span style="float: right;">
|
||||
<span class="to_right">
|
||||
{{if .Settings}}<a href="/panel/settings/" class="panel_tag">{{lang "panel_plugins_settings"}}</a>{{end}}
|
||||
{{if .Active}}<a href="/panel/plugins/deactivate/{{.UName}}?session={{$.CurrentUser.Session}}" class="panel_tag">{{lang "panel_plugins_deactivate"}}</a>
|
||||
{{else if .Installable}}
|
||||
|
|
Loading…
Reference in New Issue