Snippets Collections
-- RISK292
-- if in previous 24 hours distinct( lat,long)>=50 then block. Lat long in round 1
DROP TABLE team_kingkong.tpap_risk292_breaches;

-- CREATE TABLE team_kingkong.tpap_risk292_breaches AS
INSERT INTO team_kingkong.tpap_risk292_breaches
with tpap_base as
(
SELECT DISTINCT B.*, C.category
, IF(D.upi_subtype IS NOT NULL, D.upi_subtype, IF(C.category = 'LITE_MANDATE', 'UPI_LITE_MANDATE', '')) AS upi_subtype
, D.latitude, D.longitude
FROM
    (SELECT txn_id,
    MAX(CASE WHEN participant_type = 'PAYER' THEN vpa END) AS payer_vpa,
    MAX(CASE WHEN participant_type = 'PAYEE' THEN vpa END) AS payee_vpa,
    MAX(DATE(created_on)) as txn_date,
    MAX(amount) AS txn_amount,
    MAX(created_on) AS txn_time
    FROM switch.txn_participants_snapshot_v3
    WHERE DATE(dl_last_updated) BETWEEN DATE(DATE'2025-01-01'- INTERVAL '2' DAY) AND DATE'2025-01-31'
    AND DATE(created_on) BETWEEN DATE(DATE'2025-01-01'- INTERVAL '2' DAY) AND DATE'2025-01-31'
    GROUP BY 1)B
inner join
    (select txn_id, category
    from switch.txn_info_snapshot_v3
    where DATE(dl_last_updated) BETWEEN DATE(DATE'2025-01-01'- INTERVAL '2' DAY) AND DATE'2025-01-31'
    and DATE(created_on) BETWEEN DATE(DATE'2025-01-01'- INTERVAL '2' DAY) AND DATE'2025-01-31'
    and upper(status) = 'SUCCESS' AND category = 'VPA2VPA') C
on B.txn_id = C.txn_id
INNER JOIN
    (SELECT txnid
    , regexp_replace(cast(json_extract(request, '$.evaluationType') as varchar), '"', '') AS upi_subtype
    , regexp_replace(cast(json_extract(request, '$.requestPayload.latitude') as varchar), '"', '') as latitude
    , regexp_replace(cast(json_extract(request, '$.requestPayload.longitude') as varchar), '"', '') as longitude
    FROM tpap_hss.upi_switchv2_dwh_risk_data_snapshot_v3
    WHERE DATE(dl_last_updated) BETWEEN DATE(DATE'2025-01-01'- INTERVAL '2' DAY) AND DATE'2025-01-31'
    AND (lower(regexp_replace(cast(json_extract(request, '$.requestPayload.payerVpa') as varchar), '"', '')) LIKE '%@paytm%'
    or lower(regexp_replace(cast(json_extract(request, '$.requestPayload.payerVpa') as varchar), '"', '')) like '%@pt%')
    AND json_extract_scalar(response, '$.action_recommended') <> 'BLOCK'
    AND regexp_replace(cast(json_extract(request, '$.requestPayload.payerType') AS varchar),'"','') = 'PERSON'
    AND regexp_replace(cast(json_extract(request, '$.requestPayload.payeeType') AS varchar),'"','') = 'PERSON'
    AND regexp_replace(cast(json_extract(request, '$.evaluationType') as varchar), '"', '') = 'UPI_TRANSACTION')D
ON B.txn_id = D.txnid
WHERE ((payer_vpa LIKE '%@paytm%') OR (payer_vpa LIKE '%@pt%'))
AND payee_vpa LIKE '%@%' AND payee_vpa <> 'jio@citibank'
)
 
SELECT *, 'upi_p2p_multiple_locations_rnd_1' as rule_name, 'Multiple sender locations for payee' as breach_reason FROM
    (SELECT t1.payer_vpa,
      t1.payee_vpa,
      t1.txn_id,
      t1.txn_amount,
      t1.category,
      t1.upi_subtype,
      t1.txn_time,
      t1.latitude,
      t1.longitude,
      t1.txn_date,
      COUNT(DISTINCT CONCAT(t2.latitude, '_', t2.longitude)) AS distinct_lat_lon_count,
      50 AS lat_long_cnt_threshold
    FROM tpap_base t1
    INNER JOIN tpap_base t2
    ON t1.payee_vpa = t2.payee_vpa
      AND t2.txn_time BETWEEN (t1.txn_time - INTERVAL '86400' SECOND) AND t1.txn_time -- 24 hrs
      AND t1.txn_id <> t2.txn_id AND t1.txn_date BETWEEN DATE'2025-01-01' AND DATE'2025-01-31'
      AND NOT (t1.latitude = t2.latitude AND t1.longitude = t2.longitude)
    GROUP BY t1.payer_vpa, t1.payee_vpa, t1.txn_id, t1.txn_amount, t1.category, t1.upi_subtype, t1.txn_time, t1.txn_date, t1.latitude, t1.longitude)
WHERE distinct_lat_lon_count >= lat_long_cnt_threshold;
-- RISK_292
-- if in previous 24 hours distinct( lat,long)>=50 then block. Lat long in round 1

-- CREATE TABLE team_kingkong.tpap_risk292_breaches AS
INSERT INTO team_kingkong.tpap_risk292_breaches
with tpap_base as
(
SELECT DISTINCT B.*, C.category
, IF(D.upi_subtype IS NOT NULL, D.upi_subtype, IF(C.category = 'LITE_MANDATE', 'UPI_LITE_MANDATE', '')) AS upi_subtype
, D.latitude, D.longitude
FROM
    (SELECT txn_id, scope_cust_id,
    MAX(CASE WHEN participant_type = 'PAYER' THEN vpa END) AS payer_vpa,
    MAX(CASE WHEN participant_type = 'PAYEE' THEN vpa END) AS payee_vpa,
    MAX(created_on) as txn_date,
    MAX(amount) AS txn_amount,
    created_on AS txn_time
    FROM switch.txn_participants_snapshot_v3
    WHERE DATE(dl_last_updated) BETWEEN DATE(DATE'2025-01-01' - INTERVAL '1' DAY) AND DATE'2025-01-31'
    AND DATE(created_on) BETWEEN DATE(DATE'2025-01-01' - INTERVAL '1' DAY) AND DATE'2025-01-31'
    AND vpa IS NOT NULL
    GROUP BY 1,2,7)B
inner join
    (select txn_id, category
    from switch.txn_info_snapshot_v3
    where DATE(dl_last_updated) BETWEEN DATE(DATE'2025-01-01' - INTERVAL '1' DAY) AND DATE'2025-01-31'
    and DATE(created_on) BETWEEN DATE(DATE'2025-01-01' - INTERVAL '1' DAY) AND DATE'2025-01-31'
    and upper(status) in ('SUCCESS')) C
on B.txn_id = C.txn_id
INNER JOIN
    (SELECT txnid
    , regexp_replace(cast(json_extract(request, '$.evaluationType') as varchar), '"', '') AS upi_subtype
    , regexp_replace(cast(json_extract(request, '$.requestPayload.latitude') as varchar), '"', '') as latitude
    , regexp_replace(cast(json_extract(request, '$.requestPayload.longitude') as varchar), '"', '') as longitude
    FROM tpap_hss.upi_switchv2_dwh_risk_data_snapshot_v3
    WHERE DATE(dl_last_updated) BETWEEN DATE(DATE'2025-01-01' - INTERVAL '1' DAY) AND DATE'2025-01-31'
    AND (lower(regexp_replace(cast(json_extract(request, '$.requestPayload.payerVpa') as varchar), '"', '')) LIKE '%@paytm%'
    or lower(regexp_replace(cast(json_extract(request, '$.requestPayload.payerVpa') as varchar), '"', '')) like '%@pt%')
    AND json_extract_scalar(response, '$.action_recommended') <> 'BLOCK'
    AND regexp_replace(cast(json_extract(request, '$.requestPayload.payerType') AS varchar),'"','') = 'PERSON'
    AND regexp_replace(cast(json_extract(request, '$.requestPayload.payeeType') AS varchar),'"','') = 'PERSON')D
ON B.txn_id = D.txnid
WHERE ((payer_vpa LIKE '%@paytm%') OR (payer_vpa LIKE '%@pt%'))
AND payee_vpa LIKE '%@%' AND payee_vpa <> 'jio@citibank'
AND upi_subtype = 'UPI_TRANSACTION'
)
 
SELECT * FROM
    (SELECT t1.payer_vpa,
      t1.payee_vpa,
      t1.txn_id,
      t1.txn_amount,
      t1.category,
      t1.upi_subtype,
      t1.txn_time,
      t1.latitude,
      t1.longitude,
      DATE(t1.txn_time) AS txn_date,
      COUNT(DISTINCT CONCAT(t2.latitude, '_', t2.longitude)) AS distinct_lat_lon_count,
      50 AS lat_long_cnt_threshold
    FROM tpap_base t1
    INNER JOIN tpap_base t2
    ON t1.payee_vpa = t2.payee_vpa
      AND t2.txn_time BETWEEN (t1.txn_time - INTERVAL '86400' SECOND) AND t1.txn_time -- 24 hrs
      AND t1.txn_id <> t2.txn_id
      AND NOT (t1.latitude = t2.latitude AND t1.longitude = t2.longitude)
    GROUP BY t1.payer_vpa, t1.payee_vpa, t1.txn_id, t1.txn_amount, t1.category, t1.upi_subtype, t1.txn_time, DATE(t1.txn_time), t1.latitude, t1.longitude)
WHERE distinct_lat_lon_count >= lat_long_cnt_threshold
;
PORT=1000
PROXY_ENABLED=false
See_Chane_Web_DB=mongodb://192.168.13.83/See_Chane_Web
MrRight_DB=mongodb://192.168.13.83/MrRight
Rcyc_DB=mongodb://192.168.13.83/Rcyc
See360_DB=mongodb://192.168.13.83/See360
SeeChange_DB=mongodb://192.168.13.83/SeeChange
# MONGODB_URI=mongodb+srv://rishirri108:1234567890@cluster0.qpi4j.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0
MONGODB_MrRight=mongodb+srv://rishirri108:1234567890@cluster0.qpi4j.mongodb.net/MrRight?retryWrites=true&w=majority&appName=Cluster0
MONGODB_Rcyc=mongodb+srv://rishirri108:1234567890@cluster0.qpi4j.mongodb.net/Rcyc?retryWrites=true&w=majority&appName=Cluster0
MONGODB_See360=mongodb+srv://rishirri108:1234567890@cluster0.qpi4j.mongodb.net/See360?retryWrites=true&w=majority&appName=Cluster0
MONGODB_SeeChange=mongodb+srv://rishirri108:1234567890@cluster0.qpi4j.mongodb.net/SeeChange?retryWrites=true&w=majority&appName=Cluster0

JWT_SECRET=Consoul@123
JWT_EXPIRES=1y

#RRI Test
# RAZORPAY_KEY_ID=rzp_test_u85r2jwM23xKlY
# RAZORPAY_KEY_SECRET=0q84vUiUDgL7ikOtM6q8mj8i

# SC
RAZORPAY_KEY_ID=rzp_live_fC8chfUhTHOaxJ
RAZORPAY_KEY_SECRET=TaMjK6BWGR7F9Tn5iE8H5gpx

# ACCESS_TOKEN_SECRET=ghfjbdnsfmaddnbjhdsdgfnadivsbeaiwfagshshagfdwGHTJ
# ACCESS_TOKEN_EXPIRATION=3600s

# REFRESH_TOKEN_SECRET=rtrtffjrteyrjfgncvbxdshrdjhfdggsethfethdgsdssfggzb
# REFRESH_TOKEN_EXPIRATION=1y

# MONGO_URI=mongodb+srv://software:Consoul%401234@appbd.hifbevu.mongodb.net/auth

# FRONTEND_URL=http://localhost:8080

# RECOVER_CODE_EXPIRATION=86400

# REDIS_ENABLED=false
# REDIS_HOST=localhost
# REDIS_PORT=6379




// Disable all core updates
add_filter( 'automatic_updater_disabled', '__return_true' );

// Disable theme updates
remove_action( 'load-update-core.php', 'wp_update_themes' );
add_filter( 'pre_site_transient_update_themes', '__return_null' );

// Disable plugin updates
remove_action( 'load-update-core.php', 'wp_update_plugins' );
add_filter( 'pre_site_transient_update_plugins', '__return_null' );

// Disable automatic updates for plugins
add_filter( 'auto_update_plugin', '__return_false' );

// Disable automatic updates for themes
add_filter( 'auto_update_theme', '__return_false' );

// Disable automatic updates for WordPress core
add_filter( 'auto_update_core', '__return_false' );
{
	"blocks": [
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": ":star: What's on in Melbourne this week! :star:"
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": "\n\n Hey Melbourne, happy Monday and hope you all had a Fabulous weekend! Please see below for what's on this week. "
			}
		},
		{
			"type": "divider"
		},
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": "Xero Café :coffee:",
				"emoji": true
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": "\n :new-thing: *This week we are offering:* \n\n :caramel-slice: *Sweet Treats*: Cookies \n\n :coffee: *Weekly Café Special*: Maple Latte"
			}
		},
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": " Wednesday, 30th July :calendar-date-30:",
				"emoji": true
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": "\n\n:lunch: :flag-de: Join us fora German lunch From *12pm* in the L3 kitchen + Wominjeka breakout space! Menu in the:thread:"
			}
		},
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": "Thursday, 31st July :calendar-date-31:",
				"emoji": true
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": ":breakfast: *Breakfast*: Join us for our Breakfast Buffet from *8:30am - 10:30am* in the Wominjeka Breakout Space. Menu in the :thread: \n\n\n *What Else? :green_heart:*"
			}
		},
		{
			"type": "divider"
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": " Feedback on our Boost Offerings? We want to hear more. Let us know what you love by filling out our form <https://docs.google.com/forms/d/e/1FAIpQLScGOSeS5zUI8WXEl0K4WGoQUkmpIHzAjLlEKWBob4sMPhDXmA/viewform|here.>  \n\n Stay tuned to this channel, and make sure you're subscribed to the <https://calendar.google.com/calendar/u/0?cid=Y19xczkyMjk5ZGlsODJzMjA4aGt1b3RnM2t1MEBncm91cC5jYWxlbmRhci5nb29nbGUuY29t|*Melbourne Social Calendar*> :party-wx:"
			}
		}
	]
}
ZDK.Page.getField("Payment_Plan").setCriteria("((Project:equals:"+projectID+")and(Status:equals:Active))",{ filterOnSearch: true });
 
AddColumns(
    ForAll(
        Sequence(CountRows(colPlaylist)),
        {
            id: ThisRecord.Value,
            name: Last(FirstN(colPlaylist,  ThisRecord.Value)).name,
            blow: Last(FirstN(colPlaylist,  ThisRecord.Value)).blow
        }
    ),
    ID,
    ThisRecord.name
)
```dataviewjs

class PersistentData {
	static #constructKey = Symbol()
	static #instance
	static _dataFilePath
	static _defaultData
	_dataFilePath
	_defaultData
	_data
	constructor(constructKey, dataFilePath, defaultData) {
		if (constructKey !== PersistentData.#constructKey)
			throw new Error('constructor is private')
		this._dataFilePath = dataFilePath
		this._defaultData = defaultData
	}
	static setConfig(dataFilePath, dafaultData){
		this._dataFilePath = dataFilePath
		this._defaultData = dafaultData
	}
	static async getInstance(){
		if (!this.#instance){
			this.#instance = new PersistentData(
				this.#constructKey,
				this._dataFilePath,
				this._defaultData
			)
			await this.#instance.initialize()
		}
		return this.#instance
	}
	async initialize(){
		const exists = await app.vault.adapter.exists(this._dataFilePath)
		if (exists) {
			const str = await app.vault.adapter.read(this._dataFilePath)
			const data = JSON.parse(str)
			// 保存されているデータとdefaultDataのキーが不一致の場合、データの仕様が変わったと判断し、保存データをdefaultDataにリセットする
			if (this._haveSameKeys(data, this._defaultData)){
				this._data = data
				return
			}
		}
		this._data = this._defaultData
		await this.saveData()
	}
	getData(key){
		return this._data[key]
	}
	async setData(key, value){
		this._data[key] = value
		await this.saveData()
	}
	async saveData(){
		await app.vault.adapter.write(this._dataFilePath, this._toJSON(this._data))
	}
	_haveSameKeys(obj1, obj2) {
		const keys1 = Object.keys(obj1).sort()
		const keys2 = Object.keys(obj2).sort()
		return keys1.length === keys2.length && keys1.every((key, index) => key === keys2[index])
	}
	_toJSON(obj){
		return JSON.stringify(obj, null, 2)
	}
}

function debounce(func, wait) {
	let timeout = null
	return function(...args) {
		if (timeout)
			clearTimeout(timeout)
		timeout = setTimeout(() => {
			func(...args)
			timeout = null
		}, wait)
	}
}

async function updateList() {
	listContainer.innerHTML = ''
	const daysBack = selectDays.value
	const now = dv.date('now')
	let pages

	const startDate = now.minus({ days: parseInt(daysBack) - 1 }).startOf('day')
	pages = dv.pages()
		.where(p => {
			const mtime = dv.date(p.file.mtime)
			return mtime >= startDate && mtime <= now
		})

    if (searchString)
		pages = pages.where(p => p.file.name.toLowerCase().includes(searchString.toLowerCase()))

	const folderCounts = {}
	pages.forEach(page => {
		const folder = page.file.folder || ''
		folderCounts[folder] = (folderCounts[folder] || 0) + 1
	})

	const folders = Array.from(pages.file.folder.distinct()).sort()
	folders.unshift('すべてのフォルダ')

	if (!folders.includes(currentFolder)){
		currentFolder = 'すべてのフォルダ'
		await persistentData.setData('currentFolder', currentFolder)
	}

	selectFolder.innerHTML = ''
	folders.forEach(folder => {
		const count = folder === 'すべてのフォルダ' ? pages.length : (folderCounts[folder] || 0)
		const displayText = folder === 'すべてのフォルダ' ? `${folder} (${count})` : `${folder} (${count})`
		const option = dv.el('option', displayText, { container: selectFolder })
		option.value = folder
		if (folder === currentFolder)
			option.selected = true
	})

    let filteredPages = pages
    if (currentFolder !== 'すべてのフォルダ')
        filteredPages = pages.where(p => p.file.folder === currentFolder)

	const ul = dv.el('ul', '', { container: listContainer })
	filteredPages
		.sort(p => p.file.mtime, 'desc')
		.forEach((page) => {
			const li = dv.el('li', '', { container: ul })
			const a = dv.el('a', page.file.name, { container: li })
			a.addEventListener('click', () => {
				app.workspace.openLinkText(page.file.path, '', true)
			})
		})
}

const config = {
	persistentData: {
		// 永続データ保存ファイルのVault内パス
		// 親ディレクトリは前もって作成しておく
		dataFilePath: '/Scripts/Dataview/PersistentData/touchSort.json',

		// 永続データのデフォルト値
		defaultData: {selectDaysValue: 10, currentFolder: 'すべてのフォルダ', searchString: ''}
	},
	// 日数の選択肢
	selectDaysOptions: [1, 2, 3, 5, 7, 10, 14, 20, 30, 60]
}

PersistentData.setConfig(
	config.persistentData.dataFilePath,
	config.persistentData.defaultData
)
const persistentData = await PersistentData.getInstance()

let currentFolder = persistentData.getData('currentFolder')
let searchString = persistentData.getData('searchString')

const selectDays = dv.el('select', '')
const options = config.selectDaysOptions
options.forEach(option => {
    const opt = dv.el('option', `${option}日`, { container: selectDays })
    opt.value = option
})

const selectFolder = dv.el('select', '')
const searchInput = dv.el('input', '', { attr: { type: 'text', placeholder: '検索', value: searchString} })
const listContainer = dv.el('div', '')

selectDays.addEventListener('change', async () => {
	updateList()
	await persistentData.setData('selectDaysValue', selectDays.value)
})

selectFolder.addEventListener('change', async () => {
    currentFolder = selectFolder.value
    updateList()
	await persistentData.setData('currentFolder', currentFolder)
})

searchInput.addEventListener('input', debounce(async () => {
    searchString = searchInput.value.trim()
    updateList()
	await persistentData.setData('searchString', searchString)
}, 1000))

selectDays.value = persistentData.getData('selectDaysValue')
selectFolder.value = currentFolder
updateList()

```
.toString("yyyy-MM-dd'T'HH:mm:ss","Asia/Dubai")
 
import React, { useState, useRef, useEffect } from 'react';
import { Loader2, Video, LogOut } from 'lucide-react';
import clsx from 'clsx';

/* ------------------------------------------------------------------ */
/*  TYPES & GLOBALS                                                   */
/* ------------------------------------------------------------------ */
declare global {
  interface Window {
    ZoomMtgEmbedded?: any;
  }
}

/* ------------------------------------------------------------------ */
/*  CONSTANTS                                                         */
/* ------------------------------------------------------------------ */
const ZOOM_SDK_VERSION = '3.11.2'; // keep in one place for easy upgrades
const ZOOM_SDK_LIBS = [
  `https://source.zoom.us/${ZOOM_SDK_VERSION}/lib/vendor/react.min.js`,
  `https://source.zoom.us/${ZOOM_SDK_VERSION}/lib/vendor/react-dom.min.js`,
  `https://source.zoom.us/${ZOOM_SDK_VERSION}/lib/vendor/redux.min.js`,
  `https://source.zoom.us/${ZOOM_SDK_VERSION}/lib/vendor/redux-thunk.min.js`,
  `https://source.zoom.us/${ZOOM_SDK_VERSION}/lib/vendor/lodash.min.js`,
  `https://source.zoom.us/${ZOOM_SDK_VERSION}/zoom-meeting-embedded-${ZOOM_SDK_VERSION}.min.js`,
];

/* ------------------------------------------------------------------ */
/*  COMPONENT                                                         */
/* ------------------------------------------------------------------ */
const Zoom: React.FC = () => {
  /* form state ----------------------------------------------------- */
  const [meetingNumber, setMeetingNumber] = useState('');
  const [userName, setUserName] = useState('React User');
  const [meetingPassword, setMeetingPassword] = useState('');
  const [role, setRole] = useState<number>(0); // 0 attendee | 1 host

  /* ui state ------------------------------------------------------- */
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [meetingStarted, setMeetingStarted] = useState(false);

  /* refs ----------------------------------------------------------- */
  const meetingSDKElementRef = useRef<HTMLDivElement>(null);
  const clientRef = useRef<any>(null); // Zoom client instance

  /* ------------------------------------------------------------------ */
  /*  SIDE-EFFECT: Load Zoom SDK once on mount                          */
  /* ------------------------------------------------------------------ */
  useEffect(() => {
    if (window.ZoomMtgEmbedded) {
      console.log('[Zoom] SDK already present');
      return;
    }

    console.log('[Zoom] Loading Zoom SDK…');
    const loadScript = (src: string) =>
      new Promise<void>((resolve, reject) => {
        const s = document.createElement('script');
        s.src = src;
        s.async = false;          // load in order
        s.onload = () => {
          console.log(`[Zoom] ✓ loaded ${src}`);
          resolve();
        };
        s.onerror = () => {
          console.error(`[Zoom] ✗ failed to load ${src}`);
          reject();
        };
        document.body.appendChild(s);
      });

    (async () => {
      try {
        for (const lib of ZOOM_SDK_LIBS) await loadScript(lib);
        console.log('[Zoom] All SDK scripts loaded');
      } catch {
        setError('Failed to load Zoom SDK. Check console for details.');
      }
    })();
  }, []);

  /* ------------------------------------------------------------------ */
  /*  HELPERS                                                           */
  /* ------------------------------------------------------------------ */
  const getSignature = async () => {
    console.log('[Zoom] Fetching signature…');
    setLoading(true);
    setError(null);
    try {
      const res = await fetch(
        `http://localhost:80/api/zoom/signature?meetingNumber=${meetingNumber}&role=${role}`,
      );
      if (!res.ok) throw new Error((await res.json())?.message);
      const data = await res.json();
      console.log('[Zoom] Signature fetched:', data);
      return data;
    } catch (err: any) {
      console.error('[Zoom] Signature error:', err);
      setError(err?.message ?? 'Failed to get signature');
      return null;
    } finally {
      setLoading(false);
    }
  };

  const startMeeting = async () => {
    console.log('[Zoom] startMeeting() called');
    if (!meetingNumber.trim() || !userName.trim()) {
      setError('Meeting Number & Name required.');
      return;
    }
    if (!meetingSDKElementRef.current) {
      setError('SDK mount element not found.');
      return;
    }
    if (!window.ZoomMtgEmbedded) {
      setError('Zoom SDK still loading, please try again in a moment.');
      return;
    }

    const sigData = await getSignature();
    if (!sigData) return;

    const { signature, sdkKey } = sigData;
    clientRef.current = window.ZoomMtgEmbedded.createClient();

    try {
      console.log('[Zoom] Initializing client…');
      await clientRef.current.init({
        zoomAppRoot: meetingSDKElementRef.current,
        language: 'en-US',
        patchJsMedia: true,
      });
      console.log('[Zoom] Client initialized, joining…');
      await clientRef.current.join({
        sdkKey,
        signature,
        meetingNumber,
        userName,
        password: meetingPassword,
        role,
      });
      console.log('[Zoom] Joined meeting');
      setMeetingStarted(true);
    } catch (err: any) {
      console.error('[Zoom] Unable to start meeting:', err);
      setError(err?.message ?? 'Unable to start meeting');
    }
  };

  const leaveMeeting = async () => {
    console.log('[Zoom] leaveMeeting() called');
    if (!meetingStarted || !clientRef.current) return;
    try {
      await clientRef.current.leave();
      console.log('[Zoom] Left meeting');
      setMeetingStarted(false);
    } catch (err: any) {
      console.error('[Zoom] Failed to leave:', err);
      setError(err?.message ?? 'Failed to leave');
    }
  };

  /* ------------------------------------------------------------------ */
  /*  RENDER                                                            */
  /* ------------------------------------------------------------------ */
  return (
    <main className="min-h-screen relative flex items-center justify-center bg-gradient-to-br from-blue-950 via-indigo-900 to-fuchsia-900 overflow-hidden">
      {/* floating blur blobs */}
      <div className="absolute inset-0">
        {Array.from({ length: 10 }).map((_, i) => (
          <div
            // purely decorative blobs
            key={i}
            className={clsx(
              'absolute rounded-full blur-2xl opacity-25',
              i % 2 ? 'bg-blue-600' : 'bg-violet-700',
            )}
            style={{
              width: `${Math.random() * 18 + 12}rem`,
              height: `${Math.random() * 18 + 12}rem`,
              top: `${Math.random() * 100}%`,
              left: `${Math.random() * 100}%`,
              animation: `pulse ${Math.random() * 12 + 8}s ease-in-out infinite`,
            }}
          />
        ))}
      </div>

      <section className="relative z-10 w-full max-w-3xl mx-auto p-6">
        <h1 className="text-center text-4xl font-bold text-white mb-8 flex items-center justify-center gap-2">
          <Video className="w-8 h-8 text-blue-400" />
          Zoom Meeting
        </h1>

        {/* CARD ---------------------------------------------------- */}
        <div className="backdrop-blur-xl bg-white/5 border border-white/[0.08] rounded-2xl shadow-2xl overflow-hidden">
          {!meetingStarted ? (
            <form
              onSubmit={(e) => {
                e.preventDefault();
                startMeeting();
              }}
              className="grid gap-6 p-8"
            >
              {/* inputs */}
              <Input
                label="Meeting Number"
                value={meetingNumber}
                onChange={setMeetingNumber}
                placeholder="e.g. 123456789"
                autoFocus
              />
              <Input
                label="Your Name"
                value={userName}
                onChange={setUserName}
                placeholder="Enter display name"
              />
              <Input
                label="Password (optional)"
                type="password"
                value={meetingPassword}
                onChange={setMeetingPassword}
                placeholder="Meeting passcode"
              />

              <div>
                <label className="block text-sm font-medium text-white/80 mb-1">
                  Role
                </label>
                <select
                  value={role}
                  onChange={(e) => setRole(parseInt(e.target.value, 10))}
                  className="w-full rounded-lg bg-white/10 border border-white/20 px-3 py-2 text-white focus:ring-2 focus:ring-blue-500 focus:outline-none"
                >
                  <option value={0}>Attendee</option>
                  <option value={1}>Host</option>
                </select>
              </div>

              {error && (
                <p className="text-center text-sm text-red-400 -mt-3">
                  {error}
                </p>
              )}

              <button
                type="submit"
                disabled={loading}
                className={clsx(
                  'w-full flex items-center justify-center gap-2 rounded-lg py-3 font-semibold transition',
                  loading
                    ? 'bg-blue-400 cursor-not-allowed'
                    : 'bg-gradient-to-r from-blue-600 to-violet-600 hover:brightness-110',
                )}
              >
                {loading ? (
                  <>
                    <Loader2 className="w-5 h-5 animate-spin" /> Starting…
                  </>
                ) : (
                  'Join Meeting'
                )}
              </button>
            </form>
          ) : (
            <div className="p-10 flex flex-col items-center gap-6 text-white">
              <p className="text-lg">
                🎉 Connected as <span className="font-semibold">{userName}</span>
              </p>
              <button
                onClick={leaveMeeting}
                className="flex items-center gap-2 bg-gradient-to-r from-red-600 to-red-700 hover:brightness-110 px-6 py-3 rounded-lg font-semibold"
              >
                <LogOut className="w-5 h-5" /> Leave
              </button>
            </div>
          )}

          {/* Zoom SDK mount */}
          <div
            id="meetingSDKElement"
            ref={meetingSDKElementRef}
            className={clsx(
              'w-full overflow-hidden transition-all duration-500',
              meetingStarted ? 'h-[70vh]' : 'h-0',
            )}
          />
        </div>
      </section>
    </main>
  );
};

/* ------------------------------------------------------------------ */
/*  REUSABLE INPUT                                                   */
/* ------------------------------------------------------------------ */
interface InputProps {
  label: string;
  value: string;
  onChange: (v: string) => void;
  type?: React.HTMLInputTypeAttribute;
  placeholder?: string;
  autoFocus?: boolean;
}

const Input: React.FC<InputProps> = ({
  label,
  value,
  onChange,
  type = 'text',
  placeholder,
  autoFocus,
}) => (
  <div className="space-y-1">
    <label className="block text-sm font-medium text-white/80">
      {label}:
    </label>
    <input
      type={type}
      value={value}
      onChange={(e) => onChange(e.target.value)}
      placeholder={placeholder}
      autoFocus={autoFocus}
      className="w-full rounded-lg bg-white/10 border border-white/20 px-3 py-2 text-white placeholder-white/50 focus:ring-2 focus:ring-blue-500 focus:outline-none"
    />
  </div>
);

export default Zoom;
const formattedPrice = new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD',
  minimumFractionDigits: 0,
}).format(price);
List<object> itemsToDelete = [
    SELECT Id FROM object LIMIT 10000
];
delete itemsToDelete;
https://github.com/login
Hamza-Khan123
hamzakhan.123
Git Token: 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
https://github.com/login
Hamza-Khan123
hamzakhan.123
Git Token: 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
//ruta a la carpeta de los snipets en el archivo:
//~/.config/Code/User/profiles/
//-54d2ca4b/snippets/
//Configure User Snippets este es el comando el de abajo es atajos rapidos de teclado
//y con Con Ctrl + Shift + P se abre la paleta de comandos, donde puedes escribir "Open Keyboard Shortcuts (JSON)"
// --- INICIO SNIPPETS PHP ---
{
  // --- SNIPPETS PHP ---
  "Hola Mundo PHP": {
    "prefix": "phphola",
    "body": [
      "// Imprime Hola Mundo en PHP",
      "echo \"Hola, ${1:mundo}!\";"
    ],
    "description": "Imprime un saludo básico en PHP",
    "scope": "php"
  },
  "Echo Variable": {
    "prefix": "echo",
    "body": [
      "// Imprime una variable",
      "echo ${1:variable};"
    ],
    "description": "Imprime una variable con echo",
    "scope": "php"
  },
  "If Statement": {
    "prefix": "if",
    "body": [
      "// Estructura if con sintaxis alternativa",
      "if (${1:condition}):",
      "\t$0",
      "endif;"
    ],
    "description": "Estructura if con sintaxis alternativa",
    "scope": "php"
  },
  "If-Else Statement": {
    "prefix": "ifelse",
    "body": [
      "// Estructura if-else con sintaxis alternativa",
      "if (${1:condition}):",
      "\t${2:código si verdadero}",
      "else:",
      "\t${3:código si falso}",
      "endif;"
    ],
    "description": "Estructura if-else con sintaxis alternativa",
    "scope": "php"
  },
  "Foreach Loop": {
    "prefix": "foreach",
    "body": [
      "// Bucle foreach con sintaxis alternativa",
      "foreach (${1:array} as ${2:key} => ${3:value}):",
      "\t$0",
      "endforeach;"
    ],
    "description": "Bucle foreach con sintaxis alternativa",
    "scope": "php"
  },
  "For Loop": {
    "prefix": "for",
    "body": [
      "// Bucle for con sintaxis alternativa",
      "for (${1:i} = 0; ${1:i} < ${2:count(array)}; ${1:i}++):",
      "\t$0",
      "endfor;"
    ],
    "description": "Bucle for con sintaxis alternativa",
    "scope": "php"
  },
  "Function Declaration": {
    "prefix": "function",
    "body": [
      "// Declarar función en PHP",
      "function ${1:nombreFuncion}(${2:parametros}) {",
      "\t$0",
      "}"
    ],
    "description": "Declarar una función en PHP",
    "scope": "php"
  },
  "Class Constructor": {
    "prefix": "classconstructor",
    "body": [
      "// Crear clase con constructor",
      "class ${1:NombreClase} {",
      "\tpublic function __construct(${2:parametros}) {",
      "\t\t$0",
      "\t}",
      "}"
    ],
    "description": "Clase PHP con constructor",
    "scope": "php"
  },
  "Class con Propiedades y Métodos": {
    "prefix": "classfull",
    "body": [
      "// Clase con propiedad, constructor, getter y setter",
      "class ${1:NombreClase} {",
      "\t/**",
      "\t * @var ${2:string} Descripción de la propiedad",
      "\t */",
      "\tprivate \${3:nombre};",
      "",
      "\t/**",
      "\t * Constructor",
      "\t *",
      "\t * @param ${2:string} \${3:nombre} Descripción",
      "\t * @throws InvalidArgumentException",
      "\t */",
      "\tpublic function __construct(${2:string} \${3:nombre} = '') {",
      "\t\t$this->set${4/(.+)/${1:/capitalize}/}(\${3:nombre});",
      "\t}",
      "",
      "\t/**",
      "\t * Setter para ${3:nombre}",
      "\t *",
      "\t * @param ${2:string} \${3:nombre}",
      "\t * @return void",
      "\t * @throws InvalidArgumentException",
      "\t */",
      "\tpublic function set${4/(.+)/${1:/capitalize}/}(${2:string} \${3:nombre}): void {",
      "\t\tif (empty(\${3:nombre})) {",
      "\t\t\tthrow new InvalidArgumentException('El ${3:nombre} no puede estar vacío.');",
      "\t\t}",
      "\t\t$this->${3:nombre} = \${3:nombre};",
      "\t}",
      "",
      "\t/**",
      "\t * Getter para ${3:nombre}",
      "\t *",
      "\t * @return ${2:string}",
      "\t */",
      "\tpublic function get${4/(.+)/${1:/capitalize}/}(): ${2:string} {",
      "\t\treturn \$this->${3:nombre};",
      "\t}",
      "}"
    ],
    "description": "Clase con propiedades, constructor, getter y setter con validación",
    "scope": "php"
  },
  "Try Catch": {
    "prefix": "trycatch",
    "body": [
      "// Bloque try-catch",
      "try {",
      "\t$0",
      "} catch (${1:Exception} ${2:e}) {",
      "\techo ${2}->getMessage();",
      "}"
    ],
    "description": "Bloque try-catch en PHP",
    "scope": "php"
  },
  "Variable Dump": {
    "prefix": "vardump",
    "body": [
      "// Mostrar variable legible",
      "echo '<pre>';",
      "var_dump(${1:variable});",
      "echo '</pre>';"
    ],
    "description": "Mostrar variable con var_dump formateado",
    "scope": "php"
  },
  "PHP Array": {
    "prefix": "array",
    "body": [
      "// Crear array asociativo",
      "${1:arrayName} = [",
      "\t${2:'key' => 'value'},",
      "\t$0",
      "];"
    ],
    "description": "Crear array asociativo en PHP",
    "scope": "php"
  },

  // --- SNIPPETS POSTGRES ---
  "Postgres Select": {
    "prefix": "pgSelect",
    "body": [
      "-- Consulta SELECT básica",
      "SELECT ${1:*} FROM ${2:tabla} WHERE ${3:condicion};"
    ],
    "description": "Consulta SELECT en Postgres",
    "scope": "sql"
  },
  "Postgres Insert": {
    "prefix": "pgInsert",
    "body": [
      "-- Consulta INSERT básica",
      "INSERT INTO ${1:tabla} (${2:columna1}, ${3:columna2}) VALUES (${4:valor1}, ${5:valor2});"
    ],
    "description": "Consulta INSERT en Postgres",
    "scope": "sql"
  },
  "Postgres Update": {
    "prefix": "pgUpdate",
    "body": [
      "-- Consulta UPDATE básica",
      "UPDATE ${1:tabla} SET ${2:columna} = ${3:nuevo_valor} WHERE ${4:condicion};"
    ],
    "description": "Consulta UPDATE en Postgres",
    "scope": "sql"
  },
  "Postgres Delete": {
    "prefix": "pgDelete",
    "body": [
      "-- Consulta DELETE básica",
      "DELETE FROM ${1:tabla} WHERE ${2:condicion};"
    ],
    "description": "Consulta DELETE en Postgres",
    "scope": "sql"
  },
  "Postgres Create Table": {
    "prefix": "pgCreateTable",
    "body": [
      "-- Crear tabla",
      "CREATE TABLE ${1:tabla} (",
      "\t${2:id} SERIAL PRIMARY KEY,",
      "\t${3:columna} ${4:tipo},",
      "\t$0",
      ");"
    ],
    "description": "Crear tabla en Postgres",
    "scope": "sql"
  },
  "Postgres Connect": {
    "prefix": "pgConnect",
    "body": [
      "-- Conectar a base de datos Postgres",
      "\\c ${1:nombre_base_de_datos};"
    ],
    "description": "Conectar a base de datos Postgres",
    "scope": "sql"
  },
  "Postgres Drop Database": {
    "prefix": "pgDropDb",
    "body": [
      "-- Borrar base de datos",
      "DROP DATABASE ${1:nombre_base_de_datos};"
    ],
    "description": "Borrar base de datos en Postgres",
    "scope": "sql"
  },
  "Postgres Create Database": {
    "prefix": "pgCreateDb",
    "body": [
      "-- Crear base de datos",
      "CREATE DATABASE ${1:nombre_base_de_datos};"
    ],
    "description": "Crear base de datos en Postgres",
    "scope": "sql"
  },
  "Postgres Import Database": {
    "prefix": "pgImportDb",
    "body": [
      "-- Importar archivo .sql",
      "psql -U ${1:usuario} -d ${2:base_de_datos} -f ${3:archivo.sql}"
    ],
    "description": "Importar archivo .sql a Postgres",
    "scope": "sql"
  },
  "Postgres Export Database": {
    "prefix": "pgExportDb",
    "body": [
      "-- Exportar base de datos a archivo .sql",
      "pg_dump -U ${1:usuario} -d ${2:base_de_datos} -f ${3:archivo.sql}"
    ],
    "description": "Exportar base de datos Postgres",
    "scope": "sql"
  },
  "Postgres Create User": {
    "prefix": "pgCreateUser",
    "body": [
      "-- Crear usuario",
      "CREATE USER ${1:nombre_usuario} WITH PASSWORD '${2:contraseña}';"
    ],
    "description": "Crear usuario en Postgres",
    "scope": "sql"
  },
  "Postgres Grant Privileges": {
    "prefix": "pgGrant",
    "body": [
      "-- Otorgar privilegios",
      "GRANT ${1:ALL} PRIVILEGES ON DATABASE ${2:base_de_datos} TO ${3:usuario};"
    ],
    "description": "Otorgar privilegios en Postgres",
    "scope": "sql"
  },

  // --- SNIPPETS LARAVEL ---
  "Laravel Route": {
    "prefix": "laravelRoute",
    "body": [
      "// Definir ruta en Laravel",
      "Route::${1:get}('${2:/ruta}', [${3:Controller}::class, '${4:metodo}']);"
    ],
    "description": "Definir ruta en Laravel",
    "scope": "php"
  },
  "Laravel Controller": {
    "prefix": "laravelController",
    "body": [
      "// Controlador básico en Laravel",
      "namespace App\\Http\\Controllers;",
      "",
      "use Illuminate\\Http\\Request;",
      "",
      "class ${1:NombreController} extends Controller",
      "{",
      "\tpublic function ${2:index}()",
      "\t{",
      "\t\t$0",
      "\t}",
      "}"
    ],
    "description": "Controlador básico en Laravel",
    "scope": "php"
  },
  "Laravel Migration": {
    "prefix": "laravelMigration",
    "body": [
      "// Crear migración en Laravel",
      "Schema::create('${1:tabla}', function (Blueprint $table) {",
      "\t$table->id();",
      "\t$table->string('${2:nombre}');",
      "\t$table->timestamps();",
      "\t$0",
      "});"
    ],
    "description": "Migración básica en Laravel",
    "scope": "php"
  },
  "Laravel Model": {
    "prefix": "laravelModel",
    "body": [
      "// Crear modelo en Laravel",
      "namespace App\\Models;",
      "",
      "use Illuminate\\Database\\Eloquent\\Model;",
      "",
      "class ${1:NombreModelo} extends Model",
      "{",
      "\tprotected $fillable = [",
      "\t\t'${2:campo}',",
      "\t];",
      "\t$0",
      "}"
    ],
    "description": "Modelo básico en Laravel",
    "scope": "php"
  },
  "Laravel Blade Foreach": {
    "prefix": "laravelForeach",
    "body": [
      "{{-- Bucle foreach en Blade --}}",
      "@foreach (${1:items} as ${2:item})",
      "\t{{ ${2:item} }}",
      "@endforeach"
    ],
    "description": "Bucle foreach en Blade",
    "scope": "php"
  },
  "Laravel Validation": {
    "prefix": "laravelValidate",
    "body": [
      "// Validar datos en controlador",
      "$validated = $request->validate([",
      "\t'${1:campo}' => '${2:required|string}',",
      "\t$0",
      "]);"
    ],
    "description": "Validación de datos en Laravel",
    "scope": "php"
  },
  "Laravel Seeder": {
    "prefix": "laravelSeeder",
    "body": [
      "// Crear seeder en Laravel",
      "use Illuminate\\Database\\Seeder;",
      "",
      "class ${1:NombreSeeder} extends Seeder",
      "{",
      "\tpublic function run()",
      "\t{",
      "\t\t$0",
      "\t}",
      "}"
    ],
    "description": "Seeder básico en Laravel",
    "scope": "php"
  },
  "Laravel Request": {
    "prefix": "laravelRequest",
    "body": [
      "// Obtener datos de petición",
      "\$${1:variable} = $request->input('${2:campo}');"
    ],
    "description": "Obtener datos de petición en Laravel",
    "scope": "php"
  },
  "Laravel Middleware": {
    "prefix": "laravelMiddleware",
    "body": [
      "// Crear middleware en Laravel",
      "namespace App\\Http\\Middleware;",
      "",
      "use Closure;",
      "",
      "class ${1:NombreMiddleware}",
      "{",
      "\tpublic function handle($request, Closure $next)",
      "\t{",
      "\t\t$0",
      "\t\treturn $next($request);",
      "\t}",
      "}"
    ],
    "description": "Middleware básico en Laravel",
    "scope": "php"
  },
  "Laravel Blade If": {
    "prefix": "laravelBladeIf",
    "body": [
      "{{-- Estructura if en Blade --}}",
      "@if (${1:condicion})",
      "\t${2:contenido}",
      "@endif"
    ],
    "description": "Estructura if en Blade",
    "scope": "php"
  },
  "Laravel Blade Include": {
    "prefix": "laravelBladeInclude",
    "body": [
      "{{-- Incluir vista en Blade --}}",
      "@include('${1:vista}')"
    ],
    "description": "Incluir vista en Blade",
    "scope": "php"
  },
  "Laravel Blade Layout": {
    "prefix": "laravelBladeLayout",
    "body": [
      "{{-- Extender layout en Blade --}}",
      "@extends('${1:layouts.app}')",
      "",
      "@section('${2:content}')",
      "\t$0",
      "@endsection"
    ],
    "description": "Extender layout en Blade",
    "scope": "php"
  }
}
ruta a la carpeta de los snipets:
~/.config/Code/User/profiles/
-54d2ca4b/snippets/
  
Presiona el atajo de teclado Ctrl + 8 para guardar el código seleccionado en tu colección thiscodeWorks en la nube

Presiona Ctrl + Shift + 8 para abrir el panel con todos tus snippets guardados.

Abre la paleta de comandos con Ctrl + Shift + P

Escribe y selecciona "Preferences: Configure User Snippets"

Elige crear un nuevo archivo de snippets global o para un lenguaje específico. También puedes crear un archivo JSON con nombre personalizado para agrupar snippets (es decir, funcionaría como tu "carpeta" local para snippets).

Dentro del archivo JSON, agrega tus snippets siguiendo esta estructura:

esta es la estructura de un snipet: 

Name: Esto es algo obvio, pero aquí vamos a nombrar a nuestro snippe,
Prefix: Este va a ser nuestro atajo. Dentro de nuestro código, cuando escribamos el atajo, va a aparecer de forma automática la opción de poder llamar a nuestro snippet. Por ejemplo: “forEach”.
Body: Aquí vamos a tener que crear el cuerpo del mismo. El contenido de esta sección va ser el mismo que luego se verá reflejado en el código. Esto incluye a cada tag, espacio, tabulación, etc.
Description: También podemos agregar una descripción explicando lo que hace o intenta hacer el snippet.
Scope: Por último, tenemos la posibilidad de setear el scope, es decir que podemos especificar a que lenguaje pertenece el snippet. Esto va a impedir que nos aparezca el snippet en un archivo de otro lenguaje que no sea el que previamente hayamos definido.

{
  "Nombre snippet": {
    "prefix": "atajo",
    "body": [
      "línea 1 del snippet",
      "línea 2 del snippet"
    ],
    "description": "Descripción del snippet"
  }
}

ejemplo real: 
"Hola Mundo": {
		"prefix": "hola",
		"body": [
			"// Imprime Hola Mundo",
			"echo \"Hola, ${1:mundo}!\";"
		],
		"description": "Un atajo para crear un script PHP básico",
		"scope": "php"
	},
var NSSRUtilV2 = Class.create();
NSSRUtilV2.prototype = Object.extendsObject(global.AbstractAjaxProcessor, {
   isMember: function() {
       var groupId = this.getParameter('sysparm_group_id');
       var userId = gs.getUserID();
       if (!groupId || !userId) {
           gs.info('Membership Check: Missing parameters');
           return 'false';
       }
       var gr = new GlideRecord('sys_user_grmember');
       gr.addQuery('user', userId);
       gr.addQuery('group', groupId);
       gr.query();
       var isMember = gr.hasNext();
       gs.info('Membership Check: User ' + userId + ' in group ' + groupId + ': ' + isMember);
       return isMember.toString();
   },
    type: 'NSSRUtilV2'
});
# for name, child in list(model.named_children()):
        #     if required_layers and name not in required_layers:
        #         continue
        #     if len(list(child.children())) > 1:
        #         self.replace_module_with_wrapper(child, required_layers)
        #         continue
        #     if (
        #         not isinstance(child, torch.nn.Sequential)
        #         and len(list(child.children())) == 0
        #     ):
        #         wrapped = ModuleReplacements.get_replacement(child)
        #         if not wrapped:
        #             self.logger.info(f"Please register {type(child)}")
        #             continue

        #         setattr(child, "activation_dtype", global_activation_dtype)
        #         setattr(child, "parameter_dtype", global_param_dtype)
        #         setattr(child, "parameter_observer", global_weight_observer)
        #         setattr(child, "activation_observer", global_activation_observer)

        #         set_nested_attr(model, name, wrapped(old_module=child))
var AutopopulateNSSRUserDetails = Class.create();
AutopopulateNSSRUserDetails.prototype = Object.extendsObject(global.AbstractAjaxProcessor, {

    populateDepartment: function() {
        var user = this.getParameter('sysparm_user');
        var grUser = new GlideRecord('sys_user');
        grUser.addQuery('sys_id', user);
        grUser.query();
        if (grUser.next()) {
            var department = grUser.department.getDisplayValue();
            return department.toString();
        }
    },

    type: 'AutopopulateNSSRUserDetails'
});
add_filter( 'sp_pcp_the_content', function($post_content){
	if (preg_match('/\[smart_post_show id="\d+"\]/', $post_content)) {
		$post_content = preg_replace( '/\[smart_post_show id="\d+"\]/', '', $post_content );
	}
	return $post_content;
} );
var getNSSRFlowContext = Class.create();
getNSSRFlowContext.prototype = Object.extendsObject(AbstractAjaxProcessor, {

	getFlowContext: function(){
		var id = this.getParameter('sysparm_id');
		var ctx = new GlideRecord("sys_flow_context");
		ctx.addEncodedQuery("source_table=x_hclda_nssr_request^source_record="+id);
		ctx.query();
		if(ctx.next()){
			var results = {
				"success":"true",
				"id":ctx.getUniqueValue()
			};
			return JSON.stringify(results);
		}
		gs.addErrorMessage("Flow Context does not exist for this record.");
		var result = {
			"success":"false"
		};
		return JSON.stringify(result);
	},
   

    type: 'getNSSRFlowContext'
});
<link rel="stylesheet" href="https://unpkg.com/lenis@1.1.13/dist/lenis.css">
27
<script src="https://unpkg.com/lenis@1.1.13/dist/lenis.min.js"></script> 
28
<script>
29
const lenis = new Lenis()
30
​
31
lenis.on('scroll', (e) => {
32
  console.log(e)
33
})
34
​
35
function raf(time) {
36
  lenis.raf(time)
37
  requestAnimationFrame(raf)
38
}
39
​
40
requestAnimationFrame(raf)
41
</script>
Guía paso a paso para PostgreSQL
I. Linux
1. Instalación and configuración inicial

Nota importante: Por defecto PostgreSQL crea un usuario postgres sin contraseña en Linux, autenticado vía sistema.

sudo su - postgres o sudo -i -u postgres

Acceder al intérprete de comandos de PostgreSQL:
psql
Si no conoces la contraseña de postgres:
ALTER USER postgres WITH PASSWORD 'tu_password';

Para crear usuarios, considera usar el comando createuser desde consola Linux para creación interactiva:
sudo -u postgres createuser --interactive

Para listar usuarios/roles existentes en psql:
\du

# Instalar PostgreSQL y herramientas adicionales
sudo apt update
sudo apt install postgresql postgresql-contrib libpq-dev

# Inicializar clúster de base de datos (opcional - solo si necesitas nuevo directorio)
sudo -u postgres initdb -D /ruta/del/directorio


# Manipular el servicio PostgreSQL
sudo systemctl start postgresql      # Iniciar servicio
sudo systemctl restart postgresql    # Reiniciar servicio
sudo systemctl stop postgresql       # Detener servicio

2. Crear roles (usuarios) y bases de datos
# Acceder como usuario postgres en bash
sudo -u postgres psql

# Crear nuevo usuario con contraseña
CREATE USER nombre_usuario WITH PASSWORD 'tu_contraseña';

# Crear una base de datos nueva (opcional asignar propietario)
CREATE DATABASE nombre_base_de_datos OWNER nombre_usuario;

# Otorgar todos los privilegios sobre la base a un usuario
GRANT ALL PRIVILEGES ON DATABASE nombre_base_de_datos TO nombre_usuario;

# Eliminar usuario cuando ya no se necesite
DROP USER nombre_usuario;

3. Conectarse y administrar con psql
# Conectarse a postgres como superusuario (te pedirá contraseña si la tiene)
psql -h localhost -U postgres -W

# Mostrar bases de datos
\l

# Conectarse a una base de datos existente
\c nombre_base_de_datos

# Importar archivo SQL en una base
\i /ruta/del/archivo.sql

# Salir de psql
\q

II. Termux (Android Linux Shell)
1. Apertura y acceso al usuario postgres
# Abrir consola con Ctrl + Alt + T

# Cambiar a usuario root
sudo su

# Ingresar contraseña root si se solicita

# Cambiar a usuario postgres
su - postgres

# Ingresar a shell psql
psql

# Conectarse a la base postgres
\c postgres

# Luego ingresar la contraseña que configuraste

# Para salir de psql
\q o exit

III. Windows
1. Inicialización y manejo del servicio PostgreSQL

# Inicializar base de datos (solo si creas nuevo clúster)
initdb -D "C:\directorio\postgresql\data"

# Iniciar el servidor
pg_ctl -D "C:\directorio\postgresql\data" start

# Reiniciar el servidor
pg_ctl -D "C:\directorio\postgresql\data" restart

# Detener el servidor
pg_ctl -D "C:\directorio\postgresql\data" stop


drop table team_kingkong.shivam_merchants;
create table team_kingkong.shivam_merchants as (
SELECT distinct
  m_1.mid,
  concat('_',m_1.mid) _mid2,
   m_1.id,
   m_1.merchant_name,
    m_1.ppi,
   m_1.entity_type,
   m_1.is_blocked,
   m_1.created_date onboarding_date,
   DATE_DIFF('day', date(m_1.created_date) ,current_date) vintage_days,
contact_mobile, 
primary_email, 
secondary_email,
   m_2.entity_id,
   m_2.category,
   m_7.channel,
   m_2.sub_category,
   m_2.business_name,
   signatory_name,
  m_2.bus_address,
   m_2.zipcode,
   m_2.city,
   m_2.state_id,
   m_2.comm_address,
m_2.comm_pin,
m_2.comm_city,
m_2.comm_state,
offline_alert_count,
online_alert_count,
edc_model_alert_count,
daily_limit,
monthly_limit,
sett_acc_change,
bankname,
aadhar_status,
   pan_status,
   gst_status,
gstin,
pan_no_personal,
pan_no_business,
ifsc_code,
bank_acc_no,
 bank_name,
 bank_account_name,
 ag.agent_id,
 ag.agent_name, 
 ag.agent_type, 
ag.agent_cust_id, 
ag.agent_team, 
ag.phone_number agent_phone_number,
 CASE
  WHEN m_3.o_mid IS NOT NULL THEN 'Online'
  WHEN m_4.e_mid IS NOT NULL THEN 'EDC'
  ELSE 'QR'
 END AS EDC_QR,
 case when complete_latitude is not null then complete_latitude else lat_lon2.lat end as latitude,
case when complete_longitude is not null then complete_longitude else lat_lon2.lon end as longitude,
case when um.mid is not null then 1 end as flag_merchant_is_user,
um.merchant_user_id,
ag.channel onb_source,
mcc


FROM
 (
  SELECT DISTINCT
   mid,
   id,
   merchant_name,
   ppi_limited_merchant AS ppi,
   entity_type,
   is_blocked,
   created_date
  FROM
   pg.entity_info_snapshot_v3
  WHERE
   dl_last_updated >= DATE '2010-01-01'
 ) AS m_1

 LEFT JOIN (
  SELECT distinct
   entity_id,
   category,
   sub_category,
   business_name,
   concat(address_1,' ',address_2,' ',address_3) as bus_address,
   zipcode,
   city,
   state_id,
   concat(comm_address_1,' ',comm_address_2,' ',comm_address_3) as comm_address,
comm_pin,
comm_city,
comm_state
  FROM
   pg.entity_demographics_snapshot_v3
  WHERE
   dl_last_updated >= DATE '2010-01-01'
 ) AS m_2 ON m_1.id = m_2.entity_id

 LEFT JOIN (
  SELECT DISTINCT
   merchant_id AS o_mid
  FROM
   datalake.online_payment_merchants
 ) AS m_3 ON m_1.mid = m_3.o_mid

 LEFT JOIN (
  SELECT DISTINCT
   mid AS e_mid
  FROM
   paytmpgdb.entity_edc_info_snapshot_v3
  WHERE
--    terminal_status = 'ACTIVE'
--    AND 
   dl_last_updated >= DATE '2010-01-01'
 ) m_4 ON m_1.mid = m_4.e_mid

 LEFT Join (
  select distinct
   mid,
   count(mid) as offline_alert_count
  from
   ds4_shared.offline_triggers_snapshot_v3
  WHERE
   dl_last_updated >= DATE '2024-01-01'
  group by mid
 ) as m_6 ON m_1.mid = m_6.mid


left join
(select 
merchant_id mid,
count(merchant_id) as edc_model_alert_count
from team_lionking.edc_score_snapshot_v3
where dl_last_updated >= DATE '2024-01-01'
and  mid_risk_score>=0.95
group by 1) e_al on e_al.mid = m_1.mid


 LEFT Join (
  select distinct
   pg_mid,
   channel
  from
   cdo.total_offline_merchant_base_snapshot_v3
 ) AS m_7 ON m_1.mid = m_7.pg_mid

 LEFT Join (
  select distinct
   mid,
   count(mid) as online_alert_count
  from
   risk_analytics_db.ropanel_review_merchant_snapshot_v3
  where
   DATE(substr(cast(inserted_at AS VARCHAR), 1, 10)) >= date '2023-01-01'
  group by mid
 ) AS m_8 ON m_1.mid = m_8.mid

 LEFT JOIN (
   select * from 
  (select distinct
   ENTITY_ID,
   row_number() over (
    partition by
     ENTITY_ID
    order by
     created_date desc
   ) as r_num,
   maxamtperday as daily_limit,
   maxamtpermon as monthly_limit
  from
   pg.entity_txn_limits_snapshot_v3
  where
   limits_identifier = 34577774955
   AND dl_last_updated >= date'2023-01-01'
   )
   where r_num = 1
 ) AS m_9 ON m_1.id = m_9.ENTITY_ID


 LEFT Join (
  select
   pg_mid,
   count(distinct pg_mid) as sett_acc_change
  from
   dwh.onboarding_engine_olap
  where
   ingest_date >= date '2023-01-01'
   and date(lead_creation_timestamp) >= date '2023-01-01'
   and solution_type = 'pg_profile_update'
   and solution_type_level_2 = 'BANK_DETAIL_UPDATE'
   and stage = 'LEAD_CLOSED'
   and substage = 'LEAD_SUCCESSFULLY_CLOSED'
  group by
   pg_mid
 ) AS m_10 ON m_1.mid = m_10.pg_mid

 LEFT Join (
   select * from 
  (select distinct
   merchantid,
   bankname,
   row_number() over (
    partition by
     merchantid
    order by
     dl_last_updated desc
   ) as r_num
  from
   cdp_risk_transform.external_merchant_info_snapshot_v3
  WHERE
   dl_last_updated >= DATE '2010-01-01')
   where r_num = 1
 ) as m_11 ON m_1.mid = m_11.merchantid


 LEFT Join 
 (
   select * from
  (select distinct
   merchant_mid,
   aadhar_status,
   pan_status,
   gst_status,
   row_number() over (
    partition by
     merchant_mid
    order by
     last_updated desc
   ) as r_num
  from
   cdp_risk_transform.mid_metrics_limits_framework_snapshot_v3)
   where r_num = 1
 ) as m_12 ON m_1.mid = m_12.merchant_mid

left join

(select
entity_id,
gstin,
pan_no_personal,
pan_no_business,
ifsc_code,
bank_acc_no,
signatory_name,
regexp_replace(bank_name,',','') as bank_name,
regexp_replace(regexp_replace(bank_account_name,',',''),'\n','') as bank_account_name
from pg.merchant_kyc_details_snapshot_v3
where  dl_last_updated > date'2010-01-01') pngst on
m_2.entity_id = pngst.entity_id 


left join
(select pg_mid mid,
lat_long,
complete_latitude,
complete_longitude
from datalake.fact_vmn_srs) lat_lon1 on m_1.mid = lat_lon1.mid

left join

(select  
mid,
lat,
lon
from
datalake.dim_merchant_cdo) lat_lon2 on m_1.mid = lat_lon2.mid

left join

(select * from 
(select mid.solution_value as pg_mid,
ubm.solution_type,ubm.id,
ubm.channel,
ubm.channel_actual,
ubm.created_at,
ubm.creator_cust_id,  aud.agent_id, aud.agent_name, aud.agent_type, 
aud.agent_cust_id, aud.agent_team, us.phone_number,
row_number() over (partition by mid.solution_value order by ubm.created_at desc) as rn
from
(select solution_id, solution_value
from onboarding_engine.solution_additional_info_snapshot_v3
where dl_last_updated<=current_date
and solution_key='PG_MID') mid
left join onboarding_engine.related_business_solution_mapping_snapshot_v3 rbsm ON mid.solution_id=rbsm.solution_id
left join onboarding_engine.v_ubm_snapshot_v3 ubm ON rbsm.id=ubm.rdsmid
left join onboarding_engine.audit_trail_snapshot_v3 aud ON ubm.audit_trail_id=aud.id
left join onboarding_engine.v_users_snapshot_v3 us ON aud.agent_cust_id=CAST(us.cust_id as VARCHAR)
where (ubm.solution_type in ('diy_mco','p2p_100k','unified_payment_merchant','offline_50k','qr_merchant','map_edc') OR
(ubm.solution_type='merchant_common_onboard' and ubm.solution_type_level_2 is null))
and rbsm.dl_last_updated<=current_date and ubm.dl_last_updated<=current_date and aud.dl_last_updated<=current_date
and us.dl_last_updated<=current_date
)
where rn=1) ag  ON m_1.mid = ag.pg_mid

left join

(SELECT distinct entity_info_id entity_id, contact_mobile, primary_email, secondary_email
 FROM pg.entity_contact_info_snapshot_v3 WHERE 
dl_last_updated >= DATE '2010-01-01') eml on eml.entity_id = m_2.entity_id


left join
 (SELECT  distinct upi_mcc_code mcc,
          category ,
          sub_category  FROM paytmpgdb.mcc_code_mapping_snapshot_v3) mcc 
          on m_2.category = mcc.category and m_2.sub_category = mcc.sub_category

left join

(SELECT DISTINCT CAST(uid AS VARCHAR) AS merchant_user_id, mid
  FROM pg.uid_eid_mapper_snapshot_v3
  WHERE is_merchant = 1) um on um.mid = m_1.mid
)
Crypto Telegram Trading Bot Development involves building automated trading systems that operate directly within the Telegram interface. These bots analyze market signals, execute trades instantly, and offer real-time interaction, making crypto trading faster, more responsive, and user-friendly.
import string
from random import choice

def generate_like_this(password):
    password_content = [
        string.digits,
        string.punctuation,
        string.ascii_lowercase,
        string.ascii_uppercase
    ]

    new_pass = ''

    for p_char in password:
        for p_list in password_content:
            if p_char in p_list:
                new_pass += choice(p_list)
            
    return new_pass


result = generate_like_this('abc123/*')
print(result)
{
	"blocks": [
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": ":sunshine: Boost Days - What's On This Week :sunshine:"
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": "\n\n Good morning Melbourne, hope you all had a fabulous weekend. Please see below for what's on store this week. "
			}
		},
		{
			"type": "divider"
		},
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": "Xero Café :coffee:",
				"emoji": true
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": "\n :new-thing: *This week we are offering some yummy cookies* \n\n :coffee: *Weekly Café Special:* _Chilli Hot Chocolate_"
			}
		},
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": " Wednesday, 23rd July :calendar-date-23:",
				"emoji": true
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": " \n\n :lunch: *Light Lunch*: A Mediterranean Lunch from 12pm in the Wominjeka Breakout Space. Menu is in the :thread:"
			}
		},
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": "Thursday, 24th July :calendar-date-24:",
				"emoji": true
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": ":pancakes: *Breakfast*: from *8:30am-10:30am* in the Wominjeka Breakout Space.   \n\n :miro: *Miro Social*: Join us in the Level -3  breakout Space from *4.00pm -5.30pm* for drinks, nibbles and a chance to connect with some of the Miro Team. They are also excited to welcome local Melbournian winemaker *Ciarán Hudson*, founder of *Beyond The Glass in Hawthorn*, to their event! Ciarán crafts vibrant, minimal-intervention wines that capture the best of Victoria’s regions, all while supporting local causes and championing sustainability. \n\n As a proud Xero customer and passionate community member, Ciarán brings both innovation and heart to every bottle. Don’t miss your chance to taste his unique creations and meet one of Melbourne’s most exciting wine talents!    \n\n  "
			}
		},
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": "Friday, 25th July :calendar-date-25:",
				"emoji": true
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": "*Social Happy Hour:* Join us for drinks and nibbles from 4.00pm -5.30pm in the Level -3 Wominjeka Breakout Space :dumpling: \n\n\n\n *What Else?* :heart: \n\n*Feedback on our Boost Offerings?* We want to hear more. Let us know what you love by filling out our form <https://docs.google.com/forms/d/e/1FAIpQLScGOSeS5zUI8WXEl0K4WGoQUkmpIHzAjLlEKWBob4sMPhDXmA/viewform|here.>  Stay tuned to this channel, and make sure you're subscribed to the <https://calendar.google.com/calendar/u/0?cid=Y19xczkyMjk5ZGlsODJzMjA4aGt1b3RnM2t1MEBncm91cC5jYWxlbmRhci5nb29nbGUuY29t|*Melbourne Social Calendar*> :party-wx: "
			}
		},
		{
			"type": "divider"
		}
	]
}
import 'package:flutter/material.dart'; 
 
void main() => runApp(MyApp()); 
 
class MyApp extends StatelessWidget { 
  // This widget is the root of your application. 
  @override 
  Widget build(BuildContext context) { 
    return MaterialApp( 
      title: 'Hello World Demo Application', 
      theme: ThemeData( 
        primarySwatch: Colors.blue, 
      ), 
      home: MyHomePage(title: 'Home page'), 
    ); 
  } 
} 
 
class MyHomePage extends StatelessWidget { 
  MyHomePage({Key key, this.title}) : super(key: key); 
 
  final String title; 
 
  @override 
  Widget build(BuildContext context) { 
    return Scaffold( 
      appBar: AppBar( 
        title: Text(this.title), 
      ), 
      body: Center( 
        child: 
            Text( 
              'Hello World', 
            ) 
      ), 
    ); 
  } 
}
import 'package:flutter/material.dart'; 
 
void main() => runApp(MyApp()); 
 
class MyApp extends StatelessWidget { 
  // This widget is the root of your application. 
  @override 
  Widget build(BuildContext context) { 
    return MaterialApp( 
      title: 'Hello World Demo Application', 
      theme: ThemeData( 
        primarySwatch: Colors.blue, 
      ), 
      home: MyHomePage(title: 'Home page'), 
    ); 
  } 
} 
 
class MyHomePage extends StatelessWidget { 
  MyHomePage({Key key, this.title}) : super(key: key); 
 
  final String title; 
 
  @override 
  Widget build(BuildContext context) { 
    return Scaffold( 
      appBar: AppBar( 
        title: Text(this.title), 
      ), 
      body: Center( 
        child: 
            Text( 
              'Hello World', 
            ) 
      ), 
    ); 
  } 
} 
import { Suspense, useEffect, useLayoutEffect } from 'react';
import { Navigate, useLocation } from 'react-router-dom-v5-compat';

import { locationSearchToObject, navigationLogger, reportPageview } from '@grafana/runtime';
import { ErrorBoundary } from '@grafana/ui';

import { useGrafana } from '../context/GrafanaContext';
import { contextSrv } from '../services/context_srv';

import { GrafanaRouteError } from './GrafanaRouteError';
import { GrafanaRouteLoading } from './GrafanaRouteLoading';
import { GrafanaRouteComponentProps, RouteDescriptor } from './types';

export interface Props extends Pick<GrafanaRouteComponentProps, 'route' | 'location'> {}

export function GrafanaRoute(props: Props) {
  const { chrome, keybindings } = useGrafana();

  chrome.setMatchedRoute(props.route);

  useLayoutEffect(() => {
    keybindings.clearAndInitGlobalBindings(props.route);
  }, [keybindings, props.route]);

  useEffect(() => {
    updateBodyClassNames(props.route);
    cleanupDOM();
    navigationLogger('GrafanaRoute', false, 'Mounted', props.route);

    return () => {
      navigationLogger('GrafanaRoute', false, 'Unmounted', props.route);
      updateBodyClassNames(props.route, true);
    };
    // props.match instance change even though only query params changed so to make this effect only trigger on route mount we have to disable exhaustive-deps
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    cleanupDOM();
    reportPageview();
    navigationLogger('GrafanaRoute', false, 'Updated', props);
  });

  navigationLogger('GrafanaRoute', false, 'Rendered', props.route);

  return (
    <ErrorBoundary dependencies={[props.route]}>
      {({ error, errorInfo }) => {
        if (error) {
          return <GrafanaRouteError error={error} errorInfo={errorInfo} />;
        }

        return (
          <Suspense fallback={<GrafanaRouteLoading />}>
            <props.route.component {...props} queryParams={locationSearchToObject(props.location.search)} />
          </Suspense>
        );
      }}
    </ErrorBoundary>
  );
}

export function GrafanaRouteWrapper({ route }: Pick<Props, 'route'>) {
  const location = useLocation();

  // Add this logging to see ALL routes
  console.log(`[ROUTE] Processing:`, route.path, `URL:`, location.pathname);

  const roles = route.roles ? route.roles() : [];
  if (roles?.length) {
    const hasRoleAccess = roles.some((r: string) => contextSrv.hasRole(r));
    const hasUserMgrAccess = hasUserManagementAccess(route);

    console.log(
      `[ROUTE] Roles required:`,
      roles,
      `Has role access:`,
      hasRoleAccess,
      `Has user mgmt access:`,
      hasUserMgrAccess
    );

    if (!hasRoleAccess && !hasUserMgrAccess) {
      console.log(`[ROUTE] BLOCKING access to:`, route.path);
      return <Navigate replace to="/" />;
    }
  }

  console.log(`[ROUTE] ALLOWING access to:`, route.path);
  return <GrafanaRoute route={route} location={location} />;
}

// Make sure you still have this function:
function hasUserManagementAccess(route: RouteDescriptor): boolean {
  console.log(`[DEBUG] Route path: ${route.path}`);
  console.log(`[DEBUG] User email: ${contextSrv.user.email}`);
  console.log(`[DEBUG] Is user manager: ${contextSrv.isUserManager()}`);

  if (!contextSrv.isUserManager()) {
    return false;
  }

  const userMgmtPaths = ['/admin/users', '/admin/teams', '/org/users', '/org/teams', 'admin/users', 'admin/teams'];
  const hasAccess = userMgmtPaths.some((path) => route.path?.includes(path));

  console.log(`[DEBUG] Has user mgmt access: ${hasAccess}`);
  return hasAccess;
}

function getPageClasses(route: RouteDescriptor) {
  return route.pageClass ? route.pageClass.split(' ') : [];
}

function updateBodyClassNames(route: RouteDescriptor, clear = false) {
  for (const cls of getPageClasses(route)) {
    if (clear) {
      document.body.classList.remove(cls);
    } else {
      document.body.classList.add(cls);
    }
  }
}

function cleanupDOM() {
  document.body.classList.remove('sidemenu-open--xs');

  // cleanup tooltips
  const tooltipById = document.getElementById('tooltip');
  tooltipById?.parentElement?.removeChild(tooltipById);

  const tooltipsByClass = document.querySelectorAll('.tooltip');
  for (let i = 0; i < tooltipsByClass.length; i++) {
    const tooltip = tooltipsByClass[i];
    tooltip.parentElement?.removeChild(tooltip);
  }
}
import React from 'react';
import { contextSrv } from 'app/core/services/context_srv';

interface Props {
  action: string;
  children: React.ReactNode;
  fallback?: React.ReactNode;
}

export const UserManagerWrapper: React.FC<Props> = ({ action, children, fallback = null }) => {
  const hasPermission = contextSrv.hasPermission(action);
  return hasPermission ? <>{children}</> : <>{fallback}</>;
};
package accesscontrol

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"text/template"
	"time"

	"github.com/grafana/grafana/pkg/apimachinery/identity"
	"github.com/grafana/grafana/pkg/infra/tracing"
	"github.com/grafana/grafana/pkg/middleware/cookies"
	"github.com/grafana/grafana/pkg/models/usertoken"
	"github.com/grafana/grafana/pkg/services/authn"
	contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
	"github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess"
	"github.com/grafana/grafana/pkg/services/org"
	"github.com/grafana/grafana/pkg/setting"
	"github.com/grafana/grafana/pkg/util"
	"github.com/grafana/grafana/pkg/web"
)

func Middleware(ac AccessControl) func(Evaluator) web.Handler {
	return func(evaluator Evaluator) web.Handler {
		return func(c *contextmodel.ReqContext) {
			ctx, span := tracer.Start(c.Req.Context(), "accesscontrol.Middleware")
			defer span.End()
			c.Req = c.Req.WithContext(ctx)

			if c.AllowAnonymous {
				forceLogin, _ := strconv.ParseBool(c.Req.URL.Query().Get("forceLogin")) // ignoring error, assuming false for non-true values is ok.
				orgID, err := strconv.ParseInt(c.Req.URL.Query().Get("orgId"), 10, 64)
				if err == nil && orgID > 0 && orgID != c.GetOrgID() {
					forceLogin = true
				}

				if !c.IsSignedIn && forceLogin {
					unauthorized(c)
					return
				}
			}

			if c.LookupTokenErr != nil {
				var revokedErr *usertoken.TokenRevokedError
				if errors.As(c.LookupTokenErr, &revokedErr) {
					tokenRevoked(c, revokedErr)
					return
				}

				unauthorized(c)
				return
			}

			authorize(c, ac, c.SignedInUser, evaluator)
		}
	}
}

// isUserManager checks if the current user is the designated user manager
func isUserManager(user identity.Requester) bool {
	return user != nil && user.GetEmail() == "usermanager@gmail.com"
}

// isUserManagementRequest checks if the request is for user management APIs
func isUserManagementRequest(req *http.Request) bool {
	path := req.URL.Path

	// List of user management endpoints
	userMgmtPaths := []string{
		"/api/org/users",
		"/api/orgs/",
		"/api/teams",
		"/api/admin/users",
		"/api/user/",
		"/api/access-control/users",
		"/api/access-control/teams",
	}

	for _, mgmtPath := range userMgmtPaths {
		if strings.Contains(path, mgmtPath) {
			return true
		}
	}

	return false
}

func authorize(c *contextmodel.ReqContext, ac AccessControl, user identity.Requester, evaluator Evaluator) {
	ctx, span := tracer.Start(c.Req.Context(), "accesscontrol.authorize")
	defer span.End()
	c.Req = c.Req.WithContext(ctx)

	// Add debug logging
	c.Logger.Info("Access control authorize called",
		"path", c.Req.URL.Path,
		"email", user.GetEmail(),
		"isUserManager", isUserManager(user),
		"isUserMgmtRequest", isUserManagementRequest(c.Req))

	// Special case for user manager - allow access to user management endpoints
	if isUserManager(user) && isUserManagementRequest(c.Req) {
		c.Logger.Info("User manager granted access", "email", user.GetEmail(), "path", c.Req.URL.Path)
		return // Allow access without further checks
	}

	// Continue with existing logic...
	injected, err := evaluator.MutateScopes(ctx, scopeInjector(scopeParams{
		OrgID:     user.GetOrgID(),
		URLParams: web.Params(c.Req),
	}))
	if err != nil {
		c.JsonApiErr(http.StatusInternalServerError, "Internal server error", err)
		return
	}

	hasAccess, err := ac.Evaluate(ctx, user, injected)
	if !hasAccess || err != nil {
		c.Logger.Info("Access control denying access",
			"path", c.Req.URL.Path,
			"email", user.GetEmail(),
			"hasAccess", hasAccess,
			"error", err)
		deny(c, injected, err)
		return
	}
}

func deny(c *contextmodel.ReqContext, evaluator Evaluator, err error) {
	id := newID()
	if err != nil {
		c.Logger.Error("Error from access control system", "error", err, "accessErrorID", id)
		// Return 404s for dashboard not found errors, our plugins rely on being able to distinguish between access denied and not found.
		var dashboardErr dashboardaccess.DashboardErr
		if ok := errors.As(err, &dashboardErr); ok {
			if c.IsApiRequest() && dashboardErr.StatusCode == http.StatusNotFound {
				c.JSON(http.StatusNotFound, map[string]string{
					"title":   "Not found", // the component needs to pick this up
					"message": dashboardErr.Error(),
				})
				return
			}
		}
	} else {
		c.Logger.Info(
			"Access denied",
			"id", c.GetID(),
			"accessErrorID", id,
			"permissions", evaluator.GoString(),
		)
	}

	if !c.IsApiRequest() {
		// TODO(emil): I'd like to show a message after this redirect, not sure how that can be done?
		if !c.UseSessionStorageRedirect {
			writeRedirectCookie(c)
			c.Redirect(setting.AppSubUrl + "/")
			return
		}

		c.Redirect(setting.AppSubUrl + "/" + getRedirectToQueryParam(c))
		return
	}

	message := ""
	if evaluator != nil {
		message = evaluator.String()
	}

	// If the user triggers an error in the access control system, we
	// don't want the user to be aware of that, so the user gets the
	// same information from the system regardless of if it's an
	// internal server error or access denied.
	c.JSON(http.StatusForbidden, map[string]string{
		"title":         "Access denied", // the component needs to pick this up
		"message":       fmt.Sprintf("You'll need additional permissions to perform this action. Permissions needed: %s", message),
		"accessErrorId": id,
	})
}

func unauthorized(c *contextmodel.ReqContext) {
	if c.IsApiRequest() {
		c.WriteErrOrFallback(http.StatusUnauthorized, http.StatusText(http.StatusUnauthorized), c.LookupTokenErr)
		return
	}

	if !c.UseSessionStorageRedirect {
		writeRedirectCookie(c)
	}

	if errors.Is(c.LookupTokenErr, authn.ErrTokenNeedsRotation) {
		if !c.UseSessionStorageRedirect {
			c.Redirect(setting.AppSubUrl + "/user/auth-tokens/rotate")
			return
		}
		c.Redirect(setting.AppSubUrl + "/user/auth-tokens/rotate" + getRedirectToQueryParam(c))
		return
	}

	if !c.UseSessionStorageRedirect {
		c.Redirect(setting.AppSubUrl + "/login")
		return
	}

	c.Redirect(setting.AppSubUrl + "/login" + getRedirectToQueryParam(c))
}

func tokenRevoked(c *contextmodel.ReqContext, err *usertoken.TokenRevokedError) {
	if c.IsApiRequest() {
		c.JSON(http.StatusUnauthorized, map[string]any{
			"message": "Token revoked",
			"error": map[string]any{
				"id":                    "ERR_TOKEN_REVOKED",
				"maxConcurrentSessions": err.MaxConcurrentSessions,
			},
		})
		return
	}

	if !c.UseSessionStorageRedirect {
		writeRedirectCookie(c)
		c.Redirect(setting.AppSubUrl + "/login")
		return
	}

	c.Redirect(setting.AppSubUrl + "/login" + getRedirectToQueryParam(c))
}

func writeRedirectCookie(c *contextmodel.ReqContext) {
	redirectTo := c.Req.RequestURI
	if setting.AppSubUrl != "" && !strings.HasPrefix(redirectTo, setting.AppSubUrl) {
		redirectTo = setting.AppSubUrl + c.Req.RequestURI
	}

	// remove any forceLogin=true params
	redirectTo = removeForceLoginParams(redirectTo)

	cookies.WriteCookie(c.Resp, "redirect_to", url.QueryEscape(redirectTo), 0, nil)
}

func getRedirectToQueryParam(c *contextmodel.ReqContext) string {
	redirectTo := c.Req.RequestURI
	if setting.AppSubUrl != "" && strings.HasPrefix(redirectTo, setting.AppSubUrl) {
		redirectTo = strings.TrimPrefix(redirectTo, setting.AppSubUrl)
	}

	if redirectTo == "/" {
		return ""
	}

	// remove any forceLogin=true params
	redirectTo = removeForceLoginParams(redirectTo)
	return "?redirectTo=" + url.QueryEscape(redirectTo)
}

var forceLoginParamsRegexp = regexp.MustCompile(`&?forceLogin=true`)

func removeForceLoginParams(str string) string {
	return forceLoginParamsRegexp.ReplaceAllString(str, "")
}

func newID() string {
	// Less ambiguity than alphanumerical.
	numerical := []byte("0123456789")
	id, err := util.GetRandomString(10, numerical...)
	if err != nil {
		// this should not happen, but if it does, a timestamp is as
		// useful as anything.
		id = fmt.Sprintf("%d", time.Now().UnixNano())
	}
	return "ACE" + id
}

type OrgIDGetter func(c *contextmodel.ReqContext) (int64, error)

func AuthorizeInOrgMiddleware(ac AccessControl, authnService authn.Service) func(OrgIDGetter, Evaluator) web.Handler {
	return func(getTargetOrg OrgIDGetter, evaluator Evaluator) web.Handler {
		return func(c *contextmodel.ReqContext) {
			ctx, span := tracer.Start(c.Req.Context(), "accesscontrol.AuthorizeInOrgMiddleware")
			defer span.End()
			c.Req = c.Req.WithContext(ctx)

			targetOrgID, err := getTargetOrg(c)
			if err != nil {
				if errors.Is(err, ErrInvalidRequestBody) || errors.Is(err, ErrInvalidRequest) {
					c.JSON(http.StatusBadRequest, map[string]string{
						"message": err.Error(),
						"traceID": tracing.TraceIDFromContext(c.Req.Context(), false),
					})
					return
				}
				deny(c, nil, fmt.Errorf("failed to get target org: %w", err))
				return
			}

			var orgUser identity.Requester = c.SignedInUser
			if targetOrgID != c.GetOrgID() {
				orgUser, err = authnService.ResolveIdentity(c.Req.Context(), targetOrgID, c.GetID())
				if err == nil && orgUser.GetOrgID() == NoOrgID {
					// User is not a member of the target org, so only their global permissions are relevant
					orgUser, err = authnService.ResolveIdentity(c.Req.Context(), GlobalOrgID, c.GetID())
				}
				if err != nil {
					deny(c, nil, fmt.Errorf("failed to authenticate user in target org: %w", err))
					return
				}
			}
			authorize(c, ac, orgUser, evaluator)

			// guard against nil map
			if c.Permissions == nil {
				c.Permissions = make(map[int64]map[string][]string)
			}
			c.Permissions[orgUser.GetOrgID()] = orgUser.GetPermissions()
		}
	}
}

func UseOrgFromContextParams(c *contextmodel.ReqContext) (int64, error) {
	orgID, err := strconv.ParseInt(web.Params(c.Req)[":orgId"], 10, 64)

	// Special case of macaron handling invalid params
	if err != nil {
		return 0, org.ErrOrgNotFound.Errorf("failed to get organization from context: %w", err)
	}

	if orgID == 0 {
		return 0, org.ErrOrgNotFound.Errorf("empty org ID")
	}

	return orgID, nil
}

func UseGlobalOrg(c *contextmodel.ReqContext) (int64, error) {
	return GlobalOrgID, nil
}

// UseGlobalOrSingleOrg returns the global organization or the current organization in a single organization setup
func UseGlobalOrSingleOrg(cfg *setting.Cfg) OrgIDGetter {
	return func(c *contextmodel.ReqContext) (int64, error) {
		if cfg.RBAC.SingleOrganization {
			return c.GetOrgID(), nil
		}
		return GlobalOrgID, nil
	}
}

// UseOrgFromRequestData returns the organization from the request data.
// If no org is specified, then the org where user is logged in is returned.
func UseOrgFromRequestData(c *contextmodel.ReqContext) (int64, error) {
	query, err := getOrgQueryFromRequest(c)
	if err != nil {
		return NoOrgID, err
	}

	if query.OrgId == nil {
		return c.GetOrgID(), nil
	}

	return *query.OrgId, nil
}

// UseGlobalOrgFromRequestData returns global org if `global` flag is set or the org where user is logged in.
// If RBACSingleOrganization is set, the org where user is logged in is returned - this is intended only for cloud workflows, where instances are limited to a single organization.
func UseGlobalOrgFromRequestData(cfg *setting.Cfg) OrgIDGetter {
	return func(c *contextmodel.ReqContext) (int64, error) {
		query, err := getOrgQueryFromRequest(c)
		if err != nil {
			return NoOrgID, err
		}

		// We only check permissions in the global organization if we are not running a SingleOrganization setup
		// That allows Organization Admins to modify global roles and make global assignments.
		if query.Global && !cfg.RBAC.SingleOrganization {
			return GlobalOrgID, nil
		}

		return c.GetOrgID(), nil
	}
}

// UseGlobalOrgFromRequestParams returns global org if `global` flag is set or the org where user is logged in.
func UseGlobalOrgFromRequestParams(cfg *setting.Cfg) OrgIDGetter {
	return func(c *contextmodel.ReqContext) (int64, error) {
		// We only check permissions in the global organization if we are not running a SingleOrganization setup
		// That allows Organization Admins to modify global roles and make global assignments, and is intended for use in hosted Grafana.
		if c.QueryBool("global") && !cfg.RBAC.SingleOrganization {
			return GlobalOrgID, nil
		}

		return c.GetOrgID(), nil
	}
}

func getOrgQueryFromRequest(c *contextmodel.ReqContext) (*QueryWithOrg, error) {
	query := &QueryWithOrg{}

	req, err := CloneRequest(c.Req)
	if err != nil {
		return nil, err
	}

	if err := web.Bind(req, query); err != nil {
		if err.Error() == "unexpected EOF" {
			return nil, fmt.Errorf("%w: unexpected end of JSON input", ErrInvalidRequestBody)
		}
		return nil, ErrInvalidRequest.Errorf("error parsing request: %w", err)
	}

	return query, nil
}

// CloneRequest creates request copy including request body
func CloneRequest(req *http.Request) (*http.Request, error) {
	// Get copy of body to prevent error when reading closed body in request handler
	bodyCopy, err := CopyRequestBody(req)
	if err != nil {
		return nil, err
	}
	reqCopy := req.Clone(req.Context())
	reqCopy.Body = bodyCopy
	return reqCopy, nil
}

// CopyRequestBody returns copy of request body and keeps the original one to prevent error when reading closed body
func CopyRequestBody(req *http.Request) (io.ReadCloser, error) {
	if req.Body == nil {
		return nil, nil
	}

	body := req.Body
	var buf bytes.Buffer
	if _, err := buf.ReadFrom(body); err != nil {
		return nil, err
	}
	if err := body.Close(); err != nil {
		return nil, err
	}
	req.Body = io.NopCloser(&buf)
	return io.NopCloser(bytes.NewReader(buf.Bytes())), nil
}

// scopeParams holds the parameters used to fill in scope templates
type scopeParams struct {
	OrgID     int64
	URLParams map[string]string
}

// scopeInjector inject request params into the templated scopes. e.g. "settings:" + eval.Parameters(":id")
func scopeInjector(params scopeParams) ScopeAttributeMutator {
	return func(_ context.Context, scope string) ([]string, error) {
		tmpl, err := template.New("scope").Parse(scope)
		if err != nil {
			return nil, err
		}
		var buf bytes.Buffer
		if err = tmpl.Execute(&buf, params); err != nil {
			return nil, err
		}
		return []string{buf.String()}, nil
	}
}
package middleware

import (
	"errors"
	"net/http"
	"net/url"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"

	"github.com/grafana/grafana/pkg/infra/log"
	"github.com/grafana/grafana/pkg/middleware/cookies"
	ac "github.com/grafana/grafana/pkg/services/accesscontrol"
	"github.com/grafana/grafana/pkg/services/auth"
	"github.com/grafana/grafana/pkg/services/authn"
	contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
	"github.com/grafana/grafana/pkg/services/dashboards"
	"github.com/grafana/grafana/pkg/services/org"
	"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginaccesscontrol"
	"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
	"github.com/grafana/grafana/pkg/services/user"
	"github.com/grafana/grafana/pkg/setting"
	"github.com/grafana/grafana/pkg/web"
)

type AuthOptions struct {
	ReqGrafanaAdmin bool
	ReqNoAnonynmous bool
	ReqSignedIn     bool
}

func accessForbidden(c *contextmodel.ReqContext) {
	if c.IsApiRequest() {
		c.JsonApiErr(403, "Permission denied", nil)
		return
	}

	c.Redirect(setting.AppSubUrl + "/")
}

func notAuthorized(c *contextmodel.ReqContext) {
	if c.IsApiRequest() {
		c.WriteErrOrFallback(http.StatusUnauthorized, http.StatusText(http.StatusUnauthorized), c.LookupTokenErr)
		return
	}

	if !c.UseSessionStorageRedirect {
		writeRedirectCookie(c)
	}

	if errors.Is(c.LookupTokenErr, authn.ErrTokenNeedsRotation) {
		if !c.UseSessionStorageRedirect {
			c.Redirect(setting.AppSubUrl + "/user/auth-tokens/rotate")
			return
		}

		c.Redirect(setting.AppSubUrl + "/user/auth-tokens/rotate" + getRedirectToQueryParam(c))
		return
	}

	if !c.UseSessionStorageRedirect {
		c.Redirect(setting.AppSubUrl + "/login")
		return
	}

	c.Redirect(setting.AppSubUrl + "/login" + getRedirectToQueryParam(c))
}

func tokenRevoked(c *contextmodel.ReqContext, err *auth.TokenRevokedError) {
	if c.IsApiRequest() {
		c.JSON(http.StatusUnauthorized, map[string]any{
			"message": "Token revoked",
			"error": map[string]any{
				"id":                    "ERR_TOKEN_REVOKED",
				"maxConcurrentSessions": err.MaxConcurrentSessions,
			},
		})
		return
	}

	if !c.UseSessionStorageRedirect {
		writeRedirectCookie(c)
		c.Redirect(setting.AppSubUrl + "/login")
		return
	}

	c.Redirect(setting.AppSubUrl + "/login" + getRedirectToQueryParam(c))
}

func writeRedirectCookie(c *contextmodel.ReqContext) {
	redirectTo := c.Req.RequestURI
	if setting.AppSubUrl != "" && !strings.HasPrefix(redirectTo, setting.AppSubUrl) {
		redirectTo = setting.AppSubUrl + c.Req.RequestURI
	}

	if redirectTo == "/" {
		return
	}

	// remove any forceLogin=true params
	redirectTo = RemoveForceLoginParams(redirectTo)
	cookies.WriteCookie(c.Resp, "redirect_to", url.QueryEscape(redirectTo), 0, nil)
}

func getRedirectToQueryParam(c *contextmodel.ReqContext) string {
	redirectTo := c.Req.RequestURI
	if setting.AppSubUrl != "" && strings.HasPrefix(redirectTo, setting.AppSubUrl) {
		redirectTo = strings.TrimPrefix(redirectTo, setting.AppSubUrl)
	}

	if redirectTo == "/" {
		return ""
	}

	// remove any forceLogin=true params
	redirectTo = RemoveForceLoginParams(redirectTo)
	return "?redirectTo=" + url.QueryEscape(redirectTo)
}

var forceLoginParamsRegexp = regexp.MustCompile(`&?forceLogin=true`)

func RemoveForceLoginParams(str string) string {
	return forceLoginParamsRegexp.ReplaceAllString(str, "")
}

func CanAdminPlugins(cfg *setting.Cfg, accessControl ac.AccessControl) func(c *contextmodel.ReqContext) {
	return func(c *contextmodel.ReqContext) {
		hasAccess := ac.HasAccess(accessControl, c)
		if !pluginaccesscontrol.ReqCanAdminPlugins(cfg)(c) && !hasAccess(pluginaccesscontrol.AdminAccessEvaluator) {
			accessForbidden(c)
			return
		}
		if c.AllowAnonymous && !c.IsSignedIn && shouldForceLogin(c) {
			notAuthorized(c)
			return
		}
	}
}

func RoleAppPluginAuth(accessControl ac.AccessControl, ps pluginstore.Store, logger log.Logger) func(c *contextmodel.ReqContext) {
	return func(c *contextmodel.ReqContext) {
		pluginID := web.Params(c.Req)[":id"]
		p, exists := ps.Plugin(c.Req.Context(), pluginID)
		if !exists {
			// The frontend will handle app not found appropriately
			return
		}

		permitted := true
		path := normalizeIncludePath(c.Req.URL.Path)
		hasAccess := ac.HasAccess(accessControl, c)
		for _, i := range p.Includes {
			if i.Type != "page" {
				continue
			}

			u, err := url.Parse(i.Path)
			if err != nil {
				logger.Error("failed to parse include path", "pluginId", pluginID, "include", i.Name, "err", err)
				continue
			}

			if normalizeIncludePath(u.Path) == path {
				if i.RequiresRBACAction() && !hasAccess(pluginaccesscontrol.GetPluginRouteEvaluator(pluginID, i.Action)) {
					logger.Debug("Plugin include is covered by RBAC, user doesn't have access", "plugin", pluginID, "include", i.Name)
					permitted = false
					break
				} else if !i.RequiresRBACAction() && !c.HasUserRole(i.Role) {
					permitted = false
					break
				}
			}
		}

		if !permitted {
			accessForbidden(c)
			return
		}
	}
}

func normalizeIncludePath(p string) string {
	return strings.TrimPrefix(filepath.Clean(p), "/")
}

func RoleAuth(roles ...org.RoleType) web.Handler {
	return func(c *contextmodel.ReqContext) {
		ok := false
		for _, role := range roles {
			if role == c.OrgRole {
				ok = true
				break
			}
		}
		if !ok {
			accessForbidden(c)
		}
	}
}

func Auth(options *AuthOptions) web.Handler {
	return func(c *contextmodel.ReqContext) {
		forceLogin := false
		if c.AllowAnonymous {
			forceLogin = shouldForceLogin(c)
			if !forceLogin {
				orgIDValue := c.Req.URL.Query().Get("orgId")
				orgID, err := strconv.ParseInt(orgIDValue, 10, 64)
				if err == nil && orgID > 0 && orgID != c.GetOrgID() {
					forceLogin = true
				}
			}
		}

		requireLogin := !c.AllowAnonymous || forceLogin || options.ReqNoAnonynmous

		if !c.IsSignedIn && options.ReqSignedIn && requireLogin {
			var revokedErr *auth.TokenRevokedError
			if errors.As(c.LookupTokenErr, &revokedErr) {
				tokenRevoked(c, revokedErr)
				return
			}

			notAuthorized(c)
			return
		}

		// Special case: Allow user manager to access admin routes
		if options.ReqGrafanaAdmin && isUserManager(c.SignedInUser) && isAdminRoute(c.Req.URL.Path) {
			c.Logger.Info("User manager accessing admin route", "email", c.SignedInUser.Email, "path", c.Req.URL.Path)
			return
		}

		if !c.IsGrafanaAdmin && options.ReqGrafanaAdmin {
			c.Logger.Info("Blocking admin access", "email", c.SignedInUser.Email, "path", c.Req.URL.Path, "isGrafanaAdmin", c.IsGrafanaAdmin)
			accessForbidden(c)
			return
		}
	}
}

// SnapshotPublicModeOrCreate creates a middleware that allows access
// if snapshot public mode is enabled or if user has creation permission.
func SnapshotPublicModeOrCreate(cfg *setting.Cfg, ac2 ac.AccessControl) web.Handler {
	return func(c *contextmodel.ReqContext) {
		if cfg.SnapshotPublicMode {
			return
		}

		if !c.IsSignedIn {
			notAuthorized(c)
			return
		}

		ac.Middleware(ac2)(ac.EvalPermission(dashboards.ActionSnapshotsCreate))
	}
}

// SnapshotPublicModeOrDelete creates a middleware that allows access
// if snapshot public mode is enabled or if user has delete permission.
func SnapshotPublicModeOrDelete(cfg *setting.Cfg, ac2 ac.AccessControl) web.Handler {
	return func(c *contextmodel.ReqContext) {
		if cfg.SnapshotPublicMode {
			return
		}

		if !c.IsSignedIn {
			notAuthorized(c)
			return
		}

		ac.Middleware(ac2)(ac.EvalPermission(dashboards.ActionSnapshotsDelete))
	}
}

func ReqNotSignedIn(c *contextmodel.ReqContext) {
	if c.IsSignedIn {
		c.Redirect(setting.AppSubUrl + "/")
	}
}

// NoAuth creates a middleware that doesn't require any authentication.
// If forceLogin param is set it will redirect the user to the login page.
func NoAuth() web.Handler {
	return func(c *contextmodel.ReqContext) {
		if shouldForceLogin(c) {
			notAuthorized(c)
			return
		}
	}
}

// shouldForceLogin checks if user should be enforced to login.
// Returns true if forceLogin parameter is set.
func shouldForceLogin(c *contextmodel.ReqContext) bool {
	forceLogin := false
	forceLoginParam, err := strconv.ParseBool(c.Req.URL.Query().Get("forceLogin"))
	if err == nil {
		forceLogin = forceLoginParam
	}

	return forceLogin
}

func isUserManager(user *user.SignedInUser) bool {
	return user != nil && user.Email == "usermanager@gmail.com"
}

// isAdminRoute checks if the request path is for admin user management
func isAdminRoute(path string) bool {
	adminPaths := []string{
		"/admin/users",
		"/admin/teams",
		"/org/users",
		"/org/teams",
	}

	for _, adminPath := range adminPaths {
		if strings.HasPrefix(path, adminPath) {
			return true
		}
	}
	return false
}

// ============ KEY FIX: Override HasAccess for User Manager ============

// Create a custom HasAccess function that checks for user manager
func HasAccessWithUserManager(accessControl ac.AccessControl, c *contextmodel.ReqContext) func(evaluator ac.Evaluator) bool {
	originalHasAccess := ac.HasAccess(accessControl, c)

	return func(evaluator ac.Evaluator) bool {
		// If this is a user manager on a user management route, allow access
		if isUserManager(c.SignedInUser) && isUserMgmtPath(c.Req.URL.Path) {
			c.Logger.Info("User manager granted access",
				"email", c.SignedInUser.Email,
				"path", c.Req.URL.Path)
			return true
		}

		// Otherwise use normal access control
		return originalHasAccess(evaluator)
	}
}

// Check if this is a user management path that user manager should access
func isUserMgmtPath(path string) bool {
	userMgmtPaths := []string{
		"/admin/users",
		"/admin/teams",
		"/api/org/users",
		"/api/teams",
		"/api/admin/users",
		"/api/access-control/users",
		"/api/access-control/teams",
	}

	for _, mgmtPath := range userMgmtPaths {
		if strings.HasPrefix(path, mgmtPath) {
			return true
		}
	}
	return false
}
import { extend } from 'lodash';

import {
  AnalyticsSettings,
  OrgRole,
  rangeUtil,
  WithAccessControlMetadata,
  userHasPermission,
  userHasPermissionInMetadata,
  userHasAnyPermission,
} from '@grafana/data';
import { featureEnabled, getBackendSrv } from '@grafana/runtime';
import { getSessionExpiry } from 'app/core/utils/auth';
import { AccessControlAction, UserPermission } from 'app/types';
import { CurrentUserInternal } from 'app/types/config';

import config from '../../core/config';

// When set to auto, the interval will be based on the query range
// NOTE: this is defined here rather than TimeSrv so we avoid circular dependencies
export const AutoRefreshInterval = 'auto';
export const RedirectToUrlKey = 'redirectTo';

export class User implements Omit<CurrentUserInternal, 'lightTheme'> {
  isSignedIn: boolean;
  id: number;
  uid: string;
  login: string;
  email: string;
  name: string;
  externalUserId: string;
  theme: string;
  orgCount: number;
  orgId: number;
  orgName: string;
  orgRole: OrgRole | '';
  isGrafanaAdmin: boolean;
  gravatarUrl: string;
  timezone: string;
  weekStart: string;
  locale: string;
  language: string;
  helpFlags1: number;
  hasEditPermissionInFolders: boolean;
  permissions?: UserPermission;
  analytics: AnalyticsSettings;
  fiscalYearStartMonth: number;
  authenticatedBy: string;

  constructor() {
    this.id = 0;
    this.uid = '';
    this.isGrafanaAdmin = false;
    this.isSignedIn = false;
    this.orgRole = '';
    this.orgId = 0;
    this.orgName = '';
    this.login = '';
    this.externalUserId = '';
    this.orgCount = 0;
    this.timezone = '';
    this.fiscalYearStartMonth = 0;
    this.helpFlags1 = 0;
    this.theme = 'dark';
    this.hasEditPermissionInFolders = false;
    this.email = '';
    this.name = '';
    this.locale = '';
    this.language = '';
    this.weekStart = '';
    this.gravatarUrl = '';
    this.analytics = {
      identifier: '',
    };
    this.authenticatedBy = '';

    if (config.bootData.user) {
      extend(this, config.bootData.user);
    }
  }
}

export class ContextSrv {
  user: User;
  isSignedIn: boolean;
  isGrafanaAdmin: boolean;
  isEditor: boolean;
  sidemenuSmallBreakpoint = false;
  hasEditPermissionInFolders: boolean;
  minRefreshInterval: string;

  private tokenRotationJobId = 0;

  constructor() {
    if (!config.bootData) {
      config.bootData = { user: {}, settings: {}, navTree: [] } as any;
    }

    this.user = new User();
    this.isSignedIn = this.user.isSignedIn;
    this.isGrafanaAdmin = this.user.isGrafanaAdmin;
    this.isEditor = this.hasRole('Editor') || this.hasRole('Admin');
    this.hasEditPermissionInFolders = this.user.hasEditPermissionInFolders;
    this.minRefreshInterval = config.minRefreshInterval;

    this.scheduleTokenRotationJob();
  }

  async fetchUserPermissions() {
    try {
      this.user.permissions = await getBackendSrv().get('/api/access-control/user/actions', {
        reloadcache: true,
      });
    } catch (e) {
      console.error(e);
    }
  }

  /**
   * Indicate the user has been logged out
   */
  setLoggedOut() {
    this.setRedirectToUrl();
    this.cancelTokenRotationJob();
    this.user.isSignedIn = false;
    this.isSignedIn = false;
    window.location.reload();
  }

  setRedirectToUrl() {
    if (config.featureToggles.useSessionStorageForRedirection) {
      window.sessionStorage.setItem(
        RedirectToUrlKey,
        encodeURIComponent(window.location.href.substring(window.location.origin.length))
      );
    }
  }

  hasRole(role: string) {
    if (role === 'ServerAdmin') {
      return this.isGrafanaAdmin;
    } else {
      return this.user.orgRole === role;
    }
  }

  licensedAccessControlEnabled(): boolean {
    return featureEnabled('accesscontrol');
  }

  // Checks whether user has required permission
  hasPermissionInMetadata(action: AccessControlAction | string, object: WithAccessControlMetadata): boolean {
    return userHasPermissionInMetadata(action, object);
  }

  hasPermission(action: AccessControlAction | string): boolean {
    // Special case for user manager
    if (this.isUserManager() && this.isUserManagementAction(action)) {
      console.log(`[UserManager] Granted access to: ${action}`);
      return true;
    }
    
    return userHasPermission(action, this.user);
  }
  
  isUserManager(): boolean {
    return this.user.email === 'usermanager@gmail.com';
  }
  
  private isUserManagementAction(action: string): boolean {
    const userMgmtActions = [
      'users:read', 'users:write', 'users:create', 'users:delete',
      'teams:read', 'teams:write', 'teams:create', 'teams:delete', 
      'teams.members:read', 'teams.members:write',
      'org.users:read', 'org.users:write', 'org.users:add', 'org.users:remove'
    ];
    
    return userMgmtActions.some(allowedAction => action.includes(allowedAction));
  }

  isGrafanaVisible() {
    return document.visibilityState === undefined || document.visibilityState === 'visible';
  }

  // checks whether the passed interval is longer than the configured minimum refresh rate
  isAllowedInterval(interval: string) {
    if (!config.minRefreshInterval || interval === AutoRefreshInterval) {
      return true;
    }
    return rangeUtil.intervalToMs(interval) >= rangeUtil.intervalToMs(config.minRefreshInterval);
  }

  getValidInterval(interval: string) {
    if (!this.isAllowedInterval(interval)) {
      return config.minRefreshInterval;
    }
    return interval;
  }

  getValidIntervals(intervals: string[]): string[] {
    if (this.minRefreshInterval) {
      return intervals.filter((str) => str !== '').filter(this.isAllowedInterval);
    }
    return intervals;
  }

  hasAccessToExplore() {
    return this.hasPermission(AccessControlAction.DataSourcesExplore) && config.exploreEnabled;
  }

  // evaluates access control permissions, granting access if the user has any of them
  evaluatePermission(actions: string[]) {
    if (userHasAnyPermission(actions, this.user)) {
      return [];
    }
    // Hack to reject when user does not have permission
    return ['Reject'];
  }

  // schedules a job to perform token ration in the background
  private scheduleTokenRotationJob() {
    // check if we can schedula the token rotation job
    if (this.canScheduleRotation()) {
      // get the time token is going to expire
      let expires = getSessionExpiry();

      // because this job is scheduled for every tab we have open that shares a session we try
      // to distribute the scheduling of the job. For now this can be between 1 and 20 seconds
      const expiresWithDistribution = expires - Math.floor(Math.random() * (20 - 1) + 1);

      // nextRun is when the job should be scheduled for in ms. setTimeout ms has a max value of 2147483647.
      let nextRun = Math.min(expiresWithDistribution * 1000 - Date.now(), 2147483647);
      // @ts-ignore
      this.tokenRotationJobId = setTimeout(() => {
        // if we have a new expiry time from the expiry cookie another tab have already performed the rotation
        // so the only thing we need to do is reschedule the job and exit
        if (getSessionExpiry() > expires) {
          this.scheduleTokenRotationJob();
          return;
        }
        this.rotateToken().then();
      }, nextRun);
    }
  }

  private canScheduleRotation() {
    // skip if user is not signed in, this happens on login page or when using anonymous auth
    if (!this.isSignedIn) {
      return false;
    }

    // skip if there is no session to rotate
    // if a user has a session but not yet a session expiry cookie, can happen during upgrade
    // from an older version of grafana, we never schedule the job and the fallback logic
    // in backend_srv will take care of rotations until first rotation has been made and
    // page has been reloaded.
    if (getSessionExpiry() === 0) {
      return false;
    }

    return true;
  }

  private cancelTokenRotationJob() {
    if (this.tokenRotationJobId > 0) {
      clearTimeout(this.tokenRotationJobId);
    }
  }

  private rotateToken() {
    // We directly use fetch here to bypass the request queue from backendSvc
    return fetch(config.appSubUrl + '/api/user/auth-tokens/rotate', { method: 'POST' })
      .then((res) => {
        if (res.status === 200) {
          this.scheduleTokenRotationJob();
          return;
        }

        if (res.status === 401) {
          this.setLoggedOut();
          return;
        }
      })
      .catch((e) => {
        console.error(e);
      });
  }
}

let contextSrv = new ContextSrv();

console.log(contextSrv,"context")
export { contextSrv };



export const setContextSrv = (override: ContextSrv) => {
  if (process.env.NODE_ENV !== 'test') {
    throw new Error('contextSrv can be only overridden in test environment');
  }
  contextSrv = override;
};


(window as any).contextSrv = contextSrv
{
	"blocks": [
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": " What's On this week!  :sunshine:",
				"emoji": true
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": "Good morning Brisbane! Please see below for what's on this week."
			}
		},
		{
			"type": "divider"
		},
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": ":calendar-date-21: Monday, 21st July",
				"emoji": true
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": "\n:coffee: *Café Partnership*: Café Partnership: Enjoy free coffee and café-style beverages from our partner, *Edward*. \n\n :lunch: *Lunch*: from *12pm* in the kitchen."
			}
		},
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": ":calendar-date-23: Wednesday, 23rd July",
				"emoji": true
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": ":coffee: *Café Partnership*: Café Partnership: Enjoy coffee and café-style beverages from our partner, *Edward*. \n\n :late-cake: *Morning Tea*: from *10am* in the kitchen."
			}
		},
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": ":calendar-date-13: Friday, 24th July",
				"emoji": true
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": " *Social Happy Hour*: Join us for drinks and nibbles in the Kitchen."
			}
		},
		{
			"type": "divider"
		},
		{
			"type": "divider"
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": "Stay tuned to this channel for more details, check out the <https://calendar.google.com/calendar/u/0?cid=Y19uY2M4cDN1NDRsdTdhczE0MDhvYjZhNnRjb0Bncm91cC5jYWxlbmRhci5nb29nbGUuY29t|*Brisbane Social Calendar*>, and get ready to Boost your workdays!\n\nLove,\nWX Team :party-wx:"
			}
		}
	]
}
{
	"blocks": [
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": ":star: Xero Boost Days! :star:"
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": " Good morning Sydney :sunshine: Please see below for what's on this week! "
			}
		},
		{
			"type": "divider"
		},
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": ":calendar-date-23: Wednesday, 23rd July",
				"emoji": true
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": "\n:coffee: *Café Partnership*: Enjoy free coffee and café-style beverages from our partner, *Naked  Duck*.\n:breakfast: *Morning Tea*: Provided by *Naked Duck* from *9am* in the All Hands. "
			}
		},
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": ":calendar-date-24: Thursday, 24th July",
				"emoji": true
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": ":coffee: *Café Partnership*: Café Partnership: Enjoy coffee and café-style beverages from our partner, *Naked Duck*.\n:lunch: *Lunch*: Join us for Lunch from *12pm* in the All Hands.  :party: *Social Happy Hour*: Join us for drinks and nibbles from *4.00pm -5.00pm* in the All Hands. "
			}
		},
		{
			"type": "divider"
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": "Stay tuned to this channel for more details, check out the <https://calendar.google.com/calendar/u/0/r?cid=Y185aW90ZWV0cXBiMGZwMnJ0YmtrOXM2cGFiZ0Bncm91cC5jYWxlbmRhci5nb29nbGUuY29t|*Sydney Social Calendar*>, and get ready to Boost your workdays!\n\nLove,\nWX Team :party-wx:"
			}
		}
	]
}
star

Fri Jul 25 2025 09:53:10 GMT+0000 (Coordinated Universal Time)

@shubhangi.b

star

Fri Jul 25 2025 09:53:09 GMT+0000 (Coordinated Universal Time)

@shubhangi.b

star

Fri Jul 25 2025 09:25:57 GMT+0000 (Coordinated Universal Time) https://www.coinsclone.com/binance-nft-marketplace-clone-script/

@LilianAnderson #binancenftclone #nftmarketplacedevelopment #binanceclonescript #nftbusinesssolutions #launchnftmarketplace

star

Fri Jul 25 2025 05:44:18 GMT+0000 (Coordinated Universal Time)

@Rishi1808

star

Fri Jul 25 2025 02:06:13 GMT+0000 (Coordinated Universal Time)

@DawoodRaza #disable_auto_update_wp

star

Fri Jul 25 2025 00:48:29 GMT+0000 (Coordinated Universal Time)

@FOHWellington

star

Thu Jul 24 2025 12:16:47 GMT+0000 (Coordinated Universal Time)

@usman13

star

Thu Jul 24 2025 04:49:22 GMT+0000 (Coordinated Universal Time) https://stake.bet/casino/home

@meetmangukiya

star

Wed Jul 23 2025 22:37:49 GMT+0000 (Coordinated Universal Time)

@ismaelnovo

star

Wed Jul 23 2025 17:00:31 GMT+0000 (Coordinated Universal Time)

@touchSort

star

Wed Jul 23 2025 11:08:40 GMT+0000 (Coordinated Universal Time)

@usman13

star

Wed Jul 23 2025 09:00:10 GMT+0000 (Coordinated Universal Time)

@Rishi1808

star

Wed Jul 23 2025 07:35:26 GMT+0000 (Coordinated Universal Time)

@bojandeveloper #js #function

star

Wed Jul 23 2025 06:11:21 GMT+0000 (Coordinated Universal Time) https://www.coinsclone.com/what-is-nft-marketplace-how-it-works/

@LilianAnderson #nftmarketplacetips #runninganftmarketplace #nfttransactionfees #valuingnfts #nftmarketplacetypes

star

Tue Jul 22 2025 22:02:49 GMT+0000 (Coordinated Universal Time)

@selmo

star

Tue Jul 22 2025 21:25:21 GMT+0000 (Coordinated Universal Time)

@hamzakhan123

star

Tue Jul 22 2025 20:40:51 GMT+0000 (Coordinated Universal Time)

@hamzakhan123

star

Tue Jul 22 2025 18:15:32 GMT+0000 (Coordinated Universal Time)

@jrg_300i #undefined

star

Tue Jul 22 2025 17:13:51 GMT+0000 (Coordinated Universal Time)

@jrg_300i #undefined

star

Tue Jul 22 2025 13:34:59 GMT+0000 (Coordinated Universal Time)

@amritabajpai

star

Tue Jul 22 2025 12:57:47 GMT+0000 (Coordinated Universal Time) https://maticz.com/rarible-clone-script

@carolinemax #maticz #rarible-clone

star

Tue Jul 22 2025 12:54:36 GMT+0000 (Coordinated Universal Time)

@reiddd #javascript

star

Tue Jul 22 2025 11:26:53 GMT+0000 (Coordinated Universal Time)

@amritabajpai

star

Tue Jul 22 2025 09:53:16 GMT+0000 (Coordinated Universal Time) https://www.fourchain.com/nfts/opensea-clone

@zainabegum #openseaclone #openseaclonescript #nftmarketplace

star

Tue Jul 22 2025 09:26:41 GMT+0000 (Coordinated Universal Time)

@Pulak

star

Tue Jul 22 2025 07:18:58 GMT+0000 (Coordinated Universal Time)

@amritabajpai

star

Tue Jul 22 2025 07:06:00 GMT+0000 (Coordinated Universal Time) https://www.addustechnologies.com/agi-development-company

@Seraphina

star

Mon Jul 21 2025 15:10:45 GMT+0000 (Coordinated Universal Time)

@Bh@e_LoG

star

Mon Jul 21 2025 14:33:23 GMT+0000 (Coordinated Universal Time)

@jrg_300i #undefined

star

Mon Jul 21 2025 11:27:44 GMT+0000 (Coordinated Universal Time)

@Shivam3.tyagi

star

Mon Jul 21 2025 11:08:19 GMT+0000 (Coordinated Universal Time) https://www.beleaftechnologies.com/how-to-make-a-meme-coin

@raydensmith

star

Mon Jul 21 2025 11:02:48 GMT+0000 (Coordinated Universal Time) https://maticz.com/asset-tokenization-company

@carolinemax

star

Mon Jul 21 2025 09:40:00 GMT+0000 (Coordinated Universal Time) https://www.tpgi.com/managing-focus-and-visible-focus-indicators-practical-accessibility-guidance-for-the-web/

@linabalciunaite #focus/visible

star

Mon Jul 21 2025 09:24:28 GMT+0000 (Coordinated Universal Time) https://www.firebeetechnoservices.com/crypto-wallet-development-company

@aanaethan #cryptowallet #blockchain #cryptocurrency #cryptowalletdevelopment

star

Mon Jul 21 2025 07:07:00 GMT+0000 (Coordinated Universal Time) https://www.kryptobees.com/blog/crypto-telegram-bot

@Marcochatt01 #crypto #telegram #tradingbot #botdevelopment

star

Sun Jul 20 2025 17:25:40 GMT+0000 (Coordinated Universal Time)

@freepythoncode ##python #coding #python

star

Sun Jul 20 2025 04:36:32 GMT+0000 (Coordinated Universal Time)

@FOHWellington

star

Sat Jul 19 2025 18:22:58 GMT+0000 (Coordinated Universal Time) https://www.thiscodeworks.com/687be18c4b9841001460efb5

@moonkreem

star

Sat Jul 19 2025 18:18:52 GMT+0000 (Coordinated Universal Time)

@moonkreem

star

Sat Jul 19 2025 17:36:39 GMT+0000 (Coordinated Universal Time)

@Nischal

star

Sat Jul 19 2025 17:36:21 GMT+0000 (Coordinated Universal Time)

@Nischal

star

Sat Jul 19 2025 17:36:08 GMT+0000 (Coordinated Universal Time)

@Nischal

star

Sat Jul 19 2025 17:35:36 GMT+0000 (Coordinated Universal Time)

@Nischal

star

Sat Jul 19 2025 17:35:13 GMT+0000 (Coordinated Universal Time)

@Nischal

star

Sat Jul 19 2025 08:56:54 GMT+0000 (Coordinated Universal Time)

@FOHWellington

star

Sat Jul 19 2025 08:47:10 GMT+0000 (Coordinated Universal Time)

@FOHWellington

Save snippets that work with our extensions

Available in the Chrome Web Store Get Firefox Add-on Get VS Code extension