Best Venom code snippet using http.Run
playbook_runs.go
Source:playbook_runs.go
...15 "github.com/mattermost/mattermost-plugin-playbooks/server/app"16 "github.com/mattermost/mattermost-plugin-playbooks/server/bot"17 "github.com/mattermost/mattermost-plugin-playbooks/server/config"18)19// PlaybookRunHandler is the API handler.20type PlaybookRunHandler struct {21 *ErrorHandler22 config config.Service23 playbookRunService app.PlaybookRunService24 playbookService app.PlaybookService25 permissions *app.PermissionsService26 licenseChecker app.LicenseChecker27 pluginAPI *pluginapi.Client28 poster bot.Poster29 log bot.Logger30}31// NewPlaybookRunHandler Creates a new Plugin API handler.32func NewPlaybookRunHandler(33 router *mux.Router,34 playbookRunService app.PlaybookRunService,35 playbookService app.PlaybookService,36 permissions *app.PermissionsService,37 licenseChecker app.LicenseChecker,38 api *pluginapi.Client,39 poster bot.Poster,40 log bot.Logger,41 configService config.Service,42) *PlaybookRunHandler {43 handler := &PlaybookRunHandler{44 ErrorHandler: &ErrorHandler{log: log},45 playbookRunService: playbookRunService,46 playbookService: playbookService,47 pluginAPI: api,48 poster: poster,49 log: log,50 config: configService,51 permissions: permissions,52 licenseChecker: licenseChecker,53 }54 playbookRunsRouter := router.PathPrefix("/runs").Subrouter()55 playbookRunsRouter.HandleFunc("", handler.getPlaybookRuns).Methods(http.MethodGet)56 playbookRunsRouter.HandleFunc("", handler.createPlaybookRunFromPost).Methods(http.MethodPost)57 playbookRunsRouter.HandleFunc("/dialog", handler.createPlaybookRunFromDialog).Methods(http.MethodPost)58 playbookRunsRouter.HandleFunc("/add-to-timeline-dialog", handler.addToTimelineDialog).Methods(http.MethodPost)59 playbookRunsRouter.HandleFunc("/owners", handler.getOwners).Methods(http.MethodGet)60 playbookRunsRouter.HandleFunc("/channels", handler.getChannels).Methods(http.MethodGet)61 playbookRunsRouter.HandleFunc("/checklist-autocomplete", handler.getChecklistAutocomplete).Methods(http.MethodGet)62 playbookRunsRouter.HandleFunc("/checklist-autocomplete-item", handler.getChecklistAutocompleteItem).Methods(http.MethodGet)63 playbookRunRouter := playbookRunsRouter.PathPrefix("/{id:[A-Za-z0-9]+}").Subrouter()64 playbookRunRouter.HandleFunc("", handler.getPlaybookRun).Methods(http.MethodGet)65 playbookRunRouter.HandleFunc("/metadata", handler.getPlaybookRunMetadata).Methods(http.MethodGet)66 playbookRunRouterAuthorized := playbookRunRouter.PathPrefix("").Subrouter()67 playbookRunRouterAuthorized.Use(handler.checkEditPermissions)68 playbookRunRouterAuthorized.HandleFunc("", handler.updatePlaybookRun).Methods(http.MethodPatch)69 playbookRunRouterAuthorized.HandleFunc("/owner", handler.changeOwner).Methods(http.MethodPost)70 playbookRunRouterAuthorized.HandleFunc("/status", handler.status).Methods(http.MethodPost)71 playbookRunRouterAuthorized.HandleFunc("/finish", handler.finish).Methods(http.MethodPut)72 playbookRunRouterAuthorized.HandleFunc("/finish-dialog", handler.finishDialog).Methods(http.MethodPost)73 playbookRunRouterAuthorized.HandleFunc("/update-status-dialog", handler.updateStatusDialog).Methods(http.MethodPost)74 playbookRunRouterAuthorized.HandleFunc("/reminder/button-update", handler.reminderButtonUpdate).Methods(http.MethodPost)75 playbookRunRouterAuthorized.HandleFunc("/reminder", handler.reminderReset).Methods(http.MethodPost)76 playbookRunRouterAuthorized.HandleFunc("/no-retrospective-button", handler.noRetrospectiveButton).Methods(http.MethodPost)77 playbookRunRouterAuthorized.HandleFunc("/timeline/{eventID:[A-Za-z0-9]+}", handler.removeTimelineEvent).Methods(http.MethodDelete)78 playbookRunRouterAuthorized.HandleFunc("/update-description", handler.updateDescription).Methods(http.MethodPut)79 playbookRunRouterAuthorized.HandleFunc("/restore", handler.restore).Methods(http.MethodPut)80 channelRouter := playbookRunsRouter.PathPrefix("/channel").Subrouter()81 channelRouter.HandleFunc("/{channel_id:[A-Za-z0-9]+}", handler.getPlaybookRunByChannel).Methods(http.MethodGet)82 checklistsRouter := playbookRunRouterAuthorized.PathPrefix("/checklists").Subrouter()83 checklistsRouter.HandleFunc("", handler.addChecklist).Methods(http.MethodPost)84 checklistsRouter.HandleFunc("/move", handler.moveChecklist).Methods(http.MethodPost)85 checklistsRouter.HandleFunc("/move-item", handler.moveChecklistItem).Methods(http.MethodPost)86 checklistRouter := checklistsRouter.PathPrefix("/{checklist:[0-9]+}").Subrouter()87 checklistRouter.HandleFunc("", handler.removeChecklist).Methods(http.MethodDelete)88 checklistRouter.HandleFunc("/add", handler.addChecklistItem).Methods(http.MethodPost)89 checklistRouter.HandleFunc("/rename", handler.renameChecklist).Methods(http.MethodPut)90 checklistRouter.HandleFunc("/add-dialog", handler.addChecklistItemDialog).Methods(http.MethodPost)91 checklistItem := checklistRouter.PathPrefix("/item/{item:[0-9]+}").Subrouter()92 checklistItem.HandleFunc("", handler.itemDelete).Methods(http.MethodDelete)93 checklistItem.HandleFunc("", handler.itemEdit).Methods(http.MethodPut)94 checklistItem.HandleFunc("/skip", handler.itemSkip).Methods(http.MethodPut)95 checklistItem.HandleFunc("/restore", handler.itemRestore).Methods(http.MethodPut)96 checklistItem.HandleFunc("/state", handler.itemSetState).Methods(http.MethodPut)97 checklistItem.HandleFunc("/assignee", handler.itemSetAssignee).Methods(http.MethodPut)98 checklistItem.HandleFunc("/command", handler.itemSetCommand).Methods(http.MethodPut)99 checklistItem.HandleFunc("/run", handler.itemRun).Methods(http.MethodPost)100 checklistItem.HandleFunc("/duplicate", handler.itemDuplicate).Methods(http.MethodPost)101 checklistItem.HandleFunc("/duedate", handler.itemSetDueDate).Methods(http.MethodPut)102 retrospectiveRouter := playbookRunRouterAuthorized.PathPrefix("/retrospective").Subrouter()103 retrospectiveRouter.HandleFunc("", handler.updateRetrospective).Methods(http.MethodPost)104 retrospectiveRouter.HandleFunc("/publish", handler.publishRetrospective).Methods(http.MethodPost)105 followersRouter := playbookRunRouter.PathPrefix("/followers").Subrouter()106 followersRouter.HandleFunc("", handler.follow).Methods(http.MethodPut)107 followersRouter.HandleFunc("", handler.unfollow).Methods(http.MethodDelete)108 followersRouter.HandleFunc("", handler.getFollowers).Methods(http.MethodGet)109 return handler110}111func (h *PlaybookRunHandler) checkEditPermissions(next http.Handler) http.Handler {112 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {113 vars := mux.Vars(r)114 userID := r.Header.Get("Mattermost-User-ID")115 playbookRun, err := h.playbookRunService.GetPlaybookRun(vars["id"])116 if err != nil {117 h.HandleError(w, err)118 return119 }120 if !h.PermissionsCheck(w, h.permissions.RunManageProperties(userID, playbookRun.ID)) {121 return122 }123 next.ServeHTTP(w, r)124 })125}126// createPlaybookRunFromPost handles the POST /runs endpoint127func (h *PlaybookRunHandler) createPlaybookRunFromPost(w http.ResponseWriter, r *http.Request) {128 userID := r.Header.Get("Mattermost-User-ID")129 var playbookRunCreateOptions client.PlaybookRunCreateOptions130 if err := json.NewDecoder(r.Body).Decode(&playbookRunCreateOptions); err != nil {131 h.HandleErrorWithCode(w, http.StatusBadRequest, "unable to decode playbook run create options", err)132 return133 }134 playbookRun, err := h.createPlaybookRun(135 app.PlaybookRun{136 OwnerUserID: playbookRunCreateOptions.OwnerUserID,137 TeamID: playbookRunCreateOptions.TeamID,138 ChannelID: playbookRunCreateOptions.ChannelID,139 Name: playbookRunCreateOptions.Name,140 Summary: playbookRunCreateOptions.Description,141 PostID: playbookRunCreateOptions.PostID,142 PlaybookID: playbookRunCreateOptions.PlaybookID,143 },144 userID,145 )146 if errors.Is(err, app.ErrNoPermissions) {147 h.HandleErrorWithCode(w, http.StatusForbidden, "unable to create playbook run", err)148 return149 }150 if errors.Is(err, app.ErrMalformedPlaybookRun) {151 h.HandleErrorWithCode(w, http.StatusBadRequest, "unable to create playbook run", err)152 return153 }154 if err != nil {155 h.HandleError(w, errors.Wrapf(err, "unable to create playbook run"))156 return157 }158 h.poster.PublishWebsocketEventToUser(app.PlaybookRunCreatedWSEvent, map[string]interface{}{159 "playbook_run": playbookRun,160 }, userID)161 w.Header().Add("Location", fmt.Sprintf("/api/v0/runs/%s", playbookRun.ID))162 ReturnJSON(w, &playbookRun, http.StatusCreated)163}164// Note that this currently does nothing. This is temporary given the removal of stages. Will be used by status.165func (h *PlaybookRunHandler) updatePlaybookRun(w http.ResponseWriter, r *http.Request) {166 vars := mux.Vars(r)167 playbookRunID := vars["id"]168 //userID := r.Header.Get("Mattermost-User-ID")169 oldPlaybookRun, err := h.playbookRunService.GetPlaybookRun(playbookRunID)170 if err != nil {171 h.HandleError(w, err)172 return173 }174 var updates app.UpdateOptions175 if err = json.NewDecoder(r.Body).Decode(&updates); err != nil {176 h.HandleErrorWithCode(w, http.StatusBadRequest, "unable to decode payload", err)177 return178 }179 updatedPlaybookRun := oldPlaybookRun180 ReturnJSON(w, updatedPlaybookRun, http.StatusOK)181}182// createPlaybookRunFromDialog handles the interactive dialog submission when a user presses confirm on183// the create playbook run dialog.184func (h *PlaybookRunHandler) createPlaybookRunFromDialog(w http.ResponseWriter, r *http.Request) {185 userID := r.Header.Get("Mattermost-User-ID")186 var request *model.SubmitDialogRequest187 err := json.NewDecoder(r.Body).Decode(&request)188 if err != nil || request == nil {189 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to decode SubmitDialogRequest", err)190 return191 }192 if userID != request.UserId {193 h.HandleErrorWithCode(w, http.StatusBadRequest, "interactive dialog's userID must be the same as the requester's userID", nil)194 return195 }196 var state app.DialogState197 err = json.Unmarshal([]byte(request.State), &state)198 if err != nil {199 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to unmarshal dialog state", err)200 return201 }202 var playbookID, name string203 if rawPlaybookID, ok := request.Submission[app.DialogFieldPlaybookIDKey].(string); ok {204 playbookID = rawPlaybookID205 }206 if rawName, ok := request.Submission[app.DialogFieldNameKey].(string); ok {207 name = rawName208 }209 playbookRun, err := h.createPlaybookRun(210 app.PlaybookRun{211 OwnerUserID: request.UserId,212 TeamID: request.TeamId,213 Name: name,214 PostID: state.PostID,215 PlaybookID: playbookID,216 },217 request.UserId,218 )219 if err != nil {220 if errors.Is(err, app.ErrMalformedPlaybookRun) {221 h.HandleErrorWithCode(w, http.StatusBadRequest, "unable to create playbook run", err)222 return223 }224 if errors.Is(err, app.ErrNoPermissions) {225 h.HandleErrorWithCode(w, http.StatusForbidden, "not authorized to make runs from this playbook", err)226 return227 }228 var msg string229 if errors.Is(err, app.ErrChannelDisplayNameInvalid) {230 msg = "The name is invalid or too long. Please use a valid name with fewer than 64 characters."231 }232 if msg != "" {233 resp := &model.SubmitDialogResponse{234 Errors: map[string]string{235 app.DialogFieldNameKey: msg,236 },237 }238 respBytes, _ := json.Marshal(resp)239 _, _ = w.Write(respBytes)240 return241 }242 h.HandleError(w, err)243 return244 }245 // If the dialog was spawn from a prompt post (the one that is automatically sent when246 // certain keywords are posted in a channel), then we need to edit that original post247 if state.PromptPostID != "" {248 if err := h.editPromptPost(state.PromptPostID, playbookID, playbookRun.ID, userID, name); err != nil {249 h.log.Warnf("failed editing the prompt post; error: %s", err.Error())250 }251 }252 channel, err := h.pluginAPI.Channel.Get(playbookRun.ChannelID)253 if err != nil {254 h.HandleErrorWithCode(w, http.StatusInternalServerError, "unable to get new channel", err)255 return256 }257 // Delay sending the websocket message because the front end may try to change to the newly created258 // channel, and the server may respond with a "channel not found" error. This happens in e2e tests,259 // and possibly in the wild.260 go func() {261 time.Sleep(1 * time.Second) // arbitrary 1 second magic number262 h.poster.PublishWebsocketEventToUser(app.PlaybookRunCreatedWSEvent, map[string]interface{}{263 "client_id": state.ClientID,264 "playbook_run": playbookRun,265 "channel_name": channel.Name,266 }, request.UserId)267 }()268 if err := h.postPlaybookRunCreatedMessage(playbookRun, request.ChannelId); err != nil {269 h.HandleError(w, err)270 return271 }272 w.Header().Add("Location", fmt.Sprintf("/api/v0/runs/%s", playbookRun.ID))273 w.WriteHeader(http.StatusCreated)274}275func (h *PlaybookRunHandler) editPromptPost(promptPostID string, playbookID string, runID string, userID string, runName string) error {276 post, err := h.pluginAPI.Post.GetPost(promptPostID)277 if err != nil {278 return errors.Wrapf(err, "unable to retrieve the post with ID %q", promptPostID)279 }280 playbook, err := h.playbookService.Get(playbookID)281 if err != nil {282 return errors.Wrapf(err, "unable to retrieve the playbook with ID %q", playbookID)283 }284 user, err := h.pluginAPI.User.Get(userID)285 if err != nil {286 return errors.Wrapf(err, "unable to retrieve the user with ID %q", userID)287 }288 // Update the message and remove the attachments; i.e., the buttons289 post.Message = fmt.Sprintf("@%s started the run [%s](%s) using the [%s](%s) playbook.",290 user.Username, runName, app.GetRunDetailsRelativeURL(runID), playbook.Title, app.GetPlaybookDetailsRelativeURL(playbookID))291 model.ParseSlackAttachment(post, []*model.SlackAttachment{})292 if err := h.pluginAPI.Post.UpdatePost(post); err != nil {293 return errors.Wrapf(err, "unable to update the post with ID %q", post.Id)294 }295 return nil296}297// addToTimelineDialog handles the interactive dialog submission when a user clicks the298// corresponding post action.299func (h *PlaybookRunHandler) addToTimelineDialog(w http.ResponseWriter, r *http.Request) {300 if !h.licenseChecker.TimelineAllowed() {301 h.HandleErrorWithCode(w, http.StatusForbidden, "timeline feature is not covered by current server license", nil)302 return303 }304 userID := r.Header.Get("Mattermost-User-ID")305 var request *model.SubmitDialogRequest306 err := json.NewDecoder(r.Body).Decode(&request)307 if err != nil || request == nil {308 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to decode SubmitDialogRequest", err)309 return310 }311 if userID != request.UserId {312 h.HandleErrorWithCode(w, http.StatusBadRequest, "interactive dialog's userID must be the same as the requester's userID", nil)313 return314 }315 var playbookRunID, summary string316 if rawPlaybookRunID, ok := request.Submission[app.DialogFieldPlaybookRunKey].(string); ok {317 playbookRunID = rawPlaybookRunID318 }319 if rawSummary, ok := request.Submission[app.DialogFieldSummary].(string); ok {320 summary = rawSummary321 }322 playbookRun, incErr := h.playbookRunService.GetPlaybookRun(playbookRunID)323 if incErr != nil {324 h.HandleError(w, incErr)325 return326 }327 if !h.PermissionsCheck(w, h.permissions.RunManageProperties(userID, playbookRun.ID)) {328 return329 }330 var state app.DialogStateAddToTimeline331 err = json.Unmarshal([]byte(request.State), &state)332 if err != nil {333 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to unmarshal dialog state", err)334 return335 }336 if err = h.playbookRunService.AddPostToTimeline(playbookRunID, userID, state.PostID, summary); err != nil {337 h.HandleError(w, errors.Wrap(err, "failed to add post to timeline"))338 return339 }340 w.WriteHeader(http.StatusOK)341}342func (h *PlaybookRunHandler) createPlaybookRun(playbookRun app.PlaybookRun, userID string) (*app.PlaybookRun, error) {343 if playbookRun.ID != "" {344 return nil, errors.Wrap(app.ErrMalformedPlaybookRun, "playbook run already has an id")345 }346 if playbookRun.CreateAt != 0 {347 return nil, errors.Wrap(app.ErrMalformedPlaybookRun, "playbook run channel already has created at date")348 }349 if playbookRun.TeamID == "" && playbookRun.ChannelID == "" {350 return nil, errors.Wrap(app.ErrMalformedPlaybookRun, "must provide team or channel to create playbook run")351 }352 // If a channel is specified, ensure it's from the given team (if one provided), or353 // just grab the team for that channel.354 var channel *model.Channel355 var err error356 if playbookRun.ChannelID != "" {357 channel, err = h.pluginAPI.Channel.Get(playbookRun.ChannelID)358 if err != nil {359 return nil, errors.Wrapf(err, "failed to get channel")360 }361 if playbookRun.TeamID == "" {362 playbookRun.TeamID = channel.TeamId363 } else if channel.TeamId != playbookRun.TeamID {364 return nil, errors.Wrap(app.ErrMalformedPlaybookRun, "channel not in given team")365 }366 }367 if playbookRun.OwnerUserID == "" {368 return nil, errors.Wrap(app.ErrMalformedPlaybookRun, "missing owner user id of playbook run")369 }370 if strings.TrimSpace(playbookRun.Name) == "" && playbookRun.ChannelID == "" {371 return nil, errors.Wrap(app.ErrMalformedPlaybookRun, "missing name of playbook run")372 }373 public := true374 var playbook *app.Playbook375 if playbookRun.PlaybookID != "" {376 pb, err := h.playbookService.Get(playbookRun.PlaybookID)377 if err != nil {378 return nil, errors.Wrapf(err, "failed to get playbook")379 }380 if pb.DeleteAt != 0 {381 return nil, errors.New("playbook is archived, cannot create a new run using an archived playbook")382 }383 if err := h.permissions.RunCreate(userID, pb); err != nil {384 return nil, err385 }386 playbookRun.Checklists = pb.Checklists387 public = pb.CreatePublicPlaybookRun388 if pb.RunSummaryTemplateEnabled {389 playbookRun.Summary = pb.RunSummaryTemplate390 }391 playbookRun.ReminderMessageTemplate = pb.ReminderMessageTemplate392 playbookRun.StatusUpdateEnabled = pb.StatusUpdateEnabled393 playbookRun.PreviousReminder = time.Duration(pb.ReminderTimerDefaultSeconds) * time.Second394 playbookRun.ReminderTimerDefaultSeconds = pb.ReminderTimerDefaultSeconds395 playbookRun.InvitedUserIDs = []string{}396 playbookRun.InvitedGroupIDs = []string{}397 if pb.InviteUsersEnabled {398 playbookRun.InvitedUserIDs = pb.InvitedUserIDs399 playbookRun.InvitedGroupIDs = pb.InvitedGroupIDs400 }401 if pb.DefaultOwnerEnabled {402 playbookRun.DefaultOwnerID = pb.DefaultOwnerID403 }404 if pb.BroadcastEnabled {405 playbookRun.BroadcastChannelIDs = pb.BroadcastChannelIDs406 }407 playbookRun.WebhookOnCreationURLs = []string{}408 if pb.WebhookOnCreationEnabled {409 playbookRun.WebhookOnCreationURLs = pb.WebhookOnCreationURLs410 }411 playbookRun.WebhookOnStatusUpdateURLs = []string{}412 if pb.WebhookOnStatusUpdateEnabled {413 playbookRun.WebhookOnStatusUpdateURLs = pb.WebhookOnStatusUpdateURLs414 }415 playbookRun.RetrospectiveEnabled = pb.RetrospectiveEnabled416 if pb.RetrospectiveEnabled {417 playbookRun.RetrospectiveReminderIntervalSeconds = pb.RetrospectiveReminderIntervalSeconds418 playbookRun.Retrospective = pb.RetrospectiveTemplate419 }420 playbook = &pb421 }422 if channel == nil {423 permission := model.PermissionCreatePrivateChannel424 permissionMessage := "You are not able to create a private channel"425 if public {426 permission = model.PermissionCreatePublicChannel427 permissionMessage = "You are not able to create a public channel"428 }429 if !h.pluginAPI.User.HasPermissionToTeam(userID, playbookRun.TeamID, permission) {430 return nil, errors.Wrap(app.ErrNoPermissions, permissionMessage)431 }432 } else {433 permission := model.PermissionManagePublicChannelProperties434 permissionMessage := "You are not able to manage public channel properties"435 if channel.Type == model.ChannelTypePrivate {436 permission = model.PermissionManagePrivateChannelProperties437 permissionMessage = "You are not able to manage private channel properties"438 } else if channel.Type == model.ChannelTypeDirect || channel.Type == model.ChannelTypeGroup {439 permission = model.PermissionReadChannel440 permissionMessage = "You do not have access to this channel"441 }442 if !h.pluginAPI.User.HasPermissionToChannel(userID, channel.Id, permission) {443 return nil, errors.Wrap(app.ErrNoPermissions, permissionMessage)444 }445 }446 if playbookRun.PostID != "" {447 post, err := h.pluginAPI.Post.GetPost(playbookRun.PostID)448 if err != nil {449 return nil, errors.Wrapf(err, "failed to get playbook run original post")450 }451 if !h.pluginAPI.User.HasPermissionToChannel(userID, post.ChannelId, model.PermissionReadChannel) {452 return nil, errors.New("user does not have access to the channel containing the playbook run's original post")453 }454 }455 return h.playbookRunService.CreatePlaybookRun(&playbookRun, playbook, userID, public)456}457func (h *PlaybookRunHandler) getRequesterInfo(userID string) (app.RequesterInfo, error) {458 return app.GetRequesterInfo(userID, h.pluginAPI)459}460// getPlaybookRuns handles the GET /runs endpoint.461func (h *PlaybookRunHandler) getPlaybookRuns(w http.ResponseWriter, r *http.Request) {462 userID := r.Header.Get("Mattermost-User-ID")463 filterOptions, err := parsePlaybookRunsFilterOptions(r.URL, userID)464 if err != nil {465 h.HandleErrorWithCode(w, http.StatusBadRequest, "Bad parameter", err)466 return467 }468 requesterInfo, err := h.getRequesterInfo(userID)469 if err != nil {470 h.HandleError(w, err)471 return472 }473 results, err := h.playbookRunService.GetPlaybookRuns(requesterInfo, *filterOptions)474 if err != nil {475 h.HandleError(w, err)476 return477 }478 ReturnJSON(w, results, http.StatusOK)479}480// getPlaybookRun handles the /runs/{id} endpoint.481func (h *PlaybookRunHandler) getPlaybookRun(w http.ResponseWriter, r *http.Request) {482 vars := mux.Vars(r)483 playbookRunID := vars["id"]484 userID := r.Header.Get("Mattermost-User-ID")485 if !h.PermissionsCheck(w, h.permissions.RunView(userID, playbookRunID)) {486 return487 }488 playbookRunToGet, err := h.playbookRunService.GetPlaybookRun(playbookRunID)489 if err != nil {490 h.HandleError(w, err)491 return492 }493 ReturnJSON(w, playbookRunToGet, http.StatusOK)494}495// getPlaybookRunMetadata handles the /runs/{id}/metadata endpoint.496func (h *PlaybookRunHandler) getPlaybookRunMetadata(w http.ResponseWriter, r *http.Request) {497 vars := mux.Vars(r)498 playbookRunID := vars["id"]499 userID := r.Header.Get("Mattermost-User-ID")500 if !h.PermissionsCheck(w, h.permissions.RunView(userID, playbookRunID)) {501 return502 }503 playbookRunMetadata, err := h.playbookRunService.GetPlaybookRunMetadata(playbookRunID)504 if err != nil {505 h.HandleError(w, err)506 return507 }508 ReturnJSON(w, playbookRunMetadata, http.StatusOK)509}510// getPlaybookRunByChannel handles the /runs/channel/{channel_id} endpoint.511func (h *PlaybookRunHandler) getPlaybookRunByChannel(w http.ResponseWriter, r *http.Request) {512 vars := mux.Vars(r)513 channelID := vars["channel_id"]514 userID := r.Header.Get("Mattermost-User-ID")515 if err := h.permissions.RunViewByChannel(userID, channelID); err != nil {516 h.log.Warnf("User %s does not have permissions to get playbook run for channel %s", userID, channelID)517 h.HandleErrorWithCode(w, http.StatusNotFound, "Not found",518 errors.Errorf("playbook run for channel id %s not found", channelID))519 return520 }521 playbookRunID, err := h.playbookRunService.GetPlaybookRunIDForChannel(channelID)522 if err != nil {523 if errors.Is(err, app.ErrNotFound) {524 h.HandleErrorWithCode(w, http.StatusNotFound, "Not found",525 errors.Errorf("playbook run for channel id %s not found", channelID))526 return527 }528 h.HandleError(w, err)529 return530 }531 playbookRunToGet, err := h.playbookRunService.GetPlaybookRun(playbookRunID)532 if err != nil {533 h.HandleError(w, err)534 return535 }536 ReturnJSON(w, playbookRunToGet, http.StatusOK)537}538// getOwners handles the /runs/owners api endpoint.539func (h *PlaybookRunHandler) getOwners(w http.ResponseWriter, r *http.Request) {540 teamID := r.URL.Query().Get("team_id")541 userID := r.Header.Get("Mattermost-User-ID")542 options := app.PlaybookRunFilterOptions{543 TeamID: teamID,544 }545 requesterInfo, err := h.getRequesterInfo(userID)546 if err != nil {547 h.HandleError(w, err)548 return549 }550 owners, err := h.playbookRunService.GetOwners(requesterInfo, options)551 if err != nil {552 h.HandleError(w, errors.Wrapf(err, "failed to get owners"))553 return554 }555 if owners == nil {556 owners = []app.OwnerInfo{}557 }558 ReturnJSON(w, owners, http.StatusOK)559}560func (h *PlaybookRunHandler) getChannels(w http.ResponseWriter, r *http.Request) {561 userID := r.Header.Get("Mattermost-User-ID")562 filterOptions, err := parsePlaybookRunsFilterOptions(r.URL, userID)563 if err != nil {564 h.HandleErrorWithCode(w, http.StatusBadRequest, "Bad parameter", err)565 return566 }567 requesterInfo, err := h.getRequesterInfo(userID)568 if err != nil {569 h.HandleError(w, err)570 return571 }572 playbookRuns, err := h.playbookRunService.GetPlaybookRuns(requesterInfo, *filterOptions)573 if err != nil {574 h.HandleError(w, errors.Wrapf(err, "failed to get owners"))575 return576 }577 channelIds := make([]string, 0, len(playbookRuns.Items))578 for _, playbookRun := range playbookRuns.Items {579 channelIds = append(channelIds, playbookRun.ChannelID)580 }581 ReturnJSON(w, channelIds, http.StatusOK)582}583// changeOwner handles the /runs/{id}/change-owner api endpoint.584func (h *PlaybookRunHandler) changeOwner(w http.ResponseWriter, r *http.Request) {585 vars := mux.Vars(r)586 userID := r.Header.Get("Mattermost-User-ID")587 var params struct {588 OwnerID string `json:"owner_id"`589 }590 if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil {591 h.HandleErrorWithCode(w, http.StatusBadRequest, "could not decode request body", err)592 return593 }594 playbookRun, err := h.playbookRunService.GetPlaybookRun(vars["id"])595 if err != nil {596 h.HandleError(w, err)597 return598 }599 // Check if the target user (params.OwnerID) has permissions600 if !h.PermissionsCheck(w, h.permissions.RunManageProperties(params.OwnerID, playbookRun.ID)) {601 return602 }603 if err := h.playbookRunService.ChangeOwner(vars["id"], userID, params.OwnerID); err != nil {604 h.HandleError(w, err)605 return606 }607 ReturnJSON(w, map[string]interface{}{}, http.StatusOK)608}609// updateStatusD handles the POST /runs/{id}/status endpoint, user has edit permissions610func (h *PlaybookRunHandler) status(w http.ResponseWriter, r *http.Request) {611 playbookRunID := mux.Vars(r)["id"]612 userID := r.Header.Get("Mattermost-User-ID")613 playbookRunToModify, err := h.playbookRunService.GetPlaybookRun(playbookRunID)614 if err != nil {615 h.HandleError(w, err)616 return617 }618 if !app.CanPostToChannel(userID, playbookRunToModify.ChannelID, h.pluginAPI) {619 h.HandleErrorWithCode(w, http.StatusForbidden, "Not authorized", fmt.Errorf("user %s cannot post to playbook run channel %s", userID, playbookRunToModify.ChannelID))620 return621 }622 var options app.StatusUpdateOptions623 if err = json.NewDecoder(r.Body).Decode(&options); err != nil {624 h.HandleErrorWithCode(w, http.StatusBadRequest, "unable to decode body into StatusUpdateOptions", err)625 return626 }627 if publicMsg, internalErr := h.updateStatus(playbookRunID, userID, options); internalErr != nil {628 h.HandleErrorWithCode(w, http.StatusBadRequest, publicMsg, internalErr)629 return630 }631 w.WriteHeader(http.StatusOK)632 _, _ = w.Write([]byte(`{"status":"OK"}`))633}634// updateStatus returns a publicMessage and an internal error635func (h *PlaybookRunHandler) updateStatus(playbookRunID, userID string, options app.StatusUpdateOptions) (string, error) {636 options.Message = strings.TrimSpace(options.Message)637 if options.Message == "" {638 return "message must not be empty", errors.New("message field empty")639 }640 if options.Reminder <= 0 && !options.FinishRun {641 return "the reminder must be set and not 0", errors.New("reminder was 0")642 }643 if options.Reminder < 0 || options.FinishRun {644 options.Reminder = 0645 }646 options.Reminder = options.Reminder * time.Second647 if err := h.playbookRunService.UpdateStatus(playbookRunID, userID, options); err != nil {648 return "An internal error has occurred. Check app server logs for details.", err649 }650 if options.FinishRun {651 if err := h.playbookRunService.FinishPlaybookRun(playbookRunID, userID); err != nil {652 return "An internal error has occurred. Check app server logs for details.", err653 }654 }655 return "", nil656}657// updateStatusD handles the POST /runs/{id}/finish endpoint, user has edit permissions658func (h *PlaybookRunHandler) finish(w http.ResponseWriter, r *http.Request) {659 playbookRunID := mux.Vars(r)["id"]660 userID := r.Header.Get("Mattermost-User-ID")661 if err := h.playbookRunService.FinishPlaybookRun(playbookRunID, userID); err != nil {662 h.HandleError(w, err)663 return664 }665 w.WriteHeader(http.StatusOK)666 _, _ = w.Write([]byte(`{"status":"OK"}`))667}668// restore "un-finishes" a playbook run669func (h *PlaybookRunHandler) restore(w http.ResponseWriter, r *http.Request) {670 playbookRunID := mux.Vars(r)["id"]671 userID := r.Header.Get("Mattermost-User-ID")672 if err := h.playbookRunService.RestorePlaybookRun(playbookRunID, userID); err != nil {673 h.HandleError(w, err)674 return675 }676 w.WriteHeader(http.StatusOK)677 _, _ = w.Write([]byte(`{"status":"OK"}`))678}679// updateStatusDialog handles the POST /runs/{id}/finish-dialog endpoint, called when a680// user submits the Finish Run dialog.681func (h *PlaybookRunHandler) finishDialog(w http.ResponseWriter, r *http.Request) {682 playbookRunID := mux.Vars(r)["id"]683 userID := r.Header.Get("Mattermost-User-ID")684 playbookRun, incErr := h.playbookRunService.GetPlaybookRun(playbookRunID)685 if incErr != nil {686 h.HandleError(w, incErr)687 return688 }689 if !h.PermissionsCheck(w, h.permissions.RunManageProperties(userID, playbookRun.ID)) {690 return691 }692 if err := h.playbookRunService.FinishPlaybookRun(playbookRunID, userID); err != nil {693 h.HandleError(w, err)694 return695 }696}697// updateStatusDialog handles the POST /runs/{id}/update-status-dialog endpoint, called when a698// user submits the Update Status dialog.699func (h *PlaybookRunHandler) updateStatusDialog(w http.ResponseWriter, r *http.Request) {700 playbookRunID := mux.Vars(r)["id"]701 userID := r.Header.Get("Mattermost-User-ID")702 playbookRunToModify, err := h.playbookRunService.GetPlaybookRun(playbookRunID)703 if err != nil {704 h.HandleError(w, err)705 return706 }707 if !app.CanPostToChannel(userID, playbookRunToModify.ChannelID, h.pluginAPI) {708 h.HandleErrorWithCode(w, http.StatusForbidden, "Not authorized", fmt.Errorf("user %s cannot post to playbook run channel %s", userID, playbookRunToModify.ChannelID))709 return710 }711 var request *model.SubmitDialogRequest712 err = json.NewDecoder(r.Body).Decode(&request)713 if err != nil || request == nil {714 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to decode SubmitDialogRequest", err)715 return716 }717 var options app.StatusUpdateOptions718 if message, ok := request.Submission[app.DialogFieldMessageKey]; ok {719 options.Message = message.(string)720 }721 if reminderI, ok := request.Submission[app.DialogFieldReminderInSecondsKey]; ok {722 var reminder int723 reminder, err = strconv.Atoi(reminderI.(string))724 if err != nil {725 h.HandleError(w, err)726 return727 }728 options.Reminder = time.Duration(reminder)729 }730 if finishB, ok := request.Submission[app.DialogFieldFinishRun]; ok {731 var finish bool732 if finish, ok = finishB.(bool); ok {733 options.FinishRun = finish734 }735 }736 if publicMsg, internalErr := h.updateStatus(playbookRunID, userID, options); internalErr != nil {737 h.HandleErrorWithCode(w, http.StatusBadRequest, publicMsg, internalErr)738 return739 }740 w.WriteHeader(http.StatusOK)741}742// reminderButtonUpdate handles the POST /runs/{id}/reminder/button-update endpoint, called when a743// user clicks on the reminder interactive button744func (h *PlaybookRunHandler) reminderButtonUpdate(w http.ResponseWriter, r *http.Request) {745 var requestData *model.PostActionIntegrationRequest746 err := json.NewDecoder(r.Body).Decode(&requestData)747 if err != nil || requestData == nil {748 h.HandleErrorWithCode(w, http.StatusBadRequest, "missing request data", nil)749 return750 }751 playbookRunID, err := h.playbookRunService.GetPlaybookRunIDForChannel(requestData.ChannelId)752 if err != nil {753 h.HandleErrorWithCode(w, http.StatusInternalServerError, "error getting playbook run",754 errors.Wrapf(err, "reminderButtonUpdate failed to find playbookRunID for channelID: %s", requestData.ChannelId))755 return756 }757 if !h.PermissionsCheck(w, h.permissions.RunManageProperties(requestData.UserId, playbookRunID)) {758 return759 }760 if err = h.playbookRunService.OpenUpdateStatusDialog(playbookRunID, requestData.TriggerId); err != nil {761 h.HandleError(w, errors.New("reminderButtonUpdate failed to open update status dialog"))762 return763 }764 ReturnJSON(w, nil, http.StatusOK)765}766// reminderButtonDismiss handles the POST /runs/{id}/reminder endpoint, called when a767// user clicks on the reminder custom_update_status time selector768func (h *PlaybookRunHandler) reminderReset(w http.ResponseWriter, r *http.Request) {769 playbookRunID := mux.Vars(r)["id"]770 userID := r.Header.Get("Mattermost-User-ID")771 var payload struct {772 NewReminderSeconds int `json:"new_reminder_seconds"`773 }774 if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {775 h.HandleError(w, err)776 return777 }778 if payload.NewReminderSeconds <= 0 {779 h.HandleErrorWithCode(w, http.StatusBadRequest, "new_reminder_seconds must be > 0", errors.New("new_reminder_seconds was <= 0"))780 return781 }782 storedPlaybookRun, err := h.playbookRunService.GetPlaybookRun(playbookRunID)783 if err != nil {784 err = errors.Wrapf(err, "reminderReset: no playbook run for path's playbookRunID: %s", playbookRunID)785 h.HandleErrorWithCode(w, http.StatusBadRequest, "no playbook run for path's playbookRunID", err)786 return787 }788 if !h.PermissionsCheck(w, h.permissions.RunManageProperties(userID, storedPlaybookRun.ID)) {789 return790 }791 if err = h.playbookRunService.SetNewReminder(playbookRunID, time.Duration(payload.NewReminderSeconds)*time.Second); err != nil {792 err = errors.Wrapf(err, "reminderReset: error setting new reminder for playbookRunID %s", playbookRunID)793 h.HandleErrorWithCode(w, http.StatusBadRequest, "error removing reminder post", err)794 return795 }796 w.WriteHeader(http.StatusNoContent)797}798func (h *PlaybookRunHandler) noRetrospectiveButton(w http.ResponseWriter, r *http.Request) {799 playbookRunID := mux.Vars(r)["id"]800 userID := r.Header.Get("Mattermost-User-ID")801 playbookRunToCancelRetro, err := h.playbookRunService.GetPlaybookRun(playbookRunID)802 if err != nil {803 h.HandleError(w, err)804 return805 }806 if !h.PermissionsCheck(w, h.permissions.RunManageProperties(userID, playbookRunToCancelRetro.ID)) {807 return808 }809 if err := h.playbookRunService.CancelRetrospective(playbookRunToCancelRetro.ID, userID); err != nil {810 h.HandleErrorWithCode(w, http.StatusInternalServerError, "unable to cancel retrospective", err)811 return812 }813 ReturnJSON(w, nil, http.StatusOK)814}815// removeTimelineEvent handles the DELETE /runs/{id}/timeline/{eventID} endpoint.816// User has been authenticated to edit the playbook run.817func (h *PlaybookRunHandler) removeTimelineEvent(w http.ResponseWriter, r *http.Request) {818 vars := mux.Vars(r)819 id := vars["id"]820 userID := r.Header.Get("Mattermost-User-ID")821 eventID := vars["eventID"]822 if err := h.playbookRunService.RemoveTimelineEvent(id, userID, eventID); err != nil {823 h.HandleError(w, err)824 return825 }826 w.WriteHeader(http.StatusNoContent)827}828func (h *PlaybookRunHandler) updateDescription(w http.ResponseWriter, r *http.Request) {829 playbookRunID := mux.Vars(r)["id"]830 userID := r.Header.Get("Mattermost-User-ID")831 playbookRun, err := h.playbookRunService.GetPlaybookRun(playbookRunID)832 if err != nil {833 h.HandleError(w, err)834 return835 }836 var requestBody struct {837 Description string `json:"description"`838 }839 if err2 := json.NewDecoder(r.Body).Decode(&requestBody); err2 != nil {840 h.HandleErrorWithCode(w, http.StatusBadRequest, "unable to decode playbook run description", err2)841 return842 }843 if !h.PermissionsCheck(w, h.permissions.RunManageProperties(userID, playbookRun.ID)) {844 return845 }846 if err := h.playbookRunService.UpdateDescription(playbookRunID, requestBody.Description); err != nil {847 h.HandleErrorWithCode(w, http.StatusInternalServerError, "unable to update description", err)848 return849 }850 ReturnJSON(w, nil, http.StatusOK)851}852func (h *PlaybookRunHandler) getChecklistAutocompleteItem(w http.ResponseWriter, r *http.Request) {853 query := r.URL.Query()854 channelID := query.Get("channel_id")855 userID := r.Header.Get("Mattermost-User-ID")856 if !h.PermissionsCheck(w, h.permissions.RunViewByChannel(userID, channelID)) {857 return858 }859 playbookRunID, err := h.playbookRunService.GetPlaybookRunIDForChannel(channelID)860 if err != nil {861 h.HandleError(w, err)862 return863 }864 data, err := h.playbookRunService.GetChecklistItemAutocomplete(playbookRunID)865 if err != nil {866 h.HandleError(w, err)867 return868 }869 ReturnJSON(w, data, http.StatusOK)870}871func (h *PlaybookRunHandler) getChecklistAutocomplete(w http.ResponseWriter, r *http.Request) {872 query := r.URL.Query()873 channelID := query.Get("channel_id")874 userID := r.Header.Get("Mattermost-User-ID")875 if !h.PermissionsCheck(w, h.permissions.RunViewByChannel(userID, channelID)) {876 return877 }878 playbookRunID, err := h.playbookRunService.GetPlaybookRunIDForChannel(channelID)879 if err != nil {880 h.HandleError(w, err)881 return882 }883 data, err := h.playbookRunService.GetChecklistAutocomplete(playbookRunID)884 if err != nil {885 h.HandleError(w, err)886 return887 }888 ReturnJSON(w, data, http.StatusOK)889}890func (h *PlaybookRunHandler) itemSetState(w http.ResponseWriter, r *http.Request) {891 vars := mux.Vars(r)892 id := vars["id"]893 checklistNum, err := strconv.Atoi(vars["checklist"])894 if err != nil {895 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse checklist", err)896 return897 }898 itemNum, err := strconv.Atoi(vars["item"])899 if err != nil {900 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse item", err)901 return902 }903 userID := r.Header.Get("Mattermost-User-ID")904 var params struct {905 NewState string `json:"new_state"`906 }907 if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil {908 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to unmarshal", err)909 return910 }911 if !app.IsValidChecklistItemState(params.NewState) {912 h.HandleErrorWithCode(w, http.StatusBadRequest, "bad parameter new state", nil)913 return914 }915 if err := h.playbookRunService.ModifyCheckedState(id, userID, params.NewState, checklistNum, itemNum); err != nil {916 h.HandleError(w, err)917 return918 }919 ReturnJSON(w, map[string]interface{}{}, http.StatusOK)920}921func (h *PlaybookRunHandler) itemSetAssignee(w http.ResponseWriter, r *http.Request) {922 vars := mux.Vars(r)923 id := vars["id"]924 checklistNum, err := strconv.Atoi(vars["checklist"])925 if err != nil {926 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse checklist", err)927 return928 }929 itemNum, err := strconv.Atoi(vars["item"])930 if err != nil {931 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse item", err)932 return933 }934 userID := r.Header.Get("Mattermost-User-ID")935 var params struct {936 AssigneeID string `json:"assignee_id"`937 }938 if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil {939 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to unmarshal", err)940 return941 }942 if err := h.playbookRunService.SetAssignee(id, userID, params.AssigneeID, checklistNum, itemNum); err != nil {943 h.HandleError(w, err)944 return945 }946 ReturnJSON(w, map[string]interface{}{}, http.StatusOK)947}948func (h *PlaybookRunHandler) itemSetDueDate(w http.ResponseWriter, r *http.Request) {949 vars := mux.Vars(r)950 id := vars["id"]951 checklistNum, err := strconv.Atoi(vars["checklist"])952 if err != nil {953 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse checklist", err)954 return955 }956 itemNum, err := strconv.Atoi(vars["item"])957 if err != nil {958 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse item", err)959 return960 }961 userID := r.Header.Get("Mattermost-User-ID")962 var params struct {963 DueDate int64 `json:"due_date"`964 }965 if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil {966 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to unmarshal", err)967 return968 }969 if err := h.playbookRunService.SetDueDate(id, userID, params.DueDate, checklistNum, itemNum); err != nil {970 h.HandleError(w, err)971 return972 }973 ReturnJSON(w, map[string]interface{}{}, http.StatusOK)974}975func (h *PlaybookRunHandler) itemSetCommand(w http.ResponseWriter, r *http.Request) {976 vars := mux.Vars(r)977 id := vars["id"]978 checklistNum, err := strconv.Atoi(vars["checklist"])979 if err != nil {980 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse checklist", err)981 return982 }983 itemNum, err := strconv.Atoi(vars["item"])984 if err != nil {985 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse item", err)986 return987 }988 userID := r.Header.Get("Mattermost-User-ID")989 var params struct {990 Command string `json:"command"`991 }992 if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil {993 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to unmarshal", err)994 return995 }996 if err := h.playbookRunService.SetCommandToChecklistItem(id, userID, checklistNum, itemNum, params.Command); err != nil {997 h.HandleError(w, err)998 return999 }1000 ReturnJSON(w, map[string]interface{}{}, http.StatusOK)1001}1002func (h *PlaybookRunHandler) itemRun(w http.ResponseWriter, r *http.Request) {1003 vars := mux.Vars(r)1004 playbookRunID := vars["id"]1005 checklistNum, err := strconv.Atoi(vars["checklist"])1006 if err != nil {1007 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse checklist", err)1008 return1009 }1010 itemNum, err := strconv.Atoi(vars["item"])1011 if err != nil {1012 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse item", err)1013 return1014 }1015 userID := r.Header.Get("Mattermost-User-ID")1016 triggerID, err := h.playbookRunService.RunChecklistItemSlashCommand(playbookRunID, userID, checklistNum, itemNum)1017 if err != nil {1018 h.HandleError(w, err)1019 return1020 }1021 ReturnJSON(w, map[string]interface{}{"trigger_id": triggerID}, http.StatusOK)1022}1023func (h *PlaybookRunHandler) itemDuplicate(w http.ResponseWriter, r *http.Request) {1024 vars := mux.Vars(r)1025 playbookRunID := vars["id"]1026 checklistNum, err := strconv.Atoi(vars["checklist"])1027 if err != nil {1028 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse checklist", err)1029 return1030 }1031 itemNum, err := strconv.Atoi(vars["item"])1032 if err != nil {1033 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse item", err)1034 return1035 }1036 userID := r.Header.Get("Mattermost-User-ID")1037 if err := h.playbookRunService.DuplicateChecklistItem(playbookRunID, userID, checklistNum, itemNum); err != nil {1038 h.HandleError(w, err)1039 return1040 }1041 w.WriteHeader(http.StatusCreated)1042}1043func (h *PlaybookRunHandler) addChecklist(w http.ResponseWriter, r *http.Request) {1044 vars := mux.Vars(r)1045 id := vars["id"]1046 userID := r.Header.Get("Mattermost-User-ID")1047 var checklist app.Checklist1048 if err := json.NewDecoder(r.Body).Decode(&checklist); err != nil {1049 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to decode Checklist", err)1050 return1051 }1052 checklist.Title = strings.TrimSpace(checklist.Title)1053 if checklist.Title == "" {1054 h.HandleErrorWithCode(w, http.StatusBadRequest, "bad parameter: checklist title",1055 errors.New("checklist title must not be blank"))1056 return1057 }1058 if err := h.playbookRunService.AddChecklist(id, userID, checklist); err != nil {1059 h.HandleError(w, err)1060 return1061 }1062 w.WriteHeader(http.StatusCreated)1063}1064func (h *PlaybookRunHandler) removeChecklist(w http.ResponseWriter, r *http.Request) {1065 vars := mux.Vars(r)1066 id := vars["id"]1067 checklistNum, err := strconv.Atoi(vars["checklist"])1068 if err != nil {1069 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse checklist", err)1070 return1071 }1072 userID := r.Header.Get("Mattermost-User-ID")1073 if err := h.playbookRunService.RemoveChecklist(id, userID, checklistNum); err != nil {1074 h.HandleError(w, err)1075 return1076 }1077 w.WriteHeader(http.StatusCreated)1078}1079func (h *PlaybookRunHandler) addChecklistItem(w http.ResponseWriter, r *http.Request) {1080 vars := mux.Vars(r)1081 id := vars["id"]1082 checklistNum, err := strconv.Atoi(vars["checklist"])1083 if err != nil {1084 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse checklist", err)1085 return1086 }1087 userID := r.Header.Get("Mattermost-User-ID")1088 var checklistItem app.ChecklistItem1089 if err := json.NewDecoder(r.Body).Decode(&checklistItem); err != nil {1090 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to decode ChecklistItem", err)1091 return1092 }1093 checklistItem.Title = strings.TrimSpace(checklistItem.Title)1094 if checklistItem.Title == "" {1095 h.HandleErrorWithCode(w, http.StatusBadRequest, "bad parameter: checklist item title",1096 errors.New("checklist item title must not be blank"))1097 return1098 }1099 if err := h.playbookRunService.AddChecklistItem(id, userID, checklistNum, checklistItem); err != nil {1100 h.HandleError(w, err)1101 return1102 }1103 w.WriteHeader(http.StatusCreated)1104}1105// addChecklistItemDialog handles the interactive dialog submission when a user clicks add new task1106func (h *PlaybookRunHandler) addChecklistItemDialog(w http.ResponseWriter, r *http.Request) {1107 userID := r.Header.Get("Mattermost-User-ID")1108 vars := mux.Vars(r)1109 playbookRunID := vars["id"]1110 checklistNum, err := strconv.Atoi(vars["checklist"])1111 if err != nil {1112 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse checklist", err)1113 return1114 }1115 var request *model.SubmitDialogRequest1116 err = json.NewDecoder(r.Body).Decode(&request)1117 if err != nil || request == nil {1118 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to decode SubmitDialogRequest", err)1119 return1120 }1121 if userID != request.UserId {1122 h.HandleErrorWithCode(w, http.StatusBadRequest, "interactive dialog's userID must be the same as the requester's userID", nil)1123 return1124 }1125 var name, description string1126 if rawName, ok := request.Submission[app.DialogFieldItemNameKey].(string); ok {1127 name = rawName1128 }1129 if rawDescription, ok := request.Submission[app.DialogFieldItemDescriptionKey].(string); ok {1130 description = rawDescription1131 }1132 checklistItem := app.ChecklistItem{1133 Title: name,1134 Description: description,1135 }1136 checklistItem.Title = strings.TrimSpace(checklistItem.Title)1137 if checklistItem.Title == "" {1138 h.HandleErrorWithCode(w, http.StatusBadRequest, "bad parameter: checklist item title",1139 errors.New("checklist item title must not be blank"))1140 return1141 }1142 if err := h.playbookRunService.AddChecklistItem(playbookRunID, userID, checklistNum, checklistItem); err != nil {1143 h.HandleError(w, err)1144 return1145 }1146 w.WriteHeader(http.StatusOK)1147}1148func (h *PlaybookRunHandler) itemDelete(w http.ResponseWriter, r *http.Request) {1149 vars := mux.Vars(r)1150 id := vars["id"]1151 checklistNum, err := strconv.Atoi(vars["checklist"])1152 if err != nil {1153 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse checklist", err)1154 return1155 }1156 itemNum, err := strconv.Atoi(vars["item"])1157 if err != nil {1158 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse item", err)1159 return1160 }1161 userID := r.Header.Get("Mattermost-User-ID")1162 if err := h.playbookRunService.RemoveChecklistItem(id, userID, checklistNum, itemNum); err != nil {1163 h.HandleError(w, err)1164 return1165 }1166 w.WriteHeader(http.StatusNoContent)1167}1168func (h *PlaybookRunHandler) itemSkip(w http.ResponseWriter, r *http.Request) {1169 vars := mux.Vars(r)1170 id := vars["id"]1171 checklistNum, err := strconv.Atoi(vars["checklist"])1172 if err != nil {1173 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse checklist", err)1174 return1175 }1176 itemNum, err := strconv.Atoi(vars["item"])1177 if err != nil {1178 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse item", err)1179 return1180 }1181 userID := r.Header.Get("Mattermost-User-ID")1182 if err := h.playbookRunService.SkipChecklistItem(id, userID, checklistNum, itemNum); err != nil {1183 h.HandleError(w, err)1184 return1185 }1186 w.WriteHeader(http.StatusNoContent)1187}1188func (h *PlaybookRunHandler) itemRestore(w http.ResponseWriter, r *http.Request) {1189 vars := mux.Vars(r)1190 id := vars["id"]1191 checklistNum, err := strconv.Atoi(vars["checklist"])1192 if err != nil {1193 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse checklist", err)1194 return1195 }1196 itemNum, err := strconv.Atoi(vars["item"])1197 if err != nil {1198 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse item", err)1199 return1200 }1201 userID := r.Header.Get("Mattermost-User-ID")1202 if err := h.playbookRunService.RestoreChecklistItem(id, userID, checklistNum, itemNum); err != nil {1203 h.HandleError(w, err)1204 return1205 }1206 w.WriteHeader(http.StatusNoContent)1207}1208func (h *PlaybookRunHandler) itemEdit(w http.ResponseWriter, r *http.Request) {1209 vars := mux.Vars(r)1210 id := vars["id"]1211 checklistNum, err := strconv.Atoi(vars["checklist"])1212 if err != nil {1213 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse checklist", err)1214 return1215 }1216 itemNum, err := strconv.Atoi(vars["item"])1217 if err != nil {1218 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse item", err)1219 return1220 }1221 userID := r.Header.Get("Mattermost-User-ID")1222 var params struct {1223 Title string `json:"title"`1224 Command string `json:"command"`1225 Description string `json:"description"`1226 }1227 if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil {1228 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to unmarshal edit params state", err)1229 return1230 }1231 if err := h.playbookRunService.EditChecklistItem(id, userID, checklistNum, itemNum, params.Title, params.Command, params.Description); err != nil {1232 h.HandleError(w, err)1233 return1234 }1235 w.WriteHeader(http.StatusOK)1236}1237func (h *PlaybookRunHandler) renameChecklist(w http.ResponseWriter, r *http.Request) {1238 vars := mux.Vars(r)1239 id := vars["id"]1240 checklistNum, err := strconv.Atoi(vars["checklist"])1241 if err != nil {1242 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to parse checklist", err)1243 return1244 }1245 userID := r.Header.Get("Mattermost-User-ID")1246 var modificationParams struct {1247 NewTitle string `json:"title"`1248 }1249 if err := json.NewDecoder(r.Body).Decode(&modificationParams); err != nil {1250 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to unmarshal new title", err)1251 return1252 }1253 if modificationParams.NewTitle == "" {1254 h.HandleErrorWithCode(w, http.StatusBadRequest, "bad parameter: checklist title",1255 errors.New("checklist title must not be blank"))1256 return1257 }1258 if err := h.playbookRunService.RenameChecklist(id, userID, checklistNum, modificationParams.NewTitle); err != nil {1259 h.HandleError(w, err)1260 return1261 }1262 w.WriteHeader(http.StatusOK)1263}1264func (h *PlaybookRunHandler) moveChecklist(w http.ResponseWriter, r *http.Request) {1265 vars := mux.Vars(r)1266 id := vars["id"]1267 userID := r.Header.Get("Mattermost-User-ID")1268 var params struct {1269 SourceChecklistIdx int `json:"source_checklist_idx"`1270 DestChecklistIdx int `json:"dest_checklist_idx"`1271 }1272 if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil {1273 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to unmarshal edit params", err)1274 return1275 }1276 if err := h.playbookRunService.MoveChecklist(id, userID, params.SourceChecklistIdx, params.DestChecklistIdx); err != nil {1277 h.HandleError(w, err)1278 return1279 }1280 w.WriteHeader(http.StatusOK)1281}1282func (h *PlaybookRunHandler) moveChecklistItem(w http.ResponseWriter, r *http.Request) {1283 vars := mux.Vars(r)1284 id := vars["id"]1285 userID := r.Header.Get("Mattermost-User-ID")1286 var params struct {1287 SourceChecklistIdx int `json:"source_checklist_idx"`1288 SourceItemIdx int `json:"source_item_idx"`1289 DestChecklistIdx int `json:"dest_checklist_idx"`1290 DestItemIdx int `json:"dest_item_idx"`1291 }1292 if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil {1293 h.HandleErrorWithCode(w, http.StatusBadRequest, "failed to unmarshal edit params", err)1294 return1295 }1296 if err := h.playbookRunService.MoveChecklistItem(id, userID, params.SourceChecklistIdx, params.SourceItemIdx, params.DestChecklistIdx, params.DestItemIdx); err != nil {1297 h.HandleError(w, err)1298 return1299 }1300 w.WriteHeader(http.StatusOK)1301}1302func (h *PlaybookRunHandler) postPlaybookRunCreatedMessage(playbookRun *app.PlaybookRun, channelID string) error {1303 channel, err := h.pluginAPI.Channel.Get(playbookRun.ChannelID)1304 if err != nil {1305 return err1306 }1307 post := &model.Post{1308 Message: fmt.Sprintf("Playbook run %s started in ~%s", playbookRun.Name, channel.Name),1309 }1310 h.poster.EphemeralPost(playbookRun.OwnerUserID, channelID, post)1311 return nil1312}1313func (h *PlaybookRunHandler) updateRetrospective(w http.ResponseWriter, r *http.Request) {1314 vars := mux.Vars(r)1315 playbookRunID := vars["id"]1316 userID := r.Header.Get("Mattermost-User-ID")1317 var retroUpdate app.RetrospectiveUpdate1318 if err := json.NewDecoder(r.Body).Decode(&retroUpdate); err != nil {1319 h.HandleErrorWithCode(w, http.StatusBadRequest, "unable to decode payload", err)1320 return1321 }1322 if err := h.playbookRunService.UpdateRetrospective(playbookRunID, userID, retroUpdate); err != nil {1323 h.HandleErrorWithCode(w, http.StatusInternalServerError, "unable to update retrospective", err)1324 return1325 }1326 w.WriteHeader(http.StatusOK)1327}1328func (h *PlaybookRunHandler) publishRetrospective(w http.ResponseWriter, r *http.Request) {1329 vars := mux.Vars(r)1330 playbookRunID := vars["id"]1331 userID := r.Header.Get("Mattermost-User-ID")1332 var retroUpdate app.RetrospectiveUpdate1333 if err := json.NewDecoder(r.Body).Decode(&retroUpdate); err != nil {1334 h.HandleErrorWithCode(w, http.StatusBadRequest, "unable to decode payload", err)1335 return1336 }1337 if err := h.playbookRunService.PublishRetrospective(playbookRunID, userID, retroUpdate); err != nil {1338 h.HandleErrorWithCode(w, http.StatusInternalServerError, "unable to publish retrospective", err)1339 return1340 }1341 w.WriteHeader(http.StatusOK)1342}1343func (h *PlaybookRunHandler) follow(w http.ResponseWriter, r *http.Request) {1344 playbookRunID := mux.Vars(r)["id"]1345 userID := r.Header.Get("Mattermost-User-ID")1346 if !h.PermissionsCheck(w, h.permissions.RunView(userID, playbookRunID)) {1347 return1348 }1349 if err := h.playbookRunService.Follow(playbookRunID, userID); err != nil {1350 h.HandleError(w, err)1351 return1352 }1353 w.WriteHeader(http.StatusOK)1354}1355func (h *PlaybookRunHandler) unfollow(w http.ResponseWriter, r *http.Request) {1356 playbookRunID := mux.Vars(r)["id"]1357 userID := r.Header.Get("Mattermost-User-ID")1358 if err := h.playbookRunService.Unfollow(playbookRunID, userID); err != nil {1359 h.HandleError(w, err)1360 return1361 }1362 w.WriteHeader(http.StatusOK)1363}1364func (h *PlaybookRunHandler) getFollowers(w http.ResponseWriter, r *http.Request) {1365 playbookRunID := mux.Vars(r)["id"]1366 userID := r.Header.Get("Mattermost-User-ID")1367 if !h.PermissionsCheck(w, h.permissions.RunView(userID, playbookRunID)) {1368 return1369 }1370 var followers []string1371 var err error1372 if followers, err = h.playbookRunService.GetFollowers(playbookRunID); err != nil {1373 h.HandleError(w, err)1374 return1375 }1376 ReturnJSON(w, followers, http.StatusOK)1377}1378// parsePlaybookRunsFilterOptions is only for parsing. Put validation logic in app.validateOptions.1379func parsePlaybookRunsFilterOptions(u *url.URL, currentUserID string) (*app.PlaybookRunFilterOptions, error) {1380 teamID := u.Query().Get("team_id")1381 pageParam := u.Query().Get("page")1382 if pageParam == "" {1383 pageParam = "0"1384 }1385 page, err := strconv.Atoi(pageParam)1386 if err != nil {1387 return nil, errors.Wrapf(err, "bad parameter 'page'")1388 }1389 perPageParam := u.Query().Get("per_page")1390 if perPageParam == "" {1391 perPageParam = "0"1392 }1393 perPage, err := strconv.Atoi(perPageParam)1394 if err != nil {1395 return nil, errors.Wrapf(err, "bad parameter 'per_page'")1396 }1397 sort := u.Query().Get("sort")1398 direction := u.Query().Get("direction")1399 // Parse statuses= query string parameters as an array.1400 statuses := u.Query()["statuses"]1401 ownerID := u.Query().Get("owner_user_id")1402 if ownerID == client.Me {1403 ownerID = currentUserID1404 }1405 searchTerm := u.Query().Get("search_term")1406 participantID := u.Query().Get("participant_id")1407 if participantID == client.Me {1408 participantID = currentUserID1409 }1410 participantOrFollowerID := u.Query().Get("participant_or_follower_id")1411 if participantOrFollowerID == client.Me {1412 participantOrFollowerID = currentUserID1413 }1414 playbookID := u.Query().Get("playbook_id")1415 activeGTEParam := u.Query().Get("active_gte")1416 if activeGTEParam == "" {1417 activeGTEParam = "0"1418 }1419 activeGTE, _ := strconv.ParseInt(activeGTEParam, 10, 64)1420 activeLTParam := u.Query().Get("active_lt")1421 if activeLTParam == "" {1422 activeLTParam = "0"1423 }1424 activeLT, _ := strconv.ParseInt(activeLTParam, 10, 64)1425 startedGTEParam := u.Query().Get("started_gte")1426 if startedGTEParam == "" {1427 startedGTEParam = "0"1428 }1429 startedGTE, _ := strconv.ParseInt(startedGTEParam, 10, 64)1430 startedLTParam := u.Query().Get("started_lt")1431 if startedLTParam == "" {1432 startedLTParam = "0"1433 }1434 startedLT, _ := strconv.ParseInt(startedLTParam, 10, 64)1435 options := app.PlaybookRunFilterOptions{1436 TeamID: teamID,1437 Page: page,1438 PerPage: perPage,1439 Sort: app.SortField(sort),1440 Direction: app.SortDirection(direction),1441 Statuses: statuses,1442 OwnerID: ownerID,1443 SearchTerm: searchTerm,1444 ParticipantID: participantID,1445 ParticipantOrFollowerID: participantOrFollowerID,1446 PlaybookID: playbookID,1447 ActiveGTE: activeGTE,1448 ActiveLT: activeLT,1449 StartedGTE: startedGTE,...
gin_integration_test.go
Source:gin_integration_test.go
...19 assert.NoError(t, ioerr)20 assert.Equal(t, "it worked", string(body), "resp body should match")21 assert.Equal(t, "200 OK", resp.Status, "should get a 200")22}23func TestRunEmpty(t *testing.T) {24 os.Setenv("PORT", "")25 router := New()26 go func() {27 router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })28 assert.NoError(t, router.Run())29 }()30 // have to wait for the goroutine to start and run the server31 // otherwise the main thread will complete32 time.Sleep(5 * time.Millisecond)33 assert.Error(t, router.Run(":8080"))34 testRequest(t, "http://localhost:8080/example")35}36func TestRunEmptyWithEnv(t *testing.T) {37 os.Setenv("PORT", "3123")38 router := New()39 go func() {40 router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })41 assert.NoError(t, router.Run())42 }()43 // have to wait for the goroutine to start and run the server44 // otherwise the main thread will complete45 time.Sleep(5 * time.Millisecond)46 assert.Error(t, router.Run(":3123"))47 testRequest(t, "http://localhost:3123/example")48}49func TestRunTooMuchParams(t *testing.T) {50 router := New()51 assert.Panics(t, func() {52 router.Run("2", "2")53 })54}55func TestRunWithPort(t *testing.T) {56 router := New()57 go func() {58 router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })59 assert.NoError(t, router.Run(":5150"))60 }()61 // have to wait for the goroutine to start and run the server62 // otherwise the main thread will complete63 time.Sleep(5 * time.Millisecond)64 assert.Error(t, router.Run(":5150"))65 testRequest(t, "http://localhost:5150/example")66}67func TestUnixSocket(t *testing.T) {68 router := New()69 go func() {70 router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })71 assert.NoError(t, router.RunUnix("/tmp/unix_unit_test"))72 }()73 // have to wait for the goroutine to start and run the server74 // otherwise the main thread will complete75 time.Sleep(5 * time.Millisecond)76 c, err := net.Dial("unix", "/tmp/unix_unit_test")77 assert.NoError(t, err)78 fmt.Fprintf(c, "GET /example HTTP/1.0\r\n\r\n")79 scanner := bufio.NewScanner(c)80 var response string81 for scanner.Scan() {82 response += scanner.Text()83 }84 assert.Contains(t, response, "HTTP/1.0 200", "should get a 200")85 assert.Contains(t, response, "it worked", "resp body should match")86}87func TestBadUnixSocket(t *testing.T) {88 router := New()89 assert.Error(t, router.RunUnix("#/tmp/unix_unit_test"))90}91func TestWithHttptestWithAutoSelectedPort(t *testing.T) {92 router := New()93 router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })94 ts := httptest.NewServer(router)95 defer ts.Close()96 testRequest(t, ts.URL+"/example")97}98func TestWithHttptestWithSpecifiedPort(t *testing.T) {99 router := New()100 router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })101 l, _ := net.Listen("tcp", ":8033")102 ts := httptest.Server{103 Listener: l,...
Run
Using AI Code Generation
1import (2func main() {3 http.HandleFunc("/", handler)4 http.ListenAndServe(":8080", nil)5}6func handler(w http.ResponseWriter, r *http.Request) {7 fmt.Fprintf(w, "Hello World")8}9import (10func main() {11 http.HandleFunc("/", handler)12 http.ListenAndServe(":8080", nil)13}14func handler(w http.ResponseWriter, r *http.Request) {15 fmt.Fprintf(w, "Hello World")16}17import (18func main() {19 http.HandleFunc("/", handler)20 http.ListenAndServe(":8080", nil)21}22func handler(w http.ResponseWriter, r *http.Request) {23 fmt.Fprintf(w, "Hello World")24}25import (26func main() {27 http.HandleFunc("/", handler)28 http.ListenAndServe(":8080", nil)29}30func handler(w http.ResponseWriter, r *http.Request) {31 fmt.Fprintf(w, "Hello World")32}33import (34func main() {35 http.HandleFunc("/", handler)36 http.ListenAndServe(":8080", nil)37}38func handler(w http.ResponseWriter, r *http.Request) {39 fmt.Fprintf(w, "Hello World")40}41import (42func main() {43 http.HandleFunc("/", handler)44 http.ListenAndServe(":8080", nil)45}46func handler(w http.ResponseWriter, r *http.Request) {47 fmt.Fprintf(w, "Hello World")48}49import (50func main() {51 http.HandleFunc("/", handler)52 http.ListenAndServe(":8080", nil)53}54func handler(w http.ResponseWriter, r *http.Request) {
Run
Using AI Code Generation
1import (2func main() {3 http.HandleFunc("/", handler)4 http.ListenAndServe(":8080", nil)5}6func handler(w http.ResponseWriter, r *http.Request) {7 fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])8}9import (10func main() {11 http.HandleFunc("/", handler)12 http.ListenAndServe(":8080", nil)13}14func handler(w http.ResponseWriter, r *http.Request) {15 fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])16}17import (18func main() {19 http.HandleFunc("/", handler)20 http.ListenAndServe(":8080", nil)21}22func handler(w http.ResponseWriter, r *http.Request) {23 fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])24}25import (26func main() {27 http.HandleFunc("/", handler)28 http.ListenAndServe(":8080", nil)29}30func handler(w http.ResponseWriter, r *http.Request) {31 fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])32}33import (34func main() {35 http.HandleFunc("/", handler)36 http.ListenAndServe(":8080", nil)37}38func handler(w http.ResponseWriter, r *http.Request) {39 fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])40}41import (42func main() {43 http.HandleFunc("/", handler)44 http.ListenAndServe(":8080", nil)45}46func handler(w http.ResponseWriter, r *http.Request) {47 fmt.Fprintf(w,
Run
Using AI Code Generation
1import (2func main() {3 http.HandleFunc("/", handler)4 http.ListenAndServe(":8080", nil)5}6func handler(w http.ResponseWriter, r *http.Request) {7 w.Write([]byte("Hello World"))8}9import (10func main() {11 http.HandleFunc("/", handler)12 http.ListenAndServe(":8080", nil)13}14func handler(w http.ResponseWriter, r *http.Request) {15 w.Write([]byte("Hello World"))16}17import (18func main() {19 http.HandleFunc("/", handler)20 http.ListenAndServe(":8080", nil)21}22func handler(w http.ResponseWriter, r *http.Request) {23 w.Write([]byte("Hello World"))24}25import (26func main() {27 http.HandleFunc("/", handler)28 http.ListenAndServe(":8080", nil)29}30func handler(w http.ResponseWriter, r *http.Request) {31 w.Write([]byte("Hello World"))32}33import (34func main() {35 http.HandleFunc("/", handler)36 http.ListenAndServe(":8080", nil)37}38func handler(w http.ResponseWriter, r *http.Request) {39 w.Write([]byte("Hello World"))40}41import (42func main() {43 http.HandleFunc("/", handler)44 http.ListenAndServe(":8080", nil)45}46func handler(w http.ResponseWriter, r *http.Request) {47 w.Write([]byte("Hello World"))48}49import (50func main() {51 http.HandleFunc("/", handler)52 http.ListenAndServe(":8080", nil)53}54func handler(w http.ResponseWriter, r *http.Request) {55 w.Write([]byte("Hello World"))56}
Run
Using AI Code Generation
1import (2func main() {3 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {4 fmt.Fprintf(w, "Hello, %q", r.URL.Path)5 })6 http.ListenAndServe(":8080", nil)7}8import (9func main() {10 http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {11 fmt.Fprintf(w, "Hello, %q", r.URL.Path)12 }))13 http.ListenAndServe(":8080", nil)14}15import (16func main() {17 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {18 fmt.Fprintf(w, "Hello, %q", r.URL.Path)19 })20 http.ListenAndServe(":8080", nil)21}22import (23func main() {24 http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {25 fmt.Fprintf(w, "Hello, %q", r.URL.Path)26 }))27 http.ListenAndServe(":8080", nil)28}29import (30func main() {31 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {32 fmt.Fprintf(w, "Hello, %q", r.URL.Path)33 })34 http.ListenAndServe(":8080", nil
Run
Using AI Code Generation
1import (2func main() {3 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {4 fmt.Fprintf(w, "Hello, you've requested: %s5 })6 http.ListenAndServe(":8080", nil)7}8import (9func main() {10 mux := http.NewServeMux()11 mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {12 fmt.Fprintf(w, "Hello, you've requested: %s13 })14 http.ListenAndServe(":8080", mux)15}16import (17func main() {18 http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {19 fmt.Fprintf(w, "Hello, you've requested: %s20 }))21 http.ListenAndServe(":8080", nil)22}23import (24func main() {25 mux := http.NewServeMux()26 mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {27 fmt.Fprintf(w, "Hello, you've requested: %s28 })29 http.ListenAndServe(":8080", mux)30}31import (32func main() {33 mux := http.NewServeMux()34 mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {35 fmt.Fprintf(w, "Hello, you've requested: %s36 })37 http.ListenAndServe(":8080", mux)38}39import (40func main() {41 mux := http.NewServeMux()42 mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
Run
Using AI Code Generation
1import "net/http"2import "fmt"3func main() {4 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {5 fmt.Fprintf(w, "Hello, you've requested: %s6 })7 http.ListenAndServe(":8080", nil)8}9import "net/http"10import "fmt"11func main() {12 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {13 fmt.Fprintf(w, "Hello, you've requested: %s14 })15 http.ListenAndServe(":8080", nil)16}17import "net/http"18import "fmt"19func main() {20 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {21 fmt.Fprintf(w, "Hello, you've requested: %s22 })23 http.ListenAndServe(":8080", nil)24}25import "net/http"26import "fmt"27func main() {28 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {29 fmt.Fprintf(w, "Hello, you've requested: %s30 })31 http.ListenAndServe(":8080", nil)32}33import "net/http"34import "fmt"35func main() {36 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {37 fmt.Fprintf(w, "Hello, you've requested: %s38 })39 http.ListenAndServe(":8080", nil)40}41import "net/http"42import "fmt"43func main() {44 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {45 fmt.Fprintf(w, "Hello, you've requested: %s46 })47 http.ListenAndServe(":8080", nil)48}49import "net/http"50import "fmt"51func main() {52 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
Run
Using AI Code Generation
1import "net/http"2func main() {3http.ListenAndServe(":8080", nil)4}5import (6func main() {7err := http.ListenAndServe(":8080", nil)8if err != nil {9log.Fatal(err)10}11}12import (13func main() {14err := http.ListenAndServe(":8080", nil)15if err != nil {16log.Fatal(err)17}18}19import (20func main() {21err := http.ListenAndServe(":8080", nil)22if err != nil {23log.Fatal(err)24}25}26import (27func main() {28err := http.ListenAndServe(":8080", nil)29if err != nil {30log.Fatal(err)31}32}33import (34func main() {35err := http.ListenAndServe(":8080", nil)36if err != nil {37log.Fatal(err)38}39}40import (41func main() {42err := http.ListenAndServe(":8080", nil)43if err != nil {44log.Fatal(err)45}46}47import (48func main() {49err := http.ListenAndServe(":8080", nil)50if err != nil {51log.Fatal(err)52}53}54import (55func main() {56err := http.ListenAndServe(":8080", nil)57if err != nil {58log.Fatal(err)59}60}61import (62func main() {63err := http.ListenAndServe(":8080", nil)
Run
Using AI Code Generation
1import (2func main() {3 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {4 fmt.Fprintf(w, "Hello World")5 })6 http.ListenAndServe(":8080", nil)7}8import (9func main() {10 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {11 http.ServeFile(w, r, "index.html")12 })13 http.ListenAndServe(":8080", nil)14}15import (16func main() {17 mux := http.NewServeMux()18 mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {19 fmt.Fprintf(w, "Hello World")20 })21 http.ListenAndServe(":8080", mux)22}23import (24type MyHandler struct{}25func main() {26 http.Handle("/", new(MyHandler))27 http.ListenAndServe(":8080", nil)28}29func (this *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {30 fmt.Fprintf(w, "Hello World")31}32import (33type MyHandler struct{}34func main() {35 http.Handle("/", new(MyHandler))36 http.ListenAndServe(":8080", nil)37}38func (this *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {39 fmt.Fprintf(w, "Hello World")40}
Run
Using AI Code Generation
1import (2func main(){3 http.HandleFunc("/", index)4 http.HandleFunc("/about", about)5 http.HandleFunc("/contact", contact)6 http.HandleFunc("/apply", apply)7 http.ListenAndServe(":8080", nil)8}9func index(w http.ResponseWriter, r *http.Request){10 io.WriteString(w, "Welcome to my website!")11}12func about(w http.ResponseWriter, r *http.Request){13 io.WriteString(w, "About us")14}15func contact(w http.ResponseWriter, r *http.Request){16 io.WriteString(w, "Contact us")17}18func apply(w http.ResponseWriter, r *http.Request){19 io.WriteString(w, "Apply here")20}
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!