Friday, June 15, 2018

PowerSchool: Add Slide In Page for Custom Contact

Credit goes out to Sheldon from PSUG

Page fragment to add the button:

<script>
  jQuery(document).ready(function() {
    var url_string = window.location.href;
    console.log(url_string);
    var pStart = url_string.indexOf("contactid=", url_string.indexOf("#?")) + 10;
    var pEnd = url_string.indexOf("&", pStart);
    var contactID = 0;
    if (pEnd > 0)
      contactID = url_string.substring(pStart, pEnd);
    else
      contactID = url_string.substring(pStart);
    console.log(contactID);
    if (contactID != 0) {
      var html = '<div id="extensionfields-div"><label for="extensionfields-input">Extension Fields</label><a href="edit_extensionfields.html?id='+contactID+'" class="button dialogC dockedDialog" id="extensionfields-input" title="Extension Fields">Display</a></div>';
      jQuery("#suffix-div").after(html);
    }
  });
</script>

It looks like this:


The slide out page that has the input boxes (edit_extensionfields.html):
<script>
var existing = false;
jQuery.getJSON("edit_extensionfields.json?id=~(gpv.id)", function(data) {
  if (data.length > 1) {
    jQuery("#myfield1").val(data[0].myfield1);
    jQuery("#myfield2").val(data[0].myfield2);
    jQuery("#lastupdate").html(data[0].lastupdate);
    existing = true;
  }
});
function submitSave() {
  if (!existing) {
    jQuery.ajax({
      url: "/ws/schema/table/u_def_ext_person",
      async: false,
      method: "POST",
      contentType: "application/json",
      data: JSON.stringify({
        "tables":{
          "u_def_ext_person":{
            "personid":"~(gpv.id)",
            "myfield1":jQuery("#myfield1").val(),
            "myfield2":jQuery("#myfield2").val()
          }
        }
      }),
      complete: function(xhr, textStatus) {
        if (xhr.status == 200) {
          jQuery("#save-error").hide();
          jQuery("#save-complete").show();
        } else {
          jQuery("#save-complete").hide();
          jQuery("#save-error").show();
        }
      },
      error: function(result) {
        jQuery("#save-complete").hide();
        jQuery("#save-error").show();
      }
    });
  } else {
    jQuery.ajax({
      url: "/ws/schema/table/u_def_ext_person/~(gpv.id)",
      async: false,
      method: "PUT",
      contentType: "application/json",
      data: JSON.stringify({
        "tables":{
          "u_def_ext_person":{
            "myfield1":jQuery("#myfield1").val(),
            "myfield2":jQuery("#myfield2").val()
          }
        }
      }),
      complete: function(xhr, textStatus) {
        if (xhr.status == 200) {
          jQuery("#save-error").hide();
          jQuery("#save-complete").show();
        } else {
          jQuery("#save-complete").hide();
          jQuery("#save-error").show();
        }
      },
      error: function(result) {
        jQuery("#save-complete").hide();
        jQuery("#save-error").show();
      }
    });
  }
}
</script>
<div class="feedback-confirm" id="save-complete" style="display:none;">Record saved</div>
<div class="feedback-error" id="save-error" style="display:none;">There was a problem saving the record, please try again later</div>
<div class="box-round">
  <form action="edit.html" method="POST" id="saveForm">
  <table class="linkDescList">
    <tr>
      <td class="bold" style="width:180px;">My field 1</td>
      <td>
        <input type="text" name="myfield1" id="myfield1" value="">
      </td>
    </tr>
    <tr>
      <td class="bold">My field 2</td>
      <td>
        <input type="text" name="myfield2" id="myfield2" value="">
      </td>
    </tr>
    <tr>
      <td class="bold">Last Updated</td>
      <td>
        <span id="lastupdate"></span>
      </td>
    </tr>
  </table>
  </form>
</div>
<div class="button-row">
  <button type="button" onclick="submitSave()">Save</button>
</div>
Looks like this:


There's also a JSON (edit_extensionfields.json) that gets the existing values into slide in page:

[
~[tlist_sql;
select
myfield1,
myfield2,
nvl(whenmodified,whencreated) as lastupdate
from u_def_ext_person
where
personid = '~(gpv.id)'
;]
  {
    "myfield1":"~(myfield1;json)",
    "myfield2":"~(myfield2;json)",
    "lastupdate":"~(lastupdate;json)"
  },
[/tlist_sql]
  {}
]
And lastly, you'll need to install a plugin that gives permission to the slide in page to make the insert and update API calls (attached).  You'll need to edit the files inside to include your extension tables/fields.

Download: Contact Extension Plugin

Delete Custom Field From PowerSchool

Summary

This article explains how to properly delete a custom field.
  • Note: To avoid data loss, custom fields should only be deleted outside of regular business hours when other users are not editing PowerSchool information. 
  • Note: Deleting a custom field that has data in it can result in unexpected behaviour.  Before deleting it, always clear the custom field of any data (including for non-active students) by using Student Field Value.

Process

  1. Log in to PowerSchool Admin
  2. Select the District Office
  3. Search for all active and inactive students or staff (Search for /)
  4. From the Functions dropdown, select Student Field Value or Staff Field Value
  5. Click the Fields link to select the field you would like to delete, or type it in.
  6. Check Clear Field Value
  7. Click Submit
  8. Confirm the change by clicking Submit at the preview screen.
  9. Start >System > Page and Data Management > Manage Database Extensions
  10. Database table to extend = Students 
  11. Workflow type = Advanced Extension > Next
  12. Select extension name > Next
  13. Select table name > Next
  14. Find Field name and click on delete button then submit
  • Note: Depending on how much data is related to the custom field being deleted, it may only take a few minutes to remove the field, or in larger districts, an hour or more.
  • Note: PowerSchool may need to be restarted for the custom fields to be cleared from the cache.

Removal from Oracle

ATTENTION! If the field still shows in the search field, go delete the record out of FIELDSTABLE from Oracle.

delete from fieldstable where name = 'fieldname';

PowerSchool Customization Tips


Page fragment to add the button:

<script>
  jQuery(document).ready(
function() {
    var url_string = window.location.href;
    console.log(url_string);
    var pStart = url_string.indexOf("contactid=
", url_string.indexOf("#?")) + 10;
    var pEnd = url_string.indexOf("&", pStart);
    var contactID = 0;
    if (pEnd > 0)
      contactID = url_string.substring(pStart, pEnd);
    else
      contactID = url_string.substring(pStart);
    console.log(contactID);
 
    if (contactID != 0) {
      var html = '<div id="extensionfields-div"><
label for="extensionfields-input">Extension Fields</label><a href="edit_extensionfields.html?id='+contactID+'" class="button dialogC dockedDialog" id="extensionfields-input" title="Extension Fields">Display</a></div>';
      jQuery("#suffix-div").after(
html);
    }
  });
</script>

It looks like this:

The slide out page that has the input boxes (edit_extensionfields.html):

<script>
var existing = false;

jQuery.getJSON("edit_
extensionfields.json?id=~(gpv.id)", function(data) {
  if (data.length > 1) {
    jQuery("#myfield1").val(data[
0].myfield1);
    jQuery("#myfield2").val(data[
0].myfield2);
    jQuery("#lastupdate").html(
data[0].lastupdate);
    existing = true;
  }
});

function submitSave() {
  if (!existing) {
    jQuery.ajax({
      url: "/ws/schema/table/u_def_ext_
person",
      async: false,
      method: "POST",
      contentType: "application/json",
      data: JSON.stringify({
        "tables":{
          "u_def_ext_person":{
            "personid":"~(gpv.id)",
            "myfield1":jQuery("#myfield1")
.val(),
            "myfield2":jQuery("#myfield2")
.val()
          }
        }
      }),
      complete: function(xhr, textStatus) {
        if (xhr.status == 200) {
          jQuery("#save-error").hide();
          jQuery("#save-complete").show(
);
        } else {
          jQuery("#save-complete").hide(
);
          jQuery("#save-error").show();
        }
      },
      error: function(result) {
        jQuery("#save-complete").hide(
);
        jQuery("#save-error").show();
      }
    });

  } else {
    jQuery.ajax({
      url: "/ws/schema/table/u_def_ext_
person/~(gpv.id)",
      async: false,
      method: "PUT",
      contentType: "application/json",
      data: JSON.stringify({
        "tables":{
          "u_def_ext_person":{
            "myfield1":jQuery("#myfield1")
.val(),
            "myfield2":jQuery("#myfield2")
.val()
          }
        }
      }),
      complete: function(xhr, textStatus) {
        if (xhr.status == 200) {
          jQuery("#save-error").hide();
          jQuery("#save-complete").show(
);
        } else {
          jQuery("#save-complete").hide(
);
          jQuery("#save-error").show();
        }
      },
      error: function(result) {
        jQuery("#save-complete").hide(
);
        jQuery("#save-error").show();
      }
    });
  }

}
</script>

<div class="feedback-confirm" id="save-complete" style="display:none;">Record saved</div>
<div class="feedback-error" id="save-error" style="display:none;">There was a problem saving the record, please try again later</div>

<div class="box-round">
  <form action="edit.html" method="POST" id="saveForm">
  <table class="linkDescList">
    <tr>
      <td class="bold" style="width:180px;">My field 1</td>
      <td>
        <input type="text" name="myfield1" id="myfield1" value="">
      </td>
    </tr>
    <tr>
      <td class="bold">My field 2</td>
      <td>
        <input type="text" name="myfield2" id="myfield2" value="">
      </td>
    </tr>
    <tr>
      <td class="bold">Last Updated</td>
      <td>
        <span id="lastupdate"></span>
      </td>
    </tr>
  </table>
  </form>
</div>
<div class="button-row">
  <button type="button" onclick="submitSave()">Save</
button>
</div>

Looks like this:

There's also a JSON (edit_extensionfields.json) that gets the existing values into slide in page:

[
~[tlist_sql;
select
myfield1,
myfield2,
nvl(whenmodified,whencreated) as lastupdate

from u_def_ext_person
where
personid = '~(gpv.id)'
;]
  {
    "myfield1":"~(myfield1;json)",
    "myfield2":"~(myfield2;json)",
    "lastupdate":"~(lastupdate;
json)"
  },
[/tlist_sql]
  {}
]

And lastly, you'll need to install a plugin that gives permission to the slide in page to make the insert and update API calls (attached).  You'll need to edit the files inside to include your extension tables/fields.
Download: Contact Extension Plugin

Wednesday, May 9, 2018

VLC Skin Spaceship Air Carrier

There weren't any VLC skins that satisfied me so I created one based on an existing one.  Fell free to use it and make modifications as you feel fit.

Download VLC Skin - Spaceship Air Carrier

Plex Media Server

Implementation: We are using local storage for our Plex media.  Should we ever want to have a separate NAS, consider other options such as FreeNAS.

Ubuntu OS Installation

Install Ubuntu Server 18.04 with only OpenSSH packages

Dependencies
sudo su -
apt-get update; apt-get upgrade -y
apt-get install curl samba cifs-utils
Samba Configuration
mkdir /plex
chmod 777 /plex
vi /etc/samba/smb.conf
workgroup = ssis.edu.vn security = user winds support = yes
dns proxy = no
name resolve order = lmhost host winds bcast
... add to end of file ...
[PLEX Media]
comment = PLEX Media
path = /plex
browseable = yes
read only = no
guest ok = yes

Plex Media Server Installation

Download from https://www.plex.tv/downloads/ and
dpkg -i plexmediaserver_<version>.deb
systemctl enable plexmediaserver
systemctl start plexmediaserver

Start/Stop/Status Services

service plexmediaserver start
service plexmediaserver stop
service plexmediaserver status

Access Plex

On one terminal
ssh user@srvr-uplex.ssis.edu.vn -L 8888:localhost:32400
Then use web browser: http://localhost:8888/web

Network Settings

We disabled https for performance and there is no need for a secure connection since we only allow our internal network to access Plex.

Settings > Server > Network
Reference: https://support.plex.tv/articles/200430283-network/

Secure connections

Choose how your Plex Media Server handles secure connections.

Disabled – Don’t allow Plex apps to connect securely and instead force all communication over regular HTTP.

Advanced Settings

Custom server access URLs

A comma-separated list of URLs (either HTTP or HTTPS), which will be published to plex.tv for server discovery. This can be very useful in a few cases: if you’re using a VPN to get back home, if you’re using a reverse proxy in front of the media server, or if your networking configuration is otherwise unique. For instance, if you have your own custom domain with subdomain, you might add:

http://plex.ssis.edu.vn:32400

List of IP addresses and networks that are allowed without auth

The list of IP addresses or networks that can connect to Plex Media Server without authorization. Enter a comma-separated (no spaces or tabs!) list of IP addresses or specify a range using IP/netmask entries. This can be useful if you have an old, legacy, unsupported app (such as LG’s MediaLink or SmartShare apps) that you wish to use.

172.20.0.0/16,172.16.0.0/16,172.17.0.0/16,172.18.0.0/16